@caupulican/pi-adaptative 0.80.86 → 0.80.89
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/CHANGELOG.md +178 -0
- package/dist/core/agent-session.d.ts +412 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2053 -41
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/approval-gate.d.ts +4 -0
- package/dist/core/autonomy/approval-gate.d.ts.map +1 -0
- package/dist/core/autonomy/approval-gate.js +27 -0
- package/dist/core/autonomy/approval-gate.js.map +1 -0
- package/dist/core/autonomy/bounded-completion.d.ts +27 -0
- package/dist/core/autonomy/bounded-completion.d.ts.map +1 -0
- package/dist/core/autonomy/bounded-completion.js +44 -0
- package/dist/core/autonomy/bounded-completion.js.map +1 -0
- package/dist/core/autonomy/contracts.d.ts +129 -0
- package/dist/core/autonomy/contracts.d.ts.map +1 -0
- package/dist/core/autonomy/contracts.js +2 -0
- package/dist/core/autonomy/contracts.js.map +1 -0
- package/dist/core/autonomy/gates.d.ts +15 -0
- package/dist/core/autonomy/gates.d.ts.map +1 -0
- package/dist/core/autonomy/gates.js +205 -0
- package/dist/core/autonomy/gates.js.map +1 -0
- package/dist/core/autonomy/lane-tracker.d.ts +48 -0
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -0
- package/dist/core/autonomy/lane-tracker.js +125 -0
- package/dist/core/autonomy/lane-tracker.js.map +1 -0
- package/dist/core/autonomy/path-scope.d.ts +9 -0
- package/dist/core/autonomy/path-scope.d.ts.map +1 -0
- package/dist/core/autonomy/path-scope.js +122 -0
- package/dist/core/autonomy/path-scope.js.map +1 -0
- package/dist/core/autonomy/risk-assessment.d.ts +3 -0
- package/dist/core/autonomy/risk-assessment.d.ts.map +1 -0
- package/dist/core/autonomy/risk-assessment.js +122 -0
- package/dist/core/autonomy/risk-assessment.js.map +1 -0
- package/dist/core/autonomy/session-lane-record.d.ts +10 -0
- package/dist/core/autonomy/session-lane-record.d.ts.map +1 -0
- package/dist/core/autonomy/session-lane-record.js +36 -0
- package/dist/core/autonomy/session-lane-record.js.map +1 -0
- package/dist/core/autonomy/status.d.ts +40 -0
- package/dist/core/autonomy/status.d.ts.map +1 -0
- package/dist/core/autonomy/status.js +107 -0
- package/dist/core/autonomy/status.js.map +1 -0
- package/dist/core/autonomy/subagent-prompt.d.ts +21 -0
- package/dist/core/autonomy/subagent-prompt.d.ts.map +1 -0
- package/dist/core/autonomy/subagent-prompt.js +28 -0
- package/dist/core/autonomy/subagent-prompt.js.map +1 -0
- package/dist/core/autonomy/telemetry-events.d.ts +18 -0
- package/dist/core/autonomy/telemetry-events.d.ts.map +1 -0
- package/dist/core/autonomy/telemetry-events.js +60 -0
- package/dist/core/autonomy/telemetry-events.js.map +1 -0
- package/dist/core/context/artifact-retrieval.d.ts +49 -0
- package/dist/core/context/artifact-retrieval.d.ts.map +1 -0
- package/dist/core/context/artifact-retrieval.js +49 -0
- package/dist/core/context/artifact-retrieval.js.map +1 -0
- package/dist/core/context/brain-curator.d.ts +88 -0
- package/dist/core/context/brain-curator.d.ts.map +1 -0
- package/dist/core/context/brain-curator.js +192 -0
- package/dist/core/context/brain-curator.js.map +1 -0
- package/dist/core/context/context-artifacts.d.ts +94 -0
- package/dist/core/context/context-artifacts.d.ts.map +1 -0
- package/dist/core/context/context-artifacts.js +307 -0
- package/dist/core/context/context-artifacts.js.map +1 -0
- package/dist/core/context/context-audit.d.ts +66 -0
- package/dist/core/context/context-audit.d.ts.map +1 -0
- package/dist/core/context/context-audit.js +173 -0
- package/dist/core/context/context-audit.js.map +1 -0
- package/dist/core/context/context-composition.d.ts +122 -0
- package/dist/core/context/context-composition.d.ts.map +1 -0
- package/dist/core/context/context-composition.js +163 -0
- package/dist/core/context/context-composition.js.map +1 -0
- package/dist/core/context/context-item.d.ts +117 -0
- package/dist/core/context/context-item.d.ts.map +1 -0
- package/dist/core/context/context-item.js +36 -0
- package/dist/core/context/context-item.js.map +1 -0
- package/dist/core/context/context-prompt-enforcement.d.ts +86 -0
- package/dist/core/context/context-prompt-enforcement.d.ts.map +1 -0
- package/dist/core/context/context-prompt-enforcement.js +168 -0
- package/dist/core/context/context-prompt-enforcement.js.map +1 -0
- package/dist/core/context/context-prompt-policy.d.ts +90 -0
- package/dist/core/context/context-prompt-policy.d.ts.map +1 -0
- package/dist/core/context/context-prompt-policy.js +73 -0
- package/dist/core/context/context-prompt-policy.js.map +1 -0
- package/dist/core/context/context-retention.d.ts +36 -0
- package/dist/core/context/context-retention.d.ts.map +1 -0
- package/dist/core/context/context-retention.js +108 -0
- package/dist/core/context/context-retention.js.map +1 -0
- package/dist/core/context/context-store.d.ts +37 -0
- package/dist/core/context/context-store.d.ts.map +1 -0
- package/dist/core/context/context-store.js +45 -0
- package/dist/core/context/context-store.js.map +1 -0
- package/dist/core/context/memory-diagnostics.d.ts +50 -0
- package/dist/core/context/memory-diagnostics.d.ts.map +1 -0
- package/dist/core/context/memory-diagnostics.js +43 -0
- package/dist/core/context/memory-diagnostics.js.map +1 -0
- package/dist/core/context/memory-index-store.d.ts +28 -0
- package/dist/core/context/memory-index-store.d.ts.map +1 -0
- package/dist/core/context/memory-index-store.js +38 -0
- package/dist/core/context/memory-index-store.js.map +1 -0
- package/dist/core/context/memory-prompt-block.d.ts +34 -0
- package/dist/core/context/memory-prompt-block.d.ts.map +1 -0
- package/dist/core/context/memory-prompt-block.js +58 -0
- package/dist/core/context/memory-prompt-block.js.map +1 -0
- package/dist/core/context/memory-provider-contract.d.ts +114 -0
- package/dist/core/context/memory-provider-contract.d.ts.map +1 -0
- package/dist/core/context/memory-provider-contract.js +121 -0
- package/dist/core/context/memory-provider-contract.js.map +1 -0
- package/dist/core/context/memory-retrieval.d.ts +27 -0
- package/dist/core/context/memory-retrieval.d.ts.map +1 -0
- package/dist/core/context/memory-retrieval.js +91 -0
- package/dist/core/context/memory-retrieval.js.map +1 -0
- package/dist/core/context/okf-memory-provider.d.ts +26 -0
- package/dist/core/context/okf-memory-provider.d.ts.map +1 -0
- package/dist/core/context/okf-memory-provider.js +154 -0
- package/dist/core/context/okf-memory-provider.js.map +1 -0
- package/dist/core/context/okf-memory.d.ts +42 -0
- package/dist/core/context/okf-memory.d.ts.map +1 -0
- package/dist/core/context/okf-memory.js +175 -0
- package/dist/core/context/okf-memory.js.map +1 -0
- package/dist/core/context/policy-engine.d.ts +66 -0
- package/dist/core/context/policy-engine.d.ts.map +1 -0
- package/dist/core/context/policy-engine.js +171 -0
- package/dist/core/context/policy-engine.js.map +1 -0
- package/dist/core/context/policy-types.d.ts +102 -0
- package/dist/core/context/policy-types.d.ts.map +1 -0
- package/dist/core/context/policy-types.js +7 -0
- package/dist/core/context/policy-types.js.map +1 -0
- package/dist/core/context/sqlite-runtime-index.d.ts +19 -0
- package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -0
- package/dist/core/context/sqlite-runtime-index.js +344 -0
- package/dist/core/context/sqlite-runtime-index.js.map +1 -0
- package/dist/core/context/storage-authority.d.ts +20 -0
- package/dist/core/context/storage-authority.d.ts.map +1 -0
- package/dist/core/context/storage-authority.js +51 -0
- package/dist/core/context/storage-authority.js.map +1 -0
- package/dist/core/context/tool-output-packer.d.ts +75 -0
- package/dist/core/context/tool-output-packer.d.ts.map +1 -0
- package/dist/core/context/tool-output-packer.js +77 -0
- package/dist/core/context/tool-output-packer.js.map +1 -0
- package/dist/core/context-gc.d.ts +13 -0
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +6 -0
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/cost/session-usage.d.ts +20 -0
- package/dist/core/cost/session-usage.d.ts.map +1 -0
- package/dist/core/cost/session-usage.js +164 -0
- package/dist/core/cost/session-usage.js.map +1 -0
- package/dist/core/delegation/session-worker-result.d.ts +10 -0
- package/dist/core/delegation/session-worker-result.d.ts.map +1 -0
- package/dist/core/delegation/session-worker-result.js +36 -0
- package/dist/core/delegation/session-worker-result.js.map +1 -0
- package/dist/core/delegation/worker-result.d.ts +9 -0
- package/dist/core/delegation/worker-result.d.ts.map +1 -0
- package/dist/core/delegation/worker-result.js +152 -0
- package/dist/core/delegation/worker-result.js.map +1 -0
- package/dist/core/delegation/worker-runner.d.ts +58 -0
- package/dist/core/delegation/worker-runner.d.ts.map +1 -0
- package/dist/core/delegation/worker-runner.js +188 -0
- package/dist/core/delegation/worker-runner.js.map +1 -0
- package/dist/core/extensions/builtin.d.ts +5 -1
- package/dist/core/extensions/builtin.d.ts.map +1 -1
- package/dist/core/extensions/builtin.js +23 -1
- package/dist/core/extensions/builtin.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +5 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +13 -0
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/goals/goal-continuation-controller.d.ts +22 -0
- package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -0
- package/dist/core/goals/goal-continuation-controller.js +88 -0
- package/dist/core/goals/goal-continuation-controller.js.map +1 -0
- package/dist/core/goals/goal-continuation-defaults.d.ts +10 -0
- package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -0
- package/dist/core/goals/goal-continuation-defaults.js +10 -0
- package/dist/core/goals/goal-continuation-defaults.js.map +1 -0
- package/dist/core/goals/goal-continuation-prompt.d.ts +18 -0
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -0
- package/dist/core/goals/goal-continuation-prompt.js +141 -0
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -0
- package/dist/core/goals/goal-runtime-snapshot.d.ts +19 -0
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -0
- package/dist/core/goals/goal-runtime-snapshot.js +23 -0
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -0
- package/dist/core/goals/goal-state.d.ts +87 -0
- package/dist/core/goals/goal-state.d.ts.map +1 -0
- package/dist/core/goals/goal-state.js +259 -0
- package/dist/core/goals/goal-state.js.map +1 -0
- package/dist/core/goals/goal-tool-core.d.ts +66 -0
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -0
- package/dist/core/goals/goal-tool-core.js +146 -0
- package/dist/core/goals/goal-tool-core.js.map +1 -0
- package/dist/core/goals/session-goal-state.d.ts +10 -0
- package/dist/core/goals/session-goal-state.d.ts.map +1 -0
- package/dist/core/goals/session-goal-state.js +35 -0
- package/dist/core/goals/session-goal-state.js.map +1 -0
- package/dist/core/learning/learning-audit.d.ts +45 -0
- package/dist/core/learning/learning-audit.d.ts.map +1 -0
- package/dist/core/learning/learning-audit.js +139 -0
- package/dist/core/learning/learning-audit.js.map +1 -0
- package/dist/core/learning/learning-gate.d.ts +29 -0
- package/dist/core/learning/learning-gate.d.ts.map +1 -0
- package/dist/core/learning/learning-gate.js +150 -0
- package/dist/core/learning/learning-gate.js.map +1 -0
- package/dist/core/learning/session-learning-decision.d.ts +10 -0
- package/dist/core/learning/session-learning-decision.d.ts.map +1 -0
- package/dist/core/learning/session-learning-decision.js +36 -0
- package/dist/core/learning/session-learning-decision.js.map +1 -0
- package/dist/core/model-capability.d.ts +41 -0
- package/dist/core/model-capability.d.ts.map +1 -0
- package/dist/core/model-capability.js +101 -0
- package/dist/core/model-capability.js.map +1 -0
- package/dist/core/model-router/config-diagnostics.d.ts.map +1 -1
- package/dist/core/model-router/config-diagnostics.js +1 -0
- package/dist/core/model-router/config-diagnostics.js.map +1 -1
- package/dist/core/model-router/intent-classifier.d.ts +2 -0
- package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
- package/dist/core/model-router/intent-classifier.js +154 -9
- package/dist/core/model-router/intent-classifier.js.map +1 -1
- package/dist/core/model-router/route-judge.d.ts +54 -0
- package/dist/core/model-router/route-judge.d.ts.map +1 -0
- package/dist/core/model-router/route-judge.js +128 -0
- package/dist/core/model-router/route-judge.js.map +1 -0
- package/dist/core/model-router/status.d.ts +4 -1
- package/dist/core/model-router/status.d.ts.map +1 -1
- package/dist/core/model-router/status.js +30 -6
- package/dist/core/model-router/status.js.map +1 -1
- package/dist/core/model-router/tool-escalation.d.ts +4 -6
- package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
- package/dist/core/model-router/tool-escalation.js +1 -1
- package/dist/core/model-router/tool-escalation.js.map +1 -1
- package/dist/core/models/fitness-store.d.ts +40 -0
- package/dist/core/models/fitness-store.d.ts.map +1 -0
- package/dist/core/models/fitness-store.js +61 -0
- package/dist/core/models/fitness-store.js.map +1 -0
- package/dist/core/profile-registry.d.ts.map +1 -1
- package/dist/core/profile-registry.js +1 -1
- package/dist/core/profile-registry.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +2 -0
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +12 -4
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/research/automata-provider.d.ts +5 -0
- package/dist/core/research/automata-provider.d.ts.map +1 -0
- package/dist/core/research/automata-provider.js +15 -0
- package/dist/core/research/automata-provider.js.map +1 -0
- package/dist/core/research/evidence-bundle.d.ts +10 -0
- package/dist/core/research/evidence-bundle.d.ts.map +1 -0
- package/dist/core/research/evidence-bundle.js +116 -0
- package/dist/core/research/evidence-bundle.js.map +1 -0
- package/dist/core/research/model-fitness.d.ts +82 -0
- package/dist/core/research/model-fitness.d.ts.map +1 -0
- package/dist/core/research/model-fitness.js +308 -0
- package/dist/core/research/model-fitness.js.map +1 -0
- package/dist/core/research/research-gate.d.ts +11 -0
- package/dist/core/research/research-gate.d.ts.map +1 -0
- package/dist/core/research/research-gate.js +82 -0
- package/dist/core/research/research-gate.js.map +1 -0
- package/dist/core/research/research-runner.d.ts +59 -0
- package/dist/core/research/research-runner.d.ts.map +1 -0
- package/dist/core/research/research-runner.js +155 -0
- package/dist/core/research/research-runner.js.map +1 -0
- package/dist/core/research/session-evidence-bundle.d.ts +11 -0
- package/dist/core/research/session-evidence-bundle.d.ts.map +1 -0
- package/dist/core/research/session-evidence-bundle.js +55 -0
- package/dist/core/research/session-evidence-bundle.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +4 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +160 -4
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +304 -9
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +4 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +18 -6
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +10 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/toolkit/script-registry.d.ts +34 -0
- package/dist/core/toolkit/script-registry.d.ts.map +1 -0
- package/dist/core/toolkit/script-registry.js +71 -0
- package/dist/core/toolkit/script-registry.js.map +1 -0
- package/dist/core/toolkit/script-runner.d.ts +28 -0
- package/dist/core/toolkit/script-runner.d.ts.map +1 -0
- package/dist/core/toolkit/script-runner.js +48 -0
- package/dist/core/toolkit/script-runner.js.map +1 -0
- package/dist/core/tools/artifact-retrieve.d.ts +23 -0
- package/dist/core/tools/artifact-retrieve.d.ts.map +1 -0
- package/dist/core/tools/artifact-retrieve.js +110 -0
- package/dist/core/tools/artifact-retrieve.js.map +1 -0
- package/dist/core/tools/delegate.d.ts +32 -0
- package/dist/core/tools/delegate.d.ts.map +1 -0
- package/dist/core/tools/delegate.js +60 -0
- package/dist/core/tools/delegate.js.map +1 -0
- package/dist/core/tools/fff-search-backend.d.ts +103 -0
- package/dist/core/tools/fff-search-backend.d.ts.map +1 -0
- package/dist/core/tools/fff-search-backend.js +151 -0
- package/dist/core/tools/fff-search-backend.js.map +1 -0
- package/dist/core/tools/find.d.ts +21 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +183 -10
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/goal.d.ts +35 -0
- package/dist/core/tools/goal.d.ts.map +1 -0
- package/dist/core/tools/goal.js +122 -0
- package/dist/core/tools/goal.js.map +1 -0
- package/dist/core/tools/grep.d.ts +21 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +272 -27
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +4 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +9 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/model-fitness.d.ts +30 -0
- package/dist/core/tools/model-fitness.d.ts.map +1 -0
- package/dist/core/tools/model-fitness.js +38 -0
- package/dist/core/tools/model-fitness.js.map +1 -0
- package/dist/core/tools/run-toolkit-script.d.ts +24 -0
- package/dist/core/tools/run-toolkit-script.d.ts.map +1 -0
- package/dist/core/tools/run-toolkit-script.js +103 -0
- package/dist/core/tools/run-toolkit-script.js.map +1 -0
- package/dist/core/tools/search-router.d.ts +75 -0
- package/dist/core/tools/search-router.d.ts.map +1 -0
- package/dist/core/tools/search-router.js +85 -0
- package/dist/core/tools/search-router.js.map +1 -0
- package/dist/modes/interactive/components/fitness-role-selector.d.ts +13 -0
- package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/fitness-role-selector.js +65 -0
- package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +18 -16
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +16 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +555 -11
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +9 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +308 -39
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +2 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +154 -2
- package/dist/utils/tools-manager.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +368 -12
- package/package.json +5 -4
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const REDACTED = "[REDACTED]";
|
|
2
|
+
const CIRCULAR = "[Circular]";
|
|
3
|
+
const MAX_STRING_LENGTH = 200;
|
|
4
|
+
const SENSITIVE_KEYS = ["token", "secret", "key", "credential", "password", "authorization"];
|
|
5
|
+
const SENSITIVE_VALUE_REGEX = /bearer\s+[\w\-._]+|api[-_]?key[-_]?[\w\-._]+|sk-[\w\-._]+/i;
|
|
6
|
+
function formatCost(value) {
|
|
7
|
+
return Number.isFinite(value) ? `$${value.toFixed(4)}` : "$0.0000";
|
|
8
|
+
}
|
|
9
|
+
function redactAndTruncateString(value) {
|
|
10
|
+
if (SENSITIVE_VALUE_REGEX.test(value))
|
|
11
|
+
return REDACTED;
|
|
12
|
+
if (value.length <= MAX_STRING_LENGTH)
|
|
13
|
+
return value;
|
|
14
|
+
return `${value.slice(0, MAX_STRING_LENGTH - 1)}…`;
|
|
15
|
+
}
|
|
16
|
+
function isSensitiveKey(key) {
|
|
17
|
+
const lowerKey = key.toLowerCase();
|
|
18
|
+
return SENSITIVE_KEYS.some((sensitiveKey) => lowerKey.includes(sensitiveKey));
|
|
19
|
+
}
|
|
20
|
+
function sanitizeMetadataValue(value, seen) {
|
|
21
|
+
if (typeof value === "string")
|
|
22
|
+
return redactAndTruncateString(value);
|
|
23
|
+
if (typeof value !== "object" || value === null)
|
|
24
|
+
return value;
|
|
25
|
+
if (seen.has(value))
|
|
26
|
+
return CIRCULAR;
|
|
27
|
+
if (Array.isArray(value)) {
|
|
28
|
+
seen.add(value);
|
|
29
|
+
return value.map((item) => sanitizeMetadataValue(item, seen));
|
|
30
|
+
}
|
|
31
|
+
return sanitizeMetadata(value, seen);
|
|
32
|
+
}
|
|
33
|
+
function sanitizeMetadata(obj, seen = new WeakSet()) {
|
|
34
|
+
if (seen.has(obj))
|
|
35
|
+
return { value: CIRCULAR };
|
|
36
|
+
seen.add(obj);
|
|
37
|
+
const result = {};
|
|
38
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
39
|
+
result[key] = isSensitiveKey(key) ? REDACTED : sanitizeMetadataValue(value, seen);
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
export function formatAutonomyStatus(args) {
|
|
44
|
+
const parts = [];
|
|
45
|
+
if (args.latestRoute) {
|
|
46
|
+
const risk = args.latestRoute.risk ? ` (${redactAndTruncateString(args.latestRoute.risk)})` : "";
|
|
47
|
+
parts.push(`Route: ${redactAndTruncateString(args.latestRoute.tier)}${risk} - ${redactAndTruncateString(args.latestRoute.reasonCode)}`);
|
|
48
|
+
}
|
|
49
|
+
if (args.latestGate) {
|
|
50
|
+
parts.push(`Gate: ${redactAndTruncateString(args.latestGate.gate)} = ${redactAndTruncateString(args.latestGate.outcome)} (${redactAndTruncateString(args.latestGate.reasonCode)})`);
|
|
51
|
+
}
|
|
52
|
+
const costs = [];
|
|
53
|
+
if (args.currentCostUsd !== undefined)
|
|
54
|
+
costs.push(`current: ${formatCost(args.currentCostUsd)}`);
|
|
55
|
+
if (args.dailyCostUsd !== undefined)
|
|
56
|
+
costs.push(`daily: ${formatCost(args.dailyCostUsd)}`);
|
|
57
|
+
if (args.spawnedCostUsd !== undefined)
|
|
58
|
+
costs.push(`spawned: ${formatCost(args.spawnedCostUsd)}`);
|
|
59
|
+
if (costs.length > 0) {
|
|
60
|
+
parts.push(`Costs: ${costs.join(", ")}`);
|
|
61
|
+
}
|
|
62
|
+
if (args.activeGoal) {
|
|
63
|
+
const goal = args.activeGoal;
|
|
64
|
+
const requirements = goal.openRequirements !== undefined ? `, open reqs: ${goal.openRequirements}` : "";
|
|
65
|
+
const stalls = goal.stallTurns !== undefined ? `, stalls: ${goal.stallTurns}` : "";
|
|
66
|
+
parts.push(`Goal [${redactAndTruncateString(goal.goalId)}]: ${redactAndTruncateString(goal.status)}${requirements}${stalls}`);
|
|
67
|
+
}
|
|
68
|
+
if (args.activeLaneCount !== undefined) {
|
|
69
|
+
parts.push(`Lanes: ${args.activeLaneCount}`);
|
|
70
|
+
}
|
|
71
|
+
if (parts.length === 0)
|
|
72
|
+
return "Autonomy: idle";
|
|
73
|
+
return parts.join(" | ");
|
|
74
|
+
}
|
|
75
|
+
function formatDiagnosticSection(name, entries) {
|
|
76
|
+
if (!entries || entries.length === 0)
|
|
77
|
+
return undefined;
|
|
78
|
+
const lines = [`--- ${name} ---`];
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
let header = `- ${redactAndTruncateString(entry.title)}`;
|
|
81
|
+
if (entry.reasonCode)
|
|
82
|
+
header += ` [${redactAndTruncateString(entry.reasonCode)}]`;
|
|
83
|
+
lines.push(header);
|
|
84
|
+
if (entry.summary) {
|
|
85
|
+
lines.push(` Summary: ${redactAndTruncateString(entry.summary)}`);
|
|
86
|
+
}
|
|
87
|
+
if (entry.metadata) {
|
|
88
|
+
lines.push(` Metadata: ${JSON.stringify(sanitizeMetadata(entry.metadata))}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return lines.join("\n");
|
|
92
|
+
}
|
|
93
|
+
export function formatAutonomyDiagnostics(args) {
|
|
94
|
+
const sections = [
|
|
95
|
+
formatDiagnosticSection("Routes", args.routes),
|
|
96
|
+
formatDiagnosticSection("Gates", args.gates),
|
|
97
|
+
formatDiagnosticSection("Costs", args.costs),
|
|
98
|
+
formatDiagnosticSection("Research", args.research),
|
|
99
|
+
formatDiagnosticSection("Delegation", args.delegation),
|
|
100
|
+
formatDiagnosticSection("Learning", args.learning),
|
|
101
|
+
formatDiagnosticSection("Goals", args.goals),
|
|
102
|
+
].filter((section) => Boolean(section));
|
|
103
|
+
if (sections.length === 0)
|
|
104
|
+
return "No diagnostics available.";
|
|
105
|
+
return sections.join("\n\n");
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/core/autonomy/status.ts"],"names":[],"mappings":"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","sourcesContent":["export interface AutonomyStatusSnapshot {\n\tlatestRoute?: { tier: string; reasonCode: string; risk?: string };\n\tlatestGate?: { outcome: string; gate: string; reasonCode: string };\n\tcurrentCostUsd?: number;\n\tdailyCostUsd?: number;\n\tspawnedCostUsd?: number;\n\tactiveGoal?: { goalId: string; status: string; openRequirements?: number; stallTurns?: number };\n\tactiveLaneCount?: number;\n}\n\nexport interface DiagnosticEntry {\n\ttitle: string;\n\tsummary?: string;\n\treasonCode?: string;\n\tmetadata?: Record<string, unknown>;\n}\n\nexport interface AutonomyDiagnosticSnapshot {\n\troutes?: readonly DiagnosticEntry[];\n\tgates?: readonly DiagnosticEntry[];\n\tcosts?: readonly DiagnosticEntry[];\n\tresearch?: readonly DiagnosticEntry[];\n\tdelegation?: readonly DiagnosticEntry[];\n\tlearning?: readonly DiagnosticEntry[];\n\tgoals?: readonly DiagnosticEntry[];\n}\n\nconst REDACTED = \"[REDACTED]\";\nconst CIRCULAR = \"[Circular]\";\nconst MAX_STRING_LENGTH = 200;\nconst SENSITIVE_KEYS = [\"token\", \"secret\", \"key\", \"credential\", \"password\", \"authorization\"];\nconst SENSITIVE_VALUE_REGEX = /bearer\\s+[\\w\\-._]+|api[-_]?key[-_]?[\\w\\-._]+|sk-[\\w\\-._]+/i;\n\nfunction formatCost(value: number): string {\n\treturn Number.isFinite(value) ? `$${value.toFixed(4)}` : \"$0.0000\";\n}\n\nfunction redactAndTruncateString(value: string): string {\n\tif (SENSITIVE_VALUE_REGEX.test(value)) return REDACTED;\n\tif (value.length <= MAX_STRING_LENGTH) return value;\n\treturn `${value.slice(0, MAX_STRING_LENGTH - 1)}…`;\n}\n\nfunction isSensitiveKey(key: string): boolean {\n\tconst lowerKey = key.toLowerCase();\n\treturn SENSITIVE_KEYS.some((sensitiveKey) => lowerKey.includes(sensitiveKey));\n}\n\nfunction sanitizeMetadataValue(value: unknown, seen: WeakSet<object>): unknown {\n\tif (typeof value === \"string\") return redactAndTruncateString(value);\n\tif (typeof value !== \"object\" || value === null) return value;\n\tif (seen.has(value)) return CIRCULAR;\n\tif (Array.isArray(value)) {\n\t\tseen.add(value);\n\t\treturn value.map((item) => sanitizeMetadataValue(item, seen));\n\t}\n\treturn sanitizeMetadata(value as Record<string, unknown>, seen);\n}\n\nfunction sanitizeMetadata(\n\tobj: Record<string, unknown>,\n\tseen: WeakSet<object> = new WeakSet(),\n): Record<string, unknown> {\n\tif (seen.has(obj)) return { value: CIRCULAR };\n\tseen.add(obj);\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tresult[key] = isSensitiveKey(key) ? REDACTED : sanitizeMetadataValue(value, seen);\n\t}\n\treturn result;\n}\n\nexport function formatAutonomyStatus(args: AutonomyStatusSnapshot): string {\n\tconst parts: string[] = [];\n\n\tif (args.latestRoute) {\n\t\tconst risk = args.latestRoute.risk ? ` (${redactAndTruncateString(args.latestRoute.risk)})` : \"\";\n\t\tparts.push(\n\t\t\t`Route: ${redactAndTruncateString(args.latestRoute.tier)}${risk} - ${redactAndTruncateString(args.latestRoute.reasonCode)}`,\n\t\t);\n\t}\n\n\tif (args.latestGate) {\n\t\tparts.push(\n\t\t\t`Gate: ${redactAndTruncateString(args.latestGate.gate)} = ${redactAndTruncateString(args.latestGate.outcome)} (${redactAndTruncateString(args.latestGate.reasonCode)})`,\n\t\t);\n\t}\n\n\tconst costs: string[] = [];\n\tif (args.currentCostUsd !== undefined) costs.push(`current: ${formatCost(args.currentCostUsd)}`);\n\tif (args.dailyCostUsd !== undefined) costs.push(`daily: ${formatCost(args.dailyCostUsd)}`);\n\tif (args.spawnedCostUsd !== undefined) costs.push(`spawned: ${formatCost(args.spawnedCostUsd)}`);\n\tif (costs.length > 0) {\n\t\tparts.push(`Costs: ${costs.join(\", \")}`);\n\t}\n\n\tif (args.activeGoal) {\n\t\tconst goal = args.activeGoal;\n\t\tconst requirements = goal.openRequirements !== undefined ? `, open reqs: ${goal.openRequirements}` : \"\";\n\t\tconst stalls = goal.stallTurns !== undefined ? `, stalls: ${goal.stallTurns}` : \"\";\n\t\tparts.push(\n\t\t\t`Goal [${redactAndTruncateString(goal.goalId)}]: ${redactAndTruncateString(goal.status)}${requirements}${stalls}`,\n\t\t);\n\t}\n\n\tif (args.activeLaneCount !== undefined) {\n\t\tparts.push(`Lanes: ${args.activeLaneCount}`);\n\t}\n\n\tif (parts.length === 0) return \"Autonomy: idle\";\n\treturn parts.join(\" | \");\n}\n\nfunction formatDiagnosticSection(name: string, entries?: readonly DiagnosticEntry[]): string | undefined {\n\tif (!entries || entries.length === 0) return undefined;\n\n\tconst lines: string[] = [`--- ${name} ---`];\n\tfor (const entry of entries) {\n\t\tlet header = `- ${redactAndTruncateString(entry.title)}`;\n\t\tif (entry.reasonCode) header += ` [${redactAndTruncateString(entry.reasonCode)}]`;\n\t\tlines.push(header);\n\n\t\tif (entry.summary) {\n\t\t\tlines.push(` Summary: ${redactAndTruncateString(entry.summary)}`);\n\t\t}\n\n\t\tif (entry.metadata) {\n\t\t\tlines.push(` Metadata: ${JSON.stringify(sanitizeMetadata(entry.metadata))}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function formatAutonomyDiagnostics(args: AutonomyDiagnosticSnapshot): string {\n\tconst sections = [\n\t\tformatDiagnosticSection(\"Routes\", args.routes),\n\t\tformatDiagnosticSection(\"Gates\", args.gates),\n\t\tformatDiagnosticSection(\"Costs\", args.costs),\n\t\tformatDiagnosticSection(\"Research\", args.research),\n\t\tformatDiagnosticSection(\"Delegation\", args.delegation),\n\t\tformatDiagnosticSection(\"Learning\", args.learning),\n\t\tformatDiagnosticSection(\"Goals\", args.goals),\n\t].filter((section): section is string => Boolean(section));\n\n\tif (sections.length === 0) return \"No diagnostics available.\";\n\treturn sections.join(\"\\n\\n\");\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent system-prompt composition with an irreducible level-0 core.
|
|
3
|
+
*
|
|
4
|
+
* The core is the "ultimate level-0 default": ~80 tokens of non-negotiable rules that survive ANY
|
|
5
|
+
* customization. Everything above it — the lane's role prompt and a shipped profile's soul — is a
|
|
6
|
+
* replaceable layer: settings, a lane profile, or the calling model (delegate tool) can erase and
|
|
7
|
+
* replace it entirely. This keeps shipped subagents maximally efficient on small open models (a
|
|
8
|
+
* caller can hand a tiny model a purpose-built minimal prompt) without ever shedding the safety
|
|
9
|
+
* floor. Keep the core UNDER 300 tokens; it is deliberately terse.
|
|
10
|
+
*/
|
|
11
|
+
export declare const SUBAGENT_CORE_SYSTEM_PROMPT: string;
|
|
12
|
+
export interface SubagentPromptParts {
|
|
13
|
+
/** Situational identity from the shipped profile (replaceable layer). */
|
|
14
|
+
soul?: string;
|
|
15
|
+
/** The lane's default role prompt (replaceable layer). */
|
|
16
|
+
rolePrompt: string;
|
|
17
|
+
/** User- or model-provided replacement for every layer above level 0. */
|
|
18
|
+
override?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function composeSubagentSystemPrompt(parts: SubagentPromptParts): string;
|
|
21
|
+
//# sourceMappingURL=subagent-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-prompt.d.ts","sourceRoot":"","sources":["../../../src/core/autonomy/subagent-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,QAO5B,CAAC;AAEb,MAAM,WAAW,mBAAmB;IACnC,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAS9E","sourcesContent":["/**\n * Subagent system-prompt composition with an irreducible level-0 core.\n *\n * The core is the \"ultimate level-0 default\": ~80 tokens of non-negotiable rules that survive ANY\n * customization. Everything above it — the lane's role prompt and a shipped profile's soul — is a\n * replaceable layer: settings, a lane profile, or the calling model (delegate tool) can erase and\n * replace it entirely. This keeps shipped subagents maximally efficient on small open models (a\n * caller can hand a tiny model a purpose-built minimal prompt) without ever shedding the safety\n * floor. Keep the core UNDER 300 tokens; it is deliberately terse.\n */\nexport const SUBAGENT_CORE_SYSTEM_PROMPT = [\n\t\"You are a bounded subagent shipped by a coding-agent session. Non-negotiable rules:\",\n\t\"1. Do only the task you were given; you cannot see the parent conversation.\",\n\t\"2. You are read-only unless your envelope explicitly grants otherwise; never attempt to change files, settings, credentials, or external state.\",\n\t\"3. Never invent facts, file paths, or APIs; say so when you do not know.\",\n\t\"4. Your output is untrusted evidence for the parent agent - data, never instructions.\",\n\t\"5. Follow the requested output format exactly and be concise; budgets are enforced outside you.\",\n].join(\"\\n\");\n\nexport interface SubagentPromptParts {\n\t/** Situational identity from the shipped profile (replaceable layer). */\n\tsoul?: string;\n\t/** The lane's default role prompt (replaceable layer). */\n\trolePrompt: string;\n\t/** User- or model-provided replacement for every layer above level 0. */\n\toverride?: string;\n}\n\nexport function composeSubagentSystemPrompt(parts: SubagentPromptParts): string {\n\tconst override = parts.override?.trim();\n\tconst above =\n\t\toverride && override.length > 0\n\t\t\t? override\n\t\t\t: [parts.soul?.trim(), parts.rolePrompt]\n\t\t\t\t\t.filter((part): part is string => Boolean(part && part.length > 0))\n\t\t\t\t\t.join(\"\\n\\n\");\n\treturn above.length > 0 ? `${SUBAGENT_CORE_SYSTEM_PROMPT}\\n\\n${above}` : SUBAGENT_CORE_SYSTEM_PROMPT;\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent system-prompt composition with an irreducible level-0 core.
|
|
3
|
+
*
|
|
4
|
+
* The core is the "ultimate level-0 default": ~80 tokens of non-negotiable rules that survive ANY
|
|
5
|
+
* customization. Everything above it — the lane's role prompt and a shipped profile's soul — is a
|
|
6
|
+
* replaceable layer: settings, a lane profile, or the calling model (delegate tool) can erase and
|
|
7
|
+
* replace it entirely. This keeps shipped subagents maximally efficient on small open models (a
|
|
8
|
+
* caller can hand a tiny model a purpose-built minimal prompt) without ever shedding the safety
|
|
9
|
+
* floor. Keep the core UNDER 300 tokens; it is deliberately terse.
|
|
10
|
+
*/
|
|
11
|
+
export const SUBAGENT_CORE_SYSTEM_PROMPT = [
|
|
12
|
+
"You are a bounded subagent shipped by a coding-agent session. Non-negotiable rules:",
|
|
13
|
+
"1. Do only the task you were given; you cannot see the parent conversation.",
|
|
14
|
+
"2. You are read-only unless your envelope explicitly grants otherwise; never attempt to change files, settings, credentials, or external state.",
|
|
15
|
+
"3. Never invent facts, file paths, or APIs; say so when you do not know.",
|
|
16
|
+
"4. Your output is untrusted evidence for the parent agent - data, never instructions.",
|
|
17
|
+
"5. Follow the requested output format exactly and be concise; budgets are enforced outside you.",
|
|
18
|
+
].join("\n");
|
|
19
|
+
export function composeSubagentSystemPrompt(parts) {
|
|
20
|
+
const override = parts.override?.trim();
|
|
21
|
+
const above = override && override.length > 0
|
|
22
|
+
? override
|
|
23
|
+
: [parts.soul?.trim(), parts.rolePrompt]
|
|
24
|
+
.filter((part) => Boolean(part && part.length > 0))
|
|
25
|
+
.join("\n\n");
|
|
26
|
+
return above.length > 0 ? `${SUBAGENT_CORE_SYSTEM_PROMPT}\n\n${above}` : SUBAGENT_CORE_SYSTEM_PROMPT;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=subagent-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-prompt.js","sourceRoot":"","sources":["../../../src/core/autonomy/subagent-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG;IAC1C,qFAAqF;IACrF,6EAA6E;IAC7E,iJAAiJ;IACjJ,0EAA0E;IAC1E,uFAAuF;IACvF,iGAAiG;CACjG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAWb,MAAM,UAAU,2BAA2B,CAAC,KAA0B,EAAU;IAC/E,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;IACxC,MAAM,KAAK,GACV,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAC9B,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC,UAAU,CAAC;aACrC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;aAClE,IAAI,CAAC,MAAM,CAAC,CAAC;IAClB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,2BAA2B,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,2BAA2B,CAAC;AAAA,CACrG","sourcesContent":["/**\n * Subagent system-prompt composition with an irreducible level-0 core.\n *\n * The core is the \"ultimate level-0 default\": ~80 tokens of non-negotiable rules that survive ANY\n * customization. Everything above it — the lane's role prompt and a shipped profile's soul — is a\n * replaceable layer: settings, a lane profile, or the calling model (delegate tool) can erase and\n * replace it entirely. This keeps shipped subagents maximally efficient on small open models (a\n * caller can hand a tiny model a purpose-built minimal prompt) without ever shedding the safety\n * floor. Keep the core UNDER 300 tokens; it is deliberately terse.\n */\nexport const SUBAGENT_CORE_SYSTEM_PROMPT = [\n\t\"You are a bounded subagent shipped by a coding-agent session. Non-negotiable rules:\",\n\t\"1. Do only the task you were given; you cannot see the parent conversation.\",\n\t\"2. You are read-only unless your envelope explicitly grants otherwise; never attempt to change files, settings, credentials, or external state.\",\n\t\"3. Never invent facts, file paths, or APIs; say so when you do not know.\",\n\t\"4. Your output is untrusted evidence for the parent agent - data, never instructions.\",\n\t\"5. Follow the requested output format exactly and be concise; budgets are enforced outside you.\",\n].join(\"\\n\");\n\nexport interface SubagentPromptParts {\n\t/** Situational identity from the shipped profile (replaceable layer). */\n\tsoul?: string;\n\t/** The lane's default role prompt (replaceable layer). */\n\trolePrompt: string;\n\t/** User- or model-provided replacement for every layer above level 0. */\n\toverride?: string;\n}\n\nexport function composeSubagentSystemPrompt(parts: SubagentPromptParts): string {\n\tconst override = parts.override?.trim();\n\tconst above =\n\t\toverride && override.length > 0\n\t\t\t? override\n\t\t\t: [parts.soul?.trim(), parts.rolePrompt]\n\t\t\t\t\t.filter((part): part is string => Boolean(part && part.length > 0))\n\t\t\t\t\t.join(\"\\n\\n\");\n\treturn above.length > 0 ? `${SUBAGENT_CORE_SYSTEM_PROMPT}\\n\\n${above}` : SUBAGENT_CORE_SYSTEM_PROMPT;\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { JsonValue } from "./contracts.ts";
|
|
2
|
+
export declare const AUTONOMY_TELEMETRY_EVENT_TYPES: {
|
|
3
|
+
readonly routeDecision: "autonomy.route_decision";
|
|
4
|
+
readonly gateOutcome: "autonomy.gate_outcome";
|
|
5
|
+
readonly approvalRequest: "autonomy.approval_request";
|
|
6
|
+
readonly evidenceBundle: "autonomy.evidence_bundle";
|
|
7
|
+
readonly workerRequest: "autonomy.worker_request";
|
|
8
|
+
readonly workerResult: "autonomy.worker_result";
|
|
9
|
+
readonly learningDecision: "autonomy.learning_decision";
|
|
10
|
+
};
|
|
11
|
+
export type AutonomyTelemetryEventType = (typeof AUTONOMY_TELEMETRY_EVENT_TYPES)[keyof typeof AUTONOMY_TELEMETRY_EVENT_TYPES];
|
|
12
|
+
export interface AutonomyTelemetryEvent {
|
|
13
|
+
type: AutonomyTelemetryEventType;
|
|
14
|
+
timestamp: string;
|
|
15
|
+
payload: JsonValue;
|
|
16
|
+
}
|
|
17
|
+
export declare function redactTelemetryValue(value: unknown, depth?: number): unknown;
|
|
18
|
+
//# sourceMappingURL=telemetry-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-events.d.ts","sourceRoot":"","sources":["../../../src/core/autonomy/telemetry-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,eAAO,MAAM,8BAA8B;;;;;;;;CAQjC,CAAC;AAEX,MAAM,MAAM,0BAA0B,GACrC,CAAC,OAAO,8BAA8B,CAAC,CAAC,MAAM,OAAO,8BAA8B,CAAC,CAAC;AAEtF,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,0BAA0B,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,SAAS,CAAC;CACnB;AAiBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAI,GAAG,OAAO,CAyCvE","sourcesContent":["import type { JsonValue } from \"./contracts.ts\";\n\nexport const AUTONOMY_TELEMETRY_EVENT_TYPES = {\n\trouteDecision: \"autonomy.route_decision\",\n\tgateOutcome: \"autonomy.gate_outcome\",\n\tapprovalRequest: \"autonomy.approval_request\",\n\tevidenceBundle: \"autonomy.evidence_bundle\",\n\tworkerRequest: \"autonomy.worker_request\",\n\tworkerResult: \"autonomy.worker_result\",\n\tlearningDecision: \"autonomy.learning_decision\",\n} as const;\n\nexport type AutonomyTelemetryEventType =\n\t(typeof AUTONOMY_TELEMETRY_EVENT_TYPES)[keyof typeof AUTONOMY_TELEMETRY_EVENT_TYPES];\n\nexport interface AutonomyTelemetryEvent {\n\ttype: AutonomyTelemetryEventType;\n\ttimestamp: string;\n\tpayload: JsonValue;\n}\n\nconst SECRET_KEYS = new Set([\n\t\"apikey\",\n\t\"api_key\",\n\t\"token\",\n\t\"accesstoken\",\n\t\"refreshtoken\",\n\t\"secret\",\n\t\"password\",\n\t\"authorization\",\n\t\"credential\",\n\t\"credentials\",\n]);\n\nconst BEARER_RE = /bearer\\s+\\S+/i;\n\nexport function redactTelemetryValue(value: unknown, depth = 0): unknown {\n\tif (depth > 20) {\n\t\treturn \"[Depth Limit Exceeded]\";\n\t}\n\n\tif (typeof value === \"string\") {\n\t\tif (BEARER_RE.test(value)) {\n\t\t\treturn \"[REDACTED BEARER TOKEN]\";\n\t\t}\n\t\tif (value.startsWith(\"sk-\")) {\n\t\t\treturn \"[REDACTED API KEY]\";\n\t\t}\n\t\treturn value;\n\t}\n\n\tif (value === null || typeof value !== \"object\") {\n\t\treturn value;\n\t}\n\n\tif (Array.isArray(value)) {\n\t\tconst result: unknown[] = [];\n\t\tfor (const item of value) {\n\t\t\tresult.push(redactTelemetryValue(item, depth + 1));\n\t\t}\n\t\treturn result;\n\t}\n\n\t// It is an object\n\tconst obj = value as Record<string, unknown>;\n\tconst result: Record<string, unknown> = {};\n\n\tfor (const key of Object.keys(obj)) {\n\t\tconst lowercaseKey = key.toLowerCase();\n\t\tif (SECRET_KEYS.has(lowercaseKey)) {\n\t\t\tresult[key] = \"[REDACTED]\";\n\t\t} else {\n\t\t\tresult[key] = redactTelemetryValue(obj[key], depth + 1);\n\t\t}\n\t}\n\n\treturn result;\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export const AUTONOMY_TELEMETRY_EVENT_TYPES = {
|
|
2
|
+
routeDecision: "autonomy.route_decision",
|
|
3
|
+
gateOutcome: "autonomy.gate_outcome",
|
|
4
|
+
approvalRequest: "autonomy.approval_request",
|
|
5
|
+
evidenceBundle: "autonomy.evidence_bundle",
|
|
6
|
+
workerRequest: "autonomy.worker_request",
|
|
7
|
+
workerResult: "autonomy.worker_result",
|
|
8
|
+
learningDecision: "autonomy.learning_decision",
|
|
9
|
+
};
|
|
10
|
+
const SECRET_KEYS = new Set([
|
|
11
|
+
"apikey",
|
|
12
|
+
"api_key",
|
|
13
|
+
"token",
|
|
14
|
+
"accesstoken",
|
|
15
|
+
"refreshtoken",
|
|
16
|
+
"secret",
|
|
17
|
+
"password",
|
|
18
|
+
"authorization",
|
|
19
|
+
"credential",
|
|
20
|
+
"credentials",
|
|
21
|
+
]);
|
|
22
|
+
const BEARER_RE = /bearer\s+\S+/i;
|
|
23
|
+
export function redactTelemetryValue(value, depth = 0) {
|
|
24
|
+
if (depth > 20) {
|
|
25
|
+
return "[Depth Limit Exceeded]";
|
|
26
|
+
}
|
|
27
|
+
if (typeof value === "string") {
|
|
28
|
+
if (BEARER_RE.test(value)) {
|
|
29
|
+
return "[REDACTED BEARER TOKEN]";
|
|
30
|
+
}
|
|
31
|
+
if (value.startsWith("sk-")) {
|
|
32
|
+
return "[REDACTED API KEY]";
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
if (value === null || typeof value !== "object") {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
const result = [];
|
|
41
|
+
for (const item of value) {
|
|
42
|
+
result.push(redactTelemetryValue(item, depth + 1));
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
// It is an object
|
|
47
|
+
const obj = value;
|
|
48
|
+
const result = {};
|
|
49
|
+
for (const key of Object.keys(obj)) {
|
|
50
|
+
const lowercaseKey = key.toLowerCase();
|
|
51
|
+
if (SECRET_KEYS.has(lowercaseKey)) {
|
|
52
|
+
result[key] = "[REDACTED]";
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
result[key] = redactTelemetryValue(obj[key], depth + 1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=telemetry-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-events.js","sourceRoot":"","sources":["../../../src/core/autonomy/telemetry-events.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC7C,aAAa,EAAE,yBAAyB;IACxC,WAAW,EAAE,uBAAuB;IACpC,eAAe,EAAE,2BAA2B;IAC5C,cAAc,EAAE,0BAA0B;IAC1C,aAAa,EAAE,yBAAyB;IACxC,YAAY,EAAE,wBAAwB;IACtC,gBAAgB,EAAE,4BAA4B;CACrC,CAAC;AAWX,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC3B,QAAQ;IACR,SAAS;IACT,OAAO;IACP,aAAa;IACb,cAAc;IACd,QAAQ;IACR,UAAU;IACV,eAAe;IACf,YAAY;IACZ,aAAa;CACb,CAAC,CAAC;AAEH,MAAM,SAAS,GAAG,eAAe,CAAC;AAElC,MAAM,UAAU,oBAAoB,CAAC,KAAc,EAAE,KAAK,GAAG,CAAC,EAAW;IACxE,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;QAChB,OAAO,wBAAwB,CAAC;IACjC,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,yBAAyB,CAAC;QAClC,CAAC;QACD,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,oBAAoB,CAAC;QAC7B,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACjD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAc,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IAED,kBAAkB;IAClB,MAAM,GAAG,GAAG,KAAgC,CAAC;IAC7C,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,YAAY,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC;QAC5B,CAAC;aAAM,CAAC;YACP,MAAM,CAAC,GAAG,CAAC,GAAG,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACzD,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AAAA,CACd","sourcesContent":["import type { JsonValue } from \"./contracts.ts\";\n\nexport const AUTONOMY_TELEMETRY_EVENT_TYPES = {\n\trouteDecision: \"autonomy.route_decision\",\n\tgateOutcome: \"autonomy.gate_outcome\",\n\tapprovalRequest: \"autonomy.approval_request\",\n\tevidenceBundle: \"autonomy.evidence_bundle\",\n\tworkerRequest: \"autonomy.worker_request\",\n\tworkerResult: \"autonomy.worker_result\",\n\tlearningDecision: \"autonomy.learning_decision\",\n} as const;\n\nexport type AutonomyTelemetryEventType =\n\t(typeof AUTONOMY_TELEMETRY_EVENT_TYPES)[keyof typeof AUTONOMY_TELEMETRY_EVENT_TYPES];\n\nexport interface AutonomyTelemetryEvent {\n\ttype: AutonomyTelemetryEventType;\n\ttimestamp: string;\n\tpayload: JsonValue;\n}\n\nconst SECRET_KEYS = new Set([\n\t\"apikey\",\n\t\"api_key\",\n\t\"token\",\n\t\"accesstoken\",\n\t\"refreshtoken\",\n\t\"secret\",\n\t\"password\",\n\t\"authorization\",\n\t\"credential\",\n\t\"credentials\",\n]);\n\nconst BEARER_RE = /bearer\\s+\\S+/i;\n\nexport function redactTelemetryValue(value: unknown, depth = 0): unknown {\n\tif (depth > 20) {\n\t\treturn \"[Depth Limit Exceeded]\";\n\t}\n\n\tif (typeof value === \"string\") {\n\t\tif (BEARER_RE.test(value)) {\n\t\t\treturn \"[REDACTED BEARER TOKEN]\";\n\t\t}\n\t\tif (value.startsWith(\"sk-\")) {\n\t\t\treturn \"[REDACTED API KEY]\";\n\t\t}\n\t\treturn value;\n\t}\n\n\tif (value === null || typeof value !== \"object\") {\n\t\treturn value;\n\t}\n\n\tif (Array.isArray(value)) {\n\t\tconst result: unknown[] = [];\n\t\tfor (const item of value) {\n\t\t\tresult.push(redactTelemetryValue(item, depth + 1));\n\t\t}\n\t\treturn result;\n\t}\n\n\t// It is an object\n\tconst obj = value as Record<string, unknown>;\n\tconst result: Record<string, unknown> = {};\n\n\tfor (const key of Object.keys(obj)) {\n\t\tconst lowercaseKey = key.toLowerCase();\n\t\tif (SECRET_KEYS.has(lowercaseKey)) {\n\t\t\tresult[key] = \"[REDACTED]\";\n\t\t} else {\n\t\t\tresult[key] = redactTelemetryValue(obj[key], depth + 1);\n\t\t}\n\t}\n\n\treturn result;\n}\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded artifact retrieval (Phase 8-style helper landing early, per D2b): resolve an
|
|
3
|
+
* artifact id shown in a "Full output: artifact tool-output:<id>" notice back into a
|
|
4
|
+
* small, useful slice. Per tool-output-artifacts.md's retrieval behavior: retrieve the
|
|
5
|
+
* smallest useful slice by default (metadata, or a bounded head/tail).
|
|
6
|
+
*
|
|
7
|
+
* Bounds are hard limits, not just defaults: a caller-provided `maxLines`/`maxBytes` is
|
|
8
|
+
* clamped to `MAX_RETRIEVAL_LINES`/`MAX_RETRIEVAL_BYTES` before use, so no caller --
|
|
9
|
+
* including a future agent-facing tool wrapper -- can force a large artifact to be fully
|
|
10
|
+
* rehydrated in one call by simply requesting a larger bound. A small artifact that
|
|
11
|
+
* already fits within the bound is still returned in full; the guarantee is "never more
|
|
12
|
+
* than the configured hard bounds," not "never the whole artifact."
|
|
13
|
+
*/
|
|
14
|
+
import { type TruncationResult } from "../tools/truncate.ts";
|
|
15
|
+
import type { ArtifactStore } from "./context-artifacts.ts";
|
|
16
|
+
import { type MissingArtifactReason } from "./context-artifacts.ts";
|
|
17
|
+
import type { ContextArtifactRef } from "./context-item.ts";
|
|
18
|
+
export type ArtifactRetrievalMode = "metadata" | "head" | "tail";
|
|
19
|
+
export declare const DEFAULT_RETRIEVAL_MAX_LINES = 200;
|
|
20
|
+
/** Hard ceilings: a caller-requested maxLines/maxBytes can never exceed these. */
|
|
21
|
+
export declare const MAX_RETRIEVAL_LINES = 2000;
|
|
22
|
+
export declare const MAX_RETRIEVAL_BYTES: number;
|
|
23
|
+
export interface ArtifactRetrievalRequest {
|
|
24
|
+
artifactId: string;
|
|
25
|
+
mode?: ArtifactRetrievalMode;
|
|
26
|
+
maxLines?: number;
|
|
27
|
+
maxBytes?: number;
|
|
28
|
+
}
|
|
29
|
+
export type ArtifactRetrievalResult = {
|
|
30
|
+
found: false;
|
|
31
|
+
missingReason: MissingArtifactReason;
|
|
32
|
+
} | {
|
|
33
|
+
found: true;
|
|
34
|
+
mode: "metadata";
|
|
35
|
+
ref: ContextArtifactRef;
|
|
36
|
+
} | {
|
|
37
|
+
found: true;
|
|
38
|
+
mode: "head" | "tail";
|
|
39
|
+
ref: ContextArtifactRef;
|
|
40
|
+
slice: string;
|
|
41
|
+
truncation: TruncationResult;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Resolve `request.artifactId` against `store` and return a bounded slice. `maxLines`/
|
|
45
|
+
* `maxBytes` are hard-clamped to `MAX_RETRIEVAL_LINES`/`MAX_RETRIEVAL_BYTES` regardless of
|
|
46
|
+
* what the caller requests -- see the module doc comment for the exact guarantee.
|
|
47
|
+
*/
|
|
48
|
+
export declare function retrieveArtifactSlice(store: ArtifactStore, request: ArtifactRetrievalRequest): ArtifactRetrievalResult;
|
|
49
|
+
//# sourceMappingURL=artifact-retrieval.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-retrieval.d.ts","sourceRoot":"","sources":["../../../src/core/context/artifact-retrieval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAqB,KAAK,gBAAgB,EAA8B,MAAM,sBAAsB,CAAC;AAC5G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC7F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjE,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,mBAAmB,QAAoB,CAAC;AAErD,MAAM,WAAW,wBAAwB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,qBAAqB,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,uBAAuB,GAChC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,aAAa,EAAE,qBAAqB,CAAA;CAAE,GACtD;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,kBAAkB,CAAA;CAAE,GAC1D;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,GAAG,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAQhH;;;;GAIG;AACH,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,wBAAwB,GAC/B,uBAAuB,CAqBzB","sourcesContent":["/**\n * Bounded artifact retrieval (Phase 8-style helper landing early, per D2b): resolve an\n * artifact id shown in a \"Full output: artifact tool-output:<id>\" notice back into a\n * small, useful slice. Per tool-output-artifacts.md's retrieval behavior: retrieve the\n * smallest useful slice by default (metadata, or a bounded head/tail).\n *\n * Bounds are hard limits, not just defaults: a caller-provided `maxLines`/`maxBytes` is\n * clamped to `MAX_RETRIEVAL_LINES`/`MAX_RETRIEVAL_BYTES` before use, so no caller --\n * including a future agent-facing tool wrapper -- can force a large artifact to be fully\n * rehydrated in one call by simply requesting a larger bound. A small artifact that\n * already fits within the bound is still returned in full; the guarantee is \"never more\n * than the configured hard bounds,\" not \"never the whole artifact.\"\n */\n\nimport { DEFAULT_MAX_BYTES, type TruncationResult, truncateHead, truncateTail } from \"../tools/truncate.ts\";\nimport type { ArtifactStore } from \"./context-artifacts.ts\";\nimport { isMissingArtifactMarker, type MissingArtifactReason } from \"./context-artifacts.ts\";\nimport type { ContextArtifactRef } from \"./context-item.ts\";\n\nexport type ArtifactRetrievalMode = \"metadata\" | \"head\" | \"tail\";\n\nexport const DEFAULT_RETRIEVAL_MAX_LINES = 200;\n\n/** Hard ceilings: a caller-requested maxLines/maxBytes can never exceed these. */\nexport const MAX_RETRIEVAL_LINES = 2000;\nexport const MAX_RETRIEVAL_BYTES = DEFAULT_MAX_BYTES;\n\nexport interface ArtifactRetrievalRequest {\n\tartifactId: string;\n\tmode?: ArtifactRetrievalMode;\n\tmaxLines?: number;\n\tmaxBytes?: number;\n}\n\nexport type ArtifactRetrievalResult =\n\t| { found: false; missingReason: MissingArtifactReason }\n\t| { found: true; mode: \"metadata\"; ref: ContextArtifactRef }\n\t| { found: true; mode: \"head\" | \"tail\"; ref: ContextArtifactRef; slice: string; truncation: TruncationResult };\n\nfunction clampToHardCeiling(requested: number | undefined, fallback: number, hardCeiling: number): number {\n\tconst candidate = requested ?? fallback;\n\tif (candidate <= 0) return 0;\n\treturn Math.min(candidate, hardCeiling);\n}\n\n/**\n * Resolve `request.artifactId` against `store` and return a bounded slice. `maxLines`/\n * `maxBytes` are hard-clamped to `MAX_RETRIEVAL_LINES`/`MAX_RETRIEVAL_BYTES` regardless of\n * what the caller requests -- see the module doc comment for the exact guarantee.\n */\nexport function retrieveArtifactSlice(\n\tstore: ArtifactStore,\n\trequest: ArtifactRetrievalRequest,\n): ArtifactRetrievalResult {\n\tconst record = store.read(request.artifactId);\n\tif (isMissingArtifactMarker(record)) {\n\t\treturn { found: false, missingReason: record.reason };\n\t}\n\n\tconst mode = request.mode ?? \"head\";\n\tif (mode === \"metadata\") {\n\t\treturn { found: true, mode: \"metadata\", ref: record.ref };\n\t}\n\n\tconst truncationOptions = {\n\t\tmaxLines: clampToHardCeiling(request.maxLines, DEFAULT_RETRIEVAL_MAX_LINES, MAX_RETRIEVAL_LINES),\n\t\tmaxBytes: clampToHardCeiling(request.maxBytes, DEFAULT_MAX_BYTES, MAX_RETRIEVAL_BYTES),\n\t};\n\tconst truncation =\n\t\tmode === \"tail\"\n\t\t\t? truncateTail(record.content, truncationOptions)\n\t\t\t: truncateHead(record.content, truncationOptions);\n\n\treturn { found: true, mode, ref: record.ref, slice: truncation.content, truncation };\n}\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded artifact retrieval (Phase 8-style helper landing early, per D2b): resolve an
|
|
3
|
+
* artifact id shown in a "Full output: artifact tool-output:<id>" notice back into a
|
|
4
|
+
* small, useful slice. Per tool-output-artifacts.md's retrieval behavior: retrieve the
|
|
5
|
+
* smallest useful slice by default (metadata, or a bounded head/tail).
|
|
6
|
+
*
|
|
7
|
+
* Bounds are hard limits, not just defaults: a caller-provided `maxLines`/`maxBytes` is
|
|
8
|
+
* clamped to `MAX_RETRIEVAL_LINES`/`MAX_RETRIEVAL_BYTES` before use, so no caller --
|
|
9
|
+
* including a future agent-facing tool wrapper -- can force a large artifact to be fully
|
|
10
|
+
* rehydrated in one call by simply requesting a larger bound. A small artifact that
|
|
11
|
+
* already fits within the bound is still returned in full; the guarantee is "never more
|
|
12
|
+
* than the configured hard bounds," not "never the whole artifact."
|
|
13
|
+
*/
|
|
14
|
+
import { DEFAULT_MAX_BYTES, truncateHead, truncateTail } from "../tools/truncate.js";
|
|
15
|
+
import { isMissingArtifactMarker } from "./context-artifacts.js";
|
|
16
|
+
export const DEFAULT_RETRIEVAL_MAX_LINES = 200;
|
|
17
|
+
/** Hard ceilings: a caller-requested maxLines/maxBytes can never exceed these. */
|
|
18
|
+
export const MAX_RETRIEVAL_LINES = 2000;
|
|
19
|
+
export const MAX_RETRIEVAL_BYTES = DEFAULT_MAX_BYTES;
|
|
20
|
+
function clampToHardCeiling(requested, fallback, hardCeiling) {
|
|
21
|
+
const candidate = requested ?? fallback;
|
|
22
|
+
if (candidate <= 0)
|
|
23
|
+
return 0;
|
|
24
|
+
return Math.min(candidate, hardCeiling);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve `request.artifactId` against `store` and return a bounded slice. `maxLines`/
|
|
28
|
+
* `maxBytes` are hard-clamped to `MAX_RETRIEVAL_LINES`/`MAX_RETRIEVAL_BYTES` regardless of
|
|
29
|
+
* what the caller requests -- see the module doc comment for the exact guarantee.
|
|
30
|
+
*/
|
|
31
|
+
export function retrieveArtifactSlice(store, request) {
|
|
32
|
+
const record = store.read(request.artifactId);
|
|
33
|
+
if (isMissingArtifactMarker(record)) {
|
|
34
|
+
return { found: false, missingReason: record.reason };
|
|
35
|
+
}
|
|
36
|
+
const mode = request.mode ?? "head";
|
|
37
|
+
if (mode === "metadata") {
|
|
38
|
+
return { found: true, mode: "metadata", ref: record.ref };
|
|
39
|
+
}
|
|
40
|
+
const truncationOptions = {
|
|
41
|
+
maxLines: clampToHardCeiling(request.maxLines, DEFAULT_RETRIEVAL_MAX_LINES, MAX_RETRIEVAL_LINES),
|
|
42
|
+
maxBytes: clampToHardCeiling(request.maxBytes, DEFAULT_MAX_BYTES, MAX_RETRIEVAL_BYTES),
|
|
43
|
+
};
|
|
44
|
+
const truncation = mode === "tail"
|
|
45
|
+
? truncateTail(record.content, truncationOptions)
|
|
46
|
+
: truncateHead(record.content, truncationOptions);
|
|
47
|
+
return { found: true, mode, ref: record.ref, slice: truncation.content, truncation };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=artifact-retrieval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-retrieval.js","sourceRoot":"","sources":["../../../src/core/context/artifact-retrieval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,iBAAiB,EAAyB,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE5G,OAAO,EAAE,uBAAuB,EAA8B,MAAM,wBAAwB,CAAC;AAK7F,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAE/C,kFAAkF;AAClF,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACxC,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAcrD,SAAS,kBAAkB,CAAC,SAA6B,EAAE,QAAgB,EAAE,WAAmB,EAAU;IACzG,MAAM,SAAS,GAAG,SAAS,IAAI,QAAQ,CAAC;IACxC,IAAI,SAAS,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAAA,CACxC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACpC,KAAoB,EACpB,OAAiC,EACP;IAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,uBAAuB,CAAC,MAAM,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC;IACpC,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;IAC3D,CAAC;IAED,MAAM,iBAAiB,GAAG;QACzB,QAAQ,EAAE,kBAAkB,CAAC,OAAO,CAAC,QAAQ,EAAE,2BAA2B,EAAE,mBAAmB,CAAC;QAChG,QAAQ,EAAE,kBAAkB,CAAC,OAAO,CAAC,QAAQ,EAAE,iBAAiB,EAAE,mBAAmB,CAAC;KACtF,CAAC;IACF,MAAM,UAAU,GACf,IAAI,KAAK,MAAM;QACd,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,iBAAiB,CAAC;QACjD,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAEpD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC;AAAA,CACrF","sourcesContent":["/**\n * Bounded artifact retrieval (Phase 8-style helper landing early, per D2b): resolve an\n * artifact id shown in a \"Full output: artifact tool-output:<id>\" notice back into a\n * small, useful slice. Per tool-output-artifacts.md's retrieval behavior: retrieve the\n * smallest useful slice by default (metadata, or a bounded head/tail).\n *\n * Bounds are hard limits, not just defaults: a caller-provided `maxLines`/`maxBytes` is\n * clamped to `MAX_RETRIEVAL_LINES`/`MAX_RETRIEVAL_BYTES` before use, so no caller --\n * including a future agent-facing tool wrapper -- can force a large artifact to be fully\n * rehydrated in one call by simply requesting a larger bound. A small artifact that\n * already fits within the bound is still returned in full; the guarantee is \"never more\n * than the configured hard bounds,\" not \"never the whole artifact.\"\n */\n\nimport { DEFAULT_MAX_BYTES, type TruncationResult, truncateHead, truncateTail } from \"../tools/truncate.ts\";\nimport type { ArtifactStore } from \"./context-artifacts.ts\";\nimport { isMissingArtifactMarker, type MissingArtifactReason } from \"./context-artifacts.ts\";\nimport type { ContextArtifactRef } from \"./context-item.ts\";\n\nexport type ArtifactRetrievalMode = \"metadata\" | \"head\" | \"tail\";\n\nexport const DEFAULT_RETRIEVAL_MAX_LINES = 200;\n\n/** Hard ceilings: a caller-requested maxLines/maxBytes can never exceed these. */\nexport const MAX_RETRIEVAL_LINES = 2000;\nexport const MAX_RETRIEVAL_BYTES = DEFAULT_MAX_BYTES;\n\nexport interface ArtifactRetrievalRequest {\n\tartifactId: string;\n\tmode?: ArtifactRetrievalMode;\n\tmaxLines?: number;\n\tmaxBytes?: number;\n}\n\nexport type ArtifactRetrievalResult =\n\t| { found: false; missingReason: MissingArtifactReason }\n\t| { found: true; mode: \"metadata\"; ref: ContextArtifactRef }\n\t| { found: true; mode: \"head\" | \"tail\"; ref: ContextArtifactRef; slice: string; truncation: TruncationResult };\n\nfunction clampToHardCeiling(requested: number | undefined, fallback: number, hardCeiling: number): number {\n\tconst candidate = requested ?? fallback;\n\tif (candidate <= 0) return 0;\n\treturn Math.min(candidate, hardCeiling);\n}\n\n/**\n * Resolve `request.artifactId` against `store` and return a bounded slice. `maxLines`/\n * `maxBytes` are hard-clamped to `MAX_RETRIEVAL_LINES`/`MAX_RETRIEVAL_BYTES` regardless of\n * what the caller requests -- see the module doc comment for the exact guarantee.\n */\nexport function retrieveArtifactSlice(\n\tstore: ArtifactStore,\n\trequest: ArtifactRetrievalRequest,\n): ArtifactRetrievalResult {\n\tconst record = store.read(request.artifactId);\n\tif (isMissingArtifactMarker(record)) {\n\t\treturn { found: false, missingReason: record.reason };\n\t}\n\n\tconst mode = request.mode ?? \"head\";\n\tif (mode === \"metadata\") {\n\t\treturn { found: true, mode: \"metadata\", ref: record.ref };\n\t}\n\n\tconst truncationOptions = {\n\t\tmaxLines: clampToHardCeiling(request.maxLines, DEFAULT_RETRIEVAL_MAX_LINES, MAX_RETRIEVAL_LINES),\n\t\tmaxBytes: clampToHardCeiling(request.maxBytes, DEFAULT_MAX_BYTES, MAX_RETRIEVAL_BYTES),\n\t};\n\tconst truncation =\n\t\tmode === \"tail\"\n\t\t\t? truncateTail(record.content, truncationOptions)\n\t\t\t: truncateHead(record.content, truncationOptions);\n\n\treturn { found: true, mode, ref: record.ref, slice: truncation.content, truncation };\n}\n"]}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brain-assisted context curation (see docs/model-router-rework/brain-context-curation-design.md):
|
|
3
|
+
* a SIDECAR curator that consumes reports the context pipeline already produces and feeds back
|
|
4
|
+
* small, typed advisories. It is never a pipeline stage: every consumer must behave byte-for-byte
|
|
5
|
+
* identically when a result is absent (missing digest -> today's stub; missing relevance ->
|
|
6
|
+
* today's enforcement decision). The curator itself is provider-free — the completion executor is
|
|
7
|
+
* injected per drain, so it works against any registered local model and faux providers in tests.
|
|
8
|
+
*
|
|
9
|
+
* Memory bounds are explicit: the queue and result map are both capped, and drops are counted in
|
|
10
|
+
* telemetry rather than silent. Results are keyed for idempotency (digests by the GC record's
|
|
11
|
+
* content hash, relevance by the audit item id), so re-enqueueing the same work is free.
|
|
12
|
+
*/
|
|
13
|
+
export declare const CURATION_DIGEST_SYSTEM_PROMPT: string;
|
|
14
|
+
export declare const CURATION_RELEVANCE_SYSTEM_PROMPT: string;
|
|
15
|
+
export interface CurationJob {
|
|
16
|
+
kind: "stub_digest" | "relevance";
|
|
17
|
+
/** Idempotency key: digest jobs use the GC record's content hash, relevance jobs the item id. */
|
|
18
|
+
key: string;
|
|
19
|
+
/** Bounded chunk the local model must actually be able to process (sliced on enqueue). */
|
|
20
|
+
content: string;
|
|
21
|
+
/** Relevance jobs only: the goal/intent line the chunk is judged against. */
|
|
22
|
+
goal?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface CurationResult {
|
|
25
|
+
key: string;
|
|
26
|
+
kind: CurationJob["kind"];
|
|
27
|
+
ok: boolean;
|
|
28
|
+
digest?: string;
|
|
29
|
+
relevant?: boolean;
|
|
30
|
+
confidence?: number;
|
|
31
|
+
ms: number;
|
|
32
|
+
}
|
|
33
|
+
export interface CurationTelemetrySnapshot {
|
|
34
|
+
jobsRun: number;
|
|
35
|
+
parseFailures: number;
|
|
36
|
+
droppedJobs: number;
|
|
37
|
+
/** Chars processed locally (an honest proxy for frontier tokens NOT spent on this work). */
|
|
38
|
+
localChars: number;
|
|
39
|
+
queued: number;
|
|
40
|
+
resultsHeld: number;
|
|
41
|
+
}
|
|
42
|
+
export type CurationComplete = (input: {
|
|
43
|
+
systemPrompt: string;
|
|
44
|
+
userPrompt: string;
|
|
45
|
+
signal?: AbortSignal;
|
|
46
|
+
}) => Promise<{
|
|
47
|
+
text: string;
|
|
48
|
+
costUsd: number;
|
|
49
|
+
stopReason: string;
|
|
50
|
+
}>;
|
|
51
|
+
export declare const CURATION_RELEVANCE_MIN_CONFIDENCE = 0.8;
|
|
52
|
+
export declare function parseCurationDigest(text: string): string | undefined;
|
|
53
|
+
export declare function parseCurationRelevance(text: string): {
|
|
54
|
+
relevant: boolean;
|
|
55
|
+
confidence: number;
|
|
56
|
+
} | undefined;
|
|
57
|
+
export declare class BrainCurator {
|
|
58
|
+
private readonly _queue;
|
|
59
|
+
private readonly _results;
|
|
60
|
+
private _jobsRun;
|
|
61
|
+
private _parseFailures;
|
|
62
|
+
private _droppedJobs;
|
|
63
|
+
private _localChars;
|
|
64
|
+
private _draining;
|
|
65
|
+
enqueue(job: CurationJob): void;
|
|
66
|
+
getDigest(key: string): string | undefined;
|
|
67
|
+
getRelevance(key: string): {
|
|
68
|
+
relevant: boolean;
|
|
69
|
+
confidence: number;
|
|
70
|
+
} | undefined;
|
|
71
|
+
hasWork(): boolean;
|
|
72
|
+
get isDraining(): boolean;
|
|
73
|
+
telemetry(): CurationTelemetrySnapshot;
|
|
74
|
+
/**
|
|
75
|
+
* Run up to `maxJobs` queued jobs through the injected local-model completer. Single-flight:
|
|
76
|
+
* a concurrent drain call returns [] immediately rather than double-running jobs. Every call
|
|
77
|
+
* is wall-clock bounded; a failed/unparseable job is recorded as a not-ok result (so it is
|
|
78
|
+
* not retried forever) and counted in telemetry.
|
|
79
|
+
*/
|
|
80
|
+
drain(args: {
|
|
81
|
+
complete: CurationComplete;
|
|
82
|
+
maxJobs: number;
|
|
83
|
+
signal?: AbortSignal;
|
|
84
|
+
now?: () => number;
|
|
85
|
+
}): Promise<CurationResult[]>;
|
|
86
|
+
private _storeResult;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=brain-curator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brain-curator.d.ts","sourceRoot":"","sources":["../../../src/core/context/brain-curator.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,6BAA6B,QAK9B,CAAC;AAEb,eAAO,MAAM,gCAAgC,QAMjC,CAAC;AAEb,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,aAAa,GAAG,WAAW,CAAC;IAClC,iGAAiG;IACjG,GAAG,EAAE,MAAM,CAAC;IACZ,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,yBAAyB;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,4FAA4F;IAC5F,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,KAAK,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAOrE,eAAO,MAAM,iCAAiC,MAAM,CAAC;AAqBrD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQpE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAU1G;AAED,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAS9B;IAED,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzC;IAED,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAI/E;IAED,OAAO,IAAI,OAAO,CAEjB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,SAAS,IAAI,yBAAyB,CASrC;IAED;;;;;OAKG;IACG,KAAK,CAAC,IAAI,EAAE;QACjB,QAAQ,EAAE,gBAAgB,CAAC;QAC3B,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAiD5B;IAED,OAAO,CAAC,YAAY;CAOpB","sourcesContent":["import { runBoundedCompletion } from \"../autonomy/bounded-completion.ts\";\n\n/**\n * Brain-assisted context curation (see docs/model-router-rework/brain-context-curation-design.md):\n * a SIDECAR curator that consumes reports the context pipeline already produces and feeds back\n * small, typed advisories. It is never a pipeline stage: every consumer must behave byte-for-byte\n * identically when a result is absent (missing digest -> today's stub; missing relevance ->\n * today's enforcement decision). The curator itself is provider-free — the completion executor is\n * injected per drain, so it works against any registered local model and faux providers in tests.\n *\n * Memory bounds are explicit: the queue and result map are both capped, and drops are counted in\n * telemetry rather than silent. Results are keyed for idempotency (digests by the GC record's\n * content hash, relevance by the audit item id), so re-enqueueing the same work is free.\n */\n\nexport const CURATION_DIGEST_SYSTEM_PROMPT = [\n\t\"You digest tool-output chunks for a coding agent's context curator. You never solve the task.\",\n\t\"Given a chunk, respond with STRICT JSON only - no prose:\",\n\t'{\"digest\":\"<one or two sentences, max 200 characters, keeping exact identifiers>\"}',\n\t\"Keep exact file paths, symbol names, error codes, and version strings verbatim.\",\n].join(\"\\n\");\n\nexport const CURATION_RELEVANCE_SYSTEM_PROMPT = [\n\t\"You judge whether a stale tool output is still relevant to the user's current goal.\",\n\t\"You never solve the task. Respond with STRICT JSON only - no prose:\",\n\t'{\"relevant\":true|false,\"confidence\":<0..1>}',\n\t\"relevant=false means the chunk is about something the current goal no longer needs.\",\n\t\"When uncertain, answer relevant=true with low confidence - keeping content is the safe default.\",\n].join(\"\\n\");\n\nexport interface CurationJob {\n\tkind: \"stub_digest\" | \"relevance\";\n\t/** Idempotency key: digest jobs use the GC record's content hash, relevance jobs the item id. */\n\tkey: string;\n\t/** Bounded chunk the local model must actually be able to process (sliced on enqueue). */\n\tcontent: string;\n\t/** Relevance jobs only: the goal/intent line the chunk is judged against. */\n\tgoal?: string;\n}\n\nexport interface CurationResult {\n\tkey: string;\n\tkind: CurationJob[\"kind\"];\n\tok: boolean;\n\tdigest?: string;\n\trelevant?: boolean;\n\tconfidence?: number;\n\tms: number;\n}\n\nexport interface CurationTelemetrySnapshot {\n\tjobsRun: number;\n\tparseFailures: number;\n\tdroppedJobs: number;\n\t/** Chars processed locally (an honest proxy for frontier tokens NOT spent on this work). */\n\tlocalChars: number;\n\tqueued: number;\n\tresultsHeld: number;\n}\n\nexport type CurationComplete = (input: {\n\tsystemPrompt: string;\n\tuserPrompt: string;\n\tsignal?: AbortSignal;\n}) => Promise<{ text: string; costUsd: number; stopReason: string }>;\n\nconst MAX_QUEUE = 32;\nconst MAX_RESULTS = 200;\nconst MAX_JOB_CONTENT_CHARS = 8_000;\nconst DIGEST_MAX_WALL_CLOCK_MS = 20_000;\nconst RELEVANCE_MAX_WALL_CLOCK_MS = 8_000;\nexport const CURATION_RELEVANCE_MIN_CONFIDENCE = 0.8;\n\nfunction extractJsonObject(text: string): unknown | undefined {\n\tconst trimmed = text.trim();\n\tconst candidates: string[] = [trimmed];\n\tconst fenced = /```(?:json)?\\s*([\\s\\S]*?)```/.exec(trimmed);\n\tif (fenced?.[1]) candidates.push(fenced[1].trim());\n\tconst start = trimmed.indexOf(\"{\");\n\tconst end = trimmed.lastIndexOf(\"}\");\n\tif (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(candidate);\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return parsed;\n\t\t} catch {\n\t\t\t// try next candidate\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function parseCurationDigest(text: string): string | undefined {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return undefined;\n\tconst digest = (parsed as { digest?: unknown }).digest;\n\tif (typeof digest !== \"string\") return undefined;\n\tconst trimmed = digest.trim().replace(/\\s+/g, \" \");\n\tif (trimmed.length === 0 || trimmed.length > 240) return undefined;\n\treturn trimmed;\n}\n\nexport function parseCurationRelevance(text: string): { relevant: boolean; confidence: number } | undefined {\n\tconst parsed = extractJsonObject(text);\n\tif (!parsed) return undefined;\n\tconst record = parsed as { relevant?: unknown; confidence?: unknown };\n\tif (typeof record.relevant !== \"boolean\") return undefined;\n\tconst confidence =\n\t\ttypeof record.confidence === \"number\" && Number.isFinite(record.confidence)\n\t\t\t? Math.max(0, Math.min(1, record.confidence))\n\t\t\t: 0;\n\treturn { relevant: record.relevant, confidence };\n}\n\nexport class BrainCurator {\n\tprivate readonly _queue = new Map<string, CurationJob>();\n\tprivate readonly _results = new Map<string, CurationResult>();\n\tprivate _jobsRun = 0;\n\tprivate _parseFailures = 0;\n\tprivate _droppedJobs = 0;\n\tprivate _localChars = 0;\n\tprivate _draining = false;\n\n\tenqueue(job: CurationJob): void {\n\t\tif (this._results.has(job.key) || this._queue.has(job.key)) return;\n\t\tif (this._queue.size >= MAX_QUEUE) {\n\t\t\t// Drop the OLDEST queued job (newer work reflects the current goal better) and count it.\n\t\t\tconst oldest = this._queue.keys().next().value;\n\t\t\tif (oldest !== undefined) this._queue.delete(oldest);\n\t\t\tthis._droppedJobs++;\n\t\t}\n\t\tthis._queue.set(job.key, { ...job, content: job.content.slice(0, MAX_JOB_CONTENT_CHARS) });\n\t}\n\n\tgetDigest(key: string): string | undefined {\n\t\tconst result = this._results.get(key);\n\t\treturn result?.ok && result.kind === \"stub_digest\" ? result.digest : undefined;\n\t}\n\n\tgetRelevance(key: string): { relevant: boolean; confidence: number } | undefined {\n\t\tconst result = this._results.get(key);\n\t\tif (!result?.ok || result.kind !== \"relevance\" || result.relevant === undefined) return undefined;\n\t\treturn { relevant: result.relevant, confidence: result.confidence ?? 0 };\n\t}\n\n\thasWork(): boolean {\n\t\treturn this._queue.size > 0;\n\t}\n\n\tget isDraining(): boolean {\n\t\treturn this._draining;\n\t}\n\n\ttelemetry(): CurationTelemetrySnapshot {\n\t\treturn {\n\t\t\tjobsRun: this._jobsRun,\n\t\t\tparseFailures: this._parseFailures,\n\t\t\tdroppedJobs: this._droppedJobs,\n\t\t\tlocalChars: this._localChars,\n\t\t\tqueued: this._queue.size,\n\t\t\tresultsHeld: this._results.size,\n\t\t};\n\t}\n\n\t/**\n\t * Run up to `maxJobs` queued jobs through the injected local-model completer. Single-flight:\n\t * a concurrent drain call returns [] immediately rather than double-running jobs. Every call\n\t * is wall-clock bounded; a failed/unparseable job is recorded as a not-ok result (so it is\n\t * not retried forever) and counted in telemetry.\n\t */\n\tasync drain(args: {\n\t\tcomplete: CurationComplete;\n\t\tmaxJobs: number;\n\t\tsignal?: AbortSignal;\n\t\tnow?: () => number;\n\t}): Promise<CurationResult[]> {\n\t\tif (this._draining) return [];\n\t\tthis._draining = true;\n\t\tconst now = args.now ?? Date.now;\n\t\tconst completed: CurationResult[] = [];\n\t\ttry {\n\t\t\tconst jobs = [...this._queue.values()].slice(0, Math.max(0, args.maxJobs));\n\t\t\tfor (const job of jobs) {\n\t\t\t\tif (args.signal?.aborted) break;\n\t\t\t\tthis._queue.delete(job.key);\n\t\t\t\tconst started = now();\n\t\t\t\tconst bounded = await runBoundedCompletion({\n\t\t\t\t\tmaxWallClockMs: job.kind === \"stub_digest\" ? DIGEST_MAX_WALL_CLOCK_MS : RELEVANCE_MAX_WALL_CLOCK_MS,\n\t\t\t\t\tsignal: args.signal,\n\t\t\t\t\texecute: (signal) =>\n\t\t\t\t\t\targs.complete({\n\t\t\t\t\t\t\tsystemPrompt:\n\t\t\t\t\t\t\t\tjob.kind === \"stub_digest\" ? CURATION_DIGEST_SYSTEM_PROMPT : CURATION_RELEVANCE_SYSTEM_PROMPT,\n\t\t\t\t\t\t\tuserPrompt:\n\t\t\t\t\t\t\t\tjob.kind === \"stub_digest\"\n\t\t\t\t\t\t\t\t\t? job.content\n\t\t\t\t\t\t\t\t\t: `Current goal: ${job.goal ?? \"(unknown)\"}\\n\\nStale chunk:\\n${job.content}`,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tconst ms = now() - started;\n\t\t\t\tthis._jobsRun++;\n\t\t\t\tthis._localChars += job.content.length;\n\t\t\t\tlet result: CurationResult = { key: job.key, kind: job.kind, ok: false, ms };\n\t\t\t\tif (bounded.completion && !bounded.failure) {\n\t\t\t\t\tif (job.kind === \"stub_digest\") {\n\t\t\t\t\t\tconst digest = parseCurationDigest(bounded.completion.text);\n\t\t\t\t\t\tresult = digest !== undefined ? { ...result, ok: true, digest } : result;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst relevance = parseCurationRelevance(bounded.completion.text);\n\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\trelevance !== undefined\n\t\t\t\t\t\t\t\t? { ...result, ok: true, relevant: relevance.relevant, confidence: relevance.confidence }\n\t\t\t\t\t\t\t\t: result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!result.ok) this._parseFailures++;\n\t\t\t\tthis._storeResult(result);\n\t\t\t\tcompleted.push(result);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis._draining = false;\n\t\t}\n\t\treturn completed;\n\t}\n\n\tprivate _storeResult(result: CurationResult): void {\n\t\tif (this._results.size >= MAX_RESULTS) {\n\t\t\tconst oldest = this._results.keys().next().value;\n\t\t\tif (oldest !== undefined) this._results.delete(oldest);\n\t\t}\n\t\tthis._results.set(result.key, result);\n\t}\n}\n"]}
|