agent-nuvira 3.3.3 → 3.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -5
- package/dist/agent-sdk/src/agent.d.ts +2 -0
- package/dist/agent-sdk/src/agent.d.ts.map +1 -1
- package/dist/agent-sdk/src/define.d.ts +64 -0
- package/dist/agent-sdk/src/define.d.ts.map +1 -0
- package/dist/agent-sdk/src/define.js +76 -0
- package/dist/agent-sdk/src/define.js.map +1 -0
- package/dist/agent-sdk/src/index.d.ts +9 -0
- package/dist/agent-sdk/src/index.d.ts.map +1 -1
- package/dist/agent-sdk/src/index.js +9 -0
- package/dist/agent-sdk/src/index.js.map +1 -1
- package/dist/agent-sdk/src/scaffold.d.ts +11 -0
- package/dist/agent-sdk/src/scaffold.d.ts.map +1 -1
- package/dist/agent-sdk/src/scaffold.js +16 -6
- package/dist/agent-sdk/src/scaffold.js.map +1 -1
- package/dist/agents/long-form-plan.d.ts.map +1 -1
- package/dist/agents/long-form-plan.js +2 -1
- package/dist/agents/long-form-plan.js.map +1 -1
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/orchestrator.js +5 -4
- package/dist/agents/orchestrator.js.map +1 -1
- package/dist/cli/agent.d.ts +2 -2
- package/dist/cli/agent.js +10 -10
- package/dist/cli/chat.d.ts +94 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +354 -20
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/cli-program.d.ts.map +1 -1
- package/dist/cli/cli-program.js +5 -0
- package/dist/cli/cli-program.js.map +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +9 -1
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +3 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/edit.js +2 -2
- package/dist/cli/eval.d.ts +17 -0
- package/dist/cli/eval.d.ts.map +1 -1
- package/dist/cli/eval.js +105 -2
- package/dist/cli/eval.js.map +1 -1
- package/dist/cli/execute.d.ts +16 -1
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/execute.js +192 -22
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/loop-executor.d.ts +55 -0
- package/dist/cli/loop-executor.d.ts.map +1 -1
- package/dist/cli/loop-executor.js +212 -13
- package/dist/cli/loop-executor.js.map +1 -1
- package/dist/cli/model.d.ts.map +1 -1
- package/dist/cli/model.js +9 -8
- package/dist/cli/model.js.map +1 -1
- package/dist/cli/models.d.ts +1 -1
- package/dist/cli/models.js +4 -4
- package/dist/cli/parity.d.ts +85 -0
- package/dist/cli/parity.d.ts.map +1 -0
- package/dist/cli/parity.js +506 -0
- package/dist/cli/parity.js.map +1 -0
- package/dist/cli/plan.d.ts.map +1 -1
- package/dist/cli/plan.js +2 -1
- package/dist/cli/plan.js.map +1 -1
- package/dist/cli/retrieval.d.ts.map +1 -1
- package/dist/cli/retrieval.js +5 -4
- package/dist/cli/retrieval.js.map +1 -1
- package/dist/cli/sdk.js +4 -4
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli/trace.d.ts.map +1 -1
- package/dist/cli/trace.js +2 -1
- package/dist/cli/trace.js.map +1 -1
- package/dist/cli/workflow.js +2 -2
- package/dist/cli/workflow.js.map +1 -1
- package/dist/config/types.d.ts +44 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/findings/verdicts.d.ts +241 -0
- package/dist/findings/verdicts.d.ts.map +1 -0
- package/dist/findings/verdicts.js +284 -0
- package/dist/findings/verdicts.js.map +1 -0
- package/dist/gateway/adapters.d.ts +65 -0
- package/dist/gateway/adapters.d.ts.map +1 -1
- package/dist/gateway/adapters.js +216 -10
- package/dist/gateway/adapters.js.map +1 -1
- package/dist/gateway/channel-directory.d.ts +31 -0
- package/dist/gateway/channel-directory.d.ts.map +1 -1
- package/dist/gateway/channel-directory.js +40 -0
- package/dist/gateway/channel-directory.js.map +1 -1
- package/dist/gateway/gateway-log.d.ts +1 -1
- package/dist/gateway/gateway-log.d.ts.map +1 -1
- package/dist/gateway/gateway-log.js.map +1 -1
- package/dist/gateway/hooks.d.ts +87 -19
- package/dist/gateway/hooks.d.ts.map +1 -1
- package/dist/gateway/hooks.js +62 -23
- package/dist/gateway/hooks.js.map +1 -1
- package/dist/gateway/inbound-media.d.ts +147 -0
- package/dist/gateway/inbound-media.d.ts.map +1 -0
- package/dist/gateway/inbound-media.js +317 -0
- package/dist/gateway/inbound-media.js.map +1 -0
- package/dist/gateway/inbox.d.ts +8 -1
- package/dist/gateway/inbox.d.ts.map +1 -1
- package/dist/gateway/inbox.js.map +1 -1
- package/dist/gateway/platform-config.d.ts +14 -0
- package/dist/gateway/platform-config.d.ts.map +1 -1
- package/dist/gateway/platform-config.js +26 -8
- package/dist/gateway/platform-config.js.map +1 -1
- package/dist/gateway/realtime.d.ts +114 -0
- package/dist/gateway/realtime.d.ts.map +1 -0
- package/dist/gateway/realtime.js +402 -0
- package/dist/gateway/realtime.js.map +1 -0
- package/dist/gateway/registry.d.ts +31 -0
- package/dist/gateway/registry.d.ts.map +1 -1
- package/dist/gateway/registry.js +224 -4
- package/dist/gateway/registry.js.map +1 -1
- package/dist/gateway/whatsapp/baileys-bridge.d.ts +11 -1
- package/dist/gateway/whatsapp/baileys-bridge.d.ts.map +1 -1
- package/dist/gateway/whatsapp/baileys-bridge.js +123 -4
- package/dist/gateway/whatsapp/baileys-bridge.js.map +1 -1
- package/dist/gateway/whatsapp/bridge.d.ts +6 -2
- package/dist/gateway/whatsapp/bridge.d.ts.map +1 -1
- package/dist/gateway/whatsapp/bridge.js.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/inference/factory.d.ts +14 -0
- package/dist/inference/factory.d.ts.map +1 -1
- package/dist/inference/factory.js +17 -0
- package/dist/inference/factory.js.map +1 -1
- package/dist/inference/groq-adapter.d.ts +2 -0
- package/dist/inference/groq-adapter.d.ts.map +1 -1
- package/dist/inference/groq-adapter.js +16 -6
- package/dist/inference/groq-adapter.js.map +1 -1
- package/dist/inference/tools.d.ts.map +1 -1
- package/dist/inference/tools.js +29 -0
- package/dist/inference/tools.js.map +1 -1
- package/dist/learning/benchmark.d.ts.map +1 -1
- package/dist/learning/benchmark.js +3 -2
- package/dist/learning/benchmark.js.map +1 -1
- package/dist/learning/continuation.d.ts.map +1 -1
- package/dist/learning/continuation.js +2 -1
- package/dist/learning/continuation.js.map +1 -1
- package/dist/learning/cost-tracker.d.ts.map +1 -1
- package/dist/learning/cost-tracker.js +2 -1
- package/dist/learning/cost-tracker.js.map +1 -1
- package/dist/learning/deferred-task.d.ts.map +1 -1
- package/dist/learning/deferred-task.js +13 -4
- package/dist/learning/deferred-task.js.map +1 -1
- package/dist/learning/eval-framework.d.ts.map +1 -1
- package/dist/learning/eval-framework.js +2 -1
- package/dist/learning/eval-framework.js.map +1 -1
- package/dist/learning/long-form.d.ts.map +1 -1
- package/dist/learning/long-form.js +2 -1
- package/dist/learning/long-form.js.map +1 -1
- package/dist/learning/model-registry.d.ts.map +1 -1
- package/dist/learning/model-registry.js +2 -1
- package/dist/learning/model-registry.js.map +1 -1
- package/dist/learning/reasoning-cache.d.ts.map +1 -1
- package/dist/learning/reasoning-cache.js +2 -1
- package/dist/learning/reasoning-cache.js.map +1 -1
- package/dist/learning/reasoning-trace.d.ts +37 -1
- package/dist/learning/reasoning-trace.d.ts.map +1 -1
- package/dist/learning/reasoning-trace.js +66 -0
- package/dist/learning/reasoning-trace.js.map +1 -1
- package/dist/learning/resilient-call.d.ts.map +1 -1
- package/dist/learning/resilient-call.js +2 -1
- package/dist/learning/resilient-call.js.map +1 -1
- package/dist/learning/retrieval.d.ts.map +1 -1
- package/dist/learning/retrieval.js +2 -1
- package/dist/learning/retrieval.js.map +1 -1
- package/dist/learning/seeded-benchmark.d.ts +160 -0
- package/dist/learning/seeded-benchmark.d.ts.map +1 -0
- package/dist/learning/seeded-benchmark.js +321 -0
- package/dist/learning/seeded-benchmark.js.map +1 -0
- package/dist/learning/seeded-bugs.d.ts +142 -0
- package/dist/learning/seeded-bugs.d.ts.map +1 -0
- package/dist/learning/seeded-bugs.js +535 -0
- package/dist/learning/seeded-bugs.js.map +1 -0
- package/dist/learning/step-checkpoint.d.ts +127 -0
- package/dist/learning/step-checkpoint.d.ts.map +1 -0
- package/dist/learning/step-checkpoint.js +244 -0
- package/dist/learning/step-checkpoint.js.map +1 -0
- package/dist/nlu/intent-confirm.d.ts +23 -1
- package/dist/nlu/intent-confirm.d.ts.map +1 -1
- package/dist/nlu/intent-confirm.js +85 -2
- package/dist/nlu/intent-confirm.js.map +1 -1
- package/dist/nlu/learnings.d.ts +7 -0
- package/dist/nlu/learnings.d.ts.map +1 -1
- package/dist/nlu/learnings.js +7 -0
- package/dist/nlu/learnings.js.map +1 -1
- package/dist/observability/debug-log.d.ts +250 -0
- package/dist/observability/debug-log.d.ts.map +1 -0
- package/dist/observability/debug-log.js +500 -0
- package/dist/observability/debug-log.js.map +1 -0
- package/dist/observability/event-bus.d.ts.map +1 -1
- package/dist/observability/event-bus.js +4 -1
- package/dist/observability/event-bus.js.map +1 -1
- package/dist/observability/otel.d.ts +278 -0
- package/dist/observability/otel.d.ts.map +1 -0
- package/dist/observability/otel.js +590 -0
- package/dist/observability/otel.js.map +1 -0
- package/dist/parity/drivers.d.ts +99 -0
- package/dist/parity/drivers.d.ts.map +1 -0
- package/dist/parity/drivers.js +1362 -0
- package/dist/parity/drivers.js.map +1 -0
- package/dist/parity/graph.d.ts +73 -0
- package/dist/parity/graph.d.ts.map +1 -0
- package/dist/parity/graph.js +162 -0
- package/dist/parity/graph.js.map +1 -0
- package/dist/parity/matrix.d.ts +105 -0
- package/dist/parity/matrix.d.ts.map +1 -0
- package/dist/parity/matrix.js +352 -0
- package/dist/parity/matrix.js.map +1 -0
- package/dist/parity/observation.d.ts +444 -0
- package/dist/parity/observation.d.ts.map +1 -0
- package/dist/parity/observation.js +333 -0
- package/dist/parity/observation.js.map +1 -0
- package/dist/parity/scenarios.d.ts +229 -0
- package/dist/parity/scenarios.d.ts.map +1 -0
- package/dist/parity/scenarios.js +175 -0
- package/dist/parity/scenarios.js.map +1 -0
- package/dist/parity/surfaces.d.ts +122 -0
- package/dist/parity/surfaces.d.ts.map +1 -0
- package/dist/parity/surfaces.js +190 -0
- package/dist/parity/surfaces.js.map +1 -0
- package/dist/runtime/fault-injection.d.ts +173 -0
- package/dist/runtime/fault-injection.d.ts.map +1 -0
- package/dist/runtime/fault-injection.js +281 -0
- package/dist/runtime/fault-injection.js.map +1 -0
- package/dist/tools/child-agent-entry.d.ts +23 -0
- package/dist/tools/child-agent-entry.d.ts.map +1 -0
- package/dist/tools/child-agent-entry.js +129 -0
- package/dist/tools/child-agent-entry.js.map +1 -0
- package/dist/tools/child-agent-runtime.d.ts +124 -0
- package/dist/tools/child-agent-runtime.d.ts.map +1 -0
- package/dist/tools/child-agent-runtime.js +704 -0
- package/dist/tools/child-agent-runtime.js.map +1 -0
- package/dist/tools/coding-tools.d.ts.map +1 -1
- package/dist/tools/coding-tools.js +82 -10
- package/dist/tools/coding-tools.js.map +1 -1
- package/dist/tools/delegation-system.d.ts +31 -0
- package/dist/tools/delegation-system.d.ts.map +1 -1
- package/dist/tools/delegation-system.js +70 -9
- package/dist/tools/delegation-system.js.map +1 -1
- package/dist/tools/extract/docx.d.ts +27 -0
- package/dist/tools/extract/docx.d.ts.map +1 -0
- package/dist/tools/extract/docx.js +48 -0
- package/dist/tools/extract/docx.js.map +1 -0
- package/dist/tools/extract/html-text.d.ts +27 -0
- package/dist/tools/extract/html-text.d.ts.map +1 -0
- package/dist/tools/extract/html-text.js +86 -0
- package/dist/tools/extract/html-text.js.map +1 -0
- package/dist/tools/extract/pdf-ocr.d.ts +58 -0
- package/dist/tools/extract/pdf-ocr.d.ts.map +1 -0
- package/dist/tools/extract/pdf-ocr.js +116 -0
- package/dist/tools/extract/pdf-ocr.js.map +1 -0
- package/dist/tools/extract/pdf.d.ts +65 -0
- package/dist/tools/extract/pdf.d.ts.map +1 -0
- package/dist/tools/extract/pdf.js +197 -0
- package/dist/tools/extract/pdf.js.map +1 -0
- package/dist/tools/extract/pptx.d.ts +32 -0
- package/dist/tools/extract/pptx.d.ts.map +1 -0
- package/dist/tools/extract/pptx.js +77 -0
- package/dist/tools/extract/pptx.js.map +1 -0
- package/dist/tools/extract/xlsx.d.ts +47 -0
- package/dist/tools/extract/xlsx.d.ts.map +1 -0
- package/dist/tools/extract/xlsx.js +111 -0
- package/dist/tools/extract/xlsx.js.map +1 -0
- package/dist/tools/finding-tool.d.ts +76 -0
- package/dist/tools/finding-tool.d.ts.map +1 -0
- package/dist/tools/finding-tool.js +125 -0
- package/dist/tools/finding-tool.js.map +1 -0
- package/dist/tools/messaging-tools.d.ts +41 -11
- package/dist/tools/messaging-tools.d.ts.map +1 -1
- package/dist/tools/messaging-tools.js +104 -55
- package/dist/tools/messaging-tools.js.map +1 -1
- package/dist/tools/neutts-synth.d.ts +27 -3
- package/dist/tools/neutts-synth.d.ts.map +1 -1
- package/dist/tools/neutts-synth.js +57 -13
- package/dist/tools/neutts-synth.js.map +1 -1
- package/dist/tools/pipeline-tool.d.ts +43 -1
- package/dist/tools/pipeline-tool.d.ts.map +1 -1
- package/dist/tools/pipeline-tool.js +13 -2
- package/dist/tools/pipeline-tool.js.map +1 -1
- package/dist/tools/read-extract.d.ts +116 -45
- package/dist/tools/read-extract.d.ts.map +1 -1
- package/dist/tools/read-extract.js +494 -158
- package/dist/tools/read-extract.js.map +1 -1
- package/dist/tools/registry.d.ts +2 -2
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +152 -23
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/subagent-refusal.d.ts +15 -0
- package/dist/tools/subagent-refusal.d.ts.map +1 -0
- package/dist/tools/subagent-refusal.js +18 -0
- package/dist/tools/subagent-refusal.js.map +1 -0
- package/dist/tools/subagent-spawner.d.ts +122 -0
- package/dist/tools/subagent-spawner.d.ts.map +1 -1
- package/dist/tools/subagent-spawner.js +249 -28
- package/dist/tools/subagent-spawner.js.map +1 -1
- package/dist/tools/tool-hooks.d.ts +177 -0
- package/dist/tools/tool-hooks.d.ts.map +1 -0
- package/dist/tools/tool-hooks.js +427 -0
- package/dist/tools/tool-hooks.js.map +1 -0
- package/dist/tools/tool-loop.d.ts +82 -0
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +167 -9
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/tools/tool-refusal.d.ts +68 -0
- package/dist/tools/tool-refusal.d.ts.map +1 -0
- package/dist/tools/tool-refusal.js +78 -0
- package/dist/tools/tool-refusal.js.map +1 -0
- package/dist/tools/toolsets.d.ts +8 -0
- package/dist/tools/toolsets.d.ts.map +1 -1
- package/dist/tools/toolsets.js +12 -2
- package/dist/tools/toolsets.js.map +1 -1
- package/dist/tools/vision-tools.d.ts +88 -83
- package/dist/tools/vision-tools.d.ts.map +1 -1
- package/dist/tools/vision-tools.js +134 -103
- package/dist/tools/vision-tools.js.map +1 -1
- package/dist/tools/worktree.d.ts +210 -0
- package/dist/tools/worktree.d.ts.map +1 -0
- package/dist/tools/worktree.js +374 -0
- package/dist/tools/worktree.js.map +1 -0
- package/dist/utils/format.d.ts +3 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +32 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/web-dashboard/attachment-extract.d.ts +64 -0
- package/dist/web-dashboard/attachment-extract.d.ts.map +1 -0
- package/dist/web-dashboard/attachment-extract.js +154 -0
- package/dist/web-dashboard/attachment-extract.js.map +1 -0
- package/dist/web-dashboard/chat-console.d.ts +108 -1
- package/dist/web-dashboard/chat-console.d.ts.map +1 -1
- package/dist/web-dashboard/chat-console.js +36 -0
- package/dist/web-dashboard/chat-console.js.map +1 -1
- package/dist/web-dashboard/hub-data.d.ts +37 -0
- package/dist/web-dashboard/hub-data.d.ts.map +1 -1
- package/dist/web-dashboard/hub-data.js +61 -1
- package/dist/web-dashboard/hub-data.js.map +1 -1
- package/dist/web-dashboard/server.d.ts +14 -0
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +247 -13
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +196 -48
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/package.json +18 -3
- package/src/web-dashboard/public/assets/{index-Cyd6tIew.css → index-XJjj2cBX.css} +1 -1
- package/src/web-dashboard/public/assets/index-YWF9FpwQ.js +207 -0
- package/src/web-dashboard/public/assets/index-YWF9FpwQ.js.map +1 -0
- package/src/web-dashboard/public/index.html +2 -2
- package/dist/tools/child-agent-worker.js +0 -212
- package/src/web-dashboard/public/assets/index-CxDj7p6i.js +0 -207
- package/src/web-dashboard/public/assets/index-CxDj7p6i.js.map +0 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WS0 (#22) — one scenario, every surface, one verdict.
|
|
3
|
+
*
|
|
4
|
+
* The registry (`surfaces.ts`) answers "which surfaces exist and what do they
|
|
5
|
+
* run through". This module answers the harder question: did they behave the
|
|
6
|
+
* same, and is the verdict trustworthy.
|
|
7
|
+
*
|
|
8
|
+
* THREE RULES, each closing a way a parity test lies:
|
|
9
|
+
*
|
|
10
|
+
* 1. STUB DEPTH MUST BE COMPARABLE. Every driver records where its stub sits.
|
|
11
|
+
* `provider` (a stub provider object) and `transport` (a real provider
|
|
12
|
+
* object talking to a stub SERVER — the forked subagent child) both run the
|
|
13
|
+
* real turn code end to end, so they are ONE comparable class; folding them
|
|
14
|
+
* together is what makes the child readable against the in-process
|
|
15
|
+
* surfaces. `engine` replaces the very behaviour under test, so it never
|
|
16
|
+
* compares with anything, itself included. A run that would have to compare
|
|
17
|
+
* incomparable depths is refused rather than answered.
|
|
18
|
+
*
|
|
19
|
+
* 2. SKIPPED SURFACES ARE NAMED. A surface that cannot be driven appears in
|
|
20
|
+
* `skipped` with the reason it is missing. Silence is how a harness ends up
|
|
21
|
+
* "passing" for months while covering one surface.
|
|
22
|
+
*
|
|
23
|
+
* 3. TWO SURFACES IS THE MINIMUM. One available driver is not a parity run; it
|
|
24
|
+
* is a smoke test wearing a parity label. That case reports
|
|
25
|
+
* `insufficient`, never `at-par`.
|
|
26
|
+
*
|
|
27
|
+
* 4. THE TURN MUST HAVE REACHED A MODEL. The response cache is shared and
|
|
28
|
+
* enabled on the `answerOnce` path, so the second surface of a run can be
|
|
29
|
+
* served from the first one's entry — same answer, no model call, no tool
|
|
30
|
+
* lifecycle, and a flawless "agreement" between two replays that proves
|
|
31
|
+
* nothing. Measured, not hypothetical: before this rule existed, the second
|
|
32
|
+
* surface of every two-driver run was a cache hit (the drivers now isolate
|
|
33
|
+
* the cache per turn as well — belt and braces, because either guard alone
|
|
34
|
+
* would be one edit away from being removed).
|
|
35
|
+
* A zero is refused as `unreached-model` rather than compared.
|
|
36
|
+
*
|
|
37
|
+
* Pure by construction: no `fs`, no `vi`, no process env — which is what lets
|
|
38
|
+
* both the test suite and `nuvira parity run` import it. The drivers that
|
|
39
|
+
* actually drive a turn live in `./drivers.ts` (transport depth, a loopback stub
|
|
40
|
+
* server), so the CLI and CI run the SAME mechanism instead of two copies that
|
|
41
|
+
* could disagree.
|
|
42
|
+
*/
|
|
43
|
+
import { compare } from './observation.js';
|
|
44
|
+
/**
|
|
45
|
+
* Drive one scenario through every available driver and compare the results.
|
|
46
|
+
*
|
|
47
|
+
* Order matters only for the report: the first available driver is the baseline.
|
|
48
|
+
* Driver order is the caller's, so a scenario can pin a baseline deliberately.
|
|
49
|
+
*/
|
|
50
|
+
export async function runParityScenario(scenario, drivers) {
|
|
51
|
+
const skipped = drivers
|
|
52
|
+
.filter((d) => !d.available)
|
|
53
|
+
.map((d) => ({ surface: d.surface, reason: d.blockedBy ?? 'no reason recorded' }));
|
|
54
|
+
const available = drivers.filter((d) => d.available);
|
|
55
|
+
if (available.length < 2) {
|
|
56
|
+
return {
|
|
57
|
+
scenario: scenario.id,
|
|
58
|
+
depth: null,
|
|
59
|
+
observations: [],
|
|
60
|
+
differences: [],
|
|
61
|
+
skipped,
|
|
62
|
+
verdict: 'not-run',
|
|
63
|
+
refusal: {
|
|
64
|
+
kind: 'insufficient-coverage',
|
|
65
|
+
available: available.map((d) => d.surface),
|
|
66
|
+
message: `only ${available.length} surface(s) can be driven for "${scenario.id}"` +
|
|
67
|
+
(skipped.length > 0 ? `; skipped: ${skipped.map((s) => `${s.surface} (${s.reason})`).join('; ')}` : '') +
|
|
68
|
+
'. A parity verdict needs at least two.',
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const depths = [...new Set(available.map((d) => d.depth))];
|
|
73
|
+
// R2 — `provider` and `transport` are one comparable class (see rule 1 in the
|
|
74
|
+
// header). `engine` never compares, whether or not it is paired with anything.
|
|
75
|
+
if (depths.includes('engine')) {
|
|
76
|
+
return {
|
|
77
|
+
scenario: scenario.id,
|
|
78
|
+
depth: null,
|
|
79
|
+
observations: [],
|
|
80
|
+
differences: [],
|
|
81
|
+
skipped,
|
|
82
|
+
verdict: 'not-run',
|
|
83
|
+
refusal: {
|
|
84
|
+
kind: 'depth-mismatch',
|
|
85
|
+
depths: available.map((d) => ({ surface: d.surface, depth: d.depth })),
|
|
86
|
+
message: `a stub sits at the ENGINE depth (${depths.join(', ')}), so a verdict would be meaningless: ` +
|
|
87
|
+
'that surface has had the behaviour under test replaced, and it can never be compared — ' +
|
|
88
|
+
'not with a provider stub, and not with another engine stub. ' +
|
|
89
|
+
'Re-drive it at provider or transport depth, or declare the gap.',
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** No single depth to report when comparable depths were mixed. */
|
|
94
|
+
const reportedDepth = depths.length === 1 ? depths[0] : null;
|
|
95
|
+
const observations = [];
|
|
96
|
+
for (const driver of available)
|
|
97
|
+
observations.push(await driver.run(scenario));
|
|
98
|
+
// Rule 4. Checked BEFORE comparing, because a zero would otherwise surface as
|
|
99
|
+
// a "divergence" in modelCalls — the right refusal with the wrong name.
|
|
100
|
+
const unreached = observations.filter((observation) => observation.modelCalls === 0);
|
|
101
|
+
if (unreached.length > 0) {
|
|
102
|
+
return {
|
|
103
|
+
scenario: scenario.id,
|
|
104
|
+
depth: reportedDepth,
|
|
105
|
+
observations,
|
|
106
|
+
differences: [],
|
|
107
|
+
skipped,
|
|
108
|
+
verdict: 'not-run',
|
|
109
|
+
refusal: {
|
|
110
|
+
kind: 'unreached-model',
|
|
111
|
+
surfaces: unreached.map((observation) => observation.surface),
|
|
112
|
+
message: `no model call on: ${unreached.map((o) => o.surface).join(', ')}. ` +
|
|
113
|
+
'A turn served without reaching a model — a response-cache replay, or a ' +
|
|
114
|
+
'surface answering from a shortcut — did no routing and no tool work, so ' +
|
|
115
|
+
'comparing it says nothing. Isolate the cache (or use a distinct message) ' +
|
|
116
|
+
'and re-run before reading any verdict from this scenario.',
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const [baseline, ...rest] = observations;
|
|
121
|
+
// WS6 (#28) — a scenario that DECLARES a fault is compared on the FAULT-HONESTY
|
|
122
|
+
// projection instead of the full one, and the reason is measured rather than
|
|
123
|
+
// aesthetic: under a fatal dependency failure the surfaces legitimately differ in
|
|
124
|
+
// every other field. The CLI, the GUI, a messaging bridge and a forked child
|
|
125
|
+
// have different user-facing copy, different error taxonomies, different
|
|
126
|
+
// last-attempt attributions and different retry counts — comparing those would
|
|
127
|
+
// report four correct surfaces as divergent and bury the one fact the row is
|
|
128
|
+
// about. What must NOT differ is whether the failure was reported as a failure.
|
|
129
|
+
const differences = scenario.fault
|
|
130
|
+
? rest.flatMap((observation) => compareFaultHonesty(baseline, observation))
|
|
131
|
+
: rest.flatMap((observation) => compare(baseline, observation));
|
|
132
|
+
return {
|
|
133
|
+
scenario: scenario.id,
|
|
134
|
+
depth: reportedDepth,
|
|
135
|
+
observations,
|
|
136
|
+
differences,
|
|
137
|
+
skipped,
|
|
138
|
+
verdict: differences.length === 0 ? 'at-par' : 'divergent',
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* WS6 (#28) — the fields a FAULT row is compared on: what the turn was given, and
|
|
143
|
+
* whether it reported the consequence.
|
|
144
|
+
*
|
|
145
|
+
* `status` and the fault's own `asked`/`site`/`kind` say both surfaces were told
|
|
146
|
+
* the same thing and ended the same way; `took` is the load-bearing one, because a
|
|
147
|
+
* surface that SWALLOWED the fault — completed a turn the backend never served, or
|
|
148
|
+
* reported an injected tool failure as a success — reads `took: false` against
|
|
149
|
+
* every other surface's `true`. A swallowed fault leaves no other trace, which is
|
|
150
|
+
* why it is a compared field and not something a test reads off one surface.
|
|
151
|
+
*
|
|
152
|
+
* Deliberately absent: `answer`, `errorCode`, `provider`/`transport`/`model`,
|
|
153
|
+
* `debugLog`, `otel`, `modelCalls` and `toolCalls`. Each of those legitimately
|
|
154
|
+
* differs under a fatal fault (a messaging surface has no bubble to fill; a child
|
|
155
|
+
* announces its transport before it fails; the last attempt a debug header names
|
|
156
|
+
* is the fallback, not the provider that errored). They are still recorded on the
|
|
157
|
+
* observation for the failure report — only the comparison excludes them.
|
|
158
|
+
*/
|
|
159
|
+
export function compareFaultHonesty(a, b) {
|
|
160
|
+
const differences = [];
|
|
161
|
+
const who = `${a.surface} vs ${b.surface}`;
|
|
162
|
+
if (a.status !== b.status) {
|
|
163
|
+
differences.push(`${who}: status differs — ${a.status} vs ${b.status}`);
|
|
164
|
+
}
|
|
165
|
+
const fields = ['asked', 'site', 'kind', 'took'];
|
|
166
|
+
for (const field of fields) {
|
|
167
|
+
const l = a.fault[field];
|
|
168
|
+
const r = b.fault[field];
|
|
169
|
+
if (l !== r) {
|
|
170
|
+
differences.push(`${who}: fault.${field} differs — ${String(l)} vs ${String(r)}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return differences;
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=scenarios.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenarios.js","sourceRoot":"","sources":["../../src/parity/scenarios.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WS0 (#22) — the surface registry.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS FILE EXISTS. Before a capability can be promised on "every surface"
|
|
5
|
+
* (WS1-WS7), the set of surfaces has to be DECLARED. Inferred from whatever
|
|
6
|
+
* happens to import what, it is invisible: nothing fails when a new
|
|
7
|
+
* implementation appears beside the shared one, and nothing fails when a
|
|
8
|
+
* capability lands on one surface and quietly misses three.
|
|
9
|
+
*
|
|
10
|
+
* MEASURED, and the reason this is not paranoia — four ways to run an agent turn
|
|
11
|
+
* already exist over three engine labels:
|
|
12
|
+
*
|
|
13
|
+
* - `src/cli/chat.ts` runs a turn through its own `answerOnce`
|
|
14
|
+
* (`cli/chat.ts:502`), which the dashboard drives too
|
|
15
|
+
* (`web-dashboard/chat-console.ts:391` lazily imports ChatCommand, `:618`
|
|
16
|
+
* awaits `engine.answerOnce`), and which the gateway chat engine also calls
|
|
17
|
+
* (`cli/chat.ts:625` — "the chat console and the gateway chat engine both
|
|
18
|
+
* call answerOnce"). This one IS shared, and it is the model for the rest.
|
|
19
|
+
* - `src/cli/loop-executor.ts:196` `runLoopExecutor` — the loop engine.
|
|
20
|
+
* - `src/tools/pipeline-tool.ts:76` `runPipelineTool` — the pipeline engine,
|
|
21
|
+
* which is the ONLY way the gateway runs a non-chat turn.
|
|
22
|
+
* - `src/cli/execute.ts` picks between them itself (`:1655` direct, `:1725`
|
|
23
|
+
* loop, `:2009` pipeline) and reaches the provider factory directly, so its
|
|
24
|
+
* engine choice and provider construction live in the surface.
|
|
25
|
+
*
|
|
26
|
+
* Also measured: `src/web-dashboard/server.ts` does not import any turn entry —
|
|
27
|
+
* it reaches `answerOnce` indirectly through `chat-console.ts`, which is why
|
|
28
|
+
* `turnEntries` below records what a surface ends up using rather than what it
|
|
29
|
+
* imports literally. `surfacesReaching` (see `parity/graph.ts`) does the
|
|
30
|
+
* transitive check.
|
|
31
|
+
*
|
|
32
|
+
* This module is DATA plus pure lookups on purpose: it is what the parity test
|
|
33
|
+
* and the capability matrix read, so it must be cheap to import from a test and
|
|
34
|
+
* free of side effects.
|
|
35
|
+
*/
|
|
36
|
+
import type { EngineMode } from '../learning/engine-router.js';
|
|
37
|
+
/** The surfaces a person can talk to agent-nuvira through. */
|
|
38
|
+
export type SurfaceId = 'cli-chat' | 'cli-execute' | 'dashboard-chat' | 'gateway-chat' | 'subagent';
|
|
39
|
+
/**
|
|
40
|
+
* The shared turn entries. A surface runs a turn through one of these, or it is
|
|
41
|
+
* a silo — which is exactly what the architecture test in
|
|
42
|
+
* `tests/parity/cross-surface.test.ts` fails on.
|
|
43
|
+
*/
|
|
44
|
+
export type TurnEntryId = 'chat-once' | 'loop-executor' | 'pipeline-tool' | 'orchestrator' | 'child-runtime';
|
|
45
|
+
export interface TurnEntry {
|
|
46
|
+
id: TurnEntryId;
|
|
47
|
+
/** Repo-relative module that exports the entry. */
|
|
48
|
+
module: string;
|
|
49
|
+
/** The exported symbol a surface calls. */
|
|
50
|
+
symbol: string;
|
|
51
|
+
/** Engines this entry can serve. */
|
|
52
|
+
engines: readonly EngineMode[];
|
|
53
|
+
note: string;
|
|
54
|
+
}
|
|
55
|
+
export interface SurfaceDescriptor {
|
|
56
|
+
id: SurfaceId;
|
|
57
|
+
label: string;
|
|
58
|
+
/**
|
|
59
|
+
* Repo-relative modules that OWN the surface (the thing a person addresses).
|
|
60
|
+
* Paths, not globs: the registry is meant to be read.
|
|
61
|
+
*/
|
|
62
|
+
modules: readonly string[];
|
|
63
|
+
/** Shared turn entries this surface uses, transitively. */
|
|
64
|
+
turnEntries: readonly TurnEntryId[];
|
|
65
|
+
/**
|
|
66
|
+
* Engine labels observable through this surface. More than one entry means
|
|
67
|
+
* the surface chooses, and a parity test must exercise each.
|
|
68
|
+
*/
|
|
69
|
+
engines: readonly EngineMode[];
|
|
70
|
+
/**
|
|
71
|
+
* True when the surface runs in its own process. Such a surface legitimately
|
|
72
|
+
* builds its own provider and loop (that IS the isolation), so the
|
|
73
|
+
* in-process rules below do not apply to it — but its observable behaviour
|
|
74
|
+
* still must match, which is what the normalised observation checks.
|
|
75
|
+
*/
|
|
76
|
+
separateProcess?: boolean;
|
|
77
|
+
/** How a parity test drives this surface headlessly. */
|
|
78
|
+
headless: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The shared entries. `engines` is what the entry can serve, not what every
|
|
82
|
+
* caller uses: the gateway only ever asks `pipeline-tool` for pipeline work.
|
|
83
|
+
*/
|
|
84
|
+
export declare const TURN_ENTRIES: Record<TurnEntryId, TurnEntry>;
|
|
85
|
+
/**
|
|
86
|
+
* Known surface-level debt, keyed by what is wrong and why it is still here.
|
|
87
|
+
*
|
|
88
|
+
* This is a RATCHET, not an allowlist of convenience: the architecture test
|
|
89
|
+
* asserts the observed violations EQUAL this list, so adding a new bypass fails,
|
|
90
|
+
* and removing one without deleting its entry fails too (a stale entry would
|
|
91
|
+
* otherwise hide the next one). Every entry is somebody's workstream.
|
|
92
|
+
*
|
|
93
|
+
* BOTH ARE EMPTY NOW. `src/cli/execute.ts` was the whole list: it built its own
|
|
94
|
+
* provider and drove the pipeline engine through a private `Orchestrator`. It
|
|
95
|
+
* now resolves through the shared `resolveProvider` and runs pipeline turns
|
|
96
|
+
* through `runPipelineTool`. The keys stay declared with empty arrays on
|
|
97
|
+
* purpose — deleting a key would stop the rule from being measured at all, and
|
|
98
|
+
* the next bypass would then be invisible instead of a one-line diff here.
|
|
99
|
+
*/
|
|
100
|
+
export declare const SURFACE_DEBT: Record<string, readonly string[]>;
|
|
101
|
+
/**
|
|
102
|
+
* Every surface, with the evidence that it exists. Order is display order only.
|
|
103
|
+
*/
|
|
104
|
+
export declare const SURFACES: readonly SurfaceDescriptor[];
|
|
105
|
+
/** A surface by id, or undefined. */
|
|
106
|
+
export declare function surfaceById(id: SurfaceId): SurfaceDescriptor | undefined;
|
|
107
|
+
/** Every surface that runs a turn through `entry`, directly or transitively. */
|
|
108
|
+
export declare function surfacesReaching(entry: TurnEntryId): SurfaceDescriptor[];
|
|
109
|
+
/**
|
|
110
|
+
* Every (surface, engine) pair a parity test must exercise. A surface that can
|
|
111
|
+
* select between engines contributes one pair per engine, so a capability that
|
|
112
|
+
* works under `loop` and fails under `pipeline` cannot pass unnoticed.
|
|
113
|
+
*/
|
|
114
|
+
export declare function parityMatrix(): Array<{
|
|
115
|
+
surface: SurfaceId;
|
|
116
|
+
engine: EngineMode;
|
|
117
|
+
}>;
|
|
118
|
+
/** Repo-relative paths of the surface-owned modules. */
|
|
119
|
+
export declare function surfaceModulePaths(): string[];
|
|
120
|
+
/** Repo-relative paths of the shared turn entries. */
|
|
121
|
+
export declare function turnEntryModulePaths(): string[];
|
|
122
|
+
//# sourceMappingURL=surfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surfaces.d.ts","sourceRoot":"","sources":["../../src/parity/surfaces.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D,8DAA8D;AAC9D,MAAM,MAAM,SAAS,GACjB,UAAU,GACV,aAAa,GACb,gBAAgB,GAChB,cAAc,GACd,UAAU,CAAC;AAEf;;;;GAIG;AACH,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,eAAe,GACf,eAAe,GACf,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,WAAW,CAAC;IAChB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,SAAS,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,2DAA2D;IAC3D,WAAW,EAAE,SAAS,WAAW,EAAE,CAAC;IACpC;;;OAGG;IACH,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,WAAW,EAAE,SAAS,CAoCvD,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAK1D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,SAAS,iBAAiB,EA2DhD,CAAC;AAEF,qCAAqC;AACrC,wBAAgB,WAAW,CAAC,EAAE,EAAE,SAAS,GAAG,iBAAiB,GAAG,SAAS,CAExE;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,iBAAiB,EAAE,CAExE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,KAAK,CAAC;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC,CAMhF;AAED,wDAAwD;AACxD,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAE7C;AAED,sDAAsD;AACtD,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAE/C"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WS0 (#22) — the surface registry.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS FILE EXISTS. Before a capability can be promised on "every surface"
|
|
5
|
+
* (WS1-WS7), the set of surfaces has to be DECLARED. Inferred from whatever
|
|
6
|
+
* happens to import what, it is invisible: nothing fails when a new
|
|
7
|
+
* implementation appears beside the shared one, and nothing fails when a
|
|
8
|
+
* capability lands on one surface and quietly misses three.
|
|
9
|
+
*
|
|
10
|
+
* MEASURED, and the reason this is not paranoia — four ways to run an agent turn
|
|
11
|
+
* already exist over three engine labels:
|
|
12
|
+
*
|
|
13
|
+
* - `src/cli/chat.ts` runs a turn through its own `answerOnce`
|
|
14
|
+
* (`cli/chat.ts:502`), which the dashboard drives too
|
|
15
|
+
* (`web-dashboard/chat-console.ts:391` lazily imports ChatCommand, `:618`
|
|
16
|
+
* awaits `engine.answerOnce`), and which the gateway chat engine also calls
|
|
17
|
+
* (`cli/chat.ts:625` — "the chat console and the gateway chat engine both
|
|
18
|
+
* call answerOnce"). This one IS shared, and it is the model for the rest.
|
|
19
|
+
* - `src/cli/loop-executor.ts:196` `runLoopExecutor` — the loop engine.
|
|
20
|
+
* - `src/tools/pipeline-tool.ts:76` `runPipelineTool` — the pipeline engine,
|
|
21
|
+
* which is the ONLY way the gateway runs a non-chat turn.
|
|
22
|
+
* - `src/cli/execute.ts` picks between them itself (`:1655` direct, `:1725`
|
|
23
|
+
* loop, `:2009` pipeline) and reaches the provider factory directly, so its
|
|
24
|
+
* engine choice and provider construction live in the surface.
|
|
25
|
+
*
|
|
26
|
+
* Also measured: `src/web-dashboard/server.ts` does not import any turn entry —
|
|
27
|
+
* it reaches `answerOnce` indirectly through `chat-console.ts`, which is why
|
|
28
|
+
* `turnEntries` below records what a surface ends up using rather than what it
|
|
29
|
+
* imports literally. `surfacesReaching` (see `parity/graph.ts`) does the
|
|
30
|
+
* transitive check.
|
|
31
|
+
*
|
|
32
|
+
* This module is DATA plus pure lookups on purpose: it is what the parity test
|
|
33
|
+
* and the capability matrix read, so it must be cheap to import from a test and
|
|
34
|
+
* free of side effects.
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* The shared entries. `engines` is what the entry can serve, not what every
|
|
38
|
+
* caller uses: the gateway only ever asks `pipeline-tool` for pipeline work.
|
|
39
|
+
*/
|
|
40
|
+
export const TURN_ENTRIES = {
|
|
41
|
+
'chat-once': {
|
|
42
|
+
id: 'chat-once',
|
|
43
|
+
module: 'src/cli/chat.ts',
|
|
44
|
+
symbol: 'ChatCommand.answerOnce',
|
|
45
|
+
engines: ['loop'],
|
|
46
|
+
note: 'The interactive engine. Shared by the CLI chat, the dashboard console and the gateway chat path — the only entry that is genuinely cross-surface today, and therefore the template for the others.',
|
|
47
|
+
},
|
|
48
|
+
'loop-executor': {
|
|
49
|
+
id: 'loop-executor',
|
|
50
|
+
module: 'src/cli/loop-executor.ts',
|
|
51
|
+
symbol: 'runLoopExecutor',
|
|
52
|
+
engines: ['loop'],
|
|
53
|
+
note: 'The loop engine as a library. Written to give `nuvira execute` the exposure the chat path already had, so it is the intended replacement for the surface-level branch in execute.ts.',
|
|
54
|
+
},
|
|
55
|
+
'pipeline-tool': {
|
|
56
|
+
id: 'pipeline-tool',
|
|
57
|
+
module: 'src/tools/pipeline-tool.ts',
|
|
58
|
+
symbol: 'runPipelineTool',
|
|
59
|
+
engines: ['pipeline'],
|
|
60
|
+
note: 'The pipeline engine, reached through the orchestrator. The gateway runs every non-chat turn through this, which is why the gateway is pipeline-only.',
|
|
61
|
+
},
|
|
62
|
+
orchestrator: {
|
|
63
|
+
id: 'orchestrator',
|
|
64
|
+
module: 'src/agents/orchestrator.ts',
|
|
65
|
+
symbol: 'Orchestrator',
|
|
66
|
+
engines: ['pipeline'],
|
|
67
|
+
note: 'The pipeline engine core, owned by the `pipeline-tool` wrapper. A surface that reaches it DIRECTLY is driving pipeline turns itself — legitimate, but it bypasses the wrapper`s provider resolution, understand-card and checkpoint default, which is what SURFACE_DEBT used to record for `cli/execute.ts`. No surface does today; the entry stays declared because the wrapper itself is one, and the rule needs something to measure against.',
|
|
68
|
+
},
|
|
69
|
+
'child-runtime': {
|
|
70
|
+
id: 'child-runtime',
|
|
71
|
+
module: 'src/tools/child-agent-runtime.ts',
|
|
72
|
+
symbol: 'runSubagent',
|
|
73
|
+
engines: ['loop'],
|
|
74
|
+
note: 'The subagent child process. It builds its own provider and loop on purpose: it is the isolation boundary, and it reports the provider/model/transport it actually used so the parent can attribute the run.',
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Known surface-level debt, keyed by what is wrong and why it is still here.
|
|
79
|
+
*
|
|
80
|
+
* This is a RATCHET, not an allowlist of convenience: the architecture test
|
|
81
|
+
* asserts the observed violations EQUAL this list, so adding a new bypass fails,
|
|
82
|
+
* and removing one without deleting its entry fails too (a stale entry would
|
|
83
|
+
* otherwise hide the next one). Every entry is somebody's workstream.
|
|
84
|
+
*
|
|
85
|
+
* BOTH ARE EMPTY NOW. `src/cli/execute.ts` was the whole list: it built its own
|
|
86
|
+
* provider and drove the pipeline engine through a private `Orchestrator`. It
|
|
87
|
+
* now resolves through the shared `resolveProvider` and runs pipeline turns
|
|
88
|
+
* through `runPipelineTool`. The keys stay declared with empty arrays on
|
|
89
|
+
* purpose — deleting a key would stop the rule from being measured at all, and
|
|
90
|
+
* the next bypass would then be invisible instead of a one-line diff here.
|
|
91
|
+
*/
|
|
92
|
+
export const SURFACE_DEBT = {
|
|
93
|
+
/** Surface modules that construct their own provider instead of going through a shared entry. */
|
|
94
|
+
'provider-factory': [],
|
|
95
|
+
/** Surface modules that drive the pipeline engine without the `pipeline-tool` wrapper. */
|
|
96
|
+
'pipeline-wrapper-bypass': [],
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Every surface, with the evidence that it exists. Order is display order only.
|
|
100
|
+
*/
|
|
101
|
+
export const SURFACES = [
|
|
102
|
+
{
|
|
103
|
+
id: 'cli-chat',
|
|
104
|
+
label: 'CLI chat',
|
|
105
|
+
modules: ['src/cli/chat.ts', 'src/cli/cli-program.ts'],
|
|
106
|
+
// Two entries, not one: measured, `chat.ts:87` imports `runPipelineTool` and
|
|
107
|
+
// calls it at `:702`, so the chat surface can also run a pipeline turn. The
|
|
108
|
+
// engine is chosen by the user's explicit command (`:298` checks
|
|
109
|
+
// `action.run === 'pipeline'`), NOT by the router — which is why this
|
|
110
|
+
// surface declares both engines and the parity matrix exercises both.
|
|
111
|
+
turnEntries: ['chat-once', 'pipeline-tool'],
|
|
112
|
+
engines: ['loop', 'pipeline'],
|
|
113
|
+
headless: 'Drive ChatCommand.answerOnce with a stub provider and an in-memory askUser responder (the shape chat-console.ts already uses); drive the pipeline path through the same runPipelineTool wrapper.',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'cli-execute',
|
|
117
|
+
label: 'CLI execute / one-shot',
|
|
118
|
+
modules: ['src/cli/execute.ts', 'src/cli/run.ts'],
|
|
119
|
+
// `pipeline-tool` IS here now: measured, `execute.ts` drives its pipeline
|
|
120
|
+
// runs through the wrapper. It used to import the Orchestrator directly and
|
|
121
|
+
// never reach the wrapper — exactly the drift this registry exists to
|
|
122
|
+
// surface, and the reason it was the sole entry on
|
|
123
|
+
// `SURFACE_DEBT['pipeline-wrapper-bypass']`.
|
|
124
|
+
// `chat-once` is here for the same measured reason as ever: execute.ts
|
|
125
|
+
// reaches the chat engine through `import('./chat.js')`, which is also how
|
|
126
|
+
// its interactive mode works.
|
|
127
|
+
turnEntries: ['chat-once', 'loop-executor', 'pipeline-tool'],
|
|
128
|
+
engines: ['loop', 'pipeline'],
|
|
129
|
+
headless: 'Drive the command`s own single-goal path (`runSingleGoal`) with the provider stubbed at the shared factory and the engine pinned to loop, and read the turn AND its attribution (provider/model/transport) and its per-call tool outcomes off what the command returns. Both of the command`s arms report now — the loop engine through `runLoopExecutor` and the direct chat answer through the engine`s `onToolCall`.',
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 'dashboard-chat',
|
|
133
|
+
label: 'Dashboard chat',
|
|
134
|
+
modules: ['src/web-dashboard/server.ts', 'src/web-dashboard/chat-console.ts'],
|
|
135
|
+
turnEntries: ['chat-once'],
|
|
136
|
+
engines: ['loop'],
|
|
137
|
+
headless: 'Call the turn through chat-console with a stub provider and no HTTP transport; the console is the seam, not the server.',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: 'gateway-chat',
|
|
141
|
+
label: 'Gateway (Slack / Discord / Telegram / …)',
|
|
142
|
+
modules: [
|
|
143
|
+
'src/gateway/registry.ts',
|
|
144
|
+
'src/gateway/adapters.ts',
|
|
145
|
+
'src/gateway/realtime.ts',
|
|
146
|
+
],
|
|
147
|
+
turnEntries: ['chat-once', 'pipeline-tool'],
|
|
148
|
+
engines: ['loop', 'pipeline'],
|
|
149
|
+
headless: 'Invoke the registry handler with a synthetic inbound message and a stub adapter; no live transport, no credentials.',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: 'subagent',
|
|
153
|
+
label: 'Subagent child process',
|
|
154
|
+
modules: ['src/tools/child-agent-runtime.ts', 'src/tools/child-agent-entry.ts'],
|
|
155
|
+
turnEntries: ['child-runtime'],
|
|
156
|
+
engines: ['loop'],
|
|
157
|
+
separateProcess: true,
|
|
158
|
+
headless: 'Spawn the child entry with a stub provider over its IPC frames, as tests/tools/subagent-end-to-end.test.ts does.',
|
|
159
|
+
},
|
|
160
|
+
];
|
|
161
|
+
/** A surface by id, or undefined. */
|
|
162
|
+
export function surfaceById(id) {
|
|
163
|
+
return SURFACES.find((s) => s.id === id);
|
|
164
|
+
}
|
|
165
|
+
/** Every surface that runs a turn through `entry`, directly or transitively. */
|
|
166
|
+
export function surfacesReaching(entry) {
|
|
167
|
+
return SURFACES.filter((s) => s.turnEntries.includes(entry));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Every (surface, engine) pair a parity test must exercise. A surface that can
|
|
171
|
+
* select between engines contributes one pair per engine, so a capability that
|
|
172
|
+
* works under `loop` and fails under `pipeline` cannot pass unnoticed.
|
|
173
|
+
*/
|
|
174
|
+
export function parityMatrix() {
|
|
175
|
+
const pairs = [];
|
|
176
|
+
for (const surface of SURFACES) {
|
|
177
|
+
for (const engine of surface.engines)
|
|
178
|
+
pairs.push({ surface: surface.id, engine });
|
|
179
|
+
}
|
|
180
|
+
return pairs;
|
|
181
|
+
}
|
|
182
|
+
/** Repo-relative paths of the surface-owned modules. */
|
|
183
|
+
export function surfaceModulePaths() {
|
|
184
|
+
return [...new Set(SURFACES.flatMap((s) => s.modules))].sort();
|
|
185
|
+
}
|
|
186
|
+
/** Repo-relative paths of the shared turn entries. */
|
|
187
|
+
export function turnEntryModulePaths() {
|
|
188
|
+
return Object.values(TURN_ENTRIES).map((e) => e.module).sort();
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=surfaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surfaces.js","sourceRoot":"","sources":["../../src/parity/surfaces.ts"],"names":[],"mappings":"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"}
|