feat: add generated scene skill platform hardening
This commit is contained in:
@@ -0,0 +1,338 @@
|
||||
# Request URL Resolution Design
|
||||
|
||||
**Goal:** Replace the temporary line-loss hardcoded request URL logic in `src/service/server.rs` with a single bootstrap-target resolution path that prefers current page context first, then deterministic submit results, then skill-owned metadata, and only finally falls back to `about:blank`.
|
||||
|
||||
**Status:** Approved design direction for the next slice.
|
||||
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
The current callback-host bootstrap path still derives the first helper-page request URL in `src/service/server.rs`:
|
||||
|
||||
- `initial_request_url_for_submit_task(...)` prefers `request.page_url`
|
||||
- then `derive_request_url_from_instruction(...)`
|
||||
- then falls back to `about:blank`
|
||||
|
||||
This is currently patched with a temporary line-loss branch:
|
||||
|
||||
- if instruction contains `线损` or `lineloss`
|
||||
- return `http://20.76.57.61:18080`
|
||||
|
||||
That temporary branch is the wrong ownership boundary:
|
||||
|
||||
1. service code is guessing scene intent from raw instruction text
|
||||
2. deterministic submit already has a structured execution plan with `target_url`
|
||||
3. future direct-submit skills may also need a bootstrap URL, but should not require new Rust hardcoded branches every time
|
||||
|
||||
The result is duplicated routing knowledge and brittle request URL derivation.
|
||||
|
||||
---
|
||||
|
||||
## Decision Summary
|
||||
|
||||
1. Introduce one sgClaw-owned bootstrap target resolver for service submit bootstrap.
|
||||
2. Resolution order is:
|
||||
- explicit `request.page_url`
|
||||
- deterministic submit execution plan
|
||||
- skill metadata fallback
|
||||
- `about:blank`
|
||||
3. Deterministic submit is the primary source of truth for deterministic scenes such as line loss.
|
||||
4. Skill metadata provides the compatibility fallback for direct browser-script skills that do not have a deterministic plan.
|
||||
5. Remove the current line-loss text-match hardcode from `src/service/server.rs` once the resolver is in place.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Architecture
|
||||
|
||||
### 1. Add a dedicated bootstrap-target result type
|
||||
|
||||
Introduce a small sgClaw-side result type dedicated to callback-host bootstrap only.
|
||||
|
||||
Recommended shape:
|
||||
|
||||
```rust
|
||||
pub struct SubmitBootstrapTarget {
|
||||
pub request_url: String,
|
||||
pub expected_domain: Option<String>,
|
||||
pub source: BootstrapTargetSource,
|
||||
}
|
||||
|
||||
pub enum BootstrapTargetSource {
|
||||
PageContext,
|
||||
DeterministicPlan,
|
||||
SkillConfig,
|
||||
Fallback,
|
||||
}
|
||||
```
|
||||
|
||||
This type should remain intentionally small.
|
||||
|
||||
It is **not** a generic execution-plan object. Its only job is to answer:
|
||||
- what URL should the helper page bootstrap against on first submit?
|
||||
- where did that value come from?
|
||||
|
||||
Keeping this object narrow avoids coupling callback-host bootstrap to unrelated execution details.
|
||||
|
||||
---
|
||||
|
||||
### 2. Move URL derivation into one resolver
|
||||
|
||||
Replace the current `initial_request_url_for_submit_task(...)` branching with a single resolver, conceptually:
|
||||
|
||||
1. If `SubmitTaskRequest.page_url` exists and is non-empty, use it.
|
||||
2. Else attempt deterministic parsing through `decide_deterministic_submit(...)`.
|
||||
- If it returns `Execute(plan)`, use `plan.target_url`.
|
||||
3. Else inspect configured direct-submit skill metadata.
|
||||
- If metadata exposes a bootstrap URL, use it.
|
||||
4. Else return `about:blank`.
|
||||
|
||||
This keeps service bootstrap logic declarative and removes scene-specific guessing from `server.rs`.
|
||||
|
||||
---
|
||||
|
||||
### 3. Deterministic submit becomes the primary truth for line loss
|
||||
|
||||
`src/compat/deterministic_submit.rs` already contains structured line-loss routing data:
|
||||
|
||||
- `DeterministicExecutionPlan.expected_domain`
|
||||
- `DeterministicExecutionPlan.target_url`
|
||||
|
||||
For line-loss requests, service bootstrap should use `plan.target_url` rather than reconstructing or hardcoding a URL in `server.rs`.
|
||||
|
||||
That means the current temporary branch:
|
||||
|
||||
```rust
|
||||
if instruction.contains("线损") || instruction.contains("lineloss") {
|
||||
return Some("http://20.76.57.61:18080".to_string());
|
||||
}
|
||||
```
|
||||
|
||||
should disappear entirely after the resolver is introduced.
|
||||
|
||||
This is the cleanest fix because the deterministic parser already owns the scene contract.
|
||||
|
||||
---
|
||||
|
||||
### 4. Skill metadata is the fallback, not the primary owner
|
||||
|
||||
For non-deterministic direct browser-script skills, service may still need a bootstrap URL even when there is no page context.
|
||||
|
||||
The fallback should come from skill-owned metadata with minimal fields:
|
||||
|
||||
- `bootstrap_url`
|
||||
- `expected_domain`
|
||||
|
||||
Recommended semantics:
|
||||
|
||||
- `bootstrap_url`: the page URL service should use when opening the helper/bootstrap context
|
||||
- `expected_domain`: the hostname direct runtime can use when page context is absent
|
||||
|
||||
This metadata should only be consulted **after** page context and deterministic parsing fail.
|
||||
|
||||
That preserves the user-selected policy:
|
||||
- deterministic plan first
|
||||
- skill metadata second
|
||||
|
||||
It also avoids forcing deterministic scenes to duplicate already-structured routing data in skill config.
|
||||
|
||||
---
|
||||
|
||||
## Ownership Boundary
|
||||
|
||||
### sgClaw owns bootstrap resolution policy
|
||||
|
||||
sgClaw should own the policy and precedence order for request URL resolution.
|
||||
|
||||
That includes:
|
||||
- checking current page context first
|
||||
- deciding when deterministic parsing is authoritative
|
||||
- deciding when skill metadata is an allowed fallback
|
||||
- falling back to `about:blank` when nothing else resolves
|
||||
|
||||
This policy belongs in sgClaw because it is part of submit-path orchestration, not part of an individual skill script.
|
||||
|
||||
### deterministic submit owns deterministic scene targets
|
||||
|
||||
If a scene already resolves to `DeterministicExecutionPlan`, then that plan owns:
|
||||
- the authoritative `target_url`
|
||||
- the authoritative `expected_domain`
|
||||
|
||||
Service should consume that plan rather than re-deriving equivalent information from raw text.
|
||||
|
||||
### skill metadata owns direct-skill bootstrap hints
|
||||
|
||||
When there is no deterministic plan, the skill package may own the minimal hints needed for bootstrap compatibility:
|
||||
- `bootstrap_url`
|
||||
- `expected_domain`
|
||||
|
||||
The skill should not own resolution precedence. It only provides data for the fallback tier.
|
||||
|
||||
---
|
||||
|
||||
## File-Level Design
|
||||
|
||||
### `src/service/server.rs`
|
||||
|
||||
Change responsibilities here from “derive request URL by ad hoc branch logic” to “ask the resolver for a bootstrap target”.
|
||||
|
||||
Expected changes:
|
||||
- replace `initial_request_url_for_submit_task(...)` logic with a call into a resolver
|
||||
- delete `derive_request_url_from_instruction(...)` or reduce it to thin legacy glue during migration
|
||||
- remove the line-loss text-match hardcode entirely
|
||||
- keep callback-host startup logic unchanged apart from where `bootstrap_url` comes from
|
||||
|
||||
### `src/compat/deterministic_submit.rs`
|
||||
|
||||
No routing policy should move into service from this module.
|
||||
|
||||
Expected role in the new design:
|
||||
- continue producing `DeterministicExecutionPlan`
|
||||
- expose enough information for service bootstrap resolution to reuse `plan.target_url`
|
||||
- remain the source of truth for deterministic line-loss target selection
|
||||
|
||||
### `src/compat/direct_skill_runtime.rs`
|
||||
|
||||
This module currently resolves skill tool execution and derives `expected_domain` from task context.
|
||||
|
||||
For this slice, it does **not** need a full behavior rewrite.
|
||||
|
||||
Expected role:
|
||||
- add or expose a helper for reading direct skill metadata if service needs it
|
||||
- keep runtime execution behavior stable unless required by the new metadata seam
|
||||
|
||||
A later slice may allow runtime execution to use skill-owned `expected_domain` fallback too, but that is not required to land this service TODO.
|
||||
|
||||
### `src/config/settings.rs`
|
||||
|
||||
If sgClaw configuration needs to point to direct-skill metadata or enable fallback behavior explicitly, add the minimum structure here.
|
||||
|
||||
However, this slice should avoid creating a second parallel source of target URLs inside sgClaw config if the same information can be read from skill metadata.
|
||||
|
||||
The key rule is:
|
||||
- do not replace one hardcode with a different hardcoded config map inside `settings.rs`
|
||||
|
||||
### Skill metadata loading seam
|
||||
|
||||
The design assumes a small read path that can answer:
|
||||
- for the configured direct-submit skill, is there a `bootstrap_url`?
|
||||
- is there an `expected_domain`?
|
||||
|
||||
The exact storage location can follow the existing staged-skill packaging model, but the new metadata should remain minimal and execution-adjacent rather than introducing a new wide dispatch schema.
|
||||
|
||||
---
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Current desired flow
|
||||
|
||||
1. service receives `ClientMessage::SubmitTask`
|
||||
2. service converts it to `SubmitTaskRequest`
|
||||
3. service resolves `SubmitBootstrapTarget`
|
||||
4. service passes `SubmitBootstrapTarget.request_url` into `LiveBrowserCallbackHost::start_with_browser_ws_url(...)`
|
||||
5. callback-host bootstraps helper page using that URL
|
||||
6. remaining task execution continues unchanged
|
||||
|
||||
### Resolution behavior examples
|
||||
|
||||
#### Case A: page context exists
|
||||
- request includes `page_url=https://www.zhihu.com`
|
||||
- resolver returns `PageContext`
|
||||
- service uses that URL directly
|
||||
|
||||
#### Case B: line-loss deterministic request, no page context
|
||||
- request has no `page_url`
|
||||
- deterministic parser returns `Execute(plan)`
|
||||
- resolver returns `DeterministicPlan` with `request_url=plan.target_url`
|
||||
- service uses line-loss target URL from the plan
|
||||
|
||||
#### Case C: direct-submit skill with configured bootstrap URL, no page context, not deterministic
|
||||
- request has no `page_url`
|
||||
- deterministic parser returns `NotDeterministic`
|
||||
- configured direct skill metadata exposes `bootstrap_url`
|
||||
- resolver returns `SkillConfig`
|
||||
|
||||
#### Case D: nothing resolves
|
||||
- no page context
|
||||
- no deterministic plan
|
||||
- no skill metadata bootstrap URL
|
||||
- resolver returns `Fallback` with `about:blank`
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Resolver-focused tests
|
||||
|
||||
Add focused tests covering precedence:
|
||||
|
||||
1. `page_url` wins over everything else
|
||||
2. deterministic line-loss `Execute(plan)` wins when `page_url` is absent
|
||||
3. skill metadata fallback is used only when no deterministic plan exists
|
||||
4. `about:blank` remains the terminal fallback
|
||||
|
||||
### Regression coverage for the removed TODO
|
||||
|
||||
Add a regression proving that the service no longer depends on:
|
||||
- `instruction.contains("线损")`
|
||||
- `instruction.contains("lineloss")`
|
||||
|
||||
The line-loss bootstrap URL should now come from the deterministic plan only.
|
||||
|
||||
### Direct skill fallback tests
|
||||
|
||||
Add tests for:
|
||||
- configured skill metadata with valid `bootstrap_url`
|
||||
- missing `bootstrap_url`
|
||||
- malformed `bootstrap_url`
|
||||
- mismatch between metadata and current page context precedence
|
||||
|
||||
Malformed `bootstrap_url` metadata should be treated as unusable fallback data rather than a hard error for service bootstrap resolution:
|
||||
- if page context exists, page context still wins
|
||||
- if deterministic plan exists, deterministic plan still wins
|
||||
- if malformed metadata is the only candidate, resolver should ignore it and fall through to `about:blank`
|
||||
|
||||
### Existing callback-host tests remain stable
|
||||
|
||||
Do not redesign callback-host behavior in this slice.
|
||||
|
||||
The callback-host tests should only need enough updates to reflect the new bootstrap URL source, not a new helper lifecycle contract.
|
||||
|
||||
---
|
||||
|
||||
## Migration Plan Shape
|
||||
|
||||
Recommended implementation order:
|
||||
|
||||
1. Introduce the bootstrap-target resolver and narrow result type.
|
||||
2. Wire deterministic line-loss resolution into it using `DeterministicExecutionPlan.target_url`.
|
||||
3. Remove the temporary line-loss hardcode from `server.rs`.
|
||||
4. Add skill metadata fallback for configured direct-submit skills.
|
||||
5. Expand tests to lock precedence and fallback behavior.
|
||||
|
||||
This order lands the TODO removal early without forcing the full fallback design to be implemented blindly first.
|
||||
|
||||
---
|
||||
|
||||
## Explicit Non-Goals
|
||||
|
||||
This slice does **not**:
|
||||
- redesign callback-host lifecycle
|
||||
- redesign deterministic scene parsing
|
||||
- redesign direct-submit routing ownership
|
||||
- introduce a broad scene registry for request URL derivation
|
||||
- change browser command protocol
|
||||
- rewrite direct skill execution behavior beyond what is needed for metadata lookup
|
||||
- replace all current uses of page context with skill metadata
|
||||
|
||||
---
|
||||
|
||||
## Design Rule
|
||||
|
||||
For service bootstrap request URL resolution:
|
||||
|
||||
- current page context stays first
|
||||
- deterministic execution plans are the authoritative source for deterministic scenes
|
||||
- skill metadata provides a narrow fallback for non-deterministic direct skills
|
||||
- `about:blank` remains the final fallback
|
||||
- `src/service/server.rs` must not contain scene-specific text-match hardcodes such as the current line-loss TODO
|
||||
Reference in New Issue
Block a user