feat: route staged scene skills through runtime

Add registry-driven scene routing and multi-root skill loading so fault-details and 95598 scene skills can be triggered from natural language while still running through the browser-backed runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
木炎
2026-04-07 16:17:17 +08:00
parent bdf8e12246
commit 96c3bf1dee
21 changed files with 2846 additions and 240 deletions

View File

@@ -0,0 +1,455 @@
# Scene Skill Runtime Routing Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add a first scene-routing slice that recognizes staged business scenes from natural language and dispatches them through browser-backed execution, with `fault-details-report` using direct browser execution and `95598-repair-city-dispatch` using agent-mediated browser execution.
**Architecture:** Introduce a small registry module that loads the first staged `scene.json` contracts plus runtime dispatch policy from the external `skill_staging` root. Route matched scenes through one of two paths: `direct_browser` scenes execute through compat orchestration without the model choosing tools, while `agent_browser` scenes stay in the existing agent flow but get scene-specific browser-first prompt injection. Both modes must still execute through the existing `BrowserScriptSkillTool` / browser backend path so the final business action uses browser-internal methods.
**Tech Stack:** Rust, serde/JSON metadata loading, existing compat orchestration/runtime/workflow layers, browser-backed skill tools, focused `cargo test` coverage.
---
## File Map
**Create:**
- `src/runtime/scene_registry.rs` — load staged scene metadata, attach runtime dispatch policy, expose matching helpers for the first slice.
- `tests/scene_registry_test.rs` — focused tests for registry loading, matching, and policy behavior.
**Modify:**
- `src/runtime/mod.rs` — export the new scene registry module/types used by runtime and compat layers.
- `src/compat/config_adapter.rs` — verify the moved external `skill_staging` root resolves to the staged `skills` child, and only change path resolution if a targeted regression proves it is insufficient.
- `src/runtime/engine.rs` — inject scene-specific browser-first contracts for `agent_browser` scenes and keep existing Zhihu prompt behavior intact.
- `src/compat/workflow_executor.rs` — extend route detection and direct execution support for `fault-details-report` using the browser-backed skill path.
- `src/compat/orchestration.rs` — let primary orchestration prefer direct execution for `direct_browser` scenes while leaving `agent_browser` scenes in the agent path.
- `src/compat/browser_script_skill_tool.rs` — expose the thinnest reusable browser-backed execution helper needed so direct scene execution can reuse the same `browser_script` semantics instead of drifting into a duplicate local path.
- `src/compat/runtime.rs` — ensure runtime sees the staged skills root and continues exposing browser-backed scene tools.
- `tests/compat_config_test.rs` — add path-resolution coverage for the staged external root.
- `tests/runtime_profile_test.rs` — add scene-specific instruction contract assertions.
- `tests/browser_script_skill_tool_test.rs` — add coverage for any new reusable direct-execution helper introduced in the browser-script layer.
- `tests/compat_runtime_test.rs` — add orchestration/direct-route coverage for the new scene behavior.
**Reference:**
- `docs/superpowers/specs/2026-04-06-scene-skill-runtime-routing-design.md`
- `D:\data\ideaSpace\rust\sgClaw\claw\claw\skills\skill_staging\scenes\fault-details-report\scene.json`
- `D:\data\ideaSpace\rust\sgClaw\claw\claw\skills\skill_staging\scenes\95598-repair-city-dispatch\scene.json`
- `D:\data\ideaSpace\rust\sgClaw\claw\claw\skills\skill_staging\skills\fault-details-report\SKILL.toml`
- `D:\data\ideaSpace\rust\sgClaw\claw\claw\skills\skill_staging\skills\95598-repair-city-dispatch\SKILL.toml`
### Task 1: Add Scene Registry And Matching
**Files:**
- Create: `src/runtime/scene_registry.rs`
- Modify: `src/runtime/mod.rs`
- Test: `tests/scene_registry_test.rs`
- [ ] **Step 1: Write the failing registry tests**
Add tests that prove the first-slice registry can:
- load `fault-details-report` with `dispatch_mode = direct_browser`
- load `95598-repair-city-dispatch` with `dispatch_mode = agent_browser`
- match natural-language phrases like `导出故障明细` and `95598抢修市指监测`
- ignore missing/broken scene files without panicking
Example assertions to include:
```rust
assert_eq!(entry.scene_id, "fault-details-report");
assert_eq!(entry.dispatch_mode, DispatchMode::DirectBrowser);
assert_eq!(entry.tool_name(), "fault-details-report.collect_fault_details");
assert_eq!(entry.expected_domain, "__scene_fault_details__");
```
```rust
assert_eq!(matched.scene_id, "95598-repair-city-dispatch");
assert_eq!(matched.dispatch_mode, DispatchMode::AgentBrowser);
```
- [ ] **Step 2: Run the new registry tests to verify they fail**
Run:
```bash
cargo test scene_registry --test scene_registry_test -- --nocapture
```
Expected: FAIL because `src/runtime/scene_registry.rs` and the exported registry APIs do not exist yet.
- [ ] **Step 3: Implement the minimal scene registry module**
Create `src/runtime/scene_registry.rs` with:
- a small deserialized scene metadata struct for `scene.json`
- a `DispatchMode` enum
- a single runtime registry-entry struct combining scene metadata plus runtime policy
- first-slice hardcoded runtime policy for the two initial scenes
- helper methods like:
```rust
pub fn load_first_slice_scene_registry() -> Vec<SceneRegistryEntry>
pub fn match_scene_instruction(instruction: &str) -> Option<SceneRegistryEntry>
```
Use deterministic keyword/alias matching only. Do not add embeddings, fuzzy search, or generic scoring infrastructure beyond what the spec requires.
- [ ] **Step 4: Export the registry from `src/runtime/mod.rs`**
Expose the new types/helpers needed by runtime and compat layers, for example:
```rust
mod scene_registry;
pub use scene_registry::{
load_first_slice_scene_registry,
match_scene_instruction,
DispatchMode,
SceneRegistryEntry,
};
```
- [ ] **Step 5: Run the registry tests to verify they pass**
Run:
```bash
cargo test scene_registry --test scene_registry_test -- --nocapture
```
Expected: PASS
- [ ] **Step 6: Commit Task 1**
```bash
git add src/runtime/scene_registry.rs src/runtime/mod.rs tests/scene_registry_test.rs
git commit -m "feat: add staged scene registry matching"
```
### Task 2: Verify Staged Skills Root Resolution
**Files:**
- Modify if needed: `src/compat/config_adapter.rs:94`
- Modify if needed: `src/compat/runtime.rs:152`
- Test: `tests/compat_config_test.rs`
- [ ] **Step 1: Write the targeted staged-root path test**
Add a focused test that proves an external configured `skill_staging` root resolves to its `skills` child and preserves current nested-skills behavior.
Add a test shape like:
```rust
let staged_root = root.join("external/skill_staging");
fs::create_dir_all(staged_root.join("skills")).unwrap();
fs::create_dir_all(staged_root.join("scenes")).unwrap();
let settings = DeepSeekSettings {
api_key: "key".to_string(),
base_url: "https://api.deepseek.com".to_string(),
model: "deepseek-chat".to_string(),
skills_dir: Some(staged_root.clone()),
};
assert_eq!(resolve_skills_dir(&root, &settings), staged_root.join("skills"));
```
- [ ] **Step 2: Run the focused config test and record the actual result**
Run:
```bash
cargo test --test compat_config_test resolve_skills_dir_ -- --nocapture
```
Expected: either
- PASS immediately, proving current path resolution already supports the staged-root contract, or
- FAIL with a concrete staged-root regression that justifies a minimal config fix.
- [ ] **Step 3: Only if the staged-root test fails, implement the narrowest config fix**
If the test fails, update `src/compat/config_adapter.rs` so configured external staged roots resolve to the staged skill package directory used by runtime skill loading. Keep the change narrow:
- preserve current behavior for normal `skills` roots
- add the smallest extra branch needed for the failing staged-root case
- do not create a broad path-discovery system
- [ ] **Step 4: Verify runtime alignment with the resolved staged skills root**
Confirm `src/compat/runtime.rs` still uses the resolved `skills_dir` as-is. If no runtime code change is needed after the test outcome, leave the file untouched and rely on test coverage.
- [ ] **Step 5: Run the focused config tests to verify they pass**
Run:
```bash
cargo test --test compat_config_test resolve_skills_dir_ -- --nocapture
```
Expected: PASS
- [ ] **Step 6: Commit Task 2**
```bash
git add src/compat/config_adapter.rs src/compat/runtime.rs tests/compat_config_test.rs
git commit -m "test: verify staged scene skill root resolution"
```
### Task 3: Inject Agent-Browser Scene Contract For 95598
**Files:**
- Modify: `src/runtime/engine.rs:135`
- Test: `tests/runtime_profile_test.rs`
- [ ] **Step 1: Write the failing instruction-contract tests**
Add focused tests proving that when the instruction matches `95598-repair-city-dispatch`, `RuntimeEngine::build_instruction(...)` includes a scene-specific browser contract requiring the tool `95598-repair-city-dispatch.collect_repair_orders` first.
Example assertion pattern:
```rust
let instruction = engine.build_instruction(
"请做95598抢修市指监测",
Some("https://example.invalid/dispatch"),
Some("95598抢修-市指"),
true,
);
assert!(instruction.contains("95598-repair-city-dispatch.collect_repair_orders"));
assert!(instruction.contains("browser workflow, not a text-only task"));
assert!(instruction.contains("generic browser probing only after"));
```
Also add a negative control showing unrelated tasks do not receive this scene contract.
- [ ] **Step 2: Run the focused runtime-profile tests to verify they fail**
Run:
```bash
cargo test --test runtime_profile_test 95598 -- --nocapture
```
Expected: FAIL because no scene-specific contract is injected yet.
- [ ] **Step 3: Implement minimal scene-aware prompt injection**
Update `src/runtime/engine.rs` to:
- query the new scene matcher
- when the matched scene is `agent_browser`, append a scene execution contract section
- preserve existing Zhihu prompt sections unchanged
Keep the contract explicit and narrow, for example:
```text
Scene execution contract:
- Matched scene: 95598-repair-city-dispatch
- Required tool: 95598-repair-city-dispatch.collect_repair_orders
- This is a browser workflow, not a text-only task.
- Business data must come from the matched browser-backed scene tool.
- Only use generic browser probing after the matched scene tool fails.
```
Do not add hard allowed-tool narrowing in this task; slice one only promises instruction-level enforcement.
- [ ] **Step 4: Run the focused runtime-profile tests to verify they pass**
Run:
```bash
cargo test --test runtime_profile_test 95598 -- --nocapture
```
Expected: PASS
- [ ] **Step 5: Commit Task 3**
```bash
git add src/runtime/engine.rs tests/runtime_profile_test.rs
git commit -m "feat: inject 95598 scene browser contract"
```
### Task 4: Add Direct Browser Route For Fault Details
**Files:**
- Modify: `src/compat/workflow_executor.rs:58`
- Modify: `src/compat/orchestration.rs:9`
- Modify: `src/compat/browser_script_skill_tool.rs:101`
- Test: `tests/browser_script_skill_tool_test.rs`
- Test: `tests/compat_runtime_test.rs`
- [ ] **Step 1: Write the failing route-detection tests**
Add focused tests that prove:
- natural language like `导出故障明细` is detected as a direct scene route
- primary orchestration is selected for that scene
- missing scene metadata leaves unrelated routing unchanged
Target the existing routing seams with test shapes like:
```rust
assert!(sgclaw::compat::orchestration::should_use_primary_orchestration(
"导出故障明细",
Some("https://example.invalid/fault"),
Some("故障明细"),
));
```
and a focused route assertion using the new route enum variant.
- [ ] **Step 2: Run the focused route tests to verify they fail**
Run:
```bash
cargo test --test compat_runtime_test fault_details -- --nocapture
```
Expected: FAIL because no direct scene route exists yet.
- [ ] **Step 3: Write the failing browser-script helper tests**
Add focused tests in `tests/browser_script_skill_tool_test.rs` for the thinnest reusable helper needed by direct scene execution. The tests should prove that the helper:
- reads the packaged script from the skill root
- wraps args exactly like `BrowserScriptSkillTool`
- invokes browser `Eval`
- returns normalized serialized output
- fails clearly when required fields like `expected_domain` are missing
- [ ] **Step 4: Run the focused browser-script helper tests to verify they fail**
Run:
```bash
cargo test --test browser_script_skill_tool_test -- --nocapture
```
Expected: FAIL because the reusable helper does not exist yet.
- [ ] **Step 5: Implement the reusable browser-backed execution helper**
Update `src/compat/browser_script_skill_tool.rs` with the smallest reusable helper that direct scene execution can call while preserving the same `browser_script` semantics as normal skill execution. Keep it narrow:
- reuse the same script loading and wrapping rules
- require explicit `expected_domain`
- return normalized serialized output
- do not introduce a second browser-script execution model
- [ ] **Step 6: Implement the direct fault-details route on top of that helper**
Update `src/compat/workflow_executor.rs` to:
- introduce a new direct route variant for `fault-details-report`
- extend `detect_route(...)` to return it when the scene matcher says `direct_browser`
- build required args from scene runtime policy
- call the reusable browser-script execution helper
- return normalized serialized tool output
If required scene args cannot be derived safely, return a clear failure instead of guessing.
- [ ] **Step 7: Wire primary orchestration to prefer the new direct scene route**
Update `src/compat/orchestration.rs` so `should_use_primary_orchestration(...)` and the direct execution branch treat the new `fault-details-report` route like the existing direct Zhihu routes.
- [ ] **Step 8: Run the focused direct-route and helper tests to verify they pass**
Run:
```bash
cargo test --test browser_script_skill_tool_test -- --nocapture && cargo test --test compat_runtime_test fault_details -- --nocapture
```
Expected: PASS
- [ ] **Step 9: Commit Task 4**
```bash
git add src/compat/browser_script_skill_tool.rs src/compat/workflow_executor.rs src/compat/orchestration.rs tests/browser_script_skill_tool_test.rs tests/compat_runtime_test.rs
git commit -m "feat: add direct fault-details scene routing"
```
### Task 5: Verify Tool Exposure, Browser-Surface Fallback, And Mixed Routing Together
**Files:**
- Modify if needed: `src/compat/runtime.rs:142`
- Test: `tests/compat_runtime_test.rs`
- Test: `tests/runtime_profile_test.rs`
- Test: `tests/scene_registry_test.rs`
- [ ] **Step 1: Write the failing integration-shape tests**
Add focused assertions that prove the mixed-mode design works together:
- staged browser-backed tool names are exposed
- `fault-details-report` uses direct routing
- `95598-repair-city-dispatch` stays in the agent path but gets scene-specific browser-first instruction injection
- browser-surface-disabled turns do not gain scene browser contracts
- browser-surface-disabled turns do not trigger `direct_browser` scene execution
- missing scene metadata preserves unchanged runtime behavior for unrelated tasks
- unrelated Zhihu behavior still works the same way
Use existing test seams instead of broad integration scaffolding.
- [ ] **Step 2: Run the focused mixed-routing tests to verify they fail**
Run:
```bash
cargo test --test scene_registry_test -- --nocapture && cargo test --test compat_runtime_test scene_ -- --nocapture && cargo test --test runtime_profile_test scene_ -- --nocapture
```
Expected: FAIL until the mixed-routing assertions are implemented.
- [ ] **Step 3: Make the minimum runtime adjustments needed**
Only if required by the tests, adjust `src/compat/runtime.rs` so the loaded staged skills from the resolved external root are visible in the same way as existing browser-backed skills. Keep the shape of `build_browser_script_skill_tools(...)` and runtime tool assembly intact.
- [ ] **Step 4: Run the focused mixed-routing tests to verify they pass**
Run:
```bash
cargo test --test scene_registry_test -- --nocapture && cargo test --test compat_runtime_test scene_ -- --nocapture && cargo test --test runtime_profile_test scene_ -- --nocapture
```
Expected: PASS
- [ ] **Step 5: Run the broader targeted verification sweep**
Run:
```bash
cargo test --test browser_script_skill_tool_test -- --nocapture && cargo test --test scene_registry_test -- --nocapture && cargo test --test compat_config_test resolve_skills_dir_ -- --nocapture && cargo test --test runtime_profile_test -- --nocapture && cargo test --test compat_runtime_test fault_details -- --nocapture
```
Expected: PASS
- [ ] **Step 6: Commit Task 5**
```bash
git add src/compat/runtime.rs tests/scene_registry_test.rs tests/compat_runtime_test.rs tests/runtime_profile_test.rs
git commit -m "feat: wire staged scene mixed routing"
```
### Task 6: Final Verification And Handoff
**Files:**
- Verify: `src/runtime/scene_registry.rs`
- Verify: `src/compat/config_adapter.rs`
- Verify: `src/runtime/engine.rs`
- Verify: `src/compat/workflow_executor.rs`
- Verify: `src/compat/orchestration.rs`
- Verify: `tests/scene_registry_test.rs`
- Verify: `tests/compat_config_test.rs`
- Verify: `tests/runtime_profile_test.rs`
- Verify: `tests/compat_runtime_test.rs`
- [ ] **Step 1: Run the full focused verification set**
Run:
```bash
cargo test --test scene_registry_test -- --nocapture && cargo test --test compat_config_test -- --nocapture && cargo test --test runtime_profile_test -- --nocapture && cargo test --test compat_runtime_test -- --nocapture
```
Expected: PASS
- [ ] **Step 2: If any test fails, fix only the minimal root cause and re-run the same command**
Do not broaden scope. Keep fixes limited to scene registry, path resolution, prompt injection, or direct routing.
- [ ] **Step 3: Review the resulting diff against the spec**
Manually verify:
- `fault-details-report` is direct-browser
- `95598-repair-city-dispatch` is agent-browser
- both still use browser-backed execution semantics
- no broad Zhihu refactor slipped in
- the new scene-routing abstraction stays registry-driven
- [ ] **Step 4: Commit the final verification pass**
```bash
git add src/runtime/scene_registry.rs src/runtime/mod.rs src/compat/config_adapter.rs src/runtime/engine.rs src/compat/workflow_executor.rs src/compat/orchestration.rs src/compat/runtime.rs tests/scene_registry_test.rs tests/compat_config_test.rs tests/runtime_profile_test.rs tests/compat_runtime_test.rs
git commit -m "test: verify scene skill runtime routing"
```

View File

@@ -0,0 +1,291 @@
# Scene Skill Runtime Routing Design
**Goal:** Add a minimal, extensible scene-routing layer so staged business scenes can be triggered from natural language while still executing through the existing browser-backed skill path.
**Architecture:** Introduce a registry-driven scene contract loader that reads staged `scene.json` metadata, matches user instructions to a scene, and chooses one of two dispatch modes: direct browser execution or agent-mediated browser execution. Both modes must reuse the same browser-backed skill tool path so scene skills continue to execute through browser-internal methods rather than text-only responses or local fake execution.
**Tech Stack:** Rust, serde/JSON scene metadata loading, existing `BrowserScriptSkillTool`, existing compat runtime / runtime engine / workflow executor layers, focused Rust unit tests.
---
## Problem Statement
The codebase already supports two useful but separate ideas:
1. **Zhihu special-case runtime routing**
- `src/compat/workflow_executor.rs` detects a narrow set of Zhihu tasks and can execute them directly without relying on the model to choose tools.
- This is stable, but not extensible for a growing set of business scenes.
2. **Browser-backed skills**
- `src/compat/runtime.rs` loads skills and exposes `browser_script` tools through `BrowserScriptSkillTool`.
- `src/compat/browser_script_skill_tool.rs` executes those tools by calling the browser backend with `Action::Eval`, so actual execution already happens through browser-internal methods.
- This is extensible, but tool choice currently depends too heavily on generic agent behavior.
The staged business scenes under `D:\data\ideaSpace\rust\sgClaw\claw\claw\skills\skill_staging` already provide most of the metadata needed to bridge these two ideas. We need a first integration slice that uses scene metadata to improve routing without turning every scene into a hardcoded Zhihu-style exception.
## Design Goals
- Support natural-language triggering for staged scenes.
- Preserve the current browser-backed execution contract: both scene modes must end in browser-internal execution via the existing browser tool path.
- Support both dispatch styles discussed with the user:
- one scene that can execute without the model
- one scene that still uses the model for orchestration
- Keep the first slice small, covering only:
- `fault-details-report`
- `95598-repair-city-dispatch`
- Keep the design extensible so more scene skills can be added in the same directory later without more ad hoc routing branches.
- Avoid broad refactors or a new generic workflow platform in this slice.
## Non-Goals
- Do not build a scene editor, scene UI, or registry authoring workflow.
- Do not implement a full artifact post-processing platform for all report/monitor types.
- Do not convert every staged scene into a direct Rust executor.
- Do not replace the existing Zhihu-specific runtime path in this slice.
## Source of Truth and Paths
### Staged scene source
The new staged scene source for this work is:
- `D:\data\ideaSpace\rust\sgClaw\claw\claw\skills\skill_staging`
The runtime integration must read scene metadata from this location for the initial slice.
### Existing runtime integration points
- `src/compat/config_adapter.rs` — current skills-dir resolution logic
- `src/compat/runtime.rs` — current skill loading and browser-script tool exposure
- `src/runtime/engine.rs` — runtime instruction building and allowed-tool shaping
- `src/compat/workflow_executor.rs` — existing direct execution routing pattern
- `src/compat/browser_script_skill_tool.rs` — browser-backed execution path for `browser_script` tools
## Scene Contract Model
Introduce a small internal scene contract model derived from `scene.json` and paired runtime policy. The loader should extract only the fields needed for the first slice:
- `id`
- `name`
- `summary`
- `tags`
- `inputs`
- `outputs`
- `skill.package`
- `skill.tool`
- `skill.artifact_type`
Add a runtime-only dispatch policy associated with each enabled scene inside the same internal registry entry used at runtime:
- `dispatch_mode`
- `direct_browser`
- `agent_browser`
- `expected_domain`
- bare hostname required by the underlying browser-backed skill tool
- optional `aliases`
- additional deterministic keywords/phrases when `id/name/summary/tags` are not enough for first-slice matching
- optional `default_args`
- runtime-supplied tool arguments when a scene needs fixed/default values for first execution
This runtime policy may be hardcoded in Rust for the first slice, but it must be represented through one consistent scene-routing abstraction so future scenes can join the same path without rewriting the whole design. The abstraction should be a single registry entry type that combines scene metadata with runtime dispatch policy, rather than a metadata loader plus a separate ad hoc match table.
## Dispatch Modes
### 1. `direct_browser`
This mode is for scenes whose collection flow is deterministic enough to bypass the model once the scene is recognized.
**Initial scene:** `fault-details-report`
**Behavior:**
- Detect scene from natural language.
- Resolve the corresponding browser-backed skill tool.
- Execute it directly through the existing browser-backed skill path.
- Return the collected artifact result without delegating tool choice to the model.
**Important constraint:**
This is not a local fake implementation. Even in direct mode, the actual collection must still go through the existing browser-backed execution path, meaning it ultimately uses browser-internal methods through the browser backend.
### 2. `agent_browser`
This mode is for scenes that still benefit from agent orchestration, explanation, or downstream reasoning, but whose business data must still come from browser-backed execution.
**Initial scene:** `95598-repair-city-dispatch`
**Behavior:**
- Detect scene from natural language.
- Inject a strong scene execution contract into the runtime instruction.
- Treat calling the matching browser-backed skill tool first as a policy requirement for the scene.
- In slice one, enforce that policy through scene-specific instruction injection rather than a hard runtime gate.
- Allow generic browser probing only as a fallback after the scene tool fails.
- Keep final explanation/summarization in the agent path, but never let the model invent business data.
## Matching Strategy
Implement a minimal matcher that scores user instructions against enabled scenes using:
- scene `id`
- scene `name`
- scene `summary`
- scene `tags`
- optional runtime aliases for the first slice
The matcher should be intentionally simple and deterministic in this slice. Avoid semantic embedding or fuzzy retrieval infrastructure.
Expected first-slice matches:
- `fault-details-report`
- phrases like `故障明细`, `故障明细报表`, `导出故障明细`
- `95598-repair-city-dispatch`
- phrases like `95598抢修市指`, `市指抢修监测`, `95598抢修队列`
If no scene matches, runtime behavior must remain unchanged.
## Runtime Loading Design
### Scene registry loading
Add a small loader that reads enabled scenes from the staged scene directory. For the first slice, it is acceptable to read the concrete scene files directly instead of implementing a full generic registry parser, as long as the resulting module boundary is registry-oriented rather than one-off.
The loader should:
- resolve the staged scene root
- read the two initial `scene.json` files
- deserialize them into a small internal scene metadata struct
- pair them with dispatch policy in the same in-memory registry entry
- ignore malformed or missing scenes safely
- never fail runtime startup solely because one or both initial scene files are absent
### Skill loading alignment
The corresponding skill packages must still be loaded into runtime skill exposure so the browser-backed tools are available to the runtime.
For this slice, the staged scene source and staged skill packages should be treated as coming from the same external root:
- staged scenes under `.../skill_staging/scenes`
- staged skill packages under `.../skill_staging/skills`
The implementation must make that staged skill package root visible to runtime skill loading. If current `skills_dir` resolution cannot express that directly, the design should extend configuration/path resolution to support a staged external skills root explicitly rather than relying on implicit mirroring.
## Execution Design
### Direct browser path (`fault-details-report`)
Add a direct execution route that is scene-driven rather than Zhihu-specific.
High-level flow:
1. Runtime receives user instruction.
2. Scene matcher recognizes `fault-details-report`.
3. Runtime resolves the browser-backed tool name `fault-details-report.collect_fault_details`.
4. Runtime builds the required tool arguments, including:
- `expected_domain` from the matched scene's runtime policy
- any first-slice scene inputs that can be deterministically derived from the current request/context
- any fixed/default args declared in runtime policy
5. Runtime executes that skill through the existing browser-backed mechanism.
6. Runtime returns normalized tool output as the direct route result.
Input/argument rules for the first slice:
- Direct execution is only allowed when all required tool arguments are available.
- `expected_domain` must always come from runtime scene policy, not from model inference.
- If a required scene/tool input cannot be derived from the user request or current browser context, the direct route must fail clearly instead of fabricating values.
- The first slice may keep direct-mode argument mapping intentionally narrow; unsupported requests should fall back safely rather than guessing.
Return-shape rule for the first slice:
- The direct route should return normalized serialized tool output (for example, the tool payload string or normalized JSON text), not a model-authored prose summary. This keeps direct mode deterministic and makes the browser-backed result explicit.
Implementation note:
The cleanest first slice is to add a small scene direct-execution helper in the compat runtime/workflow area that invokes the already-loaded browser-backed skill tool abstraction rather than duplicating browser request logic.
### Agent browser path (`95598-repair-city-dispatch`)
This path stays inside the agent flow.
High-level flow:
1. Runtime receives user instruction.
2. Scene matcher recognizes `95598-repair-city-dispatch`.
3. `RuntimeEngine::build_instruction` injects a scene execution contract containing:
- the matched scene name
- the required tool name `95598-repair-city-dispatch.collect_repair_orders`
- explicit requirement that this is a browser workflow, not a text-only task
- explicit requirement that business data must come from the browser-backed scene tool
- fallback rules for generic browser probing only after tool failure
4. Agent runs and chooses the required tool.
5. Tool executes through the existing browser-backed skill path.
6. Agent may summarize the result, but cannot fabricate data.
Enforcement note for the first slice:
- The `agent_browser` guarantee is primarily an instruction-contract guarantee in slice one.
- If allowed-tool shaping can narrow the exposed tool set for a matched scene without destabilizing existing behavior, that is a valid enhancement, but it is not required for the first slice.
- The minimum guaranteed behavior for slice one is strong scene-specific prompt injection plus preservation of the rule that the model must not invent collected business data.
## Browser Execution Contract
This requirement is non-negotiable for both dispatch modes:
- scene skills must execute like the Zhihu flow in the sense that the final business action is performed through browser-internal methods
- scene skills must not devolve into text-only pseudo execution
- direct mode and agent mode both reuse the existing browser-backed skill execution path
Concretely, the final path for scene skill execution should remain compatible with:
- `BrowserScriptSkillTool`
- browser backend invocation
- browser-side `Eval` / browser action execution semantics
## Error Handling
- **Scene metadata missing or invalid:** skip that scene and continue with normal runtime behavior.
- **Scene matched but skill/tool unavailable:** do not crash; log enough context for diagnosis and fall back safely.
- **Browser surface unavailable:** disable scene browser routing for that turn and fall back to current non-scene behavior.
- **Tool execution fails in `agent_browser` mode:** allow existing fallback prompt behavior to continue, but preserve the rule that the model cannot invent collected data.
- **Tool execution fails in `direct_browser` mode:** return a concise execution failure instead of pretending collection succeeded.
## Extensibility Rules
This slice should be built so future scene additions only need:
- a new scene metadata file under the staged scene path
- a matching skill package/tool
- a dispatch-mode declaration/policy
- optional aliases if the natural-language names are not sufficiently explicit
Avoid these anti-patterns:
- per-scene `if user said X then do Y` branches scattered across runtime files
- duplicating browser execution code for each scene
- binding future scenes to Zhihu-specific assumptions
## Testing Strategy
### Scene registry tests
- load valid metadata for `fault-details-report`
- load valid metadata for `95598-repair-city-dispatch`
- ignore broken/missing scene files safely
### Matching tests
- instruction variants match `fault-details-report`
- instruction variants match `95598-repair-city-dispatch`
- unrelated instructions do not match
### Instruction-building tests
- `agent_browser` scene injects the required browser-first scene contract
- unmatched instructions do not gain scene-specific constraints
- Zhihu-specific instruction behavior remains unchanged
### Tool exposure tests
- staged skills from the moved path are loaded into runtime
- browser-backed tool names include:
- `fault-details-report.collect_fault_details`
- `95598-repair-city-dispatch.collect_repair_orders`
### Direct execution tests
- `fault-details-report` direct route invokes the browser-backed tool path rather than bypassing the browser layer
- direct route returns failure cleanly when tool execution fails
## Recommended First Implementation Slice
1. Add a tiny scene metadata loader and dispatch-mode policy module.
2. Extend runtime path resolution so the moved staged skills/scenes are visible.
3. Add deterministic scene matching for the two initial scenes.
4. Implement `agent_browser` instruction injection for `95598-repair-city-dispatch`.
5. Implement `direct_browser` execution for `fault-details-report` using the browser-backed skill path.
6. Add focused tests for matching, loading, tool exposure, and direct-vs-agent behavior.
## Open Design Constraint Captured From Discussion
The user explicitly requires the following combined behavior:
- support both kinds of scene execution in the same architecture
- one initial scene should be able to execute without the model
- one initial scene should execute through the model
- both must still use browser-internal execution methods like the Zhihu path
- the design must stay extensible because more staged skills may be added under the same path later
This design is built around those exact constraints.