@hassangameryt/freeflow 0.7.3 → 0.8.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/NOTICE +14 -0
- package/README.md +26 -31
- package/capabilities/cognitive-routing/SKILL.md +106 -161
- package/capabilities/cognitive-routing/references/both-mode.md +36 -0
- package/capabilities/cognitive-routing/references/executor-mode.md +48 -0
- package/capabilities/cognitive-routing/references/helper-mode.md +47 -0
- package/capabilities/compaction/SKILL.md +49 -0
- package/capabilities/compaction/references/summary-format.md +239 -0
- package/command-surface.json +4 -0
- package/gemini-extension.json +1 -1
- package/hooks/shared/runtime-context.mjs +28 -30
- package/licenses/Apache-2.0.txt +55 -0
- package/package.json +22 -9
- package/pi-extension/README.md +41 -0
- package/pi-extension/dist/cognitive-routing/assembler.js +393 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/config.js +5 -2
- package/pi-extension/dist/cognitive-routing/economics.js +45 -0
- package/pi-extension/dist/cognitive-routing/event-schema.js +388 -0
- package/pi-extension/dist/{session-sources/events.js → cognitive-routing/event-store.js} +103 -40
- package/pi-extension/dist/cognitive-routing/gate.js +241 -0
- package/pi-extension/dist/cognitive-routing/handlers.js +899 -0
- package/pi-extension/dist/cognitive-routing/handoffs.js +350 -0
- package/pi-extension/dist/cognitive-routing/model-control.js +467 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/projection.js +229 -56
- package/pi-extension/dist/cognitive-routing/provenance.js +81 -0
- package/pi-extension/dist/cognitive-routing/runtime.js +396 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/schemas.js +43 -7
- package/pi-extension/dist/cognitive-routing/session.js +221 -0
- package/pi-extension/dist/{session-sources → cognitive-routing}/sources.js +99 -85
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/state.js +37 -378
- package/pi-extension/dist/cognitive-routing/status.js +80 -0
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/tools.js +12 -12
- package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/types.js +5 -11
- package/pi-extension/dist/compaction/carry.js +191 -0
- package/pi-extension/dist/compaction/config.js +22 -0
- package/pi-extension/dist/compaction/controller.js +471 -0
- package/pi-extension/dist/compaction/harness.js +77 -0
- package/pi-extension/dist/compaction/results.js +158 -0
- package/pi-extension/dist/compaction/thresholds.js +35 -0
- package/pi-extension/dist/compaction/tool.js +57 -0
- package/pi-extension/dist/host/branch.js +13 -0
- package/pi-extension/dist/host/canonical.js +12 -0
- package/pi-extension/dist/host/catalog.js +77 -0
- package/pi-extension/dist/host/config.js +374 -0
- package/pi-extension/dist/host/projection-tags.js +60 -0
- package/pi-extension/dist/host/prompts.js +82 -0
- package/pi-extension/dist/{session-sources → host}/read-only-session.js +112 -1
- package/pi-extension/dist/{runtime → host}/request-history.js +121 -39
- package/pi-extension/dist/host/runtime-state.js +189 -0
- package/pi-extension/dist/{settings/settings-ui.js → host/settings/freeflow-command.js} +620 -410
- package/pi-extension/dist/{settings/settings-tui.js → host/settings/settings-view.js} +186 -73
- package/pi-extension/dist/host/staging.js +28 -0
- package/pi-extension/dist/host/status.js +101 -0
- package/pi-extension/dist/index.js +423 -173
- package/pi-extension/dist/provider-support/cache/anchor.js +21 -0
- package/pi-extension/dist/provider-support/cache/anthropic.js +102 -0
- package/pi-extension/dist/provider-support/cache/health.js +73 -0
- package/pi-extension/dist/provider-support/cache/index.js +58 -0
- package/pi-extension/dist/provider-support/cache/keepalive.js +210 -0
- package/pi-extension/dist/provider-support/cache/monitor.js +17 -0
- package/pi-extension/dist/provider-support/cache/openai-responses.js +48 -0
- package/pi-extension/dist/provider-support/effort.js +13 -0
- package/pi-extension/dist/provider-support/index.js +44 -3
- package/pi-extension/dist/provider-support/{astra → openai}/adapter.js +46 -29
- package/pi-extension/dist/provider-support/{astra → openai}/history.js +10 -8
- package/pi-extension/dist/provider-support/{astra → openai}/index.js +8 -4
- package/pi-extension/dist/provider-support/{astra → openai}/session-state.js +29 -38
- package/pi-extension/dist/provider-support/routes.js +17 -0
- package/pi-extension/dist/tool-execution/apply-patch/grammar.js +23 -0
- package/pi-extension/dist/tool-execution/apply-patch/match.js +38 -0
- package/pi-extension/dist/tool-execution/apply-patch/parser.js +177 -0
- package/pi-extension/dist/tool-execution/apply-patch/plan.js +201 -0
- package/pi-extension/dist/tool-execution/apply-patch/tool.js +84 -0
- package/pi-extension/dist/tool-execution/background.js +238 -0
- package/pi-extension/dist/tool-execution/bash-guard.js +23 -0
- package/pi-extension/dist/tool-execution/config.js +22 -0
- package/pi-extension/dist/tool-execution/edit-messages.js +120 -0
- package/pi-extension/dist/tool-execution/file-state.js +138 -0
- package/pi-extension/dist/tool-execution/file-tracking.js +143 -0
- package/pi-extension/dist/tool-execution/prompt.js +54 -0
- package/pi-extension/dist/tool-execution/tools.js +16 -0
- package/pi-extension/freeflow/README.md +9 -0
- package/plugin.json +1 -1
- package/runtime/prompts/cognitive-routing.md +4 -4
- package/runtime/prompts/core.md +22 -75
- package/runtime/prompts/interaction-contract.md +15 -8
- package/runtime/prompts/tool-execution.md +38 -0
- package/runtime/prompts/working-method.md +108 -0
- package/skills/action-selection/SKILL.md +39 -47
- package/skills/action-selection/references/trajectory-stalls.md +2 -0
- package/skills/bypass/SKILL.md +2 -2
- package/skills/commit-work/SKILL.md +31 -83
- package/skills/commit-work/references/git-state-edges.md +1 -1
- package/skills/commit-work/references/simple-push.md +2 -0
- package/skills/commit-work/references/staging-decisions.md +1 -1
- package/skills/decision-gate/SKILL.md +31 -50
- package/skills/design-for-depth/SKILL.md +44 -53
- package/skills/design-for-depth/references/design-pressure-signals.md +46 -144
- package/skills/design-for-depth/references/implementation-decisions.md +1 -1
- package/skills/design-for-depth/references/interface-design-loop.md +5 -36
- package/skills/design-for-depth/references/module-and-dependency-design.md +2 -32
- package/skills/design-for-depth/references/state-and-failure-boundaries.md +2 -13
- package/skills/diagnose-failure/SKILL.md +39 -24
- package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +2 -0
- package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +2 -2
- package/skills/discuss/SKILL.md +35 -11
- package/skills/discuss/references/discussion-continuity.md +7 -27
- package/skills/evaluate-skill/SKILL.md +49 -80
- package/skills/evaluate-skill/references/evaluation-definition-schema.md +35 -5
- package/skills/evaluate-skill/references/evaluation-design.md +14 -14
- package/skills/evaluate-skill/references/execution-and-evidence.md +26 -5
- package/skills/evaluate-skill/references/review-and-revision.md +3 -1
- package/skills/evaluate-skill/scripts/lib/definitions.mjs +49 -8
- package/skills/evaluate-skill/scripts/lib/pi.mjs +14 -7
- package/skills/evaluate-skill/scripts/lib/review.mjs +196 -0
- package/skills/evaluate-skill/scripts/lib/runner.mjs +45 -8
- package/skills/evaluate-skill/scripts/lib/sandbox.mjs +2 -0
- package/skills/evaluate-skill/scripts/lib/trials.mjs +103 -0
- package/skills/evaluate-skill/scripts/lib/view.mjs +67 -1
- package/skills/evaluate-skill/scripts/pi-command-tool.mjs +144 -0
- package/skills/evaluate-skill/scripts/pi-guard.mjs +30 -13
- package/skills/evaluate-skill/scripts/skill-eval.mjs +114 -34
- package/skills/execute-work/SKILL.md +41 -9
- package/skills/execute-work/references/code-practices.md +2 -0
- package/skills/execute-work/references/execute-work-edges.md +11 -1
- package/skills/handoff/SKILL.md +1 -1
- package/skills/handoff/references/handoff-templates.md +1 -1
- package/skills/review-artifact/SKILL.md +42 -41
- package/skills/review-artifact/references/adjudicate-artifact-review.md +1 -1
- package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +1 -1
- package/skills/review-work/SKILL.md +38 -32
- package/skills/review-work/references/adjudicate-work-review.md +1 -1
- package/skills/review-work/references/independent-work-reviewer-contract.md +1 -1
- package/skills/review-work/references/security-risk-lens.md +2 -4
- package/skills/setup-freeflow/SKILL.md +3 -1
- package/skills/setup-freeflow/references/activation-contract.md +7 -13
- package/skills/setup-freeflow/references/host-setup.md +3 -3
- package/skills/track-work/SKILL.md +113 -161
- package/skills/track-work/references/working-record-format.md +189 -350
- package/skills/track-work/scripts/lib/document.mjs +62 -6
- package/skills/track-work/scripts/lib/format.mjs +16 -1
- package/skills/track-work/scripts/lib/store.mjs +9 -8
- package/skills/track-work/scripts/lib/transitions.mjs +79 -4
- package/skills/track-work/scripts/working-record.mjs +34 -12
- package/skills/verify-work/SKILL.md +29 -20
- package/skills/verify-work/references/browser-runtime-evidence.md +1 -5
- package/skills/verify-work/references/integration-evidence.md +2 -0
- package/skills/verify-work/references/performance-evidence.md +3 -1
- package/skills/verify-work/references/test-design.md +3 -1
- package/skills/workflow/SKILL.md +65 -21
- package/skills/workflow/references/domain-skill-composition.md +5 -3
- package/skills/write-docs/SKILL.md +83 -0
- package/skills/write-docs/references/documentation-shapes.md +119 -0
- package/skills/write-docs/scripts/docs-check.mjs +139 -0
- package/skills/write-plan/SKILL.md +40 -40
- package/skills/write-plan/references/plan-shapes.md +1 -1
- package/skills/write-skill/SKILL.md +107 -147
- package/skills/write-skill/references/activation-boundaries.md +2 -0
- package/skills/write-skill/references/agent-first-instructions.md +22 -10
- package/skills/write-skill/references/progressive-disclosure.md +4 -2
- package/skills/write-skill/references/skill-dependency-graphs.md +2 -0
- package/skills/write-skill/scripts/lib/similarity.mjs +56 -0
- package/skills/write-skill/scripts/skill-author.mjs +18 -2
- package/skills/write-spec/SKILL.md +34 -41
- package/skills/write-spec/references/artifact-standards.md +1 -1
- package/skills/write-spec/references/decision-records.md +2 -0
- package/skills/write-spec/references/spec-shapes.md +1 -1
- package/capabilities/context-virtualization/SKILL.md +0 -103
- package/capabilities/conversation-history/SKILL.md +0 -53
- package/hooks/tests/check-host-adapters.test.mjs +0 -82
- package/hooks/tests/check-runtime-context-hook.sh +0 -212
- package/pi-extension/dist/cognitive-routing-v2/runtime.js +0 -2181
- package/pi-extension/dist/context-virtualization/commands.js +0 -89
- package/pi-extension/dist/context-virtualization/projector.js +0 -42
- package/pi-extension/dist/context-virtualization/runtime.js +0 -378
- package/pi-extension/dist/context-virtualization/state.js +0 -57
- package/pi-extension/dist/context-virtualization/types.js +0 -10
- package/pi-extension/dist/conversation-history/passages.js +0 -66
- package/pi-extension/dist/conversation-history/ranking.js +0 -105
- package/pi-extension/dist/conversation-history/runtime.js +0 -226
- package/pi-extension/dist/conversation-history/search.js +0 -56
- package/pi-extension/dist/conversation-history/types.js +0 -1
- package/pi-extension/dist/freeflow-context/resolver.js +0 -120
- package/pi-extension/dist/freeflow-context/runtime.js +0 -80
- package/pi-extension/dist/freeflow-context/source-projector.js +0 -95
- package/pi-extension/dist/freeflow-context/tool.js +0 -314
- package/pi-extension/dist/freeflow-context/types.js +0 -12
- package/pi-extension/dist/freeflow-context/visibility.js +0 -28
- package/pi-extension/dist/integrations/mcp-config.js +0 -29
- package/pi-extension/dist/runtime/runtime-context.js +0 -754
- package/pi-extension/dist/runtime/runtime-identity.js +0 -5
- package/pi-extension/dist/session-sources/provenance.js +0 -32
- package/pi-extension/dist/ui/text-component.js +0 -57
- package/pi-extension/src/cognitive-routing-v2/budget.ts +0 -42
- package/pi-extension/src/cognitive-routing-v2/config.ts +0 -173
- package/pi-extension/src/cognitive-routing-v2/projection.ts +0 -375
- package/pi-extension/src/cognitive-routing-v2/render.ts +0 -277
- package/pi-extension/src/cognitive-routing-v2/runtime.ts +0 -2241
- package/pi-extension/src/cognitive-routing-v2/schemas.ts +0 -180
- package/pi-extension/src/cognitive-routing-v2/state.ts +0 -839
- package/pi-extension/src/cognitive-routing-v2/tools.ts +0 -62
- package/pi-extension/src/cognitive-routing-v2/types.ts +0 -254
- package/pi-extension/src/context-virtualization/commands.ts +0 -111
- package/pi-extension/src/context-virtualization/projector.ts +0 -62
- package/pi-extension/src/context-virtualization/runtime.ts +0 -428
- package/pi-extension/src/context-virtualization/state.ts +0 -79
- package/pi-extension/src/context-virtualization/types.ts +0 -92
- package/pi-extension/src/conversation-history/passages.ts +0 -81
- package/pi-extension/src/conversation-history/ranking.ts +0 -155
- package/pi-extension/src/conversation-history/runtime.ts +0 -250
- package/pi-extension/src/conversation-history/search.ts +0 -79
- package/pi-extension/src/conversation-history/types.ts +0 -31
- package/pi-extension/src/freeflow-context/resolver.ts +0 -139
- package/pi-extension/src/freeflow-context/runtime.ts +0 -100
- package/pi-extension/src/freeflow-context/source-projector.ts +0 -106
- package/pi-extension/src/freeflow-context/tool.ts +0 -366
- package/pi-extension/src/freeflow-context/types.ts +0 -70
- package/pi-extension/src/freeflow-context/visibility.ts +0 -53
- package/pi-extension/src/index.ts +0 -390
- package/pi-extension/src/integrations/mcp-config.ts +0 -32
- package/pi-extension/src/provider-support/astra/adapter.ts +0 -108
- package/pi-extension/src/provider-support/astra/history.ts +0 -145
- package/pi-extension/src/provider-support/astra/index.ts +0 -12
- package/pi-extension/src/provider-support/astra/session-state.ts +0 -113
- package/pi-extension/src/provider-support/index.ts +0 -5
- package/pi-extension/src/runtime/request-history.ts +0 -243
- package/pi-extension/src/runtime/runtime-context.ts +0 -860
- package/pi-extension/src/runtime/runtime-identity.ts +0 -8
- package/pi-extension/src/session-sources/events.ts +0 -230
- package/pi-extension/src/session-sources/provenance.ts +0 -39
- package/pi-extension/src/session-sources/read-only-session.ts +0 -170
- package/pi-extension/src/session-sources/sources.ts +0 -334
- package/pi-extension/src/settings/settings-tui.ts +0 -501
- package/pi-extension/src/settings/settings-ui.ts +0 -1652
- package/pi-extension/src/ui/text-component.ts +0 -66
- package/pi-extension/tests/cache-reuse/history.test.js +0 -117
- package/pi-extension/tests/cache-reuse/native.test.js +0 -91
- package/pi-extension/tests/cache-reuse/settings.test.js +0 -211
- package/pi-extension/tests/cognitive-routing-v2/communication.test.js +0 -577
- package/pi-extension/tests/cognitive-routing-v2/compaction-input.test.js +0 -183
- package/pi-extension/tests/cognitive-routing-v2/delegation.test.js +0 -557
- package/pi-extension/tests/cognitive-routing-v2/native.test.js +0 -474
- package/pi-extension/tests/cognitive-routing-v2/performance.test.js +0 -87
- package/pi-extension/tests/cognitive-routing-v2/persistence.test.js +0 -300
- package/pi-extension/tests/cognitive-routing-v2/projection.test.js +0 -241
- package/pi-extension/tests/cognitive-routing-v2/recovery.test.js +0 -1034
- package/pi-extension/tests/cognitive-routing-v2/render.test.js +0 -244
- package/pi-extension/tests/cognitive-routing-v2/runtime.test.js +0 -423
- package/pi-extension/tests/cognitive-routing-v2/stabilization.test.js +0 -521
- package/pi-extension/tests/cognitive-routing-v2/state.test.js +0 -586
- package/pi-extension/tests/context-virtualization/extension.test.js +0 -775
- package/pi-extension/tests/context-virtualization/projector.test.js +0 -110
- package/pi-extension/tests/context-virtualization/runtime.test.js +0 -230
- package/pi-extension/tests/conversation-history/runtime.test.js +0 -98
- package/pi-extension/tests/conversation-history/search.test.js +0 -97
- package/pi-extension/tests/fixtures/pi-host.js +0 -4
- package/pi-extension/tests/fixtures/routing-native.js +0 -191
- package/pi-extension/tests/integration/mode-free-core.test.js +0 -220
- package/pi-extension/tests/integration/pi-extension.test.js +0 -1447
- package/pi-extension/tests/integration/prompt-architecture.test.js +0 -447
- package/pi-extension/tests/integration/unaffected-regressions.test.js +0 -478
- package/pi-extension/tests/provider-support/astra-boundaries.test.js +0 -75
- package/pi-extension/tests/provider-support/astra.test.js +0 -306
- package/pi-extension/tests/provider-support/cli.test.js +0 -92
- package/pi-extension/tests/provider-support/native.test.js +0 -183
- package/pi-extension/tests/settings/settings-tui.test.js +0 -243
- package/pi-extension/tsconfig.json +0 -16
- package/runtime/prompts/context-virtualization.md +0 -3
- package/runtime/prompts/conversation-history.md +0 -3
- package/skills/design-for-depth/references/software-design-philosophy.md +0 -202
- /package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/budget.js +0 -0
- /package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/render.js +0 -0
|
@@ -1,373 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
EFFORTS,
|
|
3
2
|
PROFILES,
|
|
4
3
|
ROUTING_ENTRY,
|
|
5
4
|
canonical,
|
|
6
5
|
eventKey,
|
|
7
6
|
eventValue,
|
|
8
|
-
isObject,
|
|
9
7
|
isWorkerProfile,
|
|
10
8
|
requireCondition as check,
|
|
11
9
|
} from "./types.js";
|
|
12
|
-
|
|
13
|
-
const identity = (x) => text(x, 512);
|
|
14
|
-
const nullableId = (x) => x === null || identity(x);
|
|
15
|
-
const shape = (x, keys) => isObject(x) && Object.keys(x).every((k) => keys.includes(k));
|
|
16
|
-
const uniqueStrings = (x) => Array.isArray(x) && x.every(identity) && new Set(x).size === x.length;
|
|
17
|
-
const pair = (x) =>
|
|
18
|
-
shape(x, ["provider", "modelId", "thinking"]) &&
|
|
19
|
-
identity(x.provider) &&
|
|
20
|
-
identity(x.modelId) &&
|
|
21
|
-
EFFORTS.includes(x.thinking);
|
|
22
|
-
const profileOverrides = (x) =>
|
|
23
|
-
isObject(x) &&
|
|
24
|
-
Object.keys(x).length > 0 &&
|
|
25
|
-
Object.keys(x).every((key) => PROFILES.includes(key)) &&
|
|
26
|
-
Object.values(x).every((value) => value === null || pair(value));
|
|
27
|
-
const problemList = (xs) =>
|
|
28
|
-
Array.isArray(xs) &&
|
|
29
|
-
xs.every(
|
|
30
|
-
(x) =>
|
|
31
|
-
shape(x, ["ref", "code", "detail"]) && typeof x.ref === "string" && text(x.code, 256) && text(x.detail, 4096),
|
|
32
|
-
);
|
|
33
|
-
const reservation = (r) =>
|
|
34
|
-
shape(r, [
|
|
35
|
-
"id",
|
|
36
|
-
"selectionRevision",
|
|
37
|
-
"receiver",
|
|
38
|
-
"target",
|
|
39
|
-
"qualification",
|
|
40
|
-
"sources",
|
|
41
|
-
"maximumInputTokens",
|
|
42
|
-
"outputReserve",
|
|
43
|
-
"estimateMethod",
|
|
44
|
-
]) &&
|
|
45
|
-
identity(r.id) &&
|
|
46
|
-
Number.isSafeInteger(r.selectionRevision) &&
|
|
47
|
-
r.selectionRevision >= 0 &&
|
|
48
|
-
PROFILES.includes(r.receiver) &&
|
|
49
|
-
pair(r.target) &&
|
|
50
|
-
text(r.qualification) &&
|
|
51
|
-
Array.isArray(r.sources) &&
|
|
52
|
-
r.sources.every((s) => shape(s, ["ref", "bodyHash"]) && identity(s.ref) && /^[a-f0-9]{64}$/.test(s.bodyHash)) &&
|
|
53
|
-
new Set(r.sources.map((s) => s.ref)).size === r.sources.length &&
|
|
54
|
-
Number.isFinite(r.maximumInputTokens) &&
|
|
55
|
-
r.maximumInputTokens > 0 &&
|
|
56
|
-
Number.isFinite(r.outputReserve) &&
|
|
57
|
-
r.outputReserve >= 0 &&
|
|
58
|
-
text(r.estimateMethod);
|
|
59
|
-
const recovery = (r) =>
|
|
60
|
-
shape(r, [
|
|
61
|
-
"id",
|
|
62
|
-
"assignmentId",
|
|
63
|
-
"assessmentHandoffId",
|
|
64
|
-
"baseReportRevision",
|
|
65
|
-
"request",
|
|
66
|
-
"requestedPaths",
|
|
67
|
-
"paths",
|
|
68
|
-
"state",
|
|
69
|
-
"requestHandoffId",
|
|
70
|
-
"supplementHandoffId",
|
|
71
|
-
"supplementRevision",
|
|
72
|
-
"cancellationReason",
|
|
73
|
-
]) &&
|
|
74
|
-
identity(r.id) &&
|
|
75
|
-
identity(r.assignmentId) &&
|
|
76
|
-
identity(r.assessmentHandoffId) &&
|
|
77
|
-
Number.isSafeInteger(r.baseReportRevision) &&
|
|
78
|
-
r.baseReportRevision > 0 &&
|
|
79
|
-
text(r.request) &&
|
|
80
|
-
Array.isArray(r.requestedPaths) &&
|
|
81
|
-
r.requestedPaths.length <= 32 &&
|
|
82
|
-
r.requestedPaths.every((path) => text(path, 4096)) &&
|
|
83
|
-
new Set(r.requestedPaths).size === r.requestedPaths.length &&
|
|
84
|
-
Array.isArray(r.paths) &&
|
|
85
|
-
r.paths.length <= 32 &&
|
|
86
|
-
r.paths.every((path) => text(path, 4096)) &&
|
|
87
|
-
new Set(r.paths).size === r.paths.length &&
|
|
88
|
-
["requested", "reading", "returning", "completed", "cancelled"].includes(r.state) &&
|
|
89
|
-
identity(r.requestHandoffId) &&
|
|
90
|
-
(r.supplementHandoffId === undefined || identity(r.supplementHandoffId)) &&
|
|
91
|
-
Number.isSafeInteger(r.supplementRevision) &&
|
|
92
|
-
r.supplementRevision >= 0 &&
|
|
93
|
-
(r.cancellationReason === undefined || text(r.cancellationReason, 2048));
|
|
94
|
-
const handoff = (h) =>
|
|
95
|
-
shape(h, [
|
|
96
|
-
"id",
|
|
97
|
-
"kind",
|
|
98
|
-
"assignmentId",
|
|
99
|
-
"text",
|
|
100
|
-
"from",
|
|
101
|
-
"to",
|
|
102
|
-
"executionId",
|
|
103
|
-
"toolCallId",
|
|
104
|
-
"basisUserEntryId",
|
|
105
|
-
"state",
|
|
106
|
-
"reportRevision",
|
|
107
|
-
"outcome",
|
|
108
|
-
"limitations",
|
|
109
|
-
"reason",
|
|
110
|
-
]) &&
|
|
111
|
-
identity(h.id) &&
|
|
112
|
-
identity(h.assignmentId) &&
|
|
113
|
-
text(h.text) &&
|
|
114
|
-
identity(h.executionId) &&
|
|
115
|
-
identity(h.toolCallId) &&
|
|
116
|
-
nullableId(h.basisUserEntryId) &&
|
|
117
|
-
["delegate", "return", "recovery-request", "recovery-return"].includes(h.kind) &&
|
|
118
|
-
PROFILES.includes(h.from) &&
|
|
119
|
-
PROFILES.includes(h.to) &&
|
|
120
|
-
h.from !== h.to &&
|
|
121
|
-
["pending", "configured", "blocked", "superseded"].includes(h.state) &&
|
|
122
|
-
Number.isSafeInteger(h.reportRevision) &&
|
|
123
|
-
h.reportRevision >= 0 &&
|
|
124
|
-
Array.isArray(h.limitations) &&
|
|
125
|
-
h.limitations.length <= 32 &&
|
|
126
|
-
h.limitations.every((x) => text(x, 2048)) &&
|
|
127
|
-
(h.reason === undefined || text(h.reason, 4096)) &&
|
|
128
|
-
(h.outcome === undefined || ["completed", "partial", "blocked"].includes(h.outcome)) &&
|
|
129
|
-
(["delegate", "recovery-request"].includes(h.kind)
|
|
130
|
-
? h.outcome === undefined && h.reportRevision === 0
|
|
131
|
-
: ["completed", "partial", "blocked"].includes(h.outcome) && h.reportRevision > 0);
|
|
132
|
-
const fields = {
|
|
133
|
-
"execution-interrupted": ["executionId", "reason"],
|
|
134
|
-
"assignment-resumed": ["assignmentId", "basisUserEntryId"],
|
|
135
|
-
control: ["control", "profile", "reason"],
|
|
136
|
-
"profile-overrides": ["overrides", "reason"],
|
|
137
|
-
"execution-opened": ["execution"],
|
|
138
|
-
"execution-bound": ["executionId", "assistantEntryId", "resultEntryIds", "outcome"],
|
|
139
|
-
"delegate-accepted": ["unit", "assignment", "handoff", "replacement"],
|
|
140
|
-
"return-accepted": ["handoff"],
|
|
141
|
-
"recovery-request-accepted": ["recovery", "handoff"],
|
|
142
|
-
"recovery-supplement-accepted": ["recoveryId", "handoff"],
|
|
143
|
-
"recovery-cancelled": ["recoveryId", "reason"],
|
|
144
|
-
"handoff-retry-requested": [
|
|
145
|
-
"handoffId",
|
|
146
|
-
"attemptId",
|
|
147
|
-
"executionId",
|
|
148
|
-
"toolCallId",
|
|
149
|
-
"reportRevision",
|
|
150
|
-
"selectionRevision",
|
|
151
|
-
],
|
|
152
|
-
"handoff-prepared": ["handoffId", "reservation"],
|
|
153
|
-
"handoff-state": ["handoffId", "state", "reason", "observedPair"],
|
|
154
|
-
"selection-changed": ["assignmentId", "selection"],
|
|
155
|
-
"assessment-suspended": ["handoffId", "reason", "basisUserEntryId", "problems"],
|
|
156
|
-
"assessment-resumed": ["handoffId", "basisUserEntryId", "reservation"],
|
|
157
|
-
"unit-closed": ["unitId", "outcome", "assessment", "supersededAssignmentId"],
|
|
158
|
-
"sources-exposed": ["executionId", "view", "sources"],
|
|
159
|
-
"request-observed": ["executionId", "profile", "boundary", "manifestHash", "handoffId", "selectionRevision"],
|
|
160
|
-
};
|
|
161
|
-
export function parseRoutingEvent(raw) {
|
|
162
|
-
check(
|
|
163
|
-
isObject(raw) &&
|
|
164
|
-
raw.version === 2 &&
|
|
165
|
-
identity(raw.eventId) &&
|
|
166
|
-
identity(raw.operationId) &&
|
|
167
|
-
identity(raw.stepId) &&
|
|
168
|
-
identity(raw.recordedSessionId) &&
|
|
169
|
-
isObject(raw.data),
|
|
170
|
-
"invalid_event",
|
|
171
|
-
);
|
|
172
|
-
check(
|
|
173
|
-
Object.keys(raw).every((k) =>
|
|
174
|
-
["version", "eventId", "operationId", "stepId", "recordedSessionId", "data"].includes(k),
|
|
175
|
-
),
|
|
176
|
-
"invalid_event_field",
|
|
177
|
-
);
|
|
178
|
-
const d = raw.data;
|
|
179
|
-
check(
|
|
180
|
-
typeof d.type === "string" &&
|
|
181
|
-
Object.hasOwn(fields, d.type) &&
|
|
182
|
-
Object.keys(d).every((k) => k === "type" || fields[d.type].includes(k)),
|
|
183
|
-
"invalid_event_type",
|
|
184
|
-
);
|
|
185
|
-
check(Buffer.byteLength(JSON.stringify(raw)) <= 512 * 1024, "event_too_large");
|
|
186
|
-
if (d.handoffId !== undefined) check(identity(d.handoffId), "invalid_handoff_id");
|
|
187
|
-
switch (d.type) {
|
|
188
|
-
case "execution-interrupted":
|
|
189
|
-
check(identity(d.executionId) && text(d.reason, 4096), "invalid_interruption");
|
|
190
|
-
break;
|
|
191
|
-
case "assignment-resumed":
|
|
192
|
-
check(identity(d.assignmentId) && nullableId(d.basisUserEntryId), "invalid_resume");
|
|
193
|
-
break;
|
|
194
|
-
case "control":
|
|
195
|
-
check(
|
|
196
|
-
["automatic", "manual", "inactive"].includes(d.control) &&
|
|
197
|
-
text(d.reason, 4096) &&
|
|
198
|
-
(d.profile === undefined || PROFILES.includes(d.profile)) &&
|
|
199
|
-
(d.control === "inactive" || PROFILES.includes(d.profile)),
|
|
200
|
-
"invalid_control",
|
|
201
|
-
);
|
|
202
|
-
break;
|
|
203
|
-
case "profile-overrides":
|
|
204
|
-
check(profileOverrides(d.overrides) && text(d.reason, 4096), "invalid_profile_overrides");
|
|
205
|
-
break;
|
|
206
|
-
case "execution-opened": {
|
|
207
|
-
const e = d.execution;
|
|
208
|
-
check(
|
|
209
|
-
shape(e, ["id", "profile", "assignmentId", "recoveryId", "basisUserEntryId", "pair", "resultEntryIds"]) &&
|
|
210
|
-
identity(e.id) &&
|
|
211
|
-
["solo", ...PROFILES].includes(e.profile) &&
|
|
212
|
-
nullableId(e.basisUserEntryId) &&
|
|
213
|
-
pair(e.pair) &&
|
|
214
|
-
uniqueStrings(e.resultEntryIds) &&
|
|
215
|
-
e.resultEntryIds.length === 0 &&
|
|
216
|
-
(e.assignmentId === undefined || identity(e.assignmentId)) &&
|
|
217
|
-
(e.recoveryId === undefined || identity(e.recoveryId)),
|
|
218
|
-
"invalid_execution",
|
|
219
|
-
);
|
|
220
|
-
break;
|
|
221
|
-
}
|
|
222
|
-
case "execution-bound":
|
|
223
|
-
check(
|
|
224
|
-
identity(d.executionId) &&
|
|
225
|
-
identity(d.assistantEntryId) &&
|
|
226
|
-
uniqueStrings(d.resultEntryIds) &&
|
|
227
|
-
["completed", "failed", "aborted"].includes(d.outcome),
|
|
228
|
-
"invalid_binding",
|
|
229
|
-
);
|
|
230
|
-
break;
|
|
231
|
-
case "delegate-accepted": {
|
|
232
|
-
const u = d.unit,
|
|
233
|
-
a = d.assignment,
|
|
234
|
-
r = d.replacement;
|
|
235
|
-
check(
|
|
236
|
-
shape(u, ["id", "objective", "state", "assignmentIds"]) &&
|
|
237
|
-
identity(u.id) &&
|
|
238
|
-
text(u.objective) &&
|
|
239
|
-
u.state === "open" &&
|
|
240
|
-
uniqueStrings(u.assignmentIds),
|
|
241
|
-
"invalid_unit",
|
|
242
|
-
);
|
|
243
|
-
check(
|
|
244
|
-
shape(a, ["id", "unitId", "contract", "basisUserEntryId", "state", "delegateHandoffId"]) &&
|
|
245
|
-
identity(a.id) &&
|
|
246
|
-
identity(a.unitId) &&
|
|
247
|
-
text(a.contract) &&
|
|
248
|
-
nullableId(a.basisUserEntryId) &&
|
|
249
|
-
a.state === "outstanding" &&
|
|
250
|
-
identity(a.delegateHandoffId) &&
|
|
251
|
-
handoff(d.handoff),
|
|
252
|
-
"invalid_assignment",
|
|
253
|
-
);
|
|
254
|
-
check(
|
|
255
|
-
r === undefined ||
|
|
256
|
-
(shape(r, ["assignmentId", "supersededHandoffId", "reason"]) &&
|
|
257
|
-
identity(r.assignmentId) &&
|
|
258
|
-
text(r.reason, 2048) &&
|
|
259
|
-
(r.supersededHandoffId === undefined || identity(r.supersededHandoffId))),
|
|
260
|
-
"invalid_replacement",
|
|
261
|
-
);
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
case "return-accepted":
|
|
265
|
-
check(handoff(d.handoff) && d.handoff.kind === "return", "invalid_return");
|
|
266
|
-
break;
|
|
267
|
-
case "recovery-request-accepted":
|
|
268
|
-
check(
|
|
269
|
-
recovery(d.recovery) &&
|
|
270
|
-
handoff(d.handoff) &&
|
|
271
|
-
d.handoff.kind === "recovery-request" &&
|
|
272
|
-
d.recovery.requestHandoffId === d.handoff.id &&
|
|
273
|
-
d.recovery.assignmentId === d.handoff.assignmentId &&
|
|
274
|
-
d.recovery.request === d.handoff.text,
|
|
275
|
-
"invalid_recovery_request",
|
|
276
|
-
);
|
|
277
|
-
break;
|
|
278
|
-
case "recovery-supplement-accepted":
|
|
279
|
-
check(
|
|
280
|
-
identity(d.recoveryId) && handoff(d.handoff) && d.handoff.kind === "recovery-return",
|
|
281
|
-
"invalid_recovery_supplement",
|
|
282
|
-
);
|
|
283
|
-
break;
|
|
284
|
-
case "recovery-cancelled":
|
|
285
|
-
check(identity(d.recoveryId) && text(d.reason, 2048), "invalid_recovery_cancellation");
|
|
286
|
-
break;
|
|
287
|
-
case "handoff-retry-requested":
|
|
288
|
-
check(
|
|
289
|
-
identity(d.attemptId) &&
|
|
290
|
-
identity(d.executionId) &&
|
|
291
|
-
identity(d.toolCallId) &&
|
|
292
|
-
Number.isSafeInteger(d.reportRevision) &&
|
|
293
|
-
d.reportRevision > 0 &&
|
|
294
|
-
Number.isSafeInteger(d.selectionRevision) &&
|
|
295
|
-
d.selectionRevision >= 0,
|
|
296
|
-
"invalid_retry",
|
|
297
|
-
);
|
|
298
|
-
break;
|
|
299
|
-
case "handoff-prepared":
|
|
300
|
-
check(reservation(d.reservation), "invalid_reservation");
|
|
301
|
-
break;
|
|
302
|
-
case "handoff-state":
|
|
303
|
-
check(
|
|
304
|
-
["configured", "blocked", "superseded"].includes(d.state) &&
|
|
305
|
-
(d.reason === undefined || text(d.reason, 4096)) &&
|
|
306
|
-
(d.observedPair === undefined || pair(d.observedPair)),
|
|
307
|
-
"invalid_delivery",
|
|
308
|
-
);
|
|
309
|
-
break;
|
|
310
|
-
case "selection-changed": {
|
|
311
|
-
const s = d.selection;
|
|
312
|
-
check(
|
|
313
|
-
identity(d.assignmentId) &&
|
|
314
|
-
shape(s, ["revision", "selected", "unresolved", "withdrawals"]) &&
|
|
315
|
-
Number.isSafeInteger(s.revision) &&
|
|
316
|
-
s.revision > 0 &&
|
|
317
|
-
uniqueStrings(s.selected) &&
|
|
318
|
-
problemList(s.unresolved) &&
|
|
319
|
-
Array.isArray(s.withdrawals) &&
|
|
320
|
-
s.withdrawals.every((w) => shape(w, ["ref", "reason"]) && identity(w.ref) && text(w.reason, 2048)),
|
|
321
|
-
"invalid_selection",
|
|
322
|
-
);
|
|
323
|
-
break;
|
|
324
|
-
}
|
|
325
|
-
case "assessment-suspended":
|
|
326
|
-
check(
|
|
327
|
-
["user-attention", "delivery-gap"].includes(d.reason) &&
|
|
328
|
-
nullableId(d.basisUserEntryId) &&
|
|
329
|
-
problemList(d.problems),
|
|
330
|
-
"invalid_suspension",
|
|
331
|
-
);
|
|
332
|
-
break;
|
|
333
|
-
case "assessment-resumed":
|
|
334
|
-
check(
|
|
335
|
-
nullableId(d.basisUserEntryId) && (d.reservation === undefined || reservation(d.reservation)),
|
|
336
|
-
"invalid_resumption",
|
|
337
|
-
);
|
|
338
|
-
break;
|
|
339
|
-
case "unit-closed":
|
|
340
|
-
check(
|
|
341
|
-
identity(d.unitId) &&
|
|
342
|
-
["accepted", "cancelled", "deferred"].includes(d.outcome) &&
|
|
343
|
-
text(d.assessment) &&
|
|
344
|
-
(d.supersededAssignmentId === undefined || identity(d.supersededAssignmentId)),
|
|
345
|
-
"invalid_closure",
|
|
346
|
-
);
|
|
347
|
-
break;
|
|
348
|
-
case "request-observed":
|
|
349
|
-
check(
|
|
350
|
-
identity(d.executionId) &&
|
|
351
|
-
["solo", ...PROFILES].includes(d.profile) &&
|
|
352
|
-
["assembled", "payload-hook"].includes(d.boundary) &&
|
|
353
|
-
/^[a-f0-9]{64}$/.test(d.manifestHash) &&
|
|
354
|
-
(d.selectionRevision === undefined ||
|
|
355
|
-
(Number.isSafeInteger(d.selectionRevision) && d.selectionRevision >= 0)),
|
|
356
|
-
"invalid_request_observation",
|
|
357
|
-
);
|
|
358
|
-
break;
|
|
359
|
-
case "sources-exposed":
|
|
360
|
-
check(
|
|
361
|
-
identity(d.executionId) &&
|
|
362
|
-
["solo", ...PROFILES].includes(d.view) &&
|
|
363
|
-
Array.isArray(d.sources) &&
|
|
364
|
-
d.sources.every((s) => shape(s, ["ref", "bodyHash"]) && identity(s.ref) && /^[a-f0-9]{64}$/.test(s.bodyHash)),
|
|
365
|
-
"invalid_exposure",
|
|
366
|
-
);
|
|
367
|
-
break;
|
|
368
|
-
}
|
|
369
|
-
return structuredClone(raw);
|
|
370
|
-
}
|
|
10
|
+
import { parseRoutingEvent } from "./event-schema.js";
|
|
371
11
|
export function initialState() {
|
|
372
12
|
return {
|
|
373
13
|
control: "inactive",
|
|
@@ -405,7 +45,17 @@ function applyEvent(state, event, owned = false) {
|
|
|
405
45
|
units: new Map([...state.units].map(([k, v]) => [k, { ...v }])),
|
|
406
46
|
assignments: new Map([...state.assignments].map(([k, v]) => [k, { ...v }])),
|
|
407
47
|
handoffs: new Map([...state.handoffs].map(([k, v]) => [k, { ...v }])),
|
|
408
|
-
recoveries: new Map(
|
|
48
|
+
recoveries: new Map(
|
|
49
|
+
[...state.recoveries].map(([k, v]) => [
|
|
50
|
+
k,
|
|
51
|
+
{
|
|
52
|
+
...v,
|
|
53
|
+
paths: [...v.paths],
|
|
54
|
+
requestedResults: [...(v.requestedResults ?? [])],
|
|
55
|
+
results: (v.results ?? []).map((grant) => ({ ...grant })),
|
|
56
|
+
},
|
|
57
|
+
]),
|
|
58
|
+
),
|
|
409
59
|
executions: new Map([...state.executions].map(([k, v]) => [k, { ...v }])),
|
|
410
60
|
selections: new Map(state.selections),
|
|
411
61
|
reservations: new Map(state.reservations),
|
|
@@ -426,6 +76,11 @@ function applyEvent(state, event, owned = false) {
|
|
|
426
76
|
check(h?.kind === "delegate" && h.assignmentId === a?.id && isWorkerProfile(h.to), "assignment_worker_missing");
|
|
427
77
|
return h.to;
|
|
428
78
|
};
|
|
79
|
+
// A worker response that started but was neither bound nor retired may still be producing effects.
|
|
80
|
+
const workerRunning = (belongs) =>
|
|
81
|
+
[...s.executions.values()].some(
|
|
82
|
+
(x) => belongs(x) && isWorkerProfile(x.profile) && !x.assistantEntryId && !x.interrupted,
|
|
83
|
+
);
|
|
429
84
|
const pending = () => (s.pendingId ? s.handoffs.get(s.pendingId) : undefined);
|
|
430
85
|
const isPending = () => pending() && ["pending", "blocked"].includes(pending().state);
|
|
431
86
|
const currentReturn = (id) => {
|
|
@@ -464,6 +119,9 @@ function applyEvent(state, event, owned = false) {
|
|
|
464
119
|
else s.profileOverrides.set(profile, override);
|
|
465
120
|
}
|
|
466
121
|
break;
|
|
122
|
+
case "delegation-override":
|
|
123
|
+
s.delegationOverride = d.delegation ?? undefined;
|
|
124
|
+
break;
|
|
467
125
|
case "execution-opened":
|
|
468
126
|
check(!s.executions.has(d.execution.id), "duplicate_execution");
|
|
469
127
|
s.executions.set(d.execution.id, d.execution);
|
|
@@ -513,19 +171,17 @@ function applyEvent(state, event, owned = false) {
|
|
|
513
171
|
);
|
|
514
172
|
if (d.replacement) {
|
|
515
173
|
check(a?.state === "outstanding" && a.id === d.replacement.assignmentId && u, "no_replaceable_assignment");
|
|
516
|
-
check(
|
|
517
|
-
![...s.executions.values()].some(
|
|
518
|
-
(x) => x.assignmentId === a.id && isWorkerProfile(x.profile) && !x.assistantEntryId && !x.interrupted,
|
|
519
|
-
),
|
|
520
|
-
"unresolved_worker_execution",
|
|
521
|
-
);
|
|
174
|
+
check(!workerRunning((x) => x.assignmentId === a.id), "unresolved_worker_execution");
|
|
522
175
|
check(
|
|
523
176
|
!isPending() || (pending().kind === "delegate" && d.replacement.supersededHandoffId === pending().id),
|
|
524
177
|
"handoff_pending",
|
|
525
178
|
);
|
|
526
179
|
a.state = "superseded";
|
|
527
180
|
s.handoffs.get(a.delegateHandoffId).state = "superseded";
|
|
528
|
-
} else
|
|
181
|
+
} else {
|
|
182
|
+
check(a?.state !== "outstanding" && !isPending(), "assignment_outstanding");
|
|
183
|
+
check(!s.recoveryId, "recovery_outstanding");
|
|
184
|
+
}
|
|
529
185
|
s.units.set(d.unit.id, d.unit);
|
|
530
186
|
s.unitId = d.unit.id;
|
|
531
187
|
s.assignments.set(d.assignment.id, d.assignment);
|
|
@@ -602,7 +258,11 @@ function applyEvent(state, event, owned = false) {
|
|
|
602
258
|
!s.recoveries.has(d.recovery.id),
|
|
603
259
|
"recovery_not_available",
|
|
604
260
|
);
|
|
605
|
-
s.recoveries.set(d.recovery.id,
|
|
261
|
+
s.recoveries.set(d.recovery.id, {
|
|
262
|
+
...d.recovery,
|
|
263
|
+
requestedResults: [...(d.recovery.requestedResults ?? [])],
|
|
264
|
+
results: (d.recovery.results ?? []).map((grant) => ({ ...grant })),
|
|
265
|
+
});
|
|
606
266
|
s.recoveryId = d.recovery.id;
|
|
607
267
|
s.handoffs.set(h.id, h);
|
|
608
268
|
s.pendingId = h.id;
|
|
@@ -652,6 +312,7 @@ function applyEvent(state, event, owned = false) {
|
|
|
652
312
|
["requested", "reading", "returning"].includes(r.state),
|
|
653
313
|
"recovery_not_cancellable",
|
|
654
314
|
);
|
|
315
|
+
check(!workerRunning((x) => x.recoveryId === r.id), "unresolved_worker_execution");
|
|
655
316
|
const p = pending();
|
|
656
317
|
if (p) {
|
|
657
318
|
check([r.requestHandoffId, r.supplementHandoffId].includes(p.id), "handoff_pending");
|
|
@@ -737,14 +398,10 @@ function applyEvent(state, event, owned = false) {
|
|
|
737
398
|
break;
|
|
738
399
|
}
|
|
739
400
|
case "assessment-resumed": {
|
|
740
|
-
check(
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
s.assessment?.handoffId === d.handoffId &&
|
|
745
|
-
s.assessment.view === "suspended",
|
|
746
|
-
s.recoveryId ? "recovery_outstanding" : "assessment_not_suspended",
|
|
747
|
-
);
|
|
401
|
+
check(s.control === "automatic" && s.profile === "coordinator", "wrong_control");
|
|
402
|
+
check(!s.recoveryId, "recovery_outstanding");
|
|
403
|
+
check(s.assessment?.handoffId === d.handoffId, "assessment_missing");
|
|
404
|
+
check(s.assessment.view === "suspended", "assessment_not_suspended");
|
|
748
405
|
if (d.reservation)
|
|
749
406
|
check(
|
|
750
407
|
d.reservation.selectionRevision === (s.selections.get(s.assessment.assignmentId)?.revision ?? 0),
|
|
@@ -775,6 +432,7 @@ function applyEvent(state, event, owned = false) {
|
|
|
775
432
|
d.outcome !== "accepted" && ["requested", "reading", "returning"].includes(recovery.state),
|
|
776
433
|
"unfinished_work",
|
|
777
434
|
);
|
|
435
|
+
check(!workerRunning((x) => x.recoveryId === recovery.id), "unresolved_worker_execution");
|
|
778
436
|
const transfer = pending();
|
|
779
437
|
if (transfer) {
|
|
780
438
|
check([recovery.requestHandoffId, recovery.supplementHandoffId].includes(transfer.id), "handoff_pending");
|
|
@@ -787,6 +445,7 @@ function applyEvent(state, event, owned = false) {
|
|
|
787
445
|
}
|
|
788
446
|
if (a?.state === "outstanding") {
|
|
789
447
|
check(d.supersededAssignmentId === a.id && d.outcome !== "accepted", "supersession_required");
|
|
448
|
+
check(!workerRunning((x) => x.assignmentId === a.id), "unresolved_worker_execution");
|
|
790
449
|
a.state = "superseded";
|
|
791
450
|
}
|
|
792
451
|
if (pending()) pending().state = "superseded";
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { initialState } from "./state.js";
|
|
2
|
+
/**
|
|
3
|
+
* What routing reports about itself: the summary behind Freeflow's status line and the Runtime State sent with each
|
|
4
|
+
* request (whether routing is active or blocked and why, the running profile, control mode, a switch waiting for the
|
|
5
|
+
* next prompt, preset warnings), and the detailed view with unit, assignment, handoff, recovery, and recent events
|
|
6
|
+
* used by unit status and diagnostics.
|
|
7
|
+
*/
|
|
8
|
+
export class RoutingStatus {
|
|
9
|
+
session;
|
|
10
|
+
models;
|
|
11
|
+
constructor(session, models) {
|
|
12
|
+
this.session = session;
|
|
13
|
+
this.models = models;
|
|
14
|
+
}
|
|
15
|
+
state() {
|
|
16
|
+
let state;
|
|
17
|
+
try {
|
|
18
|
+
state = this.session.stateData();
|
|
19
|
+
} catch {
|
|
20
|
+
state = initialState();
|
|
21
|
+
}
|
|
22
|
+
const blocked = this.session.error ?? this.session.store?.blocked;
|
|
23
|
+
return {
|
|
24
|
+
effective: this.session.supported() && state.control !== "inactive" && !blocked,
|
|
25
|
+
activeProfile: state.profile,
|
|
26
|
+
delegation: this.session.delegation(state),
|
|
27
|
+
controlMode: state.control === "manual" ? `manual-${state.profile}` : state.control,
|
|
28
|
+
runtimeStatus: blocked
|
|
29
|
+
? "blocked"
|
|
30
|
+
: this.session.supported() && state.control !== "inactive"
|
|
31
|
+
? "active"
|
|
32
|
+
: "inactive",
|
|
33
|
+
runtimeReason:
|
|
34
|
+
blocked ?? (this.session.suppressed ? "startup_selection" : this.session.capability?.blockingReason.message),
|
|
35
|
+
projectionFailure: this.session.projectionError,
|
|
36
|
+
...((pending) => (pending ? { pendingPair: `${pending.modelId}/${pending.thinking}` } : {}))(
|
|
37
|
+
this.models.pending(),
|
|
38
|
+
),
|
|
39
|
+
...(this.models.heldMismatch(state) ? { pairMismatch: true } : {}),
|
|
40
|
+
...((warnings) => (warnings.length ? { presetWarnings: warnings } : {}))(this.models.presetWarnings(state)),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
detail(limit = 0) {
|
|
44
|
+
const state = this.session.stateData();
|
|
45
|
+
const unit = state.unitId ? state.units.get(state.unitId) : undefined;
|
|
46
|
+
const a = state.assignmentId ? state.assignments.get(state.assignmentId) : undefined;
|
|
47
|
+
return {
|
|
48
|
+
...this.state(),
|
|
49
|
+
unit: unit ? { id: unit.id, state: unit.state, assignments: unit.assignmentIds.length } : null,
|
|
50
|
+
assignment: a ? { id: a.id, state: a.state, worker: this.session.assignedWorker(state, a.id) } : null,
|
|
51
|
+
pendingHandoff: state.pendingId ?? null,
|
|
52
|
+
recovery: state.recoveryId
|
|
53
|
+
? (() => {
|
|
54
|
+
const recovery = state.recoveries.get(state.recoveryId);
|
|
55
|
+
return recovery
|
|
56
|
+
? {
|
|
57
|
+
id: recovery.id,
|
|
58
|
+
state: recovery.state,
|
|
59
|
+
assignmentId: recovery.assignmentId,
|
|
60
|
+
assessmentHandoffId: recovery.assessmentHandoffId,
|
|
61
|
+
paths: recovery.paths,
|
|
62
|
+
results: recovery.results ?? [],
|
|
63
|
+
supplementRevision: recovery.supplementRevision,
|
|
64
|
+
}
|
|
65
|
+
: null;
|
|
66
|
+
})()
|
|
67
|
+
: null,
|
|
68
|
+
assessment: state.assessment
|
|
69
|
+
? { handoffId: state.assessment.handoffId, view: state.assessment.view, problems: state.assessment.problems }
|
|
70
|
+
: null,
|
|
71
|
+
...(limit
|
|
72
|
+
? {
|
|
73
|
+
history: [...state.events.values()]
|
|
74
|
+
.slice(-Math.min(100, Math.max(1, limit)))
|
|
75
|
+
.map((e) => ({ event: e.eventId, type: e.data.type, operation: e.operationId })),
|
|
76
|
+
}
|
|
77
|
+
: {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ROUTING_TOOLS } from "./
|
|
2
|
-
import { ROUTING_SCHEMAS, matches } from "./schemas.js";
|
|
1
|
+
import { ROUTING_TOOLS } from "./types.js";
|
|
2
|
+
import { ROUTING_SCHEMAS, explainRoutingArguments, matches } from "./schemas.js";
|
|
3
3
|
export { ROUTING_SCHEMAS } from "./schemas.js";
|
|
4
4
|
import { renderRoutingCall, renderRoutingResult } from "./render.js";
|
|
5
5
|
const descriptions = {
|
|
@@ -10,7 +10,7 @@ const descriptions = {
|
|
|
10
10
|
freeflow_unit:
|
|
11
11
|
"Inspect current responsibility, paginated work history, or exact saved communication. Coordinator can restore an assessment, request or cancel attached evidence recovery, or close a unit without clearing history.",
|
|
12
12
|
freeflow_project:
|
|
13
|
-
"Inspect current selection and scoped candidates when needed, then add or remove exposed worker task-evidence refs. Strict shapes: inspect uses operation plus optional scope/cursor; add uses operation plus eligible refs only; remove uses operation plus currently selected or unresolved refs plus required reason. Reason is remove-only.
|
|
13
|
+
"Inspect current selection and scoped candidates when needed, then add or remove exposed worker task-evidence refs. Strict shapes: inspect uses operation plus optional scope/cursor; add uses operation plus eligible refs only; remove uses operation plus currently selected or unresolved refs plus required reason. Reason is remove-only. Only tool results are evidence; put anything you would say in the report.",
|
|
14
14
|
};
|
|
15
15
|
const guidance = {
|
|
16
16
|
freeflow_delegate: [
|
|
@@ -23,7 +23,7 @@ const guidance = {
|
|
|
23
23
|
"freeflow_unit inspect defaults to current state; view history returns work refs and detail reads saved communication. Coordinator recover requests bounded evidence work against the current returned assessment; cancel-recovery ends only that recovery; assess restores a suspended evidence obligation; close changes work status without clearing communication or completing a Working Record task.",
|
|
24
24
|
],
|
|
25
25
|
freeflow_project: [
|
|
26
|
-
"Use exactly one shape: inspect {operation, scope?, cursor?}; add {operation, refs} with no reason; remove {operation, refs, reason}. Reason is required only for remove and invalid for add/inspect. Add exact eligible visible refs directly when identity and eligibility are clear; inspect when identity, eligibility, representation or selection state is unclear. Never add refs marked not offered for new evidence selection. For remove, use currently selected or unresolved refs; a non-selectable ref may be named only to clear its unresolved request and requires a reason.
|
|
26
|
+
"Use exactly one shape: inspect {operation, scope?, cursor?}; add {operation, refs} with no reason; remove {operation, refs, reason}. Reason is required only for remove and invalid for add/inspect. Add exact eligible visible refs directly when identity and eligibility are clear; inspect when identity, eligibility, representation or selection state is unclear. Never add refs marked not offered for new evidence selection. For remove, use currently selected or unresolved refs; a non-selectable ref may be named only to clear its unresolved request and requires a reason. Only tool results are evidence: select the result bodies behind your claims, not calls or your own messages, and say everything else in the report. Correct or explicitly withdraw unresolved items with a limitation. Known previously exposed bodies resolve automatically; target-representation gaps are not successful delivery.",
|
|
27
27
|
],
|
|
28
28
|
};
|
|
29
29
|
export function registerRoutingTools(pi, runtime) {
|
|
@@ -33,13 +33,14 @@ export function registerRoutingTools(pi, runtime) {
|
|
|
33
33
|
label: name.replace("freeflow_", "Routing "),
|
|
34
34
|
description: descriptions[name],
|
|
35
35
|
parameters: ROUTING_SCHEMAS[name],
|
|
36
|
+
// Handoffs and evidence selection are assistant-issued boundaries: codemode scripts must not call them.
|
|
37
|
+
exposure: "model-only",
|
|
36
38
|
executionMode: "sequential",
|
|
37
39
|
promptGuidelines: guidance[name],
|
|
38
40
|
renderCall: (args, _theme, context) => renderRoutingCall(name, args, context),
|
|
39
41
|
renderResult: (result, options, _theme, context) => renderRoutingResult(result, options, name, context),
|
|
40
42
|
async execute(id, input, signal, _update, ctx) {
|
|
41
|
-
if (!matches(input, ROUTING_SCHEMAS[name]))
|
|
42
|
-
throw new Error("Invalid routing arguments; no operation accepted.");
|
|
43
|
+
if (!matches(input, ROUTING_SCHEMAS[name])) throw new Error(explainRoutingArguments(name, input));
|
|
43
44
|
return runtime.invoke(name, id, input, signal, ctx);
|
|
44
45
|
},
|
|
45
46
|
};
|
|
@@ -49,12 +50,11 @@ export function registerRoutingTools(pi, runtime) {
|
|
|
49
50
|
export function applyRoutingToolVisibility(pi, _runtime, _available = true) {
|
|
50
51
|
if (!pi.getActiveTools || !pi.setActiveTools) return;
|
|
51
52
|
const current = pi.getActiveTools();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
name !== "freeflow_cognitive_routing_history",
|
|
53
|
+
// Missing routing tools are appended and present ones keep their place, so tools another extension adds later
|
|
54
|
+
// (tool_search, for one) are never reordered around them.
|
|
55
|
+
const kept = current.filter(
|
|
56
|
+
(name) => name !== "freeflow_switch_profile" && name !== "freeflow_cognitive_routing_history",
|
|
57
57
|
);
|
|
58
|
-
const next = [...
|
|
58
|
+
const next = [...kept, ...ROUTING_TOOLS.filter((name) => !kept.includes(name))];
|
|
59
59
|
if (JSON.stringify(next) !== JSON.stringify(current)) pi.setActiveTools(next);
|
|
60
60
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { canonical } from "../host/canonical.js";
|
|
1
2
|
export const ROUTING_ENTRY = "freeflow-routing-v2";
|
|
2
3
|
export const ROUTING_MESSAGE = "freeflow-routing-v2-state";
|
|
4
|
+
export const ROUTING_ATTENTION_MESSAGE = "freeflow-routing-attention";
|
|
3
5
|
export const WORKER_PROFILES = ["helper", "executor"];
|
|
4
6
|
export const PROFILES = ["coordinator", ...WORKER_PROFILES];
|
|
5
7
|
export const DELEGATION_MODES = ["executor", "helper", "both"];
|
|
@@ -25,16 +27,6 @@ export function requireCondition(condition, code, message = code) {
|
|
|
25
27
|
export function isObject(value) {
|
|
26
28
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
27
29
|
}
|
|
28
|
-
export function canonical(value) {
|
|
29
|
-
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
30
|
-
if (isObject(value))
|
|
31
|
-
return `{${Object.keys(value)
|
|
32
|
-
.filter((k) => value[k] !== undefined)
|
|
33
|
-
.sort()
|
|
34
|
-
.map((k) => `${JSON.stringify(k)}:${canonical(value[k])}`)
|
|
35
|
-
.join(",")}}`;
|
|
36
|
-
return JSON.stringify(value) ?? "null";
|
|
37
|
-
}
|
|
38
30
|
export function samePair(left, right) {
|
|
39
31
|
return !!left && !!right && canonical(left) === canonical(right);
|
|
40
32
|
}
|
|
@@ -44,5 +36,7 @@ export const eventValue = (event) =>
|
|
|
44
36
|
export const emptySelection = () => ({ revision: 0, selected: [], unresolved: [], withdrawals: [] });
|
|
45
37
|
export const refFor = (id) => `ctx:${id}`;
|
|
46
38
|
export function idFor(ref) {
|
|
47
|
-
return /^ctx:([^\s:#]+)
|
|
39
|
+
return /^ctx:([^\s:#]+)$/.exec(ref)?.[1];
|
|
48
40
|
}
|
|
41
|
+
export { canonical };
|
|
42
|
+
export const ROUTING_TOOLS = ["freeflow_delegate", "freeflow_return", "freeflow_unit", "freeflow_project"];
|