@caupulican/pi-adaptative 0.81.39 → 0.81.41
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 +77 -0
- package/README.md +2 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +2 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +3 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +4 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +9 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +290 -107
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +357 -122
- package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +2 -2
- package/dist/cli/args.d.ts +4 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +31 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-directory-layout.d.ts +15 -0
- package/dist/core/agent-directory-layout.d.ts.map +1 -0
- package/dist/core/agent-directory-layout.js +72 -0
- package/dist/core/agent-directory-layout.js.map +1 -0
- package/dist/core/agent-paths.d.ts +25 -2
- package/dist/core/agent-paths.d.ts.map +1 -1
- package/dist/core/agent-paths.js +79 -4
- package/dist/core/agent-paths.js.map +1 -1
- package/dist/core/agent-session-contracts.d.ts +293 -0
- package/dist/core/agent-session-contracts.d.ts.map +1 -0
- package/dist/core/agent-session-contracts.js +26 -0
- package/dist/core/agent-session-contracts.js.map +1 -0
- package/dist/core/agent-session-runtime.d.ts +52 -8
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +400 -79
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +74 -518
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +370 -1432
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +3 -1
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/autonomy/approval-gate.d.ts +3 -2
- package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
- package/dist/core/autonomy/approval-gate.js +6 -28
- package/dist/core/autonomy/approval-gate.js.map +1 -1
- package/dist/core/autonomy/bounded-completion.d.ts +1 -1
- package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
- package/dist/core/autonomy/bounded-completion.js +1 -1
- package/dist/core/autonomy/bounded-completion.js.map +1 -1
- package/dist/core/autonomy/contracts.d.ts +20 -12
- package/dist/core/autonomy/contracts.d.ts.map +1 -1
- package/dist/core/autonomy/contracts.js.map +1 -1
- package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
- package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
- package/dist/core/autonomy/foreground-envelope.js +8 -25
- package/dist/core/autonomy/foreground-envelope.js.map +1 -1
- package/dist/core/autonomy/gates.d.ts.map +1 -1
- package/dist/core/autonomy/gates.js +8 -10
- package/dist/core/autonomy/gates.js.map +1 -1
- package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
- package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
- package/dist/core/autonomy/lane-private-paths.js +16 -0
- package/dist/core/autonomy/lane-private-paths.js.map +1 -0
- package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
- package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tool-surface.js +48 -9
- package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
- package/dist/core/autonomy/lane-tracker.d.ts +14 -0
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tracker.js +38 -0
- package/dist/core/autonomy/lane-tracker.js.map +1 -1
- package/dist/core/autonomy/risk-assessment.d.ts +1 -2
- package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
- package/dist/core/autonomy/risk-assessment.js +1 -123
- package/dist/core/autonomy/risk-assessment.js.map +1 -1
- package/dist/core/autonomy/session-lane-record.d.ts +4 -4
- package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
- package/dist/core/autonomy/session-lane-record.js +16 -29
- package/dist/core/autonomy/session-lane-record.js.map +1 -1
- package/dist/core/autonomy/telemetry-events.d.ts +1 -1
- package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
- package/dist/core/autonomy/telemetry-events.js +1 -1
- package/dist/core/autonomy/telemetry-events.js.map +1 -1
- package/dist/core/autonomy-telemetry.d.ts +7 -7
- package/dist/core/autonomy-telemetry.d.ts.map +1 -1
- package/dist/core/autonomy-telemetry.js +9 -9
- package/dist/core/autonomy-telemetry.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +56 -236
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +141 -1273
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/bedrock-sso-login.d.ts +16 -0
- package/dist/core/bedrock-sso-login.d.ts.map +1 -0
- package/dist/core/bedrock-sso-login.js +98 -0
- package/dist/core/bedrock-sso-login.js.map +1 -0
- package/dist/core/capability-contract.d.ts +4 -0
- package/dist/core/capability-contract.d.ts.map +1 -0
- package/dist/core/capability-contract.js +28 -0
- package/dist/core/capability-contract.js.map +1 -0
- package/dist/core/compaction-controller.d.ts +90 -0
- package/dist/core/compaction-controller.d.ts.map +1 -0
- package/dist/core/compaction-controller.js +452 -0
- package/dist/core/compaction-controller.js.map +1 -0
- package/dist/core/compaction-support.d.ts +13 -17
- package/dist/core/compaction-support.d.ts.map +1 -1
- package/dist/core/compaction-support.js +3 -3
- package/dist/core/compaction-support.js.map +1 -1
- package/dist/core/context/context-artifacts.d.ts +6 -2
- package/dist/core/context/context-artifacts.d.ts.map +1 -1
- package/dist/core/context/context-artifacts.js +34 -2
- package/dist/core/context/context-artifacts.js.map +1 -1
- package/dist/core/context/context-store-retention.d.ts +8 -2
- package/dist/core/context/context-store-retention.d.ts.map +1 -1
- package/dist/core/context/context-store-retention.js +158 -35
- package/dist/core/context/context-store-retention.js.map +1 -1
- package/dist/core/context/okf-memory.d.ts.map +1 -1
- package/dist/core/context/okf-memory.js +9 -11
- package/dist/core/context/okf-memory.js.map +1 -1
- package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
- package/dist/core/context/sqlite-runtime-index.js +6 -8
- package/dist/core/context/sqlite-runtime-index.js.map +1 -1
- package/dist/core/context-gc.d.ts +3 -0
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +10 -5
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/context-pipeline.d.ts +1 -1
- package/dist/core/context-pipeline.d.ts.map +1 -1
- package/dist/core/context-pipeline.js +16 -37
- package/dist/core/context-pipeline.js.map +1 -1
- package/dist/core/cost/cost-summary.d.ts.map +1 -1
- package/dist/core/cost/cost-summary.js +5 -3
- package/dist/core/cost/cost-summary.js.map +1 -1
- package/dist/core/cost/daily-usage.d.ts.map +1 -1
- package/dist/core/cost/daily-usage.js +4 -5
- package/dist/core/cost/daily-usage.js.map +1 -1
- package/dist/core/default-tool-surface.d.ts.map +1 -1
- package/dist/core/default-tool-surface.js +2 -0
- package/dist/core/default-tool-surface.js.map +1 -1
- package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
- package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
- package/dist/core/delegation/managed-lane-controller.js +217 -0
- package/dist/core/delegation/managed-lane-controller.js.map +1 -0
- package/dist/core/delegation/session-worker-claim.d.ts +44 -0
- package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
- package/dist/core/delegation/session-worker-claim.js +98 -0
- package/dist/core/delegation/session-worker-claim.js.map +1 -0
- package/dist/core/delegation/worker-actions.d.ts +7 -5
- package/dist/core/delegation/worker-actions.d.ts.map +1 -1
- package/dist/core/delegation/worker-actions.js +20 -4
- package/dist/core/delegation/worker-actions.js.map +1 -1
- package/dist/core/delegation/{worker-result.d.ts → worker-claim.d.ts} +13 -13
- package/dist/core/delegation/worker-claim.d.ts.map +1 -0
- package/dist/core/delegation/{worker-result.js → worker-claim.js} +61 -51
- package/dist/core/delegation/worker-claim.js.map +1 -0
- package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
- package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
- package/dist/core/delegation/worker-delegation-controller.js +861 -0
- package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
- package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
- package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
- package/dist/core/delegation/worker-delegation-request.js +2 -0
- package/dist/core/delegation/worker-delegation-request.js.map +1 -0
- package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
- package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
- package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
- package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
- package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
- package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
- package/dist/core/delegation/worker-execution-policy.js +160 -0
- package/dist/core/delegation/worker-execution-policy.js.map +1 -0
- package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
- package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
- package/dist/core/delegation/worker-lane-projection.js +100 -0
- package/dist/core/delegation/worker-lane-projection.js.map +1 -0
- package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
- package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
- package/dist/core/delegation/worker-lifecycle.js +339 -0
- package/dist/core/delegation/worker-lifecycle.js.map +1 -0
- package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
- package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
- package/dist/core/delegation/worker-notification-coordinator.js +90 -0
- package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
- package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
- package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
- package/dist/core/delegation/worker-profile-resolver.js +113 -0
- package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
- package/dist/core/delegation/worker-runner.d.ts +25 -14
- package/dist/core/delegation/worker-runner.d.ts.map +1 -1
- package/dist/core/delegation/worker-runner.js +122 -53
- package/dist/core/delegation/worker-runner.js.map +1 -1
- package/dist/core/delegation/worker-task-label.d.ts +3 -0
- package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
- package/dist/core/delegation/worker-task-label.js +11 -0
- package/dist/core/delegation/worker-task-label.js.map +1 -0
- package/dist/core/doctor.d.ts +8 -0
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +32 -1
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/extension-import-authority.d.ts +6 -0
- package/dist/core/extension-import-authority.d.ts.map +1 -0
- package/dist/core/extension-import-authority.js +10 -0
- package/dist/core/extension-import-authority.js.map +1 -0
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +5 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +52 -18
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +20 -5
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/stale-context.d.ts +2 -0
- package/dist/core/extensions/stale-context.d.ts.map +1 -0
- package/dist/core/extensions/stale-context.js +2 -0
- package/dist/core/extensions/stale-context.js.map +1 -0
- package/dist/core/extensions/storage.d.ts +8 -0
- package/dist/core/extensions/storage.d.ts.map +1 -0
- package/dist/core/extensions/storage.js +28 -0
- package/dist/core/extensions/storage.js.map +1 -0
- package/dist/core/extensions/types.d.ts +78 -21
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/failure-corpus.d.ts +1 -15
- package/dist/core/failure-corpus.d.ts.map +1 -1
- package/dist/core/failure-corpus.js +9 -37
- package/dist/core/failure-corpus.js.map +1 -1
- package/dist/core/foreground-recovery-controller.d.ts +53 -0
- package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
- package/dist/core/foreground-recovery-controller.js +111 -0
- package/dist/core/foreground-recovery-controller.js.map +1 -0
- package/dist/core/gateways/channel-provider.d.ts +3 -0
- package/dist/core/gateways/channel-provider.d.ts.map +1 -1
- package/dist/core/gateways/channel-provider.js +31 -6
- package/dist/core/gateways/channel-provider.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts +14 -9
- package/dist/core/goal-loop-controller.d.ts.map +1 -1
- package/dist/core/goal-loop-controller.js +47 -75
- package/dist/core/goal-loop-controller.js.map +1 -1
- package/dist/core/goals/compact-goal-context.d.ts +11 -0
- package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
- package/dist/core/goals/compact-goal-context.js +59 -0
- package/dist/core/goals/compact-goal-context.js.map +1 -0
- package/dist/core/goals/goal-acceptance.d.ts +11 -0
- package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
- package/dist/core/goals/goal-acceptance.js +27 -0
- package/dist/core/goals/goal-acceptance.js.map +1 -0
- package/dist/core/goals/goal-auto-continue-controller.d.ts +28 -0
- package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
- package/dist/core/goals/goal-auto-continue-controller.js +90 -0
- package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
- package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
- package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-controller.js +52 -11
- package/dist/core/goals/goal-continuation-controller.js.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
- package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.js +4 -32
- package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.js +9 -179
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
- package/dist/core/goals/goal-lifecycle.d.ts +43 -0
- package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
- package/dist/core/goals/goal-lifecycle.js +102 -0
- package/dist/core/goals/goal-lifecycle.js.map +1 -0
- package/dist/core/goals/goal-record.d.ts +17 -0
- package/dist/core/goals/goal-record.d.ts.map +1 -0
- package/dist/core/goals/goal-record.js +31 -0
- package/dist/core/goals/goal-record.js.map +1 -0
- package/dist/core/goals/goal-runtime-snapshot.d.ts +11 -9
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.js +10 -8
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
- package/dist/core/goals/goal-session-controller.d.ts +42 -0
- package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
- package/dist/core/goals/goal-session-controller.js +128 -0
- package/dist/core/goals/goal-session-controller.js.map +1 -0
- package/dist/core/goals/goal-state.d.ts +46 -25
- package/dist/core/goals/goal-state.d.ts.map +1 -1
- package/dist/core/goals/goal-state.js +91 -24
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.d.ts +9 -10
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
- package/dist/core/goals/goal-tool-core.js +60 -75
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/goals/session-goal-state.d.ts +20 -12
- package/dist/core/goals/session-goal-state.d.ts.map +1 -1
- package/dist/core/goals/session-goal-state.js +133 -33
- package/dist/core/goals/session-goal-state.js.map +1 -1
- package/dist/core/human-input-controller.d.ts +47 -0
- package/dist/core/human-input-controller.d.ts.map +1 -0
- package/dist/core/human-input-controller.js +181 -0
- package/dist/core/human-input-controller.js.map +1 -0
- package/dist/core/human-input.d.ts +100 -0
- package/dist/core/human-input.d.ts.map +1 -0
- package/dist/core/human-input.js +362 -0
- package/dist/core/human-input.js.map +1 -0
- package/dist/core/index.d.ts +9 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
- package/dist/core/install-telemetry.d.ts.map +1 -0
- package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
- package/dist/core/install-telemetry.js.map +1 -0
- package/dist/core/keybindings.d.ts +17 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +24 -6
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/learning/learning-audit.d.ts +2 -4
- package/dist/core/learning/learning-audit.d.ts.map +1 -1
- package/dist/core/learning/learning-audit.js +9 -29
- package/dist/core/learning/learning-audit.js.map +1 -1
- package/dist/core/learning/learning-gate.d.ts.map +1 -1
- package/dist/core/learning/learning-gate.js +1 -6
- package/dist/core/learning/learning-gate.js.map +1 -1
- package/dist/core/learning/session-learning-decision.d.ts +2 -4
- package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
- package/dist/core/learning/session-learning-decision.js +9 -29
- package/dist/core/learning/session-learning-decision.js.map +1 -1
- package/dist/core/local-runtime-controller.d.ts +1 -1
- package/dist/core/local-runtime-controller.d.ts.map +1 -1
- package/dist/core/local-runtime-controller.js.map +1 -1
- package/dist/core/memory-controller.d.ts.map +1 -1
- package/dist/core/memory-controller.js +4 -4
- package/dist/core/memory-controller.js.map +1 -1
- package/dist/core/model-capability.d.ts +0 -19
- package/dist/core/model-capability.d.ts.map +1 -1
- package/dist/core/model-capability.js +1 -19
- package/dist/core/model-capability.js.map +1 -1
- package/dist/core/model-registry.d.ts +6 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +13 -5
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +17 -2
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +38 -25
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-router/intent-classifier.d.ts +1 -4
- package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
- package/dist/core/model-router/intent-classifier.js +1 -156
- package/dist/core/model-router/intent-classifier.js.map +1 -1
- package/dist/core/model-router-controller.d.ts +1 -1
- package/dist/core/model-router-controller.d.ts.map +1 -1
- package/dist/core/model-router-controller.js +2 -2
- package/dist/core/model-router-controller.js.map +1 -1
- package/dist/core/model-selection-controller.d.ts +5 -5
- package/dist/core/model-selection-controller.d.ts.map +1 -1
- package/dist/core/model-selection-controller.js.map +1 -1
- package/dist/core/model-tool-protocol.d.ts +23 -0
- package/dist/core/model-tool-protocol.d.ts.map +1 -0
- package/dist/core/model-tool-protocol.js +43 -0
- package/dist/core/model-tool-protocol.js.map +1 -0
- package/dist/core/models/adaptation-store.d.ts +4 -6
- package/dist/core/models/adaptation-store.d.ts.map +1 -1
- package/dist/core/models/adaptation-store.js +95 -83
- package/dist/core/models/adaptation-store.js.map +1 -1
- package/dist/core/models/fitness-store.d.ts +2 -12
- package/dist/core/models/fitness-store.d.ts.map +1 -1
- package/dist/core/models/fitness-store.js +84 -57
- package/dist/core/models/fitness-store.js.map +1 -1
- package/dist/core/models/host-state-store.d.ts +34 -0
- package/dist/core/models/host-state-store.d.ts.map +1 -0
- package/dist/core/models/host-state-store.js +86 -0
- package/dist/core/models/host-state-store.js.map +1 -0
- package/dist/core/orchestration/agent-resume.d.ts +24 -0
- package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
- package/dist/core/orchestration/agent-resume.js +90 -0
- package/dist/core/orchestration/agent-resume.js.map +1 -0
- package/dist/core/orchestration/capability-gateway.d.ts +61 -0
- package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
- package/dist/core/orchestration/capability-gateway.js +152 -0
- package/dist/core/orchestration/capability-gateway.js.map +1 -0
- package/dist/core/orchestration/contracts.d.ts +343 -0
- package/dist/core/orchestration/contracts.d.ts.map +1 -0
- package/dist/core/orchestration/contracts.js +135 -0
- package/dist/core/orchestration/contracts.js.map +1 -0
- package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
- package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
- package/dist/core/orchestration/delegation-ledger.js +200 -0
- package/dist/core/orchestration/delegation-ledger.js.map +1 -0
- package/dist/core/orchestration/event-store.d.ts +83 -0
- package/dist/core/orchestration/event-store.d.ts.map +1 -0
- package/dist/core/orchestration/event-store.js +560 -0
- package/dist/core/orchestration/event-store.js.map +1 -0
- package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
- package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
- package/dist/core/orchestration/lane-tool-manifests.js +37 -0
- package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
- package/dist/core/orchestration/model-binding.d.ts +15 -0
- package/dist/core/orchestration/model-binding.d.ts.map +1 -0
- package/dist/core/orchestration/model-binding.js +29 -0
- package/dist/core/orchestration/model-binding.js.map +1 -0
- package/dist/core/orchestration/policy-compiler.d.ts +49 -0
- package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
- package/dist/core/orchestration/policy-compiler.js +191 -0
- package/dist/core/orchestration/policy-compiler.js.map +1 -0
- package/dist/core/orchestration/policy-gate.d.ts +18 -0
- package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
- package/dist/core/orchestration/policy-gate.js +24 -0
- package/dist/core/orchestration/policy-gate.js.map +1 -0
- package/dist/core/orchestration/profile-registry.d.ts +51 -0
- package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
- package/dist/core/orchestration/profile-registry.js +393 -0
- package/dist/core/orchestration/profile-registry.js.map +1 -0
- package/dist/core/orchestration/profile-store.d.ts +31 -0
- package/dist/core/orchestration/profile-store.d.ts.map +1 -0
- package/dist/core/orchestration/profile-store.js +136 -0
- package/dist/core/orchestration/profile-store.js.map +1 -0
- package/dist/core/orchestration/risk-budget.d.ts +9 -0
- package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
- package/dist/core/orchestration/risk-budget.js +48 -0
- package/dist/core/orchestration/risk-budget.js.map +1 -0
- package/dist/core/orchestration/task-runtime.d.ts +168 -0
- package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
- package/dist/core/orchestration/task-runtime.js +1600 -0
- package/dist/core/orchestration/task-runtime.js.map +1 -0
- package/dist/core/orchestration/work-state-projection.d.ts +32 -0
- package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
- package/dist/core/orchestration/work-state-projection.js +116 -0
- package/dist/core/orchestration/work-state-projection.js.map +1 -0
- package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
- package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
- package/dist/core/orchestration/worker-execution-contract.js +179 -0
- package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
- package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
- package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
- package/dist/core/orchestration/worker-result-adapter.js +109 -0
- package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +20 -3
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/process-identity.d.ts +11 -0
- package/dist/core/process-identity.d.ts.map +1 -0
- package/dist/core/process-identity.js +26 -0
- package/dist/core/process-identity.js.map +1 -0
- package/dist/core/process-matrix/codes.d.ts +14 -3
- package/dist/core/process-matrix/codes.d.ts.map +1 -1
- package/dist/core/process-matrix/codes.js.map +1 -1
- package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
- package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
- package/dist/core/process-matrix/resume-launcher.js +62 -0
- package/dist/core/process-matrix/resume-launcher.js.map +1 -0
- package/dist/core/process-matrix/runtime.d.ts +37 -22
- package/dist/core/process-matrix/runtime.d.ts.map +1 -1
- package/dist/core/process-matrix/runtime.js +399 -76
- package/dist/core/process-matrix/runtime.js.map +1 -1
- package/dist/core/process-matrix/store.d.ts +5 -2
- package/dist/core/process-matrix/store.d.ts.map +1 -1
- package/dist/core/process-matrix/store.js +123 -14
- package/dist/core/process-matrix/store.js.map +1 -1
- package/dist/core/process-matrix/supervisor.d.ts +10 -7
- package/dist/core/process-matrix/supervisor.d.ts.map +1 -1
- package/dist/core/process-matrix/supervisor.js +45 -14
- package/dist/core/process-matrix/supervisor.js.map +1 -1
- package/dist/core/profile-filter-controller.d.ts +8 -1
- package/dist/core/profile-filter-controller.d.ts.map +1 -1
- package/dist/core/profile-filter-controller.js +23 -5
- package/dist/core/profile-filter-controller.js.map +1 -1
- package/dist/core/profile-registry.d.ts.map +1 -1
- package/dist/core/profile-registry.js +6 -8
- package/dist/core/profile-registry.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +1 -0
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +18 -29
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/reflection-controller.d.ts +5 -5
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +5 -2
- package/dist/core/reflection-controller.js.map +1 -1
- package/dist/core/reload-blockers.d.ts.map +1 -1
- package/dist/core/reload-blockers.js +6 -8
- package/dist/core/reload-blockers.js.map +1 -1
- package/dist/core/request-auth.d.ts +7 -0
- package/dist/core/request-auth.d.ts.map +1 -0
- package/dist/core/request-auth.js +8 -0
- package/dist/core/request-auth.js.map +1 -0
- package/dist/core/research/evidence-bundle.d.ts.map +1 -1
- package/dist/core/research/evidence-bundle.js +1 -6
- package/dist/core/research/evidence-bundle.js.map +1 -1
- package/dist/core/research/lane-model-resolver.d.ts +33 -0
- package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
- package/dist/core/research/lane-model-resolver.js +65 -0
- package/dist/core/research/lane-model-resolver.js.map +1 -0
- package/dist/core/research/model-fitness-controller.d.ts +38 -0
- package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
- package/dist/core/research/model-fitness-controller.js +106 -0
- package/dist/core/research/model-fitness-controller.js.map +1 -0
- package/dist/core/research/model-fitness.d.ts +1 -1
- package/dist/core/research/model-fitness.d.ts.map +1 -1
- package/dist/core/research/model-fitness.js +4 -4
- package/dist/core/research/model-fitness.js.map +1 -1
- package/dist/core/research/research-gate.d.ts.map +1 -1
- package/dist/core/research/research-gate.js +7 -7
- package/dist/core/research/research-gate.js.map +1 -1
- package/dist/core/research/research-lane-controller.d.ts +62 -0
- package/dist/core/research/research-lane-controller.d.ts.map +1 -0
- package/dist/core/research/research-lane-controller.js +292 -0
- package/dist/core/research/research-lane-controller.js.map +1 -0
- package/dist/core/research/session-evidence-bundle.d.ts +2 -4
- package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
- package/dist/core/research/session-evidence-bundle.js +10 -46
- package/dist/core/research/session-evidence-bundle.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +23 -8
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/risk-classifier.d.ts +6 -0
- package/dist/core/risk-classifier.d.ts.map +1 -0
- package/dist/core/risk-classifier.js +233 -0
- package/dist/core/risk-classifier.js.map +1 -0
- package/dist/core/runtime-builder.d.ts +41 -23
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +365 -253
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/sdk.d.ts +6 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +68 -25
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
- package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
- package/dist/core/secrets/credential-exposure-guard.js +241 -0
- package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
- package/dist/core/secrets/secret-dotenv.d.ts +27 -0
- package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
- package/dist/core/secrets/secret-dotenv.js +183 -0
- package/dist/core/secrets/secret-dotenv.js.map +1 -0
- package/dist/core/secrets/secret-vault-format.d.ts +112 -0
- package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
- package/dist/core/secrets/secret-vault-format.js +397 -0
- package/dist/core/secrets/secret-vault-format.js.map +1 -0
- package/dist/core/secrets/secret-vault.d.ts +72 -0
- package/dist/core/secrets/secret-vault.d.ts.map +1 -0
- package/dist/core/secrets/secret-vault.js +671 -0
- package/dist/core/secrets/secret-vault.js.map +1 -0
- package/dist/core/session-analytics.d.ts +4 -23
- package/dist/core/session-analytics.d.ts.map +1 -1
- package/dist/core/session-analytics.js +67 -70
- package/dist/core/session-analytics.js.map +1 -1
- package/dist/core/session-image-store.d.ts +33 -0
- package/dist/core/session-image-store.d.ts.map +1 -0
- package/dist/core/session-image-store.js +283 -0
- package/dist/core/session-image-store.js.map +1 -0
- package/dist/core/session-role.d.ts +11 -4
- package/dist/core/session-role.d.ts.map +1 -1
- package/dist/core/session-role.js +24 -5
- package/dist/core/session-role.js.map +1 -1
- package/dist/core/session-snapshot.d.ts +34 -0
- package/dist/core/session-snapshot.d.ts.map +1 -0
- package/dist/core/session-snapshot.js +68 -0
- package/dist/core/session-snapshot.js.map +1 -0
- package/dist/core/session-supervision-runtime.d.ts +31 -0
- package/dist/core/session-supervision-runtime.d.ts.map +1 -0
- package/dist/core/session-supervision-runtime.js +97 -0
- package/dist/core/session-supervision-runtime.js.map +1 -0
- package/dist/core/session-tree-navigator.d.ts +4 -6
- package/dist/core/session-tree-navigator.d.ts.map +1 -1
- package/dist/core/session-tree-navigator.js +4 -1
- package/dist/core/session-tree-navigator.js.map +1 -1
- package/dist/core/settings-manager.d.ts +10 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +81 -29
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tasks/session-task-state.d.ts +2 -4
- package/dist/core/tasks/session-task-state.d.ts.map +1 -1
- package/dist/core/tasks/session-task-state.js +10 -28
- package/dist/core/tasks/session-task-state.js.map +1 -1
- package/dist/core/tasks/task-projection.d.ts +20 -0
- package/dist/core/tasks/task-projection.d.ts.map +1 -0
- package/dist/core/tasks/task-projection.js +47 -0
- package/dist/core/tasks/task-projection.js.map +1 -0
- package/dist/core/tasks/task-state.d.ts +4 -0
- package/dist/core/tasks/task-state.d.ts.map +1 -1
- package/dist/core/tasks/task-state.js +28 -11
- package/dist/core/tasks/task-state.js.map +1 -1
- package/dist/core/tool-capability-policy.d.ts +13 -0
- package/dist/core/tool-capability-policy.d.ts.map +1 -0
- package/dist/core/tool-capability-policy.js +86 -0
- package/dist/core/tool-capability-policy.js.map +1 -0
- package/dist/core/tool-gate-controller.d.ts.map +1 -1
- package/dist/core/tool-gate-controller.js +8 -2
- package/dist/core/tool-gate-controller.js.map +1 -1
- package/dist/core/tool-protocol-controller.d.ts +89 -0
- package/dist/core/tool-protocol-controller.d.ts.map +1 -0
- package/dist/core/tool-protocol-controller.js +512 -0
- package/dist/core/tool-protocol-controller.js.map +1 -0
- package/dist/core/tool-recovery-log-records.d.ts +2 -3
- package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
- package/dist/core/tool-recovery-log-records.js +9 -35
- package/dist/core/tool-recovery-log-records.js.map +1 -1
- package/dist/core/tool-recovery-stats.d.ts +21 -1
- package/dist/core/tool-recovery-stats.d.ts.map +1 -1
- package/dist/core/tool-recovery-stats.js.map +1 -1
- package/dist/core/tool-selection/tool-performance-store.d.ts +3 -7
- package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-performance-store.js +97 -138
- package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
- package/dist/core/tools/ask-question.d.ts +124 -0
- package/dist/core/tools/ask-question.d.ts.map +1 -0
- package/dist/core/tools/ask-question.js +693 -0
- package/dist/core/tools/ask-question.js.map +1 -0
- package/dist/core/tools/bash.d.ts +5 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +59 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/delegate-status.d.ts +31 -3
- package/dist/core/tools/delegate-status.d.ts.map +1 -1
- package/dist/core/tools/delegate-status.js +148 -29
- package/dist/core/tools/delegate-status.js.map +1 -1
- package/dist/core/tools/delegate.d.ts +15 -13
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +106 -23
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/extensionify.d.ts.map +1 -1
- package/dist/core/tools/extensionify.js +1 -0
- package/dist/core/tools/extensionify.js.map +1 -1
- package/dist/core/tools/git-filter.d.ts +1 -8
- package/dist/core/tools/git-filter.d.ts.map +1 -1
- package/dist/core/tools/git-filter.js +2 -63
- package/dist/core/tools/git-filter.js.map +1 -1
- package/dist/core/tools/goal.d.ts +10 -8
- package/dist/core/tools/goal.d.ts.map +1 -1
- package/dist/core/tools/goal.js +106 -28
- package/dist/core/tools/goal.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/model-fitness.d.ts.map +1 -1
- package/dist/core/tools/model-fitness.js +2 -2
- package/dist/core/tools/model-fitness.js.map +1 -1
- package/dist/core/tools/orchestration-panel.d.ts +40 -0
- package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
- package/dist/core/tools/orchestration-panel.js +124 -0
- package/dist/core/tools/orchestration-panel.js.map +1 -0
- package/dist/core/tools/output-accumulator.d.ts +11 -0
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +36 -3
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/python.d.ts +2 -0
- package/dist/core/tools/python.d.ts.map +1 -1
- package/dist/core/tools/python.js +3 -1
- package/dist/core/tools/python.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/run-process.d.ts +26 -0
- package/dist/core/tools/run-process.d.ts.map +1 -0
- package/dist/core/tools/run-process.js +138 -0
- package/dist/core/tools/run-process.js.map +1 -0
- package/dist/core/tools/search-command-guard.d.ts +14 -0
- package/dist/core/tools/search-command-guard.d.ts.map +1 -0
- package/dist/core/tools/search-command-guard.js +333 -0
- package/dist/core/tools/search-command-guard.js.map +1 -0
- package/dist/core/tools/secret-store.d.ts +38 -0
- package/dist/core/tools/secret-store.d.ts.map +1 -0
- package/dist/core/tools/secret-store.js +412 -0
- package/dist/core/tools/secret-store.js.map +1 -0
- package/dist/core/tools/shell-command-parser.d.ts +16 -0
- package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
- package/dist/core/tools/shell-command-parser.js +113 -0
- package/dist/core/tools/shell-command-parser.js.map +1 -0
- package/dist/core/tools/task-steps.d.ts +2 -0
- package/dist/core/tools/task-steps.d.ts.map +1 -1
- package/dist/core/tools/task-steps.js +99 -0
- package/dist/core/tools/task-steps.js.map +1 -1
- package/dist/core/tools/tmux-dispatch.d.ts +3 -5
- package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
- package/dist/core/tools/tmux-dispatch.js +4 -4
- package/dist/core/tools/tmux-dispatch.js.map +1 -1
- package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
- package/dist/core/tools/windows-shell-engine.js +4 -6
- package/dist/core/tools/windows-shell-engine.js.map +1 -1
- package/dist/core/util/atomic-file.d.ts +6 -2
- package/dist/core/util/atomic-file.d.ts.map +1 -1
- package/dist/core/util/atomic-file.js +4 -4
- package/dist/core/util/atomic-file.js.map +1 -1
- package/dist/core/util/bounded-jsonl.d.ts +10 -0
- package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
- package/dist/core/util/bounded-jsonl.js +75 -0
- package/dist/core/util/bounded-jsonl.js.map +1 -0
- package/dist/core/util/value-guards.d.ts +5 -0
- package/dist/core/util/value-guards.d.ts.map +1 -0
- package/dist/core/util/value-guards.js +12 -0
- package/dist/core/util/value-guards.js.map +1 -0
- package/dist/core/worktree-sync/store.d.ts +3 -3
- package/dist/core/worktree-sync/store.d.ts.map +1 -1
- package/dist/core/worktree-sync/store.js +10 -5
- package/dist/core/worktree-sync/store.js.map +1 -1
- package/dist/index.d.ts +15 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +149 -51
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +4 -6
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +186 -28
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/auth-dialogs-controller.d.ts +4 -0
- package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
- package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
- package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
- package/dist/modes/interactive/clipboard-input.d.ts +7 -1
- package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
- package/dist/modes/interactive/clipboard-input.js +44 -6
- package/dist/modes/interactive/clipboard-input.js.map +1 -1
- package/dist/modes/interactive/components/activity-lane.d.ts +55 -0
- package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
- package/dist/modes/interactive/components/activity-lane.js +304 -0
- package/dist/modes/interactive/components/activity-lane.js.map +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +19 -10
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
- package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
- package/dist/modes/interactive/components/expandable-text.js +17 -0
- package/dist/modes/interactive/components/expandable-text.js.map +1 -0
- package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +30 -21
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts +1 -0
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +6 -1
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +6 -6
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +53 -20
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-group.js +3 -0
- package/dist/modes/interactive/components/tool-group.js.map +1 -1
- package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
- package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/usage-action-selector.js +46 -0
- package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
- package/dist/modes/interactive/config-backup.d.ts.map +1 -1
- package/dist/modes/interactive/config-backup.js +5 -4
- package/dist/modes/interactive/config-backup.js.map +1 -1
- package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
- package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
- package/dist/modes/interactive/extension-ui-host.js +77 -15
- package/dist/modes/interactive/extension-ui-host.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +15 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +27 -19
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/history-reload-math.d.ts +6 -2
- package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
- package/dist/modes/interactive/history-reload-math.js +10 -5
- package/dist/modes/interactive/history-reload-math.js.map +1 -1
- package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
- package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-event-controller.js +328 -0
- package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +22 -24
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +245 -595
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
- package/dist/modes/interactive/key-handlers.js +1 -1
- package/dist/modes/interactive/key-handlers.js.map +1 -1
- package/dist/modes/interactive/loaded-resources-view.d.ts +20 -0
- package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
- package/dist/modes/interactive/loaded-resources-view.js +147 -0
- package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
- package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
- package/dist/modes/interactive/profile-menu-controller.js +7 -7
- package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
- package/dist/modes/interactive/report-commands.d.ts.map +1 -1
- package/dist/modes/interactive/report-commands.js +21 -0
- package/dist/modes/interactive/report-commands.js.map +1 -1
- package/dist/modes/interactive/resource-display.d.ts.map +1 -1
- package/dist/modes/interactive/resource-display.js +8 -2
- package/dist/modes/interactive/resource-display.js.map +1 -1
- package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
- package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
- package/dist/modes/interactive/resource-shell-commands.js +0 -5
- package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts +27 -8
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +150 -64
- package/dist/modes/interactive/session-flow-commands.js.map +1 -1
- package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-io-commands.js +16 -6
- package/dist/modes/interactive/session-io-commands.js.map +1 -1
- package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
- package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
- package/dist/modes/interactive/session-replacement-errors.js +15 -0
- package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
- package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
- package/dist/modes/interactive/startup-checks.js +1 -1
- package/dist/modes/interactive/startup-checks.js.map +1 -1
- package/dist/modes/interactive/usage-commands.d.ts +34 -0
- package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
- package/dist/modes/interactive/usage-commands.js +225 -0
- package/dist/modes/interactive/usage-commands.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +82 -23
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +15 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +138 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +2 -13
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +1 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +1 -0
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +52 -1
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/platform.d.ts +3 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +8 -0
- package/dist/utils/platform.js.map +1 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +5 -3
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +3 -1
- package/dist/utils/version-check.js.map +1 -1
- package/dist/utils/work-directory.d.ts +11 -0
- package/dist/utils/work-directory.d.ts.map +1 -1
- package/dist/utils/work-directory.js +30 -9
- package/dist/utils/work-directory.js.map +1 -1
- package/docs/UI_POLISH_ORCHESTRATION.md +38 -0
- package/docs/UI_QUALITY_ORCHESTRATION.md +28 -0
- package/docs/docs.json +4 -0
- package/docs/extensions.md +62 -2
- package/docs/harness-architecture.md +156 -0
- package/docs/keybindings.md +11 -1
- package/docs/process-matrix.md +59 -26
- package/docs/providers.md +9 -1
- package/docs/rpc.md +45 -2
- package/docs/sessions.md +15 -0
- package/docs/settings.md +125 -11
- package/docs/task-steps.md +8 -0
- package/docs/telemetry.md +19 -0
- package/docs/tmux-agent-manager.md +10 -3
- package/docs/ui-reference/README.md +9 -0
- package/docs/ui-reference/orchestration-after.txt +14 -0
- package/docs/ui-reference/orchestration-before.txt +13 -0
- package/docs/ui-reference/orchestration-reference.txt +16 -0
- package/docs/usage.md +22 -2
- package/docs/work-directory.md +19 -8
- 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/question.ts +34 -245
- package/examples/extensions/questionnaire.ts +41 -407
- 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 +13 -13
- package/package.json +4 -4
- package/dist/core/delegation/session-worker-result.d.ts +0 -46
- package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
- package/dist/core/delegation/session-worker-result.js +0 -113
- package/dist/core/delegation/session-worker-result.js.map +0 -1
- package/dist/core/delegation/worker-result.d.ts.map +0 -1
- package/dist/core/delegation/worker-result.js.map +0 -1
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-protocol-controller.js","sourceRoot":"","sources":["../../src/core/tool-protocol-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { rmSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Agent, StreamFn } from \"@caupulican/pi-agent-core\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tTextContent,\n\tTextToolProtocolParseEvent,\n\tTextToolProtocolVariant,\n\tTool,\n\tToolArgumentValidationTelemetryEvent,\n\tToolRepairModeName,\n\tUsage,\n} from \"@caupulican/pi-ai\";\nimport {\n\tformatToolRepairStandingRule,\n\tformatVariantEnvelope,\n\tgenerateTextToolProtocolPrimer,\n\tparseTextToolCalls,\n\tTEXT_TOOL_PROTOCOL_VARIANTS,\n} from \"@caupulican/pi-ai\";\nimport { Type } from \"typebox\";\nimport { getProcessWorkRun } from \"../utils/work-directory.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport {\n\tMODEL_TOOL_PROTOCOL_VERSION,\n\ttype ModelToolProtocolResolution,\n\tresolveModelToolProtocol,\n} from \"./model-tool-protocol.ts\";\nimport type {\n\tModelAdaptationRule,\n\tModelAdaptationStore,\n\tModelToolProbe,\n\tModelToolProbeVerdict,\n\tNativeToolProbeGrade,\n} from \"./models/adaptation-store.ts\";\nimport type { RequestAuth } from \"./request-auth.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport type { ToolRecoveryLoggerStats } from \"./tool-recovery-logger.ts\";\nimport { formatToolRepairHealthReport } from \"./tool-repair-health.ts\";\nimport { resolveCurrentToolRepairSettings } from \"./tool-repair-settings.ts\";\n\nconst MODEL_ADAPTATION_REPAIR_THRESHOLD = 3;\nconst TEXT_TOOL_PROTOCOL_TRIALS_PER_VARIANT = 2;\nconst TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD = 3;\nconst TEXT_TOOL_PROTOCOL_STEER_INTERVAL = 5;\nconst AUTO_TOOL_PROBE_FRESHNESS_MS = 15 * 60 * 1000;\nconst TEXT_TOOL_PROTOCOL_ECHO_TOOL = {\n\tname: \"echo\",\n\tdescription: \"Echo calibration data\",\n\tparameters: Type.Object({ data: Type.String() }),\n} satisfies Tool;\nconst NATIVE_TOOL_PROBE_READ_TOOL = {\n\tname: \"read\",\n\tdescription: \"Read file contents\",\n\tparameters: Type.Object({ path: Type.String() }),\n} satisfies Tool;\n\nexport type ToolProbeVerdict = \"native\" | \"text-protocol\" | \"none\";\n\nexport interface ToolProbeResult {\n\tmodel: string;\n\tverdict: ToolProbeVerdict;\n\tvariant?: TextToolProtocolVariant;\n\tnativeGrade?: NativeToolProbeGrade;\n\tdiagnostic?: string;\n}\n\nexport interface ToolProbeReport {\n\tresults: ToolProbeResult[];\n\ttable: string;\n}\n\nexport interface ToolProtocolControllerDeps {\n\tagent: Agent;\n\tagentDir: string;\n\tsettingsManager: SettingsManager;\n\tgetModelRegistry(): ModelRegistry;\n\tadaptationStore: ModelAdaptationStore;\n\tisRawStreamSimple(fn: StreamFn): boolean;\n\tgetRequiredRequestAuth(model: Model<Api>): Promise<RequestAuth>;\n\taddSpawnedUsage(usage: Usage, opts: { label?: string; reportId: string }): string | undefined;\n\temitWarning(message: string): void;\n\tsendCorrectiveSteer(message: string): Promise<void>;\n\tfindLastAssistantMessage(): AssistantMessage | undefined;\n\tisDisposed(): boolean;\n\tprobeForAuto(model: Model<Api>): Promise<ToolProbeResult>;\n}\n\n/** Owns model tool-protocol selection, probing, circuit breaking, and repair teaching. */\nexport class ToolProtocolController {\n\tprivate readonly repairModeSessionCounts = new Map<string, number>();\n\tprivate readonly parseFailures = new Map<string, { signature: string; repeats: number }>();\n\tprivate parseObservedThisTurn = false;\n\tprivate correctiveSteerCount = 0;\n\tprivate probeUsageReportSeq = 0;\n\tprivate readonly autoProbedModels = new Set<string>();\n\tprivate validationOutcomeThisTurn: TextToolProtocolParseEvent | undefined;\n\tprivate readonly deps: ToolProtocolControllerDeps;\n\n\tconstructor(deps: ToolProtocolControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tapplyRepairLayerSettings(): void {\n\t\tthis.deps.agent.toolArgumentTeachEnabled = this.getRepairSettings().teach;\n\t}\n\n\tresetTurnState(): void {\n\t\tthis.parseObservedThisTurn = false;\n\t\tthis.validationOutcomeThisTurn = undefined;\n\t}\n\n\tgetAdaptationRulesForPrompt(): ModelAdaptationRule[] {\n\t\tif (!this.getRepairSettings().teach) return [];\n\t\tconst modelKey = this.modelKey(this.deps.agent.state.model);\n\t\treturn modelKey ? this.deps.adaptationStore.get(modelKey).rules : [];\n\t}\n\n\tresolveModelToolProtocol(model: Model<Api>): ModelToolProtocolResolution {\n\t\treturn resolveModelToolProtocol({\n\t\t\tmodel,\n\t\t\tsettingsOverride: this.getRepairSettings().textProtocol,\n\t\t\tadaptation: this.deps.adaptationStore.get(this.modelRef(model)),\n\t\t});\n\t}\n\n\tasync ensureActiveModelProtocol(): Promise<void> {\n\t\tconst model = this.deps.agent.state.model;\n\t\tconst resolution = this.resolveModelToolProtocol(model);\n\t\tthis.deps.agent.textToolCallProtocol = resolution.protocol;\n\t\tif (\n\t\t\tresolution.reasonCode !== \"probe_calibration_missing\" &&\n\t\t\tresolution.reasonCode !== \"probe_calibration_failed\" &&\n\t\t\tresolution.reasonCode !== \"probe_calibration_invalid\"\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tconst modelKey = this.modelRef(model);\n\t\tthis.deps.emitWarning(\n\t\t\tresolution.reasonCode === \"probe_calibration_failed\"\n\t\t\t\t? `Text tool protocol calibration for ${modelKey} previously failed (variants tried: ${(resolution.variantsTried ?? []).join(\", \")}); falling back to native tool calls this turn. Run /toolprobe ${modelKey} to recalibrate.`\n\t\t\t\t: `Text tool protocol for ${modelKey} has no valid calibration on record; falling back to native tool calls this turn. Run /toolprobe ${modelKey} to calibrate.`,\n\t\t);\n\t}\n\n\tgetToolProbeVerdict(model: Model<Api>): ModelToolProbeVerdict | undefined {\n\t\treturn this.deps.adaptationStore.get(this.modelRef(model)).toolProbe?.status;\n\t}\n\n\tasync probeToolCalling(target?: string): Promise<ToolProbeReport> {\n\t\tconst models = await this.resolveToolProbeModels(target);\n\t\tif (models.length === 0) throw new Error(\"No available models to probe.\");\n\t\tconst results: ToolProbeResult[] = [];\n\t\tfor (const model of models) results.push(await this.probeToolCallingForModel(model));\n\t\treturn { results, table: this.formatToolProbeReport(results) };\n\t}\n\n\tasync probeToolCallingForModel(model: Model<Api>): Promise<ToolProbeResult> {\n\t\tconst modelKey = this.modelRef(model);\n\t\tconst probedAt = new Date().toISOString();\n\t\tlet nativeGrade: NativeToolProbeGrade = \"absent\";\n\t\tlet diagnostic: string | undefined;\n\t\ttry {\n\t\t\tnativeGrade = await this.gradeNativeToolCallingForModel(model, \"pi-native-probe\");\n\t\t\tif (nativeGrade === \"task\") {\n\t\t\t\tthis.storeToolProbe(modelKey, {\n\t\t\t\t\tversion: MODEL_TOOL_PROTOCOL_VERSION,\n\t\t\t\t\tstatus: \"native\",\n\t\t\t\t\tprobedAt,\n\t\t\t\t\tnativeGrade,\n\t\t\t\t});\n\t\t\t\treturn { model: modelKey, verdict: \"native\", nativeGrade };\n\t\t\t}\n\t\t\tdiagnostic =\n\t\t\t\tnativeGrade === \"echo-only\"\n\t\t\t\t\t? \"Native echo probe passed but task-scale read probe failed.\"\n\t\t\t\t\t: \"Native task-scale read and echo probes did not produce provider-native tool calls.\";\n\t\t} catch (error) {\n\t\t\tdiagnostic = error instanceof Error ? error.message : String(error);\n\t\t}\n\n\t\ttry {\n\t\t\tconst calibrated = await this.calibrateTextToolProtocolForModel(model, modelKey, { persistFailure: false });\n\t\t\tif (calibrated.status === \"calibrated\") {\n\t\t\t\tthis.storeToolProbe(modelKey, {\n\t\t\t\t\tversion: MODEL_TOOL_PROTOCOL_VERSION,\n\t\t\t\t\tstatus: \"text-protocol\",\n\t\t\t\t\tprobedAt: calibrated.calibratedAt,\n\t\t\t\t\tvariant: calibrated.variant,\n\t\t\t\t\tnativeGrade,\n\t\t\t\t\tdiagnostic,\n\t\t\t\t});\n\t\t\t\treturn { model: modelKey, verdict: \"text-protocol\", variant: calibrated.variant, nativeGrade, diagnostic };\n\t\t\t}\n\t\t\tdiagnostic = `${diagnostic ? `${diagnostic} ` : \"\"}Text protocol variants failed: ${calibrated.variantsTried.join(\", \")}`;\n\t\t} catch (error) {\n\t\t\tdiagnostic = error instanceof Error ? error.message : String(error);\n\t\t}\n\n\t\tthis.storeToolProbe(modelKey, {\n\t\t\tversion: MODEL_TOOL_PROTOCOL_VERSION,\n\t\t\tstatus: \"none\",\n\t\t\tprobedAt,\n\t\t\tnativeGrade,\n\t\t\tdiagnostic,\n\t\t});\n\t\treturn { model: modelKey, verdict: \"none\", nativeGrade, diagnostic };\n\t}\n\n\thandleTextProtocolParse(event: TextToolProtocolParseEvent): void {\n\t\tthis.parseObservedThisTurn = true;\n\t\tconst modelKey = `${event.provider}/${event.model}`;\n\t\tif (event.status === \"parsed\") return;\n\t\tthis.maybeInjectCorrectiveSteer(event.variant);\n\t\tconst signature = `${event.variant}:${event.reason ?? \"failed\"}`;\n\t\tconst previous = this.parseFailures.get(modelKey);\n\t\tconst repeats = previous?.signature === signature ? previous.repeats + 1 : 1;\n\t\tthis.parseFailures.set(modelKey, { signature, repeats });\n\t\tif (repeats < TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD) return;\n\n\t\tconst profile = this.deps.adaptationStore.get(modelKey);\n\t\tif (profile.protocol?.version === MODEL_TOOL_PROTOCOL_VERSION && profile.protocol.status !== \"failed\") {\n\t\t\tthis.deps.adaptationStore.removeProtocol(modelKey);\n\t\t\tthis.deps.agent.textToolCallProtocol = undefined;\n\t\t}\n\t\tthis.parseFailures.delete(modelKey);\n\t\tconst probedAt = new Date().toISOString();\n\t\tthis.deps.adaptationStore.setToolProbe(\n\t\t\tmodelKey,\n\t\t\t{\n\t\t\t\tversion: MODEL_TOOL_PROTOCOL_VERSION,\n\t\t\t\tstatus: \"none\",\n\t\t\t\tprobedAt,\n\t\t\t\tnativeGrade: profile.toolProbe?.nativeGrade,\n\t\t\t\tdiagnostic: `Text protocol parsing failed ${TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD}x in a row with signature \"${signature}\".`,\n\t\t\t},\n\t\t\tprobedAt,\n\t\t);\n\t\tthis.deps.emitWarning(\n\t\t\t`Text tool protocol for ${modelKey} stopped parsing after ${TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD} attempts; demoted to native fallback. Run /toolprobe ${modelKey} to recalibrate.`,\n\t\t);\n\t}\n\n\thandleValidationOutcome(event: ToolArgumentValidationTelemetryEvent): void {\n\t\tif (event.source !== \"text-protocol\") return;\n\t\tconst protocol = this.deps.agent.textToolCallProtocol;\n\t\tconst variant = protocol === true ? \"tool-tag\" : protocol ? protocol.variant : undefined;\n\t\tif (!variant) return;\n\t\tconst status = event.outcome === \"bounced\" ? \"failed\" : \"parsed\";\n\t\tif (this.validationOutcomeThisTurn?.status === \"parsed\" && status === \"failed\") return;\n\t\tthis.validationOutcomeThisTurn = {\n\t\t\tprovider: event.provider ?? this.deps.agent.state.model.provider,\n\t\t\tmodel: event.model ?? this.deps.agent.state.model.id,\n\t\t\tvariant,\n\t\t\tstatus,\n\t\t\tcallCount: 1,\n\t\t\ttextLength: 0,\n\t\t\t...(status === \"failed\" && {\n\t\t\t\treason: event.errorKeywords?.includes(\"unknown_tool\") ? \"unknown-tool\" : \"validation-failed\",\n\t\t\t}),\n\t\t};\n\t}\n\n\trecordParseOutcomeFromLastAssistant(): void {\n\t\tconst validationOutcome = this.validationOutcomeThisTurn;\n\t\tthis.validationOutcomeThisTurn = undefined;\n\t\tif (validationOutcome?.status === \"parsed\") {\n\t\t\tthis.parseObservedThisTurn = true;\n\t\t\tthis.parseFailures.delete(`${validationOutcome.provider}/${validationOutcome.model}`);\n\t\t\treturn;\n\t\t}\n\t\tif (validationOutcome) {\n\t\t\tthis.handleTextProtocolParse(validationOutcome);\n\t\t\treturn;\n\t\t}\n\t\tif (this.parseObservedThisTurn) return;\n\t\tconst protocol = this.deps.agent.textToolCallProtocol;\n\t\tif (protocol === false || protocol === true || !protocol?.variant) return;\n\t\tconst response = this.deps.findLastAssistantMessage();\n\t\tif (!response) return;\n\t\tconst responseText = response.content\n\t\t\t.filter((content): content is TextContent => content.type === \"text\")\n\t\t\t.map((content) => content.text)\n\t\t\t.join(\"\\n\");\n\t\tif (!responseText) return;\n\n\t\tconst parsed = parseTextToolCalls(responseText, this.deps.agent.state.tools);\n\t\tconst attempted = parsed.attempted || this.looksLikeTextProtocolAttempt(responseText);\n\t\tif (!attempted) return;\n\t\tthis.handleTextProtocolParse({\n\t\t\tprovider: this.deps.agent.state.model.provider,\n\t\t\tmodel: this.deps.agent.state.model.id,\n\t\t\tvariant: protocol.variant,\n\t\t\tstatus: parsed.calls.length > 0 ? \"parsed\" : \"failed\",\n\t\t\treason: parsed.failure,\n\t\t\tcallCount: parsed.calls.length,\n\t\t\ttextLength: responseText.length,\n\t\t});\n\t}\n\n\ttagAdaptationRuleTeaching(event: ToolArgumentValidationTelemetryEvent): ToolArgumentValidationTelemetryEvent {\n\t\tif (!this.getRepairSettings().teach || event.taught !== \"none\") return event;\n\t\tconst modelKey =\n\t\t\tevent.provider && event.model\n\t\t\t\t? `${event.provider}/${event.model}`\n\t\t\t\t: this.modelKey(this.deps.agent.state.model);\n\t\tif (!modelKey) return event;\n\t\ttry {\n\t\t\tconst rules = this.deps.adaptationStore.get(modelKey).rules;\n\t\t\tconst modes = new Set([...event.failureModes, ...event.repairsApplied]);\n\t\t\tif (rules.some((rule) => modes.has(rule.mode as ToolRepairModeName))) return { ...event, taught: \"rule\" };\n\t\t} catch {\n\t\t\t// Best-effort telemetry tagging.\n\t\t}\n\t\treturn event;\n\t}\n\n\thandleAdaptationTelemetry(event: ToolArgumentValidationTelemetryEvent): void {\n\t\tif (!this.getRepairSettings().teach || event.outcome !== \"repaired\" || event.repairsApplied.length === 0) return;\n\t\tconst modelKey =\n\t\t\tevent.provider && event.model\n\t\t\t\t? `${event.provider}/${event.model}`\n\t\t\t\t: this.modelKey(this.deps.agent.state.model);\n\t\tif (!modelKey) return;\n\t\ttry {\n\t\t\tfor (const mode of [...new Set(event.repairsApplied)]) {\n\t\t\t\tconst profile = this.deps.adaptationStore.get(modelKey);\n\t\t\t\tconst stats = profile.teachStats[mode] ?? { taught: 0, recurrenceBefore: 0, recurrenceAfter: 0 };\n\t\t\t\tif (profile.rules.some((rule) => rule.mode === mode)) {\n\t\t\t\t\tthis.deps.adaptationStore.markRuleFired(modelKey, mode);\n\t\t\t\t\tthis.deps.adaptationStore.setTeachStats(modelKey, mode, {\n\t\t\t\t\t\t...stats,\n\t\t\t\t\t\trecurrenceAfter: stats.recurrenceAfter + 1,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst recurrenceBefore = stats.recurrenceBefore + 1;\n\t\t\t\tthis.deps.adaptationStore.setTeachStats(modelKey, mode, { ...stats, recurrenceBefore });\n\t\t\t\tconst sessionCount = this.repairSessionCount(modelKey, mode);\n\t\t\t\tif (\n\t\t\t\t\tsessionCount >= MODEL_ADAPTATION_REPAIR_THRESHOLD ||\n\t\t\t\t\trecurrenceBefore >= MODEL_ADAPTATION_REPAIR_THRESHOLD\n\t\t\t\t) {\n\t\t\t\t\tthis.deps.adaptationStore.addRule(modelKey, { mode, text: formatToolRepairStandingRule(mode) });\n\t\t\t\t\tthis.deps.adaptationStore.setTeachStats(modelKey, mode, {\n\t\t\t\t\t\t...stats,\n\t\t\t\t\t\ttaught: stats.taught + 1,\n\t\t\t\t\t\trecurrenceBefore,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Best-effort adaptation persistence.\n\t\t}\n\t}\n\n\tmaybeAutoProbe(model: Model<Api>): void {\n\t\tconst modelKey = this.modelRef(model);\n\t\tif (this.autoProbedModels.has(modelKey) || this.hasFreshToolProbeVerdict(modelKey)) return;\n\t\tthis.autoProbedModels.add(modelKey);\n\t\tvoid this.deps\n\t\t\t.probeForAuto(model)\n\t\t\t.then((result) => {\n\t\t\t\tif (this.deps.isDisposed()) return;\n\t\t\t\tconst detail =\n\t\t\t\t\tresult.verdict === \"text-protocol\"\n\t\t\t\t\t\t? ` (variant ${result.variant}); it will use the text tool protocol starting next turn`\n\t\t\t\t\t\t: result.verdict === \"none\"\n\t\t\t\t\t\t\t? \" — no working tool-call path was found; run /toolprobe for details\"\n\t\t\t\t\t\t\t: \"; native tool calls stay in use\";\n\t\t\t\tthis.deps.emitWarning(\n\t\t\t\t\t`Auto-probed ${modelKey} after repeated native tool-call validation failures: verdict \"${result.verdict}\"${detail}.`,\n\t\t\t\t);\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tif (this.deps.isDisposed()) return;\n\t\t\t\tthis.deps.emitWarning(\n\t\t\t\t\t`Auto-probe for ${modelKey} (triggered by repeated tool-call validation failures) did not complete: ${error instanceof Error ? error.message : String(error)}.`,\n\t\t\t\t);\n\t\t\t});\n\t}\n\n\tformatRepairHealth(stats?: ToolRecoveryLoggerStats): string {\n\t\treturn formatToolRepairHealthReport(this.deps.adaptationStore, new Date(), stats);\n\t}\n\n\tremoveRepairRule(model: string, mode: string): boolean {\n\t\treturn this.deps.adaptationStore.removeRule(model, mode);\n\t}\n\n\tresetProtocolCalibration(model: string): boolean {\n\t\tconst removed = this.deps.adaptationStore.removeProtocol(model);\n\t\tthis.parseFailures.delete(model);\n\t\treturn removed;\n\t}\n\n\tgetRepairSettings() {\n\t\treturn resolveCurrentToolRepairSettings(this.deps.settingsManager.settings);\n\t}\n\n\tprivate modelKey(model: Model<Api> | undefined): string | undefined {\n\t\treturn model ? this.modelRef(model) : undefined;\n\t}\n\n\tprivate modelRef(model: Model<Api>): string {\n\t\treturn `${model.provider}/${model.id}`;\n\t}\n\n\tprivate async streamForProbe(model: Model<Api>, context: Context, options: SimpleStreamOptions) {\n\t\tlet requestOptions = options;\n\t\tif (this.deps.isRawStreamSimple(this.deps.agent.streamFn)) {\n\t\t\tconst auth = await this.deps.getRequiredRequestAuth(model);\n\t\t\trequestOptions = {\n\t\t\t\t...options,\n\t\t\t\tapiKey: auth.apiKey,\n\t\t\t\theaders: auth.headers || options.headers ? { ...auth.headers, ...options.headers } : undefined,\n\t\t\t};\n\t\t}\n\t\treturn this.deps.agent.streamFn(model, context, requestOptions);\n\t}\n\n\tprivate nextProbeUsageReportId(model: Model<Api>, kind: string): string {\n\t\treturn `tool-probe:${this.modelRef(model)}:${kind}:${this.probeUsageReportSeq++}`;\n\t}\n\n\tprivate async resolveProbeStreamCountingUsage(\n\t\tstream: AssistantMessageEventStream,\n\t\tlabel: string,\n\t\treportId: string,\n\t): Promise<AssistantMessage> {\n\t\tconst message = await stream.result();\n\t\tconst usage = message.usage;\n\t\tif (usage && (usage.cost.total > 0 || usage.totalTokens > 0)) {\n\t\t\tthis.deps.addSpawnedUsage(usage, { label, reportId });\n\t\t}\n\t\treturn message;\n\t}\n\n\tprivate textProtocolCalibrationContext(variant: TextToolProtocolVariant, token: string): Context {\n\t\tconst primer = generateTextToolProtocolPrimer([TEXT_TOOL_PROTOCOL_ECHO_TOOL], { variant });\n\t\tconst instruction = `Text tool protocol calibration trial. Using the protocol above, call echo with data exactly \"${token}\". Output only the tool-call envelope.`;\n\t\treturn {\n\t\t\tsystemPrompt: `${primer}\\n\\n${instruction}`,\n\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: instruction }], timestamp: Date.now() }],\n\t\t};\n\t}\n\n\tprivate messageHasToolCallWithStringArgument(\n\t\tmessage: AssistantMessage,\n\t\ttoolName: string,\n\t\targName: string,\n\t\targValue: string,\n\t): boolean {\n\t\treturn message.content.some((block) => {\n\t\t\tif (block.type !== \"toolCall\" || block.name !== toolName) return false;\n\t\t\tconst args = block.arguments as unknown;\n\t\t\treturn (\n\t\t\t\ttypeof args === \"object\" &&\n\t\t\t\targs !== null &&\n\t\t\t\t!Array.isArray(args) &&\n\t\t\t\t(args as Record<string, unknown>)[argName] === argValue\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate nativeToolProbeSystemPrompt(instruction: string): string {\n\t\tconst base = (this.deps.agent.state.systemPrompt ?? \"\").trim();\n\t\treturn base ? `${base}\\n\\n${instruction}` : instruction;\n\t}\n\n\tprivate async runNativeReadTaskProbeTrial(model: Model<Api>, path: string): Promise<boolean> {\n\t\tconst instruction =\n\t\t\t`Native tool-call capability probe: task-scale read. Use provider-native tool calling, not prose. ` +\n\t\t\t`Call read exactly once with path exactly \"${path}\".`;\n\t\tconst stream = await this.streamForProbe(\n\t\t\tmodel,\n\t\t\t{\n\t\t\t\tsystemPrompt: this.nativeToolProbeSystemPrompt(instruction),\n\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: instruction }], timestamp: Date.now() }],\n\t\t\t\ttools: [NATIVE_TOOL_PROBE_READ_TOOL],\n\t\t\t},\n\t\t\t{ textToolCallProtocol: false, maxRetries: 0, temperature: 0, maxTokens: 768 },\n\t\t);\n\t\tconst message = await this.resolveProbeStreamCountingUsage(\n\t\t\tstream,\n\t\t\t\"tool-probe\",\n\t\t\tthis.nextProbeUsageReportId(model, \"read-task\"),\n\t\t);\n\t\treturn this.messageHasToolCallWithStringArgument(message, \"read\", \"path\", path);\n\t}\n\n\tprivate async runNativeEchoToolProbeTrial(model: Model<Api>, token: string): Promise<boolean> {\n\t\tconst instruction =\n\t\t\t`Native tool-call capability probe: echo-only. Use provider-native tool calling, not prose. ` +\n\t\t\t`Call echo with data exactly \"${token}\".`;\n\t\tconst stream = await this.streamForProbe(\n\t\t\tmodel,\n\t\t\t{\n\t\t\t\tsystemPrompt: this.nativeToolProbeSystemPrompt(instruction),\n\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: instruction }], timestamp: Date.now() }],\n\t\t\t\ttools: [TEXT_TOOL_PROTOCOL_ECHO_TOOL],\n\t\t\t},\n\t\t\t{ textToolCallProtocol: false, maxRetries: 0, temperature: 0, maxTokens: 256 },\n\t\t);\n\t\tconst message = await this.resolveProbeStreamCountingUsage(\n\t\t\tstream,\n\t\t\t\"tool-probe\",\n\t\t\tthis.nextProbeUsageReportId(model, \"echo\"),\n\t\t);\n\t\treturn this.messageHasToolCallWithStringArgument(message, \"echo\", \"data\", token);\n\t}\n\n\tprivate async gradeNativeToolCallingForModel(model: Model<Api>, token: string): Promise<NativeToolProbeGrade> {\n\t\tconst path = join(\n\t\t\tgetProcessWorkRun(this.deps.agentDir, \"probes\", \"native-tools\").path,\n\t\t\t`pi-native-probe-${process.pid}-${Date.now()}.txt`,\n\t\t);\n\t\twriteFileSync(path, token, \"utf-8\");\n\t\ttry {\n\t\t\tif (await this.runNativeReadTaskProbeTrial(model, path)) return \"task\";\n\t\t\tif (await this.runNativeEchoToolProbeTrial(model, token)) return \"echo-only\";\n\t\t\treturn \"absent\";\n\t\t} finally {\n\t\t\trmSync(path, { force: true });\n\t\t}\n\t}\n\n\tprivate async runTextProtocolTrial(\n\t\tmodel: Model<Api>,\n\t\tvariant: TextToolProtocolVariant,\n\t\ttoken: string,\n\t): Promise<boolean> {\n\t\tconst stream = await this.streamForProbe(model, this.textProtocolCalibrationContext(variant, token), {\n\t\t\ttextToolCallProtocol: false,\n\t\t\tmaxRetries: 0,\n\t\t\ttemperature: 0,\n\t\t\tmaxTokens: 256,\n\t\t});\n\t\tconst message = await this.resolveProbeStreamCountingUsage(\n\t\t\tstream,\n\t\t\t\"text-protocol-calibration\",\n\t\t\tthis.nextProbeUsageReportId(model, `text-protocol:${variant}`),\n\t\t);\n\t\tconst text = message.content\n\t\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t\t.map((block) => block.text)\n\t\t\t.join(\"\\n\")\n\t\t\t.trim();\n\t\tif (!text) return false;\n\t\tconst parsed = parseTextToolCalls(text, [TEXT_TOOL_PROTOCOL_ECHO_TOOL]);\n\t\treturn parsed.calls.some((call) => call.name === \"echo\" && call.arguments.data === token);\n\t}\n\n\tprivate async calibrateTextToolProtocolForModel(\n\t\tmodel: Model<Api>,\n\t\tmodelKey: string | undefined,\n\t\toptions: { persistFailure: boolean },\n\t): Promise<\n\t\t| { status: \"calibrated\"; variant: TextToolProtocolVariant; calibratedAt: string }\n\t\t| { status: \"failed\"; attemptedAt: string; variantsTried: string[] }\n\t> {\n\t\tconst variantsTried: string[] = [];\n\t\tfor (const variant of TEXT_TOOL_PROTOCOL_VARIANTS) {\n\t\t\tvariantsTried.push(variant);\n\t\t\tlet passed = true;\n\t\t\tfor (let trial = 0; trial < TEXT_TOOL_PROTOCOL_TRIALS_PER_VARIANT; trial++) {\n\t\t\t\tif (!(await this.runTextProtocolTrial(model, variant, `pi-calibration-${trial + 1}`))) {\n\t\t\t\t\tpassed = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (passed) {\n\t\t\t\tconst calibratedAt = new Date().toISOString();\n\t\t\t\tif (modelKey) {\n\t\t\t\t\tthis.deps.adaptationStore.setProtocol(\n\t\t\t\t\t\tmodelKey,\n\t\t\t\t\t\t{ version: MODEL_TOOL_PROTOCOL_VERSION, status: \"calibrated\", variant, calibratedAt },\n\t\t\t\t\t\tcalibratedAt,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn { status: \"calibrated\", variant, calibratedAt };\n\t\t\t}\n\t\t}\n\n\t\tconst attemptedAt = new Date().toISOString();\n\t\tif (modelKey && options.persistFailure) {\n\t\t\tthis.deps.adaptationStore.setProtocol(\n\t\t\t\tmodelKey,\n\t\t\t\t{ version: MODEL_TOOL_PROTOCOL_VERSION, status: \"failed\", attemptedAt, variantsTried },\n\t\t\t\tattemptedAt,\n\t\t\t);\n\t\t}\n\t\treturn { status: \"failed\", attemptedAt, variantsTried };\n\t}\n\n\tprivate formatToolProbeReport(results: readonly ToolProbeResult[]): string {\n\t\tconst lines = [\n\t\t\t\"Tool probe results:\",\n\t\t\t\"Model | Verdict | Variant | Native grade | Diagnostic\",\n\t\t\t\"--- | --- | --- | --- | ---\",\n\t\t];\n\t\tfor (const result of results) {\n\t\t\tlines.push(\n\t\t\t\t[\n\t\t\t\t\tresult.model,\n\t\t\t\t\tresult.verdict,\n\t\t\t\t\tresult.variant ?? \"-\",\n\t\t\t\t\tresult.nativeGrade ?? \"-\",\n\t\t\t\t\tresult.diagnostic ? result.diagnostic.replace(/\\s+/g, \" \").slice(0, 160) : \"-\",\n\t\t\t\t].join(\" | \"),\n\t\t\t);\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tprivate storeToolProbe(modelKey: string, probe: ModelToolProbe): void {\n\t\tthis.deps.adaptationStore.setToolProbe(modelKey, probe, probe.probedAt);\n\t}\n\n\tprivate async resolveToolProbeModels(target?: string): Promise<Model<Api>[]> {\n\t\tconst trimmed = target?.trim();\n\t\tif (!trimmed) return this.deps.getModelRegistry().getAvailable();\n\t\tconst [provider, ...modelParts] = trimmed.split(\"/\");\n\t\tconst modelId = modelParts.join(\"/\");\n\t\tif (!provider || !modelId) throw new Error(\"Usage: /toolprobe [provider/model]\");\n\t\tconst exact = this.deps.getModelRegistry().find(provider, modelId);\n\t\tif (exact) return [exact];\n\t\tconst current = this.deps.agent.state.model;\n\t\tif (current?.provider === provider && current.id === modelId) return [current];\n\t\tthrow new Error(`Model not found: ${trimmed}`);\n\t}\n\n\tprivate maybeInjectCorrectiveSteer(variant: TextToolProtocolVariant): void {\n\t\tthis.correctiveSteerCount++;\n\t\tif (this.correctiveSteerCount !== 1 && this.correctiveSteerCount % TEXT_TOOL_PROTOCOL_STEER_INTERVAL !== 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst reminder = `Reminder: to call a tool, emit exactly this envelope shape: ${formatVariantEnvelope(variant, \"TOOL\", '{\"arg\":\"value\"}')} — no other format is recognized. Reasoning may appear as prose before the envelope, never inside it.`;\n\t\tthis.deps.sendCorrectiveSteer(reminder).catch(() => {\n\t\t\t// Best-effort steer.\n\t\t});\n\t}\n\n\tprivate looksLikeTextProtocolAttempt(text: string): boolean {\n\t\treturn /<pi:call\\b|<tool_call\\b|```(?:tool|tool_call)[\\s\\S]*\"name\"\\s*:/i.test(text);\n\t}\n\n\tprivate repairSessionCount(modelKey: string, mode: ToolRepairModeName): number {\n\t\tconst key = `${modelKey}\\0${mode}`;\n\t\tconst count = (this.repairModeSessionCounts.get(key) ?? 0) + 1;\n\t\tthis.repairModeSessionCounts.set(key, count);\n\t\treturn count;\n\t}\n\n\tprivate hasFreshToolProbeVerdict(modelKey: string): boolean {\n\t\tconst probedAt = this.deps.adaptationStore.get(modelKey).toolProbe?.probedAt;\n\t\tif (!probedAt) return false;\n\t\tconst age = Date.now() - new Date(probedAt).getTime();\n\t\treturn Number.isFinite(age) && age >= 0 && age < AUTO_TOOL_PROBE_FRESHNESS_MS;\n\t}\n}\n"]}
|
|
@@ -23,9 +23,8 @@ export declare function isToolArgumentValidationLogRecord(value: unknown): value
|
|
|
23
23
|
/**
|
|
24
24
|
* Append + rotate under a single exclusive lock on `eventLogPath`. Without the lock, a concurrent
|
|
25
25
|
* writer (e.g. another session's tool-recovery worker) could append between this call's read and its
|
|
26
|
-
* rotated rewrite, and that append would be silently discarded when the rewrite lands
|
|
27
|
-
* tmp+rename
|
|
28
|
-
* a partially-rewritten (torn) log file.
|
|
26
|
+
* rotated rewrite, and that append would be silently discarded when the rewrite lands. The shared
|
|
27
|
+
* bounded JSONL sink also uses atomic tmp+rename rotation so readers never observe torn log files.
|
|
29
28
|
*/
|
|
30
29
|
export declare function writeToolRecoveryLogRecord(entry: ToolRecoveryLogWorkerRecord): void;
|
|
31
30
|
//# sourceMappingURL=tool-recovery-log-records.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-recovery-log-records.d.ts","sourceRoot":"","sources":["../../src/core/tool-recovery-log-records.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tool-recovery-log-records.d.ts","sourceRoot":"","sources":["../../src/core/tool-recovery-log-records.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,mBAAmB,CAAC;AAS9E,eAAO,MAAM,4BAA4B,+BAA+B,CAAC;AACzE,eAAO,MAAM,iCAAiC,6BAA6B,CAAC;AAU5E,MAAM,WAAW,+BAAgC,SAAQ,oCAAoC;IAC5F,IAAI,EAAE,OAAO,iCAAiC,CAAC;IAC/C,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,2BAA2B;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,+BAA+B,CAAC;CACxC;AAyBD,wBAAgB,qCAAqC,CAAC,IAAI,EAAE;IAC3D,KAAK,EAAE,oCAAoC,CAAC;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;CACX,GAAG,+BAA+B,CAmBlC;AAED,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,+BAA+B,CAc1G;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,2BAA2B,GAAG,IAAI,CAoBnF","sourcesContent":["import type { ToolArgumentValidationTelemetryEvent } from \"@caupulican/pi-ai\";\nimport {\n\tcreateToolValidationFailureCorpusRecord,\n\ttype ToolValidationFailureShapeEntry,\n\twriteFailureCorpusRecord,\n} from \"./failure-corpus.ts\";\nimport { updatePersistedToolRecoveryStats } from \"./tool-recovery-stats.ts\";\nimport { appendBoundedJsonLineSync, type BoundedJsonlLimits } from \"./util/bounded-jsonl.ts\";\n\nexport const TOOL_RECOVERY_EVENT_LOG_FILE = \"tool-recovery-events.jsonl\";\nexport const TOOL_ARGUMENT_VALIDATION_LOG_KIND = \"tool_argument_validation\";\n\nconst TOOL_RECOVERY_EVENT_LIMITS: BoundedJsonlLimits = {\n\tmaxBytes: 4 * 1024 * 1024,\n\ttargetBytes: Math.floor(4 * 1024 * 1024 * 0.75),\n\tmaxRecords: 5_000,\n};\nconst MAX_TELEMETRY_LIST_ITEMS = 50;\nconst MAX_TELEMETRY_TEXT_CHARS = 256;\n\nexport interface ToolArgumentValidationLogRecord extends ToolArgumentValidationTelemetryEvent {\n\tkind: typeof TOOL_ARGUMENT_VALIDATION_LOG_KIND;\n\tversion: 1;\n\trecordId: string;\n\tts: string;\n\tsessionId: string;\n}\n\nexport interface ToolRecoveryLogWorkerRecord {\n\teventLogPath: string;\n\tfailureCorpusPath: string;\n\trecord: ToolArgumentValidationLogRecord;\n}\n\nfunction boundedText(value: string): string {\n\treturn value.slice(0, MAX_TELEMETRY_TEXT_CHARS);\n}\n\nfunction boundedList<T extends string>(values: readonly T[] | undefined): T[] | undefined {\n\treturn values?.slice(0, MAX_TELEMETRY_LIST_ITEMS);\n}\n\nfunction boundedTextList(values: readonly string[] | undefined): string[] | undefined {\n\treturn values?.slice(0, MAX_TELEMETRY_LIST_ITEMS).map(boundedText);\n}\n\nfunction copyFailureShape(\n\tshape: readonly ToolValidationFailureShapeEntry[] | undefined,\n): ToolValidationFailureShapeEntry[] {\n\treturn (shape ?? []).slice(0, MAX_TELEMETRY_LIST_ITEMS).map((entry) => ({\n\t\tpath: boundedText(entry.path),\n\t\texpectedType: boundedText(entry.expectedType),\n\t\treceivedType: boundedText(entry.receivedType),\n\t\t...(entry.keyword ? { keyword: boundedText(entry.keyword) } : {}),\n\t}));\n}\n\nexport function createToolArgumentValidationLogRecord(args: {\n\tevent: ToolArgumentValidationTelemetryEvent;\n\trecordId: string;\n\tsessionId: string;\n\tts: string;\n}): ToolArgumentValidationLogRecord {\n\treturn {\n\t\tkind: TOOL_ARGUMENT_VALIDATION_LOG_KIND,\n\t\tversion: 1,\n\t\trecordId: args.recordId,\n\t\tts: args.ts,\n\t\tsessionId: args.sessionId,\n\t\toutcome: args.event.outcome,\n\t\tprovider: args.event.provider,\n\t\tmodel: args.event.model,\n\t\ttool: args.event.tool,\n\t\tsource: args.event.source,\n\t\tfailureModes: boundedList(args.event.failureModes) ?? [],\n\t\trepairsApplied: boundedList(args.event.repairsApplied) ?? [],\n\t\tfailureShape: copyFailureShape(args.event.failureShape),\n\t\terrorKeywords: boundedTextList(args.event.errorKeywords),\n\t\ttaught: args.event.taught,\n\t\texecutionOutcome: args.event.executionOutcome,\n\t};\n}\n\nexport function isToolArgumentValidationLogRecord(value: unknown): value is ToolArgumentValidationLogRecord {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst record = value as Partial<ToolArgumentValidationLogRecord>;\n\treturn (\n\t\trecord.kind === TOOL_ARGUMENT_VALIDATION_LOG_KIND &&\n\t\trecord.version === 1 &&\n\t\ttypeof record.recordId === \"string\" &&\n\t\ttypeof record.ts === \"string\" &&\n\t\ttypeof record.sessionId === \"string\" &&\n\t\t(record.outcome === \"repaired\" || record.outcome === \"bounced\") &&\n\t\ttypeof record.tool === \"string\" &&\n\t\tArray.isArray(record.failureModes) &&\n\t\tArray.isArray(record.repairsApplied)\n\t);\n}\n\n/**\n * Append + rotate under a single exclusive lock on `eventLogPath`. Without the lock, a concurrent\n * writer (e.g. another session's tool-recovery worker) could append between this call's read and its\n * rotated rewrite, and that append would be silently discarded when the rewrite lands. The shared\n * bounded JSONL sink also uses atomic tmp+rename rotation so readers never observe torn log files.\n */\nexport function writeToolRecoveryLogRecord(entry: ToolRecoveryLogWorkerRecord): void {\n\tappendBoundedJsonLineSync(entry.eventLogPath, entry.record, TOOL_RECOVERY_EVENT_LIMITS);\n\ttry {\n\t\tupdatePersistedToolRecoveryStats(entry.eventLogPath, entry.record);\n\t} catch {\n\t\t// The bounded event log remains the recovery source if the cumulative summary cannot be updated.\n\t}\n\tif (entry.record.outcome !== \"bounced\") return;\n\twriteFailureCorpusRecord(\n\t\tentry.failureCorpusPath,\n\t\tcreateToolValidationFailureCorpusRecord({\n\t\t\tts: entry.record.ts,\n\t\t\tprovider: entry.record.provider,\n\t\t\tmodelId: entry.record.model,\n\t\t\ttool: entry.record.tool,\n\t\t\tfailureModes: entry.record.failureModes,\n\t\t\tshape: copyFailureShape(entry.record.failureShape),\n\t\t\terrorKeywords: entry.record.errorKeywords,\n\t\t}),\n\t);\n}\n"]}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { appendFileSync, existsSync, readFileSync, statSync } from "node:fs";
|
|
2
1
|
import { createToolValidationFailureCorpusRecord, writeFailureCorpusRecord, } from "./failure-corpus.js";
|
|
3
2
|
import { updatePersistedToolRecoveryStats } from "./tool-recovery-stats.js";
|
|
4
|
-
import {
|
|
3
|
+
import { appendBoundedJsonLineSync } from "./util/bounded-jsonl.js";
|
|
5
4
|
export const TOOL_RECOVERY_EVENT_LOG_FILE = "tool-recovery-events.jsonl";
|
|
6
5
|
export const TOOL_ARGUMENT_VALIDATION_LOG_KIND = "tool_argument_validation";
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const TOOL_RECOVERY_EVENT_LIMITS = {
|
|
7
|
+
maxBytes: 4 * 1024 * 1024,
|
|
8
|
+
targetBytes: Math.floor(4 * 1024 * 1024 * 0.75),
|
|
9
|
+
maxRecords: 5_000,
|
|
10
|
+
};
|
|
10
11
|
const MAX_TELEMETRY_LIST_ITEMS = 50;
|
|
11
12
|
const MAX_TELEMETRY_TEXT_CHARS = 256;
|
|
12
13
|
function boundedText(value) {
|
|
@@ -60,41 +61,14 @@ export function isToolArgumentValidationLogRecord(value) {
|
|
|
60
61
|
Array.isArray(record.failureModes) &&
|
|
61
62
|
Array.isArray(record.repairsApplied));
|
|
62
63
|
}
|
|
63
|
-
function rotateToolRecoveryEventLogIfNeeded(filePath) {
|
|
64
|
-
if (!existsSync(filePath) || statSync(filePath).size <= MAX_EVENT_LOG_BYTES)
|
|
65
|
-
return;
|
|
66
|
-
const lines = readFileSync(filePath, "utf-8")
|
|
67
|
-
.split("\n")
|
|
68
|
-
.filter((line) => line.trim().length > 0);
|
|
69
|
-
const retained = [];
|
|
70
|
-
let retainedBytes = 0;
|
|
71
|
-
for (let index = lines.length - 1; index >= 0 && retained.length < MAX_ROTATED_EVENT_LOG_RECORDS; index--) {
|
|
72
|
-
const line = lines[index];
|
|
73
|
-
const lineBytes = Buffer.byteLength(line, "utf-8") + 1;
|
|
74
|
-
if (lineBytes > MAX_EVENT_LOG_BYTES)
|
|
75
|
-
continue;
|
|
76
|
-
if (retained.length > 0 && retainedBytes + lineBytes > ROTATED_EVENT_LOG_TARGET_BYTES)
|
|
77
|
-
break;
|
|
78
|
-
retained.push(line);
|
|
79
|
-
retainedBytes += lineBytes;
|
|
80
|
-
if (retainedBytes >= ROTATED_EVENT_LOG_TARGET_BYTES)
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
retained.reverse();
|
|
84
|
-
writeFileAtomicSync(filePath, retained.length > 0 ? `${retained.join("\n")}\n` : "");
|
|
85
|
-
}
|
|
86
64
|
/**
|
|
87
65
|
* Append + rotate under a single exclusive lock on `eventLogPath`. Without the lock, a concurrent
|
|
88
66
|
* writer (e.g. another session's tool-recovery worker) could append between this call's read and its
|
|
89
|
-
* rotated rewrite, and that append would be silently discarded when the rewrite lands
|
|
90
|
-
* tmp+rename
|
|
91
|
-
* a partially-rewritten (torn) log file.
|
|
67
|
+
* rotated rewrite, and that append would be silently discarded when the rewrite lands. The shared
|
|
68
|
+
* bounded JSONL sink also uses atomic tmp+rename rotation so readers never observe torn log files.
|
|
92
69
|
*/
|
|
93
70
|
export function writeToolRecoveryLogRecord(entry) {
|
|
94
|
-
|
|
95
|
-
appendFileSync(entry.eventLogPath, `${JSON.stringify(entry.record)}\n`, "utf-8");
|
|
96
|
-
rotateToolRecoveryEventLogIfNeeded(entry.eventLogPath);
|
|
97
|
-
});
|
|
71
|
+
appendBoundedJsonLineSync(entry.eventLogPath, entry.record, TOOL_RECOVERY_EVENT_LIMITS);
|
|
98
72
|
try {
|
|
99
73
|
updatePersistedToolRecoveryStats(entry.eventLogPath, entry.record);
|
|
100
74
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-recovery-log-records.js","sourceRoot":"","sources":["../../src/core/tool-recovery-log-records.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFileSync, existsSync, readFileSync, statSync } from \"node:fs\";\nimport type { ToolArgumentValidationTelemetryEvent } from \"@caupulican/pi-ai\";\nimport {\n\tcreateToolValidationFailureCorpusRecord,\n\ttype ToolValidationFailureShapeEntry,\n\twriteFailureCorpusRecord,\n} from \"./failure-corpus.ts\";\nimport { updatePersistedToolRecoveryStats } from \"./tool-recovery-stats.ts\";\nimport { withFileLockSync, writeFileAtomicSync } from \"./util/atomic-file.ts\";\n\nexport const TOOL_RECOVERY_EVENT_LOG_FILE = \"tool-recovery-events.jsonl\";\nexport const TOOL_ARGUMENT_VALIDATION_LOG_KIND = \"tool_argument_validation\";\n\nconst MAX_EVENT_LOG_BYTES = 4 * 1024 * 1024;\nconst ROTATED_EVENT_LOG_TARGET_BYTES = Math.floor(MAX_EVENT_LOG_BYTES * 0.75);\nconst MAX_ROTATED_EVENT_LOG_RECORDS = 5_000;\nconst MAX_TELEMETRY_LIST_ITEMS = 50;\nconst MAX_TELEMETRY_TEXT_CHARS = 256;\n\nexport interface ToolArgumentValidationLogRecord extends ToolArgumentValidationTelemetryEvent {\n\tkind: typeof TOOL_ARGUMENT_VALIDATION_LOG_KIND;\n\tversion: 1;\n\trecordId: string;\n\tts: string;\n\tsessionId: string;\n}\n\nexport interface ToolRecoveryLogWorkerRecord {\n\teventLogPath: string;\n\tfailureCorpusPath: string;\n\trecord: ToolArgumentValidationLogRecord;\n}\n\nfunction boundedText(value: string): string {\n\treturn value.slice(0, MAX_TELEMETRY_TEXT_CHARS);\n}\n\nfunction boundedList<T extends string>(values: readonly T[] | undefined): T[] | undefined {\n\treturn values?.slice(0, MAX_TELEMETRY_LIST_ITEMS);\n}\n\nfunction boundedTextList(values: readonly string[] | undefined): string[] | undefined {\n\treturn values?.slice(0, MAX_TELEMETRY_LIST_ITEMS).map(boundedText);\n}\n\nfunction copyFailureShape(\n\tshape: readonly ToolValidationFailureShapeEntry[] | undefined,\n): ToolValidationFailureShapeEntry[] {\n\treturn (shape ?? []).slice(0, MAX_TELEMETRY_LIST_ITEMS).map((entry) => ({\n\t\tpath: boundedText(entry.path),\n\t\texpectedType: boundedText(entry.expectedType),\n\t\treceivedType: boundedText(entry.receivedType),\n\t\t...(entry.keyword ? { keyword: boundedText(entry.keyword) } : {}),\n\t}));\n}\n\nexport function createToolArgumentValidationLogRecord(args: {\n\tevent: ToolArgumentValidationTelemetryEvent;\n\trecordId: string;\n\tsessionId: string;\n\tts: string;\n}): ToolArgumentValidationLogRecord {\n\treturn {\n\t\tkind: TOOL_ARGUMENT_VALIDATION_LOG_KIND,\n\t\tversion: 1,\n\t\trecordId: args.recordId,\n\t\tts: args.ts,\n\t\tsessionId: args.sessionId,\n\t\toutcome: args.event.outcome,\n\t\tprovider: args.event.provider,\n\t\tmodel: args.event.model,\n\t\ttool: args.event.tool,\n\t\tsource: args.event.source,\n\t\tfailureModes: boundedList(args.event.failureModes) ?? [],\n\t\trepairsApplied: boundedList(args.event.repairsApplied) ?? [],\n\t\tfailureShape: copyFailureShape(args.event.failureShape),\n\t\terrorKeywords: boundedTextList(args.event.errorKeywords),\n\t\ttaught: args.event.taught,\n\t\texecutionOutcome: args.event.executionOutcome,\n\t};\n}\n\nexport function isToolArgumentValidationLogRecord(value: unknown): value is ToolArgumentValidationLogRecord {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst record = value as Partial<ToolArgumentValidationLogRecord>;\n\treturn (\n\t\trecord.kind === TOOL_ARGUMENT_VALIDATION_LOG_KIND &&\n\t\trecord.version === 1 &&\n\t\ttypeof record.recordId === \"string\" &&\n\t\ttypeof record.ts === \"string\" &&\n\t\ttypeof record.sessionId === \"string\" &&\n\t\t(record.outcome === \"repaired\" || record.outcome === \"bounced\") &&\n\t\ttypeof record.tool === \"string\" &&\n\t\tArray.isArray(record.failureModes) &&\n\t\tArray.isArray(record.repairsApplied)\n\t);\n}\n\nfunction rotateToolRecoveryEventLogIfNeeded(filePath: string): void {\n\tif (!existsSync(filePath) || statSync(filePath).size <= MAX_EVENT_LOG_BYTES) return;\n\tconst lines = readFileSync(filePath, \"utf-8\")\n\t\t.split(\"\\n\")\n\t\t.filter((line) => line.trim().length > 0);\n\tconst retained: string[] = [];\n\tlet retainedBytes = 0;\n\tfor (let index = lines.length - 1; index >= 0 && retained.length < MAX_ROTATED_EVENT_LOG_RECORDS; index--) {\n\t\tconst line = lines[index];\n\t\tconst lineBytes = Buffer.byteLength(line, \"utf-8\") + 1;\n\t\tif (lineBytes > MAX_EVENT_LOG_BYTES) continue;\n\t\tif (retained.length > 0 && retainedBytes + lineBytes > ROTATED_EVENT_LOG_TARGET_BYTES) break;\n\t\tretained.push(line);\n\t\tretainedBytes += lineBytes;\n\t\tif (retainedBytes >= ROTATED_EVENT_LOG_TARGET_BYTES) break;\n\t}\n\tretained.reverse();\n\twriteFileAtomicSync(filePath, retained.length > 0 ? `${retained.join(\"\\n\")}\\n` : \"\");\n}\n\n/**\n * Append + rotate under a single exclusive lock on `eventLogPath`. Without the lock, a concurrent\n * writer (e.g. another session's tool-recovery worker) could append between this call's read and its\n * rotated rewrite, and that append would be silently discarded when the rewrite lands; the atomic\n * tmp+rename in {@link rotateToolRecoveryEventLogIfNeeded} additionally ensures a reader never observes\n * a partially-rewritten (torn) log file.\n */\nexport function writeToolRecoveryLogRecord(entry: ToolRecoveryLogWorkerRecord): void {\n\twithFileLockSync(entry.eventLogPath, () => {\n\t\tappendFileSync(entry.eventLogPath, `${JSON.stringify(entry.record)}\\n`, \"utf-8\");\n\t\trotateToolRecoveryEventLogIfNeeded(entry.eventLogPath);\n\t});\n\ttry {\n\t\tupdatePersistedToolRecoveryStats(entry.eventLogPath, entry.record);\n\t} catch {\n\t\t// The bounded event log remains the recovery source if the cumulative summary cannot be updated.\n\t}\n\tif (entry.record.outcome !== \"bounced\") return;\n\twriteFailureCorpusRecord(\n\t\tentry.failureCorpusPath,\n\t\tcreateToolValidationFailureCorpusRecord({\n\t\t\tts: entry.record.ts,\n\t\t\tprovider: entry.record.provider,\n\t\t\tmodelId: entry.record.model,\n\t\t\ttool: entry.record.tool,\n\t\t\tfailureModes: entry.record.failureModes,\n\t\t\tshape: copyFailureShape(entry.record.failureShape),\n\t\t\terrorKeywords: entry.record.errorKeywords,\n\t\t}),\n\t);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool-recovery-log-records.js","sourceRoot":"","sources":["../../src/core/tool-recovery-log-records.ts"],"names":[],"mappings":"AACA,OAAO,EACN,uCAAuC,EAEvC,wBAAwB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gCAAgC,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EAAE,yBAAyB,EAA2B,MAAM,yBAAyB,CAAC;AAE7F,MAAM,CAAC,MAAM,4BAA4B,GAAG,4BAA4B,CAAC;AACzE,MAAM,CAAC,MAAM,iCAAiC,GAAG,0BAA0B,CAAC;AAE5E,MAAM,0BAA0B,GAAuB;IACtD,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;IACzB,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC/C,UAAU,EAAE,KAAK;CACjB,CAAC;AACF,MAAM,wBAAwB,GAAG,EAAE,CAAC;AACpC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAgBrC,SAAS,WAAW,CAAC,KAAa,EAAU;IAC3C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC;AAAA,CAChD;AAED,SAAS,WAAW,CAAmB,MAAgC,EAAmB;IACzF,OAAO,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC;AAAA,CAClD;AAED,SAAS,eAAe,CAAC,MAAqC,EAAwB;IACrF,OAAO,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAAA,CACnE;AAED,SAAS,gBAAgB,CACxB,KAA6D,EACzB;IACpC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC;QAC7B,YAAY,EAAE,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC;QAC7C,YAAY,EAAE,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC;QAC7C,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC,CAAC,CAAC;AAAA,CACJ;AAED,MAAM,UAAU,qCAAqC,CAAC,IAKrD,EAAmC;IACnC,OAAO;QACN,IAAI,EAAE,iCAAiC;QACvC,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;QAC3B,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;QACvB,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;QACrB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;QACzB,YAAY,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE;QACxD,cAAc,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE;QAC5D,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;QACvD,aAAa,EAAE,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;QACxD,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;QACzB,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,gBAAgB;KAC7C,CAAC;AAAA,CACF;AAED,MAAM,UAAU,iCAAiC,CAAC,KAAc,EAA4C;IAC3G,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,MAAM,GAAG,KAAiD,CAAC;IACjE,OAAO,CACN,MAAM,CAAC,IAAI,KAAK,iCAAiC;QACjD,MAAM,CAAC,OAAO,KAAK,CAAC;QACpB,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;QACnC,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ;QAC7B,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;QACpC,CAAC,MAAM,CAAC,OAAO,KAAK,UAAU,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC;QAC/D,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC/B,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC;QAClC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CACpC,CAAC;AAAA,CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAAkC,EAAQ;IACpF,yBAAyB,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;IACxF,IAAI,CAAC;QACJ,gCAAgC,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACR,iGAAiG;IAClG,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO;IAC/C,wBAAwB,CACvB,KAAK,CAAC,iBAAiB,EACvB,uCAAuC,CAAC;QACvC,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE;QACnB,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ;QAC/B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;QAC3B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;QACvB,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,YAAY;QACvC,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC;QAClD,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,aAAa;KACzC,CAAC,CACF,CAAC;AAAA,CACF","sourcesContent":["import type { ToolArgumentValidationTelemetryEvent } from \"@caupulican/pi-ai\";\nimport {\n\tcreateToolValidationFailureCorpusRecord,\n\ttype ToolValidationFailureShapeEntry,\n\twriteFailureCorpusRecord,\n} from \"./failure-corpus.ts\";\nimport { updatePersistedToolRecoveryStats } from \"./tool-recovery-stats.ts\";\nimport { appendBoundedJsonLineSync, type BoundedJsonlLimits } from \"./util/bounded-jsonl.ts\";\n\nexport const TOOL_RECOVERY_EVENT_LOG_FILE = \"tool-recovery-events.jsonl\";\nexport const TOOL_ARGUMENT_VALIDATION_LOG_KIND = \"tool_argument_validation\";\n\nconst TOOL_RECOVERY_EVENT_LIMITS: BoundedJsonlLimits = {\n\tmaxBytes: 4 * 1024 * 1024,\n\ttargetBytes: Math.floor(4 * 1024 * 1024 * 0.75),\n\tmaxRecords: 5_000,\n};\nconst MAX_TELEMETRY_LIST_ITEMS = 50;\nconst MAX_TELEMETRY_TEXT_CHARS = 256;\n\nexport interface ToolArgumentValidationLogRecord extends ToolArgumentValidationTelemetryEvent {\n\tkind: typeof TOOL_ARGUMENT_VALIDATION_LOG_KIND;\n\tversion: 1;\n\trecordId: string;\n\tts: string;\n\tsessionId: string;\n}\n\nexport interface ToolRecoveryLogWorkerRecord {\n\teventLogPath: string;\n\tfailureCorpusPath: string;\n\trecord: ToolArgumentValidationLogRecord;\n}\n\nfunction boundedText(value: string): string {\n\treturn value.slice(0, MAX_TELEMETRY_TEXT_CHARS);\n}\n\nfunction boundedList<T extends string>(values: readonly T[] | undefined): T[] | undefined {\n\treturn values?.slice(0, MAX_TELEMETRY_LIST_ITEMS);\n}\n\nfunction boundedTextList(values: readonly string[] | undefined): string[] | undefined {\n\treturn values?.slice(0, MAX_TELEMETRY_LIST_ITEMS).map(boundedText);\n}\n\nfunction copyFailureShape(\n\tshape: readonly ToolValidationFailureShapeEntry[] | undefined,\n): ToolValidationFailureShapeEntry[] {\n\treturn (shape ?? []).slice(0, MAX_TELEMETRY_LIST_ITEMS).map((entry) => ({\n\t\tpath: boundedText(entry.path),\n\t\texpectedType: boundedText(entry.expectedType),\n\t\treceivedType: boundedText(entry.receivedType),\n\t\t...(entry.keyword ? { keyword: boundedText(entry.keyword) } : {}),\n\t}));\n}\n\nexport function createToolArgumentValidationLogRecord(args: {\n\tevent: ToolArgumentValidationTelemetryEvent;\n\trecordId: string;\n\tsessionId: string;\n\tts: string;\n}): ToolArgumentValidationLogRecord {\n\treturn {\n\t\tkind: TOOL_ARGUMENT_VALIDATION_LOG_KIND,\n\t\tversion: 1,\n\t\trecordId: args.recordId,\n\t\tts: args.ts,\n\t\tsessionId: args.sessionId,\n\t\toutcome: args.event.outcome,\n\t\tprovider: args.event.provider,\n\t\tmodel: args.event.model,\n\t\ttool: args.event.tool,\n\t\tsource: args.event.source,\n\t\tfailureModes: boundedList(args.event.failureModes) ?? [],\n\t\trepairsApplied: boundedList(args.event.repairsApplied) ?? [],\n\t\tfailureShape: copyFailureShape(args.event.failureShape),\n\t\terrorKeywords: boundedTextList(args.event.errorKeywords),\n\t\ttaught: args.event.taught,\n\t\texecutionOutcome: args.event.executionOutcome,\n\t};\n}\n\nexport function isToolArgumentValidationLogRecord(value: unknown): value is ToolArgumentValidationLogRecord {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst record = value as Partial<ToolArgumentValidationLogRecord>;\n\treturn (\n\t\trecord.kind === TOOL_ARGUMENT_VALIDATION_LOG_KIND &&\n\t\trecord.version === 1 &&\n\t\ttypeof record.recordId === \"string\" &&\n\t\ttypeof record.ts === \"string\" &&\n\t\ttypeof record.sessionId === \"string\" &&\n\t\t(record.outcome === \"repaired\" || record.outcome === \"bounced\") &&\n\t\ttypeof record.tool === \"string\" &&\n\t\tArray.isArray(record.failureModes) &&\n\t\tArray.isArray(record.repairsApplied)\n\t);\n}\n\n/**\n * Append + rotate under a single exclusive lock on `eventLogPath`. Without the lock, a concurrent\n * writer (e.g. another session's tool-recovery worker) could append between this call's read and its\n * rotated rewrite, and that append would be silently discarded when the rewrite lands. The shared\n * bounded JSONL sink also uses atomic tmp+rename rotation so readers never observe torn log files.\n */\nexport function writeToolRecoveryLogRecord(entry: ToolRecoveryLogWorkerRecord): void {\n\tappendBoundedJsonLineSync(entry.eventLogPath, entry.record, TOOL_RECOVERY_EVENT_LIMITS);\n\ttry {\n\t\tupdatePersistedToolRecoveryStats(entry.eventLogPath, entry.record);\n\t} catch {\n\t\t// The bounded event log remains the recovery source if the cumulative summary cannot be updated.\n\t}\n\tif (entry.record.outcome !== \"bounced\") return;\n\twriteFailureCorpusRecord(\n\t\tentry.failureCorpusPath,\n\t\tcreateToolValidationFailureCorpusRecord({\n\t\t\tts: entry.record.ts,\n\t\t\tprovider: entry.record.provider,\n\t\t\tmodelId: entry.record.model,\n\t\t\ttool: entry.record.tool,\n\t\t\tfailureModes: entry.record.failureModes,\n\t\t\tshape: copyFailureShape(entry.record.failureShape),\n\t\t\terrorKeywords: entry.record.errorKeywords,\n\t\t}),\n\t);\n}\n"]}
|
|
@@ -1,5 +1,25 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ToolArgumentExecutionOutcome, ToolArgumentTeachState, ToolArgumentValidationTelemetryEvent } from "@caupulican/pi-ai";
|
|
2
2
|
import { type ToolArgumentValidationLogRecord } from "./tool-recovery-log-records.ts";
|
|
3
|
+
export interface ToolArgumentValidationTeachEfficacy {
|
|
4
|
+
recurrenceBefore: number;
|
|
5
|
+
recurrenceAfter: number;
|
|
6
|
+
repairedThenSucceeded: number;
|
|
7
|
+
repairedThenFailed: number;
|
|
8
|
+
repairedThenNotRun: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ToolArgumentValidationStats {
|
|
11
|
+
clean: number;
|
|
12
|
+
repaired: number;
|
|
13
|
+
bounced: number;
|
|
14
|
+
failureModes: Record<string, number>;
|
|
15
|
+
repairsApplied: Record<string, number>;
|
|
16
|
+
taught: Record<ToolArgumentTeachState, number>;
|
|
17
|
+
executionOutcome: Record<ToolArgumentExecutionOutcome, number>;
|
|
18
|
+
teachEfficacy: Record<string, ToolArgumentValidationTeachEfficacy>;
|
|
19
|
+
}
|
|
20
|
+
export interface ToolArgumentValidationRecord extends ToolArgumentValidationTelemetryEvent {
|
|
21
|
+
version: 1;
|
|
22
|
+
}
|
|
3
23
|
interface PersistedToolRecoveryStats {
|
|
4
24
|
version: 1;
|
|
5
25
|
sessionId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-recovery-stats.d.ts","sourceRoot":"","sources":["../../src/core/tool-recovery-stats.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AACxG,OAAO,EAEN,KAAK,+BAA+B,EACpC,MAAM,gCAAgC,CAAC;AAOxC,UAAU,0BAA0B;IACnC,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,2BAA2B,CAAC;CACnC;AAED,wBAAgB,sCAAsC,IAAI,2BAA2B,CAWpF;AAOD,wBAAgB,mCAAmC,CAClD,KAAK,EAAE,2BAA2B,EAClC,MAAM,EAAE,4BAA4B,GAClC,IAAI,CAwDN;AAED,wBAAgB,6BAA6B,CAC5C,MAAM,EAAE,IAAI,CAAC,+BAA+B,EAAE,UAAU,GAAG,WAAW,CAAC,GACrE,MAAM,CAKR;AA4CD,wBAAgB,8BAA8B,CAC7C,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GACf,0BAA0B,GAAG,SAAS,CASxC;AAiCD,wBAAgB,gCAAgC,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,+BAA+B,GAAG,IAAI,CA6BpH","sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tstatSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ToolArgumentValidationRecord, ToolArgumentValidationStats } from \"./session-analytics.ts\";\nimport {\n\tisToolArgumentValidationLogRecord,\n\ttype ToolArgumentValidationLogRecord,\n} from \"./tool-recovery-log-records.ts\";\n\nconst MAX_DETAIL_KEYS = 1_000;\nconst MAX_STATS_FILES = 1_000;\nconst MAX_STATS_FILE_AGE_MS = 90 * 24 * 60 * 60 * 1000;\nconst OTHER_DETAIL_KEY = \"__other__\";\n\ninterface PersistedToolRecoveryStats {\n\tversion: 1;\n\tsessionId: string;\n\tlastRecordSequence: number;\n\tstats: ToolArgumentValidationStats;\n}\n\nexport function createEmptyToolArgumentValidationStats(): ToolArgumentValidationStats {\n\treturn {\n\t\tclean: 0,\n\t\trepaired: 0,\n\t\tbounced: 0,\n\t\tfailureModes: {},\n\t\trepairsApplied: {},\n\t\ttaught: { none: 0, note: 0, rule: 0 },\n\t\texecutionOutcome: { not_run: 0, succeeded: 0, failed: 0 },\n\t\tteachEfficacy: {},\n\t};\n}\n\nfunction boundedDetailKey(record: Record<string, unknown>, key: string): string {\n\tif (record[key] !== undefined || Object.keys(record).length < MAX_DETAIL_KEYS - 1) return key;\n\treturn OTHER_DETAIL_KEY;\n}\n\nexport function consumeToolArgumentValidationRecord(\n\tstats: ToolArgumentValidationStats,\n\trecord: ToolArgumentValidationRecord,\n): void {\n\tstats[record.outcome] += 1;\n\tconst taught = record.taught ?? \"none\";\n\tconst executionOutcome = record.executionOutcome ?? \"not_run\";\n\tstats.taught[taught] += 1;\n\tstats.executionOutcome[executionOutcome] += 1;\n\tconst modes = new Set([...record.failureModes, ...record.repairsApplied]);\n\tfor (const mode of record.failureModes) {\n\t\tconst key = boundedDetailKey(stats.failureModes, mode);\n\t\tstats.failureModes[key] = (stats.failureModes[key] ?? 0) + 1;\n\t}\n\tfor (const repair of record.repairsApplied) {\n\t\tconst key = boundedDetailKey(stats.repairsApplied, repair);\n\t\tstats.repairsApplied[key] = (stats.repairsApplied[key] ?? 0) + 1;\n\t}\n\tfor (const mode of modes) {\n\t\tconst key = boundedDetailKey(\n\t\t\tstats.teachEfficacy,\n\t\t\t`${record.provider ?? \"unknown\"}/${record.model ?? \"unknown\"}:${mode}`,\n\t\t);\n\t\tlet efficacy = stats.teachEfficacy[key];\n\t\tif (!efficacy) {\n\t\t\tefficacy = {\n\t\t\t\trecurrenceBefore: 0,\n\t\t\t\trecurrenceAfter: 0,\n\t\t\t\trepairedThenSucceeded: 0,\n\t\t\t\trepairedThenFailed: 0,\n\t\t\t\trepairedThenNotRun: 0,\n\t\t\t};\n\t\t\tstats.teachEfficacy[key] = efficacy;\n\t\t}\n\t\tif (taught === \"none\") efficacy.recurrenceBefore++;\n\t\telse efficacy.recurrenceAfter++;\n\t}\n\tif (record.outcome === \"repaired\") {\n\t\tfor (const repair of record.repairsApplied) {\n\t\t\tconst key = boundedDetailKey(\n\t\t\t\tstats.teachEfficacy,\n\t\t\t\t`${record.provider ?? \"unknown\"}/${record.model ?? \"unknown\"}:${repair}`,\n\t\t\t);\n\t\t\tlet efficacy = stats.teachEfficacy[key];\n\t\t\tif (!efficacy) {\n\t\t\t\tefficacy = {\n\t\t\t\t\trecurrenceBefore: 0,\n\t\t\t\t\trecurrenceAfter: 0,\n\t\t\t\t\trepairedThenSucceeded: 0,\n\t\t\t\t\trepairedThenFailed: 0,\n\t\t\t\t\trepairedThenNotRun: 0,\n\t\t\t\t};\n\t\t\t\tstats.teachEfficacy[key] = efficacy;\n\t\t\t}\n\t\t\tif (executionOutcome === \"succeeded\") efficacy.repairedThenSucceeded++;\n\t\t\tif (executionOutcome === \"failed\") efficacy.repairedThenFailed++;\n\t\t\tif (executionOutcome === \"not_run\") efficacy.repairedThenNotRun++;\n\t\t}\n\t}\n}\n\nexport function getToolRecoveryRecordSequence(\n\trecord: Pick<ToolArgumentValidationLogRecord, \"recordId\" | \"sessionId\">,\n): number {\n\tconst prefix = `${record.sessionId}:`;\n\tif (!record.recordId.startsWith(prefix)) return -1;\n\tconst sequence = Number(record.recordId.slice(prefix.length));\n\treturn Number.isSafeInteger(sequence) && sequence >= 0 ? sequence : -1;\n}\n\nfunction statsPath(eventLogPath: string, sessionId: string): string {\n\tconst id = createHash(\"sha256\").update(sessionId).digest(\"hex\").slice(0, 24);\n\treturn join(dirname(eventLogPath), \"tool-recovery-stats\", `${id}.json`);\n}\n\nfunction isFiniteCount(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\nfunction isCountRecord(value: unknown): value is Record<string, number> {\n\treturn !!value && typeof value === \"object\" && Object.values(value).every(isFiniteCount);\n}\n\nfunction isStatsShape(value: unknown): value is ToolArgumentValidationStats {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst stats = value as Partial<ToolArgumentValidationStats>;\n\tif (!isFiniteCount(stats.clean) || !isFiniteCount(stats.repaired) || !isFiniteCount(stats.bounced)) return false;\n\tif (!isCountRecord(stats.failureModes) || !isCountRecord(stats.repairsApplied)) return false;\n\tif (!isCountRecord(stats.taught) || !isCountRecord(stats.executionOutcome)) return false;\n\tif (!stats.teachEfficacy || typeof stats.teachEfficacy !== \"object\") return false;\n\treturn Object.values(stats.teachEfficacy).every(\n\t\t(value) =>\n\t\t\t!!value &&\n\t\t\tisFiniteCount(value.recurrenceBefore) &&\n\t\t\tisFiniteCount(value.recurrenceAfter) &&\n\t\t\tisFiniteCount(value.repairedThenSucceeded) &&\n\t\t\tisFiniteCount(value.repairedThenFailed) &&\n\t\t\tisFiniteCount(value.repairedThenNotRun),\n\t);\n}\n\nfunction isPersistedStats(value: unknown, sessionId: string): value is PersistedToolRecoveryStats {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst record = value as Partial<PersistedToolRecoveryStats>;\n\treturn (\n\t\trecord.version === 1 &&\n\t\trecord.sessionId === sessionId &&\n\t\tisFiniteCount(record.lastRecordSequence) &&\n\t\tisStatsShape(record.stats)\n\t);\n}\n\nexport function readPersistedToolRecoveryStats(\n\teventLogPath: string,\n\tsessionId: string,\n): PersistedToolRecoveryStats | undefined {\n\tconst path = statsPath(eventLogPath, sessionId);\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(readFileSync(path, \"utf-8\"));\n\t\treturn isPersistedStats(parsed, sessionId) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction pruneStatsFiles(directory: string, currentPath: string): void {\n\tconst now = Date.now();\n\tconst files = readdirSync(directory)\n\t\t.filter((name) => name.endsWith(\".json\"))\n\t\t.map((name) => {\n\t\t\tconst path = join(directory, name);\n\t\t\treturn { path, mtimeMs: statSync(path).mtimeMs };\n\t\t})\n\t\t.sort((left, right) => left.mtimeMs - right.mtimeMs);\n\tlet retained = files.length;\n\tfor (const file of files) {\n\t\tif (file.path === currentPath) continue;\n\t\tif (retained <= MAX_STATS_FILES && now - file.mtimeMs <= MAX_STATS_FILE_AGE_MS) continue;\n\t\ttry {\n\t\t\tunlinkSync(file.path);\n\t\t\tretained--;\n\t\t} catch {}\n\t}\n}\n\nfunction writePersistedToolRecoveryStats(eventLogPath: string, summary: PersistedToolRecoveryStats): void {\n\tconst path = statsPath(eventLogPath, summary.sessionId);\n\tconst directory = dirname(path);\n\tmkdirSync(directory, { recursive: true });\n\tconst isNewSummary = !existsSync(path);\n\tconst temporaryPath = `${path}.${process.pid}.tmp`;\n\twriteFileSync(temporaryPath, JSON.stringify(summary), \"utf-8\");\n\trenameSync(temporaryPath, path);\n\tif (isNewSummary) pruneStatsFiles(directory, path);\n}\n\nexport function updatePersistedToolRecoveryStats(eventLogPath: string, record: ToolArgumentValidationLogRecord): void {\n\tlet summary = readPersistedToolRecoveryStats(eventLogPath, record.sessionId);\n\tif (!summary) {\n\t\tsummary = {\n\t\t\tversion: 1,\n\t\t\tsessionId: record.sessionId,\n\t\t\tlastRecordSequence: -1,\n\t\t\tstats: createEmptyToolArgumentValidationStats(),\n\t\t};\n\t\ttry {\n\t\t\tfor (const line of readFileSync(eventLogPath, \"utf-8\").split(\"\\n\")) {\n\t\t\t\tif (line.trim().length === 0) continue;\n\t\t\t\tconst parsed: unknown = JSON.parse(line);\n\t\t\t\tif (!isToolArgumentValidationLogRecord(parsed) || parsed.sessionId !== record.sessionId) continue;\n\t\t\t\tconst sequence = getToolRecoveryRecordSequence(parsed);\n\t\t\t\tif (sequence <= summary.lastRecordSequence) continue;\n\t\t\t\tconsumeToolArgumentValidationRecord(summary.stats, parsed);\n\t\t\t\tsummary.lastRecordSequence = sequence;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through and at least account for the current record.\n\t\t}\n\t}\n\tconst sequence = getToolRecoveryRecordSequence(record);\n\tif (sequence > summary.lastRecordSequence) {\n\t\tconsumeToolArgumentValidationRecord(summary.stats, record);\n\t\tsummary.lastRecordSequence = sequence;\n\t}\n\twritePersistedToolRecoveryStats(eventLogPath, summary);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool-recovery-stats.d.ts","sourceRoot":"","sources":["../../src/core/tool-recovery-stats.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACX,4BAA4B,EAC5B,sBAAsB,EACtB,oCAAoC,EACpC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEN,KAAK,+BAA+B,EACpC,MAAM,gCAAgC,CAAC;AAOxC,MAAM,WAAW,mCAAmC;IACnD,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,2BAA2B;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;IAC/C,gBAAgB,EAAE,MAAM,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAC;IAC/D,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,mCAAmC,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,4BAA6B,SAAQ,oCAAoC;IACzF,OAAO,EAAE,CAAC,CAAC;CACX;AAED,UAAU,0BAA0B;IACnC,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,2BAA2B,CAAC;CACnC;AAED,wBAAgB,sCAAsC,IAAI,2BAA2B,CAWpF;AAOD,wBAAgB,mCAAmC,CAClD,KAAK,EAAE,2BAA2B,EAClC,MAAM,EAAE,4BAA4B,GAClC,IAAI,CAwDN;AAED,wBAAgB,6BAA6B,CAC5C,MAAM,EAAE,IAAI,CAAC,+BAA+B,EAAE,UAAU,GAAG,WAAW,CAAC,GACrE,MAAM,CAKR;AA4CD,wBAAgB,8BAA8B,CAC7C,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GACf,0BAA0B,GAAG,SAAS,CASxC;AAiCD,wBAAgB,gCAAgC,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,+BAA+B,GAAG,IAAI,CA6BpH","sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tstatSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type {\n\tToolArgumentExecutionOutcome,\n\tToolArgumentTeachState,\n\tToolArgumentValidationTelemetryEvent,\n} from \"@caupulican/pi-ai\";\nimport {\n\tisToolArgumentValidationLogRecord,\n\ttype ToolArgumentValidationLogRecord,\n} from \"./tool-recovery-log-records.ts\";\n\nconst MAX_DETAIL_KEYS = 1_000;\nconst MAX_STATS_FILES = 1_000;\nconst MAX_STATS_FILE_AGE_MS = 90 * 24 * 60 * 60 * 1000;\nconst OTHER_DETAIL_KEY = \"__other__\";\n\nexport interface ToolArgumentValidationTeachEfficacy {\n\trecurrenceBefore: number;\n\trecurrenceAfter: number;\n\trepairedThenSucceeded: number;\n\trepairedThenFailed: number;\n\trepairedThenNotRun: number;\n}\n\nexport interface ToolArgumentValidationStats {\n\tclean: number;\n\trepaired: number;\n\tbounced: number;\n\tfailureModes: Record<string, number>;\n\trepairsApplied: Record<string, number>;\n\ttaught: Record<ToolArgumentTeachState, number>;\n\texecutionOutcome: Record<ToolArgumentExecutionOutcome, number>;\n\tteachEfficacy: Record<string, ToolArgumentValidationTeachEfficacy>;\n}\n\nexport interface ToolArgumentValidationRecord extends ToolArgumentValidationTelemetryEvent {\n\tversion: 1;\n}\n\ninterface PersistedToolRecoveryStats {\n\tversion: 1;\n\tsessionId: string;\n\tlastRecordSequence: number;\n\tstats: ToolArgumentValidationStats;\n}\n\nexport function createEmptyToolArgumentValidationStats(): ToolArgumentValidationStats {\n\treturn {\n\t\tclean: 0,\n\t\trepaired: 0,\n\t\tbounced: 0,\n\t\tfailureModes: {},\n\t\trepairsApplied: {},\n\t\ttaught: { none: 0, note: 0, rule: 0 },\n\t\texecutionOutcome: { not_run: 0, succeeded: 0, failed: 0 },\n\t\tteachEfficacy: {},\n\t};\n}\n\nfunction boundedDetailKey(record: Record<string, unknown>, key: string): string {\n\tif (record[key] !== undefined || Object.keys(record).length < MAX_DETAIL_KEYS - 1) return key;\n\treturn OTHER_DETAIL_KEY;\n}\n\nexport function consumeToolArgumentValidationRecord(\n\tstats: ToolArgumentValidationStats,\n\trecord: ToolArgumentValidationRecord,\n): void {\n\tstats[record.outcome] += 1;\n\tconst taught = record.taught ?? \"none\";\n\tconst executionOutcome = record.executionOutcome ?? \"not_run\";\n\tstats.taught[taught] += 1;\n\tstats.executionOutcome[executionOutcome] += 1;\n\tconst modes = new Set([...record.failureModes, ...record.repairsApplied]);\n\tfor (const mode of record.failureModes) {\n\t\tconst key = boundedDetailKey(stats.failureModes, mode);\n\t\tstats.failureModes[key] = (stats.failureModes[key] ?? 0) + 1;\n\t}\n\tfor (const repair of record.repairsApplied) {\n\t\tconst key = boundedDetailKey(stats.repairsApplied, repair);\n\t\tstats.repairsApplied[key] = (stats.repairsApplied[key] ?? 0) + 1;\n\t}\n\tfor (const mode of modes) {\n\t\tconst key = boundedDetailKey(\n\t\t\tstats.teachEfficacy,\n\t\t\t`${record.provider ?? \"unknown\"}/${record.model ?? \"unknown\"}:${mode}`,\n\t\t);\n\t\tlet efficacy = stats.teachEfficacy[key];\n\t\tif (!efficacy) {\n\t\t\tefficacy = {\n\t\t\t\trecurrenceBefore: 0,\n\t\t\t\trecurrenceAfter: 0,\n\t\t\t\trepairedThenSucceeded: 0,\n\t\t\t\trepairedThenFailed: 0,\n\t\t\t\trepairedThenNotRun: 0,\n\t\t\t};\n\t\t\tstats.teachEfficacy[key] = efficacy;\n\t\t}\n\t\tif (taught === \"none\") efficacy.recurrenceBefore++;\n\t\telse efficacy.recurrenceAfter++;\n\t}\n\tif (record.outcome === \"repaired\") {\n\t\tfor (const repair of record.repairsApplied) {\n\t\t\tconst key = boundedDetailKey(\n\t\t\t\tstats.teachEfficacy,\n\t\t\t\t`${record.provider ?? \"unknown\"}/${record.model ?? \"unknown\"}:${repair}`,\n\t\t\t);\n\t\t\tlet efficacy = stats.teachEfficacy[key];\n\t\t\tif (!efficacy) {\n\t\t\t\tefficacy = {\n\t\t\t\t\trecurrenceBefore: 0,\n\t\t\t\t\trecurrenceAfter: 0,\n\t\t\t\t\trepairedThenSucceeded: 0,\n\t\t\t\t\trepairedThenFailed: 0,\n\t\t\t\t\trepairedThenNotRun: 0,\n\t\t\t\t};\n\t\t\t\tstats.teachEfficacy[key] = efficacy;\n\t\t\t}\n\t\t\tif (executionOutcome === \"succeeded\") efficacy.repairedThenSucceeded++;\n\t\t\tif (executionOutcome === \"failed\") efficacy.repairedThenFailed++;\n\t\t\tif (executionOutcome === \"not_run\") efficacy.repairedThenNotRun++;\n\t\t}\n\t}\n}\n\nexport function getToolRecoveryRecordSequence(\n\trecord: Pick<ToolArgumentValidationLogRecord, \"recordId\" | \"sessionId\">,\n): number {\n\tconst prefix = `${record.sessionId}:`;\n\tif (!record.recordId.startsWith(prefix)) return -1;\n\tconst sequence = Number(record.recordId.slice(prefix.length));\n\treturn Number.isSafeInteger(sequence) && sequence >= 0 ? sequence : -1;\n}\n\nfunction statsPath(eventLogPath: string, sessionId: string): string {\n\tconst id = createHash(\"sha256\").update(sessionId).digest(\"hex\").slice(0, 24);\n\treturn join(dirname(eventLogPath), \"tool-recovery-stats\", `${id}.json`);\n}\n\nfunction isFiniteCount(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\nfunction isCountRecord(value: unknown): value is Record<string, number> {\n\treturn !!value && typeof value === \"object\" && Object.values(value).every(isFiniteCount);\n}\n\nfunction isStatsShape(value: unknown): value is ToolArgumentValidationStats {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst stats = value as Partial<ToolArgumentValidationStats>;\n\tif (!isFiniteCount(stats.clean) || !isFiniteCount(stats.repaired) || !isFiniteCount(stats.bounced)) return false;\n\tif (!isCountRecord(stats.failureModes) || !isCountRecord(stats.repairsApplied)) return false;\n\tif (!isCountRecord(stats.taught) || !isCountRecord(stats.executionOutcome)) return false;\n\tif (!stats.teachEfficacy || typeof stats.teachEfficacy !== \"object\") return false;\n\treturn Object.values(stats.teachEfficacy).every(\n\t\t(value) =>\n\t\t\t!!value &&\n\t\t\tisFiniteCount(value.recurrenceBefore) &&\n\t\t\tisFiniteCount(value.recurrenceAfter) &&\n\t\t\tisFiniteCount(value.repairedThenSucceeded) &&\n\t\t\tisFiniteCount(value.repairedThenFailed) &&\n\t\t\tisFiniteCount(value.repairedThenNotRun),\n\t);\n}\n\nfunction isPersistedStats(value: unknown, sessionId: string): value is PersistedToolRecoveryStats {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst record = value as Partial<PersistedToolRecoveryStats>;\n\treturn (\n\t\trecord.version === 1 &&\n\t\trecord.sessionId === sessionId &&\n\t\tisFiniteCount(record.lastRecordSequence) &&\n\t\tisStatsShape(record.stats)\n\t);\n}\n\nexport function readPersistedToolRecoveryStats(\n\teventLogPath: string,\n\tsessionId: string,\n): PersistedToolRecoveryStats | undefined {\n\tconst path = statsPath(eventLogPath, sessionId);\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(readFileSync(path, \"utf-8\"));\n\t\treturn isPersistedStats(parsed, sessionId) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction pruneStatsFiles(directory: string, currentPath: string): void {\n\tconst now = Date.now();\n\tconst files = readdirSync(directory)\n\t\t.filter((name) => name.endsWith(\".json\"))\n\t\t.map((name) => {\n\t\t\tconst path = join(directory, name);\n\t\t\treturn { path, mtimeMs: statSync(path).mtimeMs };\n\t\t})\n\t\t.sort((left, right) => left.mtimeMs - right.mtimeMs);\n\tlet retained = files.length;\n\tfor (const file of files) {\n\t\tif (file.path === currentPath) continue;\n\t\tif (retained <= MAX_STATS_FILES && now - file.mtimeMs <= MAX_STATS_FILE_AGE_MS) continue;\n\t\ttry {\n\t\t\tunlinkSync(file.path);\n\t\t\tretained--;\n\t\t} catch {}\n\t}\n}\n\nfunction writePersistedToolRecoveryStats(eventLogPath: string, summary: PersistedToolRecoveryStats): void {\n\tconst path = statsPath(eventLogPath, summary.sessionId);\n\tconst directory = dirname(path);\n\tmkdirSync(directory, { recursive: true });\n\tconst isNewSummary = !existsSync(path);\n\tconst temporaryPath = `${path}.${process.pid}.tmp`;\n\twriteFileSync(temporaryPath, JSON.stringify(summary), \"utf-8\");\n\trenameSync(temporaryPath, path);\n\tif (isNewSummary) pruneStatsFiles(directory, path);\n}\n\nexport function updatePersistedToolRecoveryStats(eventLogPath: string, record: ToolArgumentValidationLogRecord): void {\n\tlet summary = readPersistedToolRecoveryStats(eventLogPath, record.sessionId);\n\tif (!summary) {\n\t\tsummary = {\n\t\t\tversion: 1,\n\t\t\tsessionId: record.sessionId,\n\t\t\tlastRecordSequence: -1,\n\t\t\tstats: createEmptyToolArgumentValidationStats(),\n\t\t};\n\t\ttry {\n\t\t\tfor (const line of readFileSync(eventLogPath, \"utf-8\").split(\"\\n\")) {\n\t\t\t\tif (line.trim().length === 0) continue;\n\t\t\t\tconst parsed: unknown = JSON.parse(line);\n\t\t\t\tif (!isToolArgumentValidationLogRecord(parsed) || parsed.sessionId !== record.sessionId) continue;\n\t\t\t\tconst sequence = getToolRecoveryRecordSequence(parsed);\n\t\t\t\tif (sequence <= summary.lastRecordSequence) continue;\n\t\t\t\tconsumeToolArgumentValidationRecord(summary.stats, parsed);\n\t\t\t\tsummary.lastRecordSequence = sequence;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through and at least account for the current record.\n\t\t}\n\t}\n\tconst sequence = getToolRecoveryRecordSequence(record);\n\tif (sequence > summary.lastRecordSequence) {\n\t\tconsumeToolArgumentValidationRecord(summary.stats, record);\n\t\tsummary.lastRecordSequence = sequence;\n\t}\n\twritePersistedToolRecoveryStats(eventLogPath, summary);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-recovery-stats.js","sourceRoot":"","sources":["../../src/core/tool-recovery-stats.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tstatSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ToolArgumentValidationRecord, ToolArgumentValidationStats } from \"./session-analytics.ts\";\nimport {\n\tisToolArgumentValidationLogRecord,\n\ttype ToolArgumentValidationLogRecord,\n} from \"./tool-recovery-log-records.ts\";\n\nconst MAX_DETAIL_KEYS = 1_000;\nconst MAX_STATS_FILES = 1_000;\nconst MAX_STATS_FILE_AGE_MS = 90 * 24 * 60 * 60 * 1000;\nconst OTHER_DETAIL_KEY = \"__other__\";\n\ninterface PersistedToolRecoveryStats {\n\tversion: 1;\n\tsessionId: string;\n\tlastRecordSequence: number;\n\tstats: ToolArgumentValidationStats;\n}\n\nexport function createEmptyToolArgumentValidationStats(): ToolArgumentValidationStats {\n\treturn {\n\t\tclean: 0,\n\t\trepaired: 0,\n\t\tbounced: 0,\n\t\tfailureModes: {},\n\t\trepairsApplied: {},\n\t\ttaught: { none: 0, note: 0, rule: 0 },\n\t\texecutionOutcome: { not_run: 0, succeeded: 0, failed: 0 },\n\t\tteachEfficacy: {},\n\t};\n}\n\nfunction boundedDetailKey(record: Record<string, unknown>, key: string): string {\n\tif (record[key] !== undefined || Object.keys(record).length < MAX_DETAIL_KEYS - 1) return key;\n\treturn OTHER_DETAIL_KEY;\n}\n\nexport function consumeToolArgumentValidationRecord(\n\tstats: ToolArgumentValidationStats,\n\trecord: ToolArgumentValidationRecord,\n): void {\n\tstats[record.outcome] += 1;\n\tconst taught = record.taught ?? \"none\";\n\tconst executionOutcome = record.executionOutcome ?? \"not_run\";\n\tstats.taught[taught] += 1;\n\tstats.executionOutcome[executionOutcome] += 1;\n\tconst modes = new Set([...record.failureModes, ...record.repairsApplied]);\n\tfor (const mode of record.failureModes) {\n\t\tconst key = boundedDetailKey(stats.failureModes, mode);\n\t\tstats.failureModes[key] = (stats.failureModes[key] ?? 0) + 1;\n\t}\n\tfor (const repair of record.repairsApplied) {\n\t\tconst key = boundedDetailKey(stats.repairsApplied, repair);\n\t\tstats.repairsApplied[key] = (stats.repairsApplied[key] ?? 0) + 1;\n\t}\n\tfor (const mode of modes) {\n\t\tconst key = boundedDetailKey(\n\t\t\tstats.teachEfficacy,\n\t\t\t`${record.provider ?? \"unknown\"}/${record.model ?? \"unknown\"}:${mode}`,\n\t\t);\n\t\tlet efficacy = stats.teachEfficacy[key];\n\t\tif (!efficacy) {\n\t\t\tefficacy = {\n\t\t\t\trecurrenceBefore: 0,\n\t\t\t\trecurrenceAfter: 0,\n\t\t\t\trepairedThenSucceeded: 0,\n\t\t\t\trepairedThenFailed: 0,\n\t\t\t\trepairedThenNotRun: 0,\n\t\t\t};\n\t\t\tstats.teachEfficacy[key] = efficacy;\n\t\t}\n\t\tif (taught === \"none\") efficacy.recurrenceBefore++;\n\t\telse efficacy.recurrenceAfter++;\n\t}\n\tif (record.outcome === \"repaired\") {\n\t\tfor (const repair of record.repairsApplied) {\n\t\t\tconst key = boundedDetailKey(\n\t\t\t\tstats.teachEfficacy,\n\t\t\t\t`${record.provider ?? \"unknown\"}/${record.model ?? \"unknown\"}:${repair}`,\n\t\t\t);\n\t\t\tlet efficacy = stats.teachEfficacy[key];\n\t\t\tif (!efficacy) {\n\t\t\t\tefficacy = {\n\t\t\t\t\trecurrenceBefore: 0,\n\t\t\t\t\trecurrenceAfter: 0,\n\t\t\t\t\trepairedThenSucceeded: 0,\n\t\t\t\t\trepairedThenFailed: 0,\n\t\t\t\t\trepairedThenNotRun: 0,\n\t\t\t\t};\n\t\t\t\tstats.teachEfficacy[key] = efficacy;\n\t\t\t}\n\t\t\tif (executionOutcome === \"succeeded\") efficacy.repairedThenSucceeded++;\n\t\t\tif (executionOutcome === \"failed\") efficacy.repairedThenFailed++;\n\t\t\tif (executionOutcome === \"not_run\") efficacy.repairedThenNotRun++;\n\t\t}\n\t}\n}\n\nexport function getToolRecoveryRecordSequence(\n\trecord: Pick<ToolArgumentValidationLogRecord, \"recordId\" | \"sessionId\">,\n): number {\n\tconst prefix = `${record.sessionId}:`;\n\tif (!record.recordId.startsWith(prefix)) return -1;\n\tconst sequence = Number(record.recordId.slice(prefix.length));\n\treturn Number.isSafeInteger(sequence) && sequence >= 0 ? sequence : -1;\n}\n\nfunction statsPath(eventLogPath: string, sessionId: string): string {\n\tconst id = createHash(\"sha256\").update(sessionId).digest(\"hex\").slice(0, 24);\n\treturn join(dirname(eventLogPath), \"tool-recovery-stats\", `${id}.json`);\n}\n\nfunction isFiniteCount(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\nfunction isCountRecord(value: unknown): value is Record<string, number> {\n\treturn !!value && typeof value === \"object\" && Object.values(value).every(isFiniteCount);\n}\n\nfunction isStatsShape(value: unknown): value is ToolArgumentValidationStats {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst stats = value as Partial<ToolArgumentValidationStats>;\n\tif (!isFiniteCount(stats.clean) || !isFiniteCount(stats.repaired) || !isFiniteCount(stats.bounced)) return false;\n\tif (!isCountRecord(stats.failureModes) || !isCountRecord(stats.repairsApplied)) return false;\n\tif (!isCountRecord(stats.taught) || !isCountRecord(stats.executionOutcome)) return false;\n\tif (!stats.teachEfficacy || typeof stats.teachEfficacy !== \"object\") return false;\n\treturn Object.values(stats.teachEfficacy).every(\n\t\t(value) =>\n\t\t\t!!value &&\n\t\t\tisFiniteCount(value.recurrenceBefore) &&\n\t\t\tisFiniteCount(value.recurrenceAfter) &&\n\t\t\tisFiniteCount(value.repairedThenSucceeded) &&\n\t\t\tisFiniteCount(value.repairedThenFailed) &&\n\t\t\tisFiniteCount(value.repairedThenNotRun),\n\t);\n}\n\nfunction isPersistedStats(value: unknown, sessionId: string): value is PersistedToolRecoveryStats {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst record = value as Partial<PersistedToolRecoveryStats>;\n\treturn (\n\t\trecord.version === 1 &&\n\t\trecord.sessionId === sessionId &&\n\t\tisFiniteCount(record.lastRecordSequence) &&\n\t\tisStatsShape(record.stats)\n\t);\n}\n\nexport function readPersistedToolRecoveryStats(\n\teventLogPath: string,\n\tsessionId: string,\n): PersistedToolRecoveryStats | undefined {\n\tconst path = statsPath(eventLogPath, sessionId);\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(readFileSync(path, \"utf-8\"));\n\t\treturn isPersistedStats(parsed, sessionId) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction pruneStatsFiles(directory: string, currentPath: string): void {\n\tconst now = Date.now();\n\tconst files = readdirSync(directory)\n\t\t.filter((name) => name.endsWith(\".json\"))\n\t\t.map((name) => {\n\t\t\tconst path = join(directory, name);\n\t\t\treturn { path, mtimeMs: statSync(path).mtimeMs };\n\t\t})\n\t\t.sort((left, right) => left.mtimeMs - right.mtimeMs);\n\tlet retained = files.length;\n\tfor (const file of files) {\n\t\tif (file.path === currentPath) continue;\n\t\tif (retained <= MAX_STATS_FILES && now - file.mtimeMs <= MAX_STATS_FILE_AGE_MS) continue;\n\t\ttry {\n\t\t\tunlinkSync(file.path);\n\t\t\tretained--;\n\t\t} catch {}\n\t}\n}\n\nfunction writePersistedToolRecoveryStats(eventLogPath: string, summary: PersistedToolRecoveryStats): void {\n\tconst path = statsPath(eventLogPath, summary.sessionId);\n\tconst directory = dirname(path);\n\tmkdirSync(directory, { recursive: true });\n\tconst isNewSummary = !existsSync(path);\n\tconst temporaryPath = `${path}.${process.pid}.tmp`;\n\twriteFileSync(temporaryPath, JSON.stringify(summary), \"utf-8\");\n\trenameSync(temporaryPath, path);\n\tif (isNewSummary) pruneStatsFiles(directory, path);\n}\n\nexport function updatePersistedToolRecoveryStats(eventLogPath: string, record: ToolArgumentValidationLogRecord): void {\n\tlet summary = readPersistedToolRecoveryStats(eventLogPath, record.sessionId);\n\tif (!summary) {\n\t\tsummary = {\n\t\t\tversion: 1,\n\t\t\tsessionId: record.sessionId,\n\t\t\tlastRecordSequence: -1,\n\t\t\tstats: createEmptyToolArgumentValidationStats(),\n\t\t};\n\t\ttry {\n\t\t\tfor (const line of readFileSync(eventLogPath, \"utf-8\").split(\"\\n\")) {\n\t\t\t\tif (line.trim().length === 0) continue;\n\t\t\t\tconst parsed: unknown = JSON.parse(line);\n\t\t\t\tif (!isToolArgumentValidationLogRecord(parsed) || parsed.sessionId !== record.sessionId) continue;\n\t\t\t\tconst sequence = getToolRecoveryRecordSequence(parsed);\n\t\t\t\tif (sequence <= summary.lastRecordSequence) continue;\n\t\t\t\tconsumeToolArgumentValidationRecord(summary.stats, parsed);\n\t\t\t\tsummary.lastRecordSequence = sequence;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through and at least account for the current record.\n\t\t}\n\t}\n\tconst sequence = getToolRecoveryRecordSequence(record);\n\tif (sequence > summary.lastRecordSequence) {\n\t\tconsumeToolArgumentValidationRecord(summary.stats, record);\n\t\tsummary.lastRecordSequence = sequence;\n\t}\n\twritePersistedToolRecoveryStats(eventLogPath, summary);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool-recovery-stats.js","sourceRoot":"","sources":["../../src/core/tool-recovery-stats.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\tstatSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type {\n\tToolArgumentExecutionOutcome,\n\tToolArgumentTeachState,\n\tToolArgumentValidationTelemetryEvent,\n} from \"@caupulican/pi-ai\";\nimport {\n\tisToolArgumentValidationLogRecord,\n\ttype ToolArgumentValidationLogRecord,\n} from \"./tool-recovery-log-records.ts\";\n\nconst MAX_DETAIL_KEYS = 1_000;\nconst MAX_STATS_FILES = 1_000;\nconst MAX_STATS_FILE_AGE_MS = 90 * 24 * 60 * 60 * 1000;\nconst OTHER_DETAIL_KEY = \"__other__\";\n\nexport interface ToolArgumentValidationTeachEfficacy {\n\trecurrenceBefore: number;\n\trecurrenceAfter: number;\n\trepairedThenSucceeded: number;\n\trepairedThenFailed: number;\n\trepairedThenNotRun: number;\n}\n\nexport interface ToolArgumentValidationStats {\n\tclean: number;\n\trepaired: number;\n\tbounced: number;\n\tfailureModes: Record<string, number>;\n\trepairsApplied: Record<string, number>;\n\ttaught: Record<ToolArgumentTeachState, number>;\n\texecutionOutcome: Record<ToolArgumentExecutionOutcome, number>;\n\tteachEfficacy: Record<string, ToolArgumentValidationTeachEfficacy>;\n}\n\nexport interface ToolArgumentValidationRecord extends ToolArgumentValidationTelemetryEvent {\n\tversion: 1;\n}\n\ninterface PersistedToolRecoveryStats {\n\tversion: 1;\n\tsessionId: string;\n\tlastRecordSequence: number;\n\tstats: ToolArgumentValidationStats;\n}\n\nexport function createEmptyToolArgumentValidationStats(): ToolArgumentValidationStats {\n\treturn {\n\t\tclean: 0,\n\t\trepaired: 0,\n\t\tbounced: 0,\n\t\tfailureModes: {},\n\t\trepairsApplied: {},\n\t\ttaught: { none: 0, note: 0, rule: 0 },\n\t\texecutionOutcome: { not_run: 0, succeeded: 0, failed: 0 },\n\t\tteachEfficacy: {},\n\t};\n}\n\nfunction boundedDetailKey(record: Record<string, unknown>, key: string): string {\n\tif (record[key] !== undefined || Object.keys(record).length < MAX_DETAIL_KEYS - 1) return key;\n\treturn OTHER_DETAIL_KEY;\n}\n\nexport function consumeToolArgumentValidationRecord(\n\tstats: ToolArgumentValidationStats,\n\trecord: ToolArgumentValidationRecord,\n): void {\n\tstats[record.outcome] += 1;\n\tconst taught = record.taught ?? \"none\";\n\tconst executionOutcome = record.executionOutcome ?? \"not_run\";\n\tstats.taught[taught] += 1;\n\tstats.executionOutcome[executionOutcome] += 1;\n\tconst modes = new Set([...record.failureModes, ...record.repairsApplied]);\n\tfor (const mode of record.failureModes) {\n\t\tconst key = boundedDetailKey(stats.failureModes, mode);\n\t\tstats.failureModes[key] = (stats.failureModes[key] ?? 0) + 1;\n\t}\n\tfor (const repair of record.repairsApplied) {\n\t\tconst key = boundedDetailKey(stats.repairsApplied, repair);\n\t\tstats.repairsApplied[key] = (stats.repairsApplied[key] ?? 0) + 1;\n\t}\n\tfor (const mode of modes) {\n\t\tconst key = boundedDetailKey(\n\t\t\tstats.teachEfficacy,\n\t\t\t`${record.provider ?? \"unknown\"}/${record.model ?? \"unknown\"}:${mode}`,\n\t\t);\n\t\tlet efficacy = stats.teachEfficacy[key];\n\t\tif (!efficacy) {\n\t\t\tefficacy = {\n\t\t\t\trecurrenceBefore: 0,\n\t\t\t\trecurrenceAfter: 0,\n\t\t\t\trepairedThenSucceeded: 0,\n\t\t\t\trepairedThenFailed: 0,\n\t\t\t\trepairedThenNotRun: 0,\n\t\t\t};\n\t\t\tstats.teachEfficacy[key] = efficacy;\n\t\t}\n\t\tif (taught === \"none\") efficacy.recurrenceBefore++;\n\t\telse efficacy.recurrenceAfter++;\n\t}\n\tif (record.outcome === \"repaired\") {\n\t\tfor (const repair of record.repairsApplied) {\n\t\t\tconst key = boundedDetailKey(\n\t\t\t\tstats.teachEfficacy,\n\t\t\t\t`${record.provider ?? \"unknown\"}/${record.model ?? \"unknown\"}:${repair}`,\n\t\t\t);\n\t\t\tlet efficacy = stats.teachEfficacy[key];\n\t\t\tif (!efficacy) {\n\t\t\t\tefficacy = {\n\t\t\t\t\trecurrenceBefore: 0,\n\t\t\t\t\trecurrenceAfter: 0,\n\t\t\t\t\trepairedThenSucceeded: 0,\n\t\t\t\t\trepairedThenFailed: 0,\n\t\t\t\t\trepairedThenNotRun: 0,\n\t\t\t\t};\n\t\t\t\tstats.teachEfficacy[key] = efficacy;\n\t\t\t}\n\t\t\tif (executionOutcome === \"succeeded\") efficacy.repairedThenSucceeded++;\n\t\t\tif (executionOutcome === \"failed\") efficacy.repairedThenFailed++;\n\t\t\tif (executionOutcome === \"not_run\") efficacy.repairedThenNotRun++;\n\t\t}\n\t}\n}\n\nexport function getToolRecoveryRecordSequence(\n\trecord: Pick<ToolArgumentValidationLogRecord, \"recordId\" | \"sessionId\">,\n): number {\n\tconst prefix = `${record.sessionId}:`;\n\tif (!record.recordId.startsWith(prefix)) return -1;\n\tconst sequence = Number(record.recordId.slice(prefix.length));\n\treturn Number.isSafeInteger(sequence) && sequence >= 0 ? sequence : -1;\n}\n\nfunction statsPath(eventLogPath: string, sessionId: string): string {\n\tconst id = createHash(\"sha256\").update(sessionId).digest(\"hex\").slice(0, 24);\n\treturn join(dirname(eventLogPath), \"tool-recovery-stats\", `${id}.json`);\n}\n\nfunction isFiniteCount(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\nfunction isCountRecord(value: unknown): value is Record<string, number> {\n\treturn !!value && typeof value === \"object\" && Object.values(value).every(isFiniteCount);\n}\n\nfunction isStatsShape(value: unknown): value is ToolArgumentValidationStats {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst stats = value as Partial<ToolArgumentValidationStats>;\n\tif (!isFiniteCount(stats.clean) || !isFiniteCount(stats.repaired) || !isFiniteCount(stats.bounced)) return false;\n\tif (!isCountRecord(stats.failureModes) || !isCountRecord(stats.repairsApplied)) return false;\n\tif (!isCountRecord(stats.taught) || !isCountRecord(stats.executionOutcome)) return false;\n\tif (!stats.teachEfficacy || typeof stats.teachEfficacy !== \"object\") return false;\n\treturn Object.values(stats.teachEfficacy).every(\n\t\t(value) =>\n\t\t\t!!value &&\n\t\t\tisFiniteCount(value.recurrenceBefore) &&\n\t\t\tisFiniteCount(value.recurrenceAfter) &&\n\t\t\tisFiniteCount(value.repairedThenSucceeded) &&\n\t\t\tisFiniteCount(value.repairedThenFailed) &&\n\t\t\tisFiniteCount(value.repairedThenNotRun),\n\t);\n}\n\nfunction isPersistedStats(value: unknown, sessionId: string): value is PersistedToolRecoveryStats {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst record = value as Partial<PersistedToolRecoveryStats>;\n\treturn (\n\t\trecord.version === 1 &&\n\t\trecord.sessionId === sessionId &&\n\t\tisFiniteCount(record.lastRecordSequence) &&\n\t\tisStatsShape(record.stats)\n\t);\n}\n\nexport function readPersistedToolRecoveryStats(\n\teventLogPath: string,\n\tsessionId: string,\n): PersistedToolRecoveryStats | undefined {\n\tconst path = statsPath(eventLogPath, sessionId);\n\tif (!existsSync(path)) return undefined;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(readFileSync(path, \"utf-8\"));\n\t\treturn isPersistedStats(parsed, sessionId) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction pruneStatsFiles(directory: string, currentPath: string): void {\n\tconst now = Date.now();\n\tconst files = readdirSync(directory)\n\t\t.filter((name) => name.endsWith(\".json\"))\n\t\t.map((name) => {\n\t\t\tconst path = join(directory, name);\n\t\t\treturn { path, mtimeMs: statSync(path).mtimeMs };\n\t\t})\n\t\t.sort((left, right) => left.mtimeMs - right.mtimeMs);\n\tlet retained = files.length;\n\tfor (const file of files) {\n\t\tif (file.path === currentPath) continue;\n\t\tif (retained <= MAX_STATS_FILES && now - file.mtimeMs <= MAX_STATS_FILE_AGE_MS) continue;\n\t\ttry {\n\t\t\tunlinkSync(file.path);\n\t\t\tretained--;\n\t\t} catch {}\n\t}\n}\n\nfunction writePersistedToolRecoveryStats(eventLogPath: string, summary: PersistedToolRecoveryStats): void {\n\tconst path = statsPath(eventLogPath, summary.sessionId);\n\tconst directory = dirname(path);\n\tmkdirSync(directory, { recursive: true });\n\tconst isNewSummary = !existsSync(path);\n\tconst temporaryPath = `${path}.${process.pid}.tmp`;\n\twriteFileSync(temporaryPath, JSON.stringify(summary), \"utf-8\");\n\trenameSync(temporaryPath, path);\n\tif (isNewSummary) pruneStatsFiles(directory, path);\n}\n\nexport function updatePersistedToolRecoveryStats(eventLogPath: string, record: ToolArgumentValidationLogRecord): void {\n\tlet summary = readPersistedToolRecoveryStats(eventLogPath, record.sessionId);\n\tif (!summary) {\n\t\tsummary = {\n\t\t\tversion: 1,\n\t\t\tsessionId: record.sessionId,\n\t\t\tlastRecordSequence: -1,\n\t\t\tstats: createEmptyToolArgumentValidationStats(),\n\t\t};\n\t\ttry {\n\t\t\tfor (const line of readFileSync(eventLogPath, \"utf-8\").split(\"\\n\")) {\n\t\t\t\tif (line.trim().length === 0) continue;\n\t\t\t\tconst parsed: unknown = JSON.parse(line);\n\t\t\t\tif (!isToolArgumentValidationLogRecord(parsed) || parsed.sessionId !== record.sessionId) continue;\n\t\t\t\tconst sequence = getToolRecoveryRecordSequence(parsed);\n\t\t\t\tif (sequence <= summary.lastRecordSequence) continue;\n\t\t\t\tconsumeToolArgumentValidationRecord(summary.stats, parsed);\n\t\t\t\tsummary.lastRecordSequence = sequence;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through and at least account for the current record.\n\t\t}\n\t}\n\tconst sequence = getToolRecoveryRecordSequence(record);\n\tif (sequence > summary.lastRecordSequence) {\n\t\tconsumeToolArgumentValidationRecord(summary.stats, record);\n\t\tsummary.lastRecordSequence = sequence;\n\t}\n\twritePersistedToolRecoveryStats(eventLogPath, summary);\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type HostFingerprint } from "../models/
|
|
1
|
+
import { type HostFingerprint } from "../models/host-state-store.ts";
|
|
2
2
|
export type ToolSelectionIntentClass = "read" | "search" | "execute" | "write" | "retrieve" | "explain" | "other";
|
|
3
3
|
export interface ToolPerformanceKey {
|
|
4
4
|
modelRef: string;
|
|
@@ -90,9 +90,7 @@ export interface ToolExecutionObservation {
|
|
|
90
90
|
hintActiveAtCallTime?: boolean;
|
|
91
91
|
}
|
|
92
92
|
export declare class ToolPerformanceStore {
|
|
93
|
-
private readonly
|
|
94
|
-
private readonly fingerprint;
|
|
95
|
-
private readonly readOnly;
|
|
93
|
+
private readonly storage;
|
|
96
94
|
constructor(filePath: string, options?: {
|
|
97
95
|
fingerprint?: () => HostFingerprint;
|
|
98
96
|
readOnly?: boolean;
|
|
@@ -101,9 +99,7 @@ export declare class ToolPerformanceStore {
|
|
|
101
99
|
fingerprint?: () => HostFingerprint;
|
|
102
100
|
readOnly?: boolean;
|
|
103
101
|
}): ToolPerformanceStore;
|
|
104
|
-
private
|
|
105
|
-
private save;
|
|
106
|
-
private hostData;
|
|
102
|
+
private createHostData;
|
|
107
103
|
get(key: ToolPerformanceKey): ToolPerformanceStats;
|
|
108
104
|
/** Every per-tool track record recorded for a (model,intent) bucket — the promotion.ts input. */
|
|
109
105
|
getStatsForIntent(modelRef: string, intentClass: ToolSelectionIntentClass): ToolPerformanceStats[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-performance-store.d.ts","sourceRoot":"","sources":["../../../src/core/tool-selection/tool-performance-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { stateFile } from \"../agent-paths.ts\";\nimport { currentHostFingerprint, type HostFingerprint } from \"../models/fitness-store.ts\";\nimport { isWorkerSession } from \"../session-role.ts\";\n\nconst STORE_VERSION = 1;\nconst MAX_STATS_PER_HOST = 500;\nconst MAX_OBSERVATIONS_PER_HOST = 1_000;\nconst MAX_INTENT_AGREEMENT_PER_HOST = 500;\nconst EWMA_ALPHA = 0.25;\n\nexport type ToolSelectionIntentClass = \"read\" | \"search\" | \"execute\" | \"write\" | \"retrieve\" | \"explain\" | \"other\";\n\nexport interface ToolPerformanceKey {\n\tmodelRef: string;\n\tintentClass: ToolSelectionIntentClass;\n\ttool: string;\n}\n\nexport interface ToolPerformanceStats extends ToolPerformanceKey {\n\talpha: number;\n\tbeta: number;\n\tsampleCount: number;\n\tlatencyEwmaMs?: number;\n\tlatencyDeviationEwmaMs?: number;\n\tinputTokenEstimateEwma?: number;\n\toutputTokenEstimateEwma?: number;\n\trepairCount: number;\n\tbounceCount: number;\n\tfailureCount: number;\n\tlastUsedAt: string;\n}\n\nexport interface ToolSelectionObservation {\n\tat: string;\n\tmodelRef: string;\n\tintentClass: ToolSelectionIntentClass;\n\tactualTool: string;\n\tfirstTool: boolean;\n\tsucceeded: boolean;\n\tdisposition: \"recommend\" | \"shortlist\" | \"abstain\";\n\trecommendation?: string;\n\tshortlist: string[];\n\tentropy: number;\n\tmargin: number;\n\t/** Redacted ranking: names and numeric scores only, never prompts, arguments, paths, or output. */\n\tranked: Array<{ tool: string; utility: number; probability: number }>;\n\tlatencyMs?: number;\n\tinputTokenEstimate?: number;\n\toutputTokenEstimate?: number;\n}\n\nexport interface ToolSelectionMetrics {\n\tfirstToolAttempts: number;\n\tfirstToolSuccesses: number;\n\twrongToolOrFailureCount: number;\n\trecommendationCount: number;\n\trecommendationMatchedCount: number;\n\tshortlistCount: number;\n\tabstentionCount: number;\n\taverageLatencyMs?: number;\n\taverageInputTokenEstimate?: number;\n\taverageOutputTokenEstimate?: number;\n}\n\n/**\n * Durable, per-(model,intent) aggregate of the observe-mode loop: does the raw expected-utility\n * ranking's top pick (`ToolSelectionObservation.ranked[0]`) match what the model actually called\n * (`ToolSelectionObservation.actualTool`)? Tracked separately from the capped, rolling\n * `observations` log so evidence for a given (model,intent) pair survives that log's trimming.\n * `hintActive*` fields are the SAME agreement measure, but restricted to calls made while an\n * evidence-gated promotion hint (see promotion.ts) was active for this bucket — the hint's own\n * efficacy trace: it never gates activation directly (that is always\n * recomputed live from `ToolPerformanceStats`), but it is the durable evidence a report can show\n * for \"is the hint still earning its keep\".\n */\nexport interface ToolSelectionIntentAgreement {\n\tmodelRef: string;\n\tintentClass: ToolSelectionIntentClass;\n\tsampleCount: number;\n\tagreementCount: number;\n\thintActiveSampleCount: number;\n\thintActiveAgreementCount: number;\n\tlastUpdatedAt: string;\n}\n\ninterface HostToolPerformanceData {\n\thost: HostFingerprint;\n\tstats: Record<string, ToolPerformanceStats>;\n\tobservations: ToolSelectionObservation[];\n\tintentAgreement: Record<string, ToolSelectionIntentAgreement>;\n}\n\ninterface ToolPerformanceStoreFile {\n\tversion: 1;\n\thosts: Record<string, HostToolPerformanceData>;\n}\n\nexport interface ToolExecutionObservation {\n\tkey: ToolPerformanceKey;\n\tsuccess: boolean;\n\tlatencyMs: number;\n\tinputTokenEstimate?: number;\n\toutputTokenEstimate?: number;\n\tselection: Omit<ToolSelectionObservation, \"at\" | \"modelRef\" | \"intentClass\" | \"actualTool\" | \"succeeded\">;\n\tat?: string;\n\t/**\n\t * Whether an evidence-gated promotion hint (promotion.ts) was already active for this\n\t * (model,intent) bucket BEFORE this call was recorded — captured by the controller at\n\t * `begin()` time, so it reflects evidence up to but not including this observation. Used only\n\t * to bucket the durable agreement stats (`ToolSelectionIntentAgreement.hintActive*`); never\n\t * changes what gets recorded, only how it is split for the efficacy report.\n\t */\n\thintActiveAtCallTime?: boolean;\n}\n\nfunction statKey(key: ToolPerformanceKey): string {\n\treturn `${key.modelRef}\\0${key.intentClass}\\0${key.tool}`;\n}\n\nfunction intentAgreementKey(modelRef: string, intentClass: ToolSelectionIntentClass): string {\n\treturn `${modelRef}\\0${intentClass}`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isIntentClass(value: unknown): value is ToolSelectionIntentClass {\n\treturn (\n\t\tvalue === \"read\" ||\n\t\tvalue === \"search\" ||\n\t\tvalue === \"execute\" ||\n\t\tvalue === \"write\" ||\n\t\tvalue === \"retrieve\" ||\n\t\tvalue === \"explain\" ||\n\t\tvalue === \"other\"\n\t);\n}\n\nfunction isStats(value: unknown): value is ToolPerformanceStats {\n\treturn (\n\t\tisRecord(value) &&\n\t\ttypeof value.modelRef === \"string\" &&\n\t\tisIntentClass(value.intentClass) &&\n\t\ttypeof value.tool === \"string\" &&\n\t\ttypeof value.alpha === \"number\" &&\n\t\ttypeof value.beta === \"number\" &&\n\t\ttypeof value.sampleCount === \"number\" &&\n\t\ttypeof value.repairCount === \"number\" &&\n\t\ttypeof value.bounceCount === \"number\" &&\n\t\ttypeof value.failureCount === \"number\" &&\n\t\ttypeof value.lastUsedAt === \"string\"\n\t);\n}\n\nfunction isObservation(value: unknown): value is ToolSelectionObservation {\n\treturn (\n\t\tisRecord(value) &&\n\t\ttypeof value.at === \"string\" &&\n\t\ttypeof value.modelRef === \"string\" &&\n\t\tisIntentClass(value.intentClass) &&\n\t\ttypeof value.actualTool === \"string\" &&\n\t\ttypeof value.firstTool === \"boolean\" &&\n\t\ttypeof value.succeeded === \"boolean\" &&\n\t\t(value.disposition === \"recommend\" || value.disposition === \"shortlist\" || value.disposition === \"abstain\") &&\n\t\tArray.isArray(value.shortlist) &&\n\t\tvalue.shortlist.every((tool) => typeof tool === \"string\") &&\n\t\ttypeof value.entropy === \"number\" &&\n\t\ttypeof value.margin === \"number\" &&\n\t\tArray.isArray(value.ranked) &&\n\t\tvalue.ranked.every(\n\t\t\t(entry) =>\n\t\t\t\tisRecord(entry) &&\n\t\t\t\ttypeof entry.tool === \"string\" &&\n\t\t\t\ttypeof entry.utility === \"number\" &&\n\t\t\t\ttypeof entry.probability === \"number\",\n\t\t) &&\n\t\t(value.latencyMs === undefined || typeof value.latencyMs === \"number\") &&\n\t\t(value.inputTokenEstimate === undefined || typeof value.inputTokenEstimate === \"number\") &&\n\t\t(value.outputTokenEstimate === undefined || typeof value.outputTokenEstimate === \"number\")\n\t);\n}\n\nfunction isIntentAgreement(value: unknown): value is ToolSelectionIntentAgreement {\n\treturn (\n\t\tisRecord(value) &&\n\t\ttypeof value.modelRef === \"string\" &&\n\t\tisIntentClass(value.intentClass) &&\n\t\ttypeof value.sampleCount === \"number\" &&\n\t\ttypeof value.agreementCount === \"number\" &&\n\t\ttypeof value.hintActiveSampleCount === \"number\" &&\n\t\ttypeof value.hintActiveAgreementCount === \"number\" &&\n\t\ttypeof value.lastUpdatedAt === \"string\"\n\t);\n}\n\nfunction emptyStats(key: ToolPerformanceKey, at: string): ToolPerformanceStats {\n\treturn {\n\t\t...key,\n\t\talpha: 1,\n\t\tbeta: 1,\n\t\tsampleCount: 0,\n\t\trepairCount: 0,\n\t\tbounceCount: 0,\n\t\tfailureCount: 0,\n\t\tlastUsedAt: at,\n\t};\n}\n\nfunction emptyIntentAgreement(\n\tmodelRef: string,\n\tintentClass: ToolSelectionIntentClass,\n\tat: string,\n): ToolSelectionIntentAgreement {\n\treturn {\n\t\tmodelRef,\n\t\tintentClass,\n\t\tsampleCount: 0,\n\t\tagreementCount: 0,\n\t\thintActiveSampleCount: 0,\n\t\thintActiveAgreementCount: 0,\n\t\tlastUpdatedAt: at,\n\t};\n}\n\nfunction finiteNonNegative(value: number | undefined): number | undefined {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nfunction updateEwma(previous: number | undefined, next: number | undefined): number | undefined {\n\tif (next === undefined) return previous;\n\treturn previous === undefined ? next : previous + EWMA_ALPHA * (next - previous);\n}\n\nfunction updateDeviation(\n\tpreviousValue: number | undefined,\n\tpreviousDeviation: number | undefined,\n\tnext: number | undefined,\n): number | undefined {\n\tif (next === undefined) return previousDeviation;\n\tconst deviation = previousValue === undefined ? 0 : Math.abs(next - previousValue);\n\treturn updateEwma(previousDeviation, deviation);\n}\n\nfunction parseHost(value: unknown): HostToolPerformanceData | undefined {\n\tif (!isRecord(value) || !isRecord(value.host) || !isRecord(value.stats) || !Array.isArray(value.observations))\n\t\treturn undefined;\n\tconst host = value.host;\n\tif (\n\t\ttypeof host.id !== \"string\" ||\n\t\ttypeof host.cpu !== \"string\" ||\n\t\ttypeof host.cores !== \"number\" ||\n\t\ttypeof host.totalMemGb !== \"number\"\n\t)\n\t\treturn undefined;\n\t// intentAgreement is a purely additive field (older store files predate it) — tolerate absence\n\t// rather than bumping STORE_VERSION, same as any other backward-compatible default-empty field.\n\tconst intentAgreementRaw = isRecord(value.intentAgreement) ? value.intentAgreement : {};\n\treturn {\n\t\thost: { id: host.id, cpu: host.cpu, cores: host.cores, totalMemGb: host.totalMemGb },\n\t\tstats: Object.fromEntries(\n\t\t\tObject.entries(value.stats).filter((entry): entry is [string, ToolPerformanceStats] => isStats(entry[1])),\n\t\t),\n\t\tobservations: value.observations.filter(isObservation),\n\t\tintentAgreement: Object.fromEntries(\n\t\t\tObject.entries(intentAgreementRaw).filter((entry): entry is [string, ToolSelectionIntentAgreement] =>\n\t\t\t\tisIntentAgreement(entry[1]),\n\t\t\t),\n\t\t),\n\t};\n}\n\nfunction parseFile(value: unknown): ToolPerformanceStoreFile {\n\tif (!isRecord(value) || value.version !== STORE_VERSION || !isRecord(value.hosts)) {\n\t\treturn { version: STORE_VERSION, hosts: {} };\n\t}\n\treturn {\n\t\tversion: STORE_VERSION,\n\t\thosts: Object.fromEntries(\n\t\t\tObject.entries(value.hosts)\n\t\t\t\t.map(([hostId, host]) => [hostId, parseHost(host)] as const)\n\t\t\t\t.filter((entry): entry is readonly [string, HostToolPerformanceData] => entry[1] !== undefined),\n\t\t),\n\t};\n}\n\nfunction trimStats(stats: Record<string, ToolPerformanceStats>): Record<string, ToolPerformanceStats> {\n\tconst entries = Object.entries(stats);\n\tif (entries.length <= MAX_STATS_PER_HOST) return stats;\n\treturn Object.fromEntries(\n\t\tentries\n\t\t\t.sort(([, left], [, right]) => Date.parse(right.lastUsedAt) - Date.parse(left.lastUsedAt))\n\t\t\t.slice(0, MAX_STATS_PER_HOST),\n\t);\n}\n\nfunction trimIntentAgreement(\n\trecords: Record<string, ToolSelectionIntentAgreement>,\n): Record<string, ToolSelectionIntentAgreement> {\n\tconst entries = Object.entries(records);\n\tif (entries.length <= MAX_INTENT_AGREEMENT_PER_HOST) return records;\n\treturn Object.fromEntries(\n\t\tentries\n\t\t\t.sort(([, left], [, right]) => Date.parse(right.lastUpdatedAt) - Date.parse(left.lastUpdatedAt))\n\t\t\t.slice(0, MAX_INTENT_AGREEMENT_PER_HOST),\n\t);\n}\n\nexport class ToolPerformanceStore {\n\tprivate readonly filePath: string;\n\tprivate readonly fingerprint: () => HostFingerprint;\n\tprivate readonly readOnly: boolean;\n\n\tconstructor(filePath: string, options: { fingerprint?: () => HostFingerprint; readOnly?: boolean } = {}) {\n\t\tthis.filePath = filePath;\n\t\tthis.fingerprint = options.fingerprint ?? currentHostFingerprint;\n\t\tthis.readOnly = options.readOnly ?? isWorkerSession();\n\t}\n\n\tstatic forAgentDir(\n\t\tagentDir: string,\n\t\toptions: { fingerprint?: () => HostFingerprint; readOnly?: boolean } = {},\n\t): ToolPerformanceStore {\n\t\treturn new ToolPerformanceStore(stateFile(agentDir, \"tool-performance.json\"), options);\n\t}\n\n\tprivate load(): ToolPerformanceStoreFile {\n\t\ttry {\n\t\t\tif (!existsSync(this.filePath)) return { version: STORE_VERSION, hosts: {} };\n\t\t\treturn parseFile(JSON.parse(readFileSync(this.filePath, \"utf8\")));\n\t\t} catch {\n\t\t\treturn { version: STORE_VERSION, hosts: {} };\n\t\t}\n\t}\n\n\tprivate save(file: ToolPerformanceStoreFile): void {\n\t\t// Zero-footprint (worker session): never create the state dir, lock, or file -- the caller\n\t\t// still gets its normally-computed return value from the in-memory `file`.\n\t\tif (this.readOnly) return;\n\t\tmkdirSync(dirname(this.filePath), { recursive: true });\n\t\twriteFileSync(this.filePath, `${JSON.stringify(file, null, \"\\t\")}\\n`, \"utf8\");\n\t}\n\n\tprivate hostData(file: ToolPerformanceStoreFile): HostToolPerformanceData {\n\t\tconst fingerprint = this.fingerprint();\n\t\tconst existing = file.hosts[fingerprint.id];\n\t\tif (existing) return existing;\n\t\tconst created: HostToolPerformanceData = { host: fingerprint, stats: {}, observations: [], intentAgreement: {} };\n\t\tfile.hosts[fingerprint.id] = created;\n\t\treturn created;\n\t}\n\n\tget(key: ToolPerformanceKey): ToolPerformanceStats {\n\t\tconst file = this.load();\n\t\tconst host = file.hosts[this.fingerprint().id];\n\t\tconst stats = host?.stats[statKey(key)];\n\t\treturn stats ? { ...stats } : emptyStats(key, new Date(0).toISOString());\n\t}\n\n\t/** Every per-tool track record recorded for a (model,intent) bucket — the promotion.ts input. */\n\tgetStatsForIntent(modelRef: string, intentClass: ToolSelectionIntentClass): ToolPerformanceStats[] {\n\t\tconst host = this.load().hosts[this.fingerprint().id];\n\t\tif (!host) return [];\n\t\treturn Object.values(host.stats)\n\t\t\t.filter((stats) => stats.modelRef === modelRef && stats.intentClass === intentClass)\n\t\t\t.map((stats) => ({ ...stats }));\n\t}\n\n\t/** Durable observe-mode agreement for one (model,intent) bucket (see {@link ToolSelectionIntentAgreement}). */\n\tgetIntentAgreement(modelRef: string, intentClass: ToolSelectionIntentClass): ToolSelectionIntentAgreement {\n\t\tconst host = this.load().hosts[this.fingerprint().id];\n\t\tconst record = host?.intentAgreement[intentAgreementKey(modelRef, intentClass)];\n\t\treturn record ? { ...record } : emptyIntentAgreement(modelRef, intentClass, new Date(0).toISOString());\n\t}\n\n\t/** All recorded (model,intent) agreement buckets, optionally scoped to one model — report input. */\n\tgetAllIntentAgreements(modelRef?: string): ToolSelectionIntentAgreement[] {\n\t\tconst host = this.load().hosts[this.fingerprint().id];\n\t\treturn Object.values(host?.intentAgreement ?? {})\n\t\t\t.filter((record) => modelRef === undefined || record.modelRef === modelRef)\n\t\t\t.map((record) => ({ ...record }));\n\t}\n\n\trecordValidation(\n\t\tkey: ToolPerformanceKey,\n\t\toutcome: \"repaired\" | \"bounced\",\n\t\tat = new Date().toISOString(),\n\t): ToolPerformanceStats {\n\t\tconst file = this.load();\n\t\tconst host = this.hostData(file);\n\t\tconst storageKey = statKey(key);\n\t\tconst current = host.stats[storageKey] ?? emptyStats(key, at);\n\t\tconst next: ToolPerformanceStats = {\n\t\t\t...current,\n\t\t\trepairCount: current.repairCount + (outcome === \"repaired\" ? 1 : 0),\n\t\t\tbounceCount: current.bounceCount + (outcome === \"bounced\" ? 1 : 0),\n\t\t\tlastUsedAt: at,\n\t\t};\n\t\thost.stats[storageKey] = next;\n\t\thost.stats = trimStats(host.stats);\n\t\tthis.save(file);\n\t\treturn { ...next };\n\t}\n\n\trecordExecution(observation: ToolExecutionObservation): ToolPerformanceStats {\n\t\tconst at = observation.at ?? new Date().toISOString();\n\t\tconst file = this.load();\n\t\tconst host = this.hostData(file);\n\t\tconst storageKey = statKey(observation.key);\n\t\tconst current = host.stats[storageKey] ?? emptyStats(observation.key, at);\n\t\tconst latencyMs = finiteNonNegative(observation.latencyMs);\n\t\tconst inputTokenEstimate = finiteNonNegative(observation.inputTokenEstimate);\n\t\tconst outputTokenEstimate = finiteNonNegative(observation.outputTokenEstimate);\n\t\tconst next: ToolPerformanceStats = {\n\t\t\t...current,\n\t\t\talpha: current.alpha + (observation.success ? 1 : 0),\n\t\t\tbeta: current.beta + (observation.success ? 0 : 1),\n\t\t\tsampleCount: current.sampleCount + 1,\n\t\t\tlatencyEwmaMs: updateEwma(current.latencyEwmaMs, latencyMs),\n\t\t\tlatencyDeviationEwmaMs: updateDeviation(current.latencyEwmaMs, current.latencyDeviationEwmaMs, latencyMs),\n\t\t\tinputTokenEstimateEwma: updateEwma(current.inputTokenEstimateEwma, inputTokenEstimate),\n\t\t\toutputTokenEstimateEwma: updateEwma(current.outputTokenEstimateEwma, outputTokenEstimate),\n\t\t\tfailureCount: current.failureCount + (observation.success ? 0 : 1),\n\t\t\tlastUsedAt: at,\n\t\t};\n\t\thost.stats[storageKey] = next;\n\t\thost.stats = trimStats(host.stats);\n\t\thost.observations.push({\n\t\t\t...observation.selection,\n\t\t\tat,\n\t\t\tmodelRef: observation.key.modelRef,\n\t\t\tintentClass: observation.key.intentClass,\n\t\t\tactualTool: observation.key.tool,\n\t\t\tsucceeded: observation.success,\n\t\t\tranked: observation.selection.ranked.slice(0, 6),\n\t\t\tshortlist: observation.selection.shortlist.slice(0, 3),\n\t\t\tlatencyMs,\n\t\t\tinputTokenEstimate,\n\t\t\toutputTokenEstimate,\n\t\t});\n\t\tif (host.observations.length > MAX_OBSERVATIONS_PER_HOST) {\n\t\t\thost.observations = host.observations.slice(-MAX_OBSERVATIONS_PER_HOST);\n\t\t}\n\n\t\t// Observe-mode agreement: did the RAW ranking's top pick (before any actual-tool-only\n\t\t// eligibility gating) match what the model actually called? Recorded durably per\n\t\t// (model,intent), separate from the capped `observations` log above, so it survives trimming.\n\t\tconst predictedBest = observation.selection.ranked[0]?.tool;\n\t\tconst agreed = predictedBest !== undefined && predictedBest === observation.key.tool;\n\t\tconst agreementKey = intentAgreementKey(observation.key.modelRef, observation.key.intentClass);\n\t\tconst currentAgreement =\n\t\t\thost.intentAgreement[agreementKey] ??\n\t\t\temptyIntentAgreement(observation.key.modelRef, observation.key.intentClass, at);\n\t\thost.intentAgreement[agreementKey] = {\n\t\t\t...currentAgreement,\n\t\t\tsampleCount: currentAgreement.sampleCount + 1,\n\t\t\tagreementCount: currentAgreement.agreementCount + (agreed ? 1 : 0),\n\t\t\thintActiveSampleCount: currentAgreement.hintActiveSampleCount + (observation.hintActiveAtCallTime ? 1 : 0),\n\t\t\thintActiveAgreementCount:\n\t\t\t\tcurrentAgreement.hintActiveAgreementCount + (observation.hintActiveAtCallTime && agreed ? 1 : 0),\n\t\t\tlastUpdatedAt: at,\n\t\t};\n\t\thost.intentAgreement = trimIntentAgreement(host.intentAgreement);\n\n\t\tthis.save(file);\n\t\treturn { ...next };\n\t}\n\n\tgetMetrics(modelRef?: string): ToolSelectionMetrics {\n\t\tconst host = this.load().hosts[this.fingerprint().id];\n\t\tconst observations = (host?.observations ?? []).filter(\n\t\t\t(observation) => modelRef === undefined || observation.modelRef === modelRef,\n\t\t);\n\t\tconst firstTools = observations.filter((observation) => observation.firstTool);\n\t\tconst recommended = observations.filter((observation) => observation.disposition === \"recommend\");\n\t\tconst average = (values: Array<number | undefined>): number | undefined => {\n\t\t\tconst present = values.filter((value): value is number => value !== undefined);\n\t\t\treturn present.length > 0 ? present.reduce((sum, value) => sum + value, 0) / present.length : undefined;\n\t\t};\n\t\treturn {\n\t\t\tfirstToolAttempts: firstTools.length,\n\t\t\tfirstToolSuccesses: firstTools.filter((observation) => observation.succeeded).length,\n\t\t\twrongToolOrFailureCount: observations.filter(\n\t\t\t\t(observation) =>\n\t\t\t\t\t!observation.succeeded ||\n\t\t\t\t\t(observation.disposition === \"recommend\" && observation.recommendation !== observation.actualTool),\n\t\t\t).length,\n\t\t\trecommendationCount: recommended.length,\n\t\t\trecommendationMatchedCount: recommended.filter(\n\t\t\t\t(observation) => observation.recommendation === observation.actualTool,\n\t\t\t).length,\n\t\t\tshortlistCount: observations.filter((observation) => observation.disposition === \"shortlist\").length,\n\t\t\tabstentionCount: observations.filter((observation) => observation.disposition === \"abstain\").length,\n\t\t\taverageLatencyMs: average(observations.map((observation) => observation.latencyMs)),\n\t\t\taverageInputTokenEstimate: average(observations.map((observation) => observation.inputTokenEstimate)),\n\t\t\taverageOutputTokenEstimate: average(observations.map((observation) => observation.outputTokenEstimate)),\n\t\t};\n\t}\n\n\tgetObservations(modelRef?: string): ToolSelectionObservation[] {\n\t\tconst host = this.load().hosts[this.fingerprint().id];\n\t\treturn (host?.observations ?? [])\n\t\t\t.filter((observation) => modelRef === undefined || observation.modelRef === modelRef)\n\t\t\t.map((observation) => ({\n\t\t\t\t...observation,\n\t\t\t\tshortlist: [...observation.shortlist],\n\t\t\t\tranked: observation.ranked.map((candidate) => ({ ...candidate })),\n\t\t\t}));\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool-performance-store.d.ts","sourceRoot":"","sources":["../../../src/core/tool-selection/tool-performance-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { stateFile } from \"../agent-paths.ts\";\nimport { type HostFingerprint, HostStateStore, isHostFingerprint } from \"../models/host-state-store.ts\";\nimport { isWorkerSession } from \"../session-role.ts\";\nimport { isRecordObject } from \"../util/value-guards.ts\";\n\nconst STORE_VERSION = 1;\nconst MAX_STATS_PER_HOST = 500;\nconst MAX_OBSERVATIONS_PER_HOST = 1_000;\nconst MAX_INTENT_AGREEMENT_PER_HOST = 500;\nconst EWMA_ALPHA = 0.25;\n\nexport type ToolSelectionIntentClass = \"read\" | \"search\" | \"execute\" | \"write\" | \"retrieve\" | \"explain\" | \"other\";\n\nexport interface ToolPerformanceKey {\n\tmodelRef: string;\n\tintentClass: ToolSelectionIntentClass;\n\ttool: string;\n}\n\nexport interface ToolPerformanceStats extends ToolPerformanceKey {\n\talpha: number;\n\tbeta: number;\n\tsampleCount: number;\n\tlatencyEwmaMs?: number;\n\tlatencyDeviationEwmaMs?: number;\n\tinputTokenEstimateEwma?: number;\n\toutputTokenEstimateEwma?: number;\n\trepairCount: number;\n\tbounceCount: number;\n\tfailureCount: number;\n\tlastUsedAt: string;\n}\n\nexport interface ToolSelectionObservation {\n\tat: string;\n\tmodelRef: string;\n\tintentClass: ToolSelectionIntentClass;\n\tactualTool: string;\n\tfirstTool: boolean;\n\tsucceeded: boolean;\n\tdisposition: \"recommend\" | \"shortlist\" | \"abstain\";\n\trecommendation?: string;\n\tshortlist: string[];\n\tentropy: number;\n\tmargin: number;\n\t/** Redacted ranking: names and numeric scores only, never prompts, arguments, paths, or output. */\n\tranked: Array<{ tool: string; utility: number; probability: number }>;\n\tlatencyMs?: number;\n\tinputTokenEstimate?: number;\n\toutputTokenEstimate?: number;\n}\n\nexport interface ToolSelectionMetrics {\n\tfirstToolAttempts: number;\n\tfirstToolSuccesses: number;\n\twrongToolOrFailureCount: number;\n\trecommendationCount: number;\n\trecommendationMatchedCount: number;\n\tshortlistCount: number;\n\tabstentionCount: number;\n\taverageLatencyMs?: number;\n\taverageInputTokenEstimate?: number;\n\taverageOutputTokenEstimate?: number;\n}\n\n/**\n * Durable, per-(model,intent) aggregate of the observe-mode loop: does the raw expected-utility\n * ranking's top pick (`ToolSelectionObservation.ranked[0]`) match what the model actually called\n * (`ToolSelectionObservation.actualTool`)? Tracked separately from the capped, rolling\n * `observations` log so evidence for a given (model,intent) pair survives that log's trimming.\n * `hintActive*` fields are the SAME agreement measure, but restricted to calls made while an\n * evidence-gated promotion hint (see promotion.ts) was active for this bucket — the hint's own\n * efficacy trace: it never gates activation directly (that is always\n * recomputed live from `ToolPerformanceStats`), but it is the durable evidence a report can show\n * for \"is the hint still earning its keep\".\n */\nexport interface ToolSelectionIntentAgreement {\n\tmodelRef: string;\n\tintentClass: ToolSelectionIntentClass;\n\tsampleCount: number;\n\tagreementCount: number;\n\thintActiveSampleCount: number;\n\thintActiveAgreementCount: number;\n\tlastUpdatedAt: string;\n}\n\ninterface HostToolPerformanceData {\n\thost: HostFingerprint;\n\tstats: Record<string, ToolPerformanceStats>;\n\tobservations: ToolSelectionObservation[];\n\tintentAgreement: Record<string, ToolSelectionIntentAgreement>;\n}\n\nexport interface ToolExecutionObservation {\n\tkey: ToolPerformanceKey;\n\tsuccess: boolean;\n\tlatencyMs: number;\n\tinputTokenEstimate?: number;\n\toutputTokenEstimate?: number;\n\tselection: Omit<ToolSelectionObservation, \"at\" | \"modelRef\" | \"intentClass\" | \"actualTool\" | \"succeeded\">;\n\tat?: string;\n\t/**\n\t * Whether an evidence-gated promotion hint (promotion.ts) was already active for this\n\t * (model,intent) bucket BEFORE this call was recorded — captured by the controller at\n\t * `begin()` time, so it reflects evidence up to but not including this observation. Used only\n\t * to bucket the durable agreement stats (`ToolSelectionIntentAgreement.hintActive*`); never\n\t * changes what gets recorded, only how it is split for the efficacy report.\n\t */\n\thintActiveAtCallTime?: boolean;\n}\n\nfunction statKey(key: ToolPerformanceKey): string {\n\treturn `${key.modelRef}\\0${key.intentClass}\\0${key.tool}`;\n}\n\nfunction intentAgreementKey(modelRef: string, intentClass: ToolSelectionIntentClass): string {\n\treturn `${modelRef}\\0${intentClass}`;\n}\n\nfunction isIntentClass(value: unknown): value is ToolSelectionIntentClass {\n\treturn (\n\t\tvalue === \"read\" ||\n\t\tvalue === \"search\" ||\n\t\tvalue === \"execute\" ||\n\t\tvalue === \"write\" ||\n\t\tvalue === \"retrieve\" ||\n\t\tvalue === \"explain\" ||\n\t\tvalue === \"other\"\n\t);\n}\n\nfunction isStats(value: unknown): value is ToolPerformanceStats {\n\treturn (\n\t\tisRecordObject(value) &&\n\t\ttypeof value.modelRef === \"string\" &&\n\t\tisIntentClass(value.intentClass) &&\n\t\ttypeof value.tool === \"string\" &&\n\t\ttypeof value.alpha === \"number\" &&\n\t\ttypeof value.beta === \"number\" &&\n\t\ttypeof value.sampleCount === \"number\" &&\n\t\ttypeof value.repairCount === \"number\" &&\n\t\ttypeof value.bounceCount === \"number\" &&\n\t\ttypeof value.failureCount === \"number\" &&\n\t\ttypeof value.lastUsedAt === \"string\"\n\t);\n}\n\nfunction isObservation(value: unknown): value is ToolSelectionObservation {\n\treturn (\n\t\tisRecordObject(value) &&\n\t\ttypeof value.at === \"string\" &&\n\t\ttypeof value.modelRef === \"string\" &&\n\t\tisIntentClass(value.intentClass) &&\n\t\ttypeof value.actualTool === \"string\" &&\n\t\ttypeof value.firstTool === \"boolean\" &&\n\t\ttypeof value.succeeded === \"boolean\" &&\n\t\t(value.disposition === \"recommend\" || value.disposition === \"shortlist\" || value.disposition === \"abstain\") &&\n\t\tArray.isArray(value.shortlist) &&\n\t\tvalue.shortlist.every((tool) => typeof tool === \"string\") &&\n\t\ttypeof value.entropy === \"number\" &&\n\t\ttypeof value.margin === \"number\" &&\n\t\tArray.isArray(value.ranked) &&\n\t\tvalue.ranked.every(\n\t\t\t(entry) =>\n\t\t\t\tisRecordObject(entry) &&\n\t\t\t\ttypeof entry.tool === \"string\" &&\n\t\t\t\ttypeof entry.utility === \"number\" &&\n\t\t\t\ttypeof entry.probability === \"number\",\n\t\t) &&\n\t\t(value.latencyMs === undefined || typeof value.latencyMs === \"number\") &&\n\t\t(value.inputTokenEstimate === undefined || typeof value.inputTokenEstimate === \"number\") &&\n\t\t(value.outputTokenEstimate === undefined || typeof value.outputTokenEstimate === \"number\")\n\t);\n}\n\nfunction isIntentAgreement(value: unknown): value is ToolSelectionIntentAgreement {\n\treturn (\n\t\tisRecordObject(value) &&\n\t\ttypeof value.modelRef === \"string\" &&\n\t\tisIntentClass(value.intentClass) &&\n\t\ttypeof value.sampleCount === \"number\" &&\n\t\ttypeof value.agreementCount === \"number\" &&\n\t\ttypeof value.hintActiveSampleCount === \"number\" &&\n\t\ttypeof value.hintActiveAgreementCount === \"number\" &&\n\t\ttypeof value.lastUpdatedAt === \"string\"\n\t);\n}\n\nfunction emptyStats(key: ToolPerformanceKey, at: string): ToolPerformanceStats {\n\treturn {\n\t\t...key,\n\t\talpha: 1,\n\t\tbeta: 1,\n\t\tsampleCount: 0,\n\t\trepairCount: 0,\n\t\tbounceCount: 0,\n\t\tfailureCount: 0,\n\t\tlastUsedAt: at,\n\t};\n}\n\nfunction emptyIntentAgreement(\n\tmodelRef: string,\n\tintentClass: ToolSelectionIntentClass,\n\tat: string,\n): ToolSelectionIntentAgreement {\n\treturn {\n\t\tmodelRef,\n\t\tintentClass,\n\t\tsampleCount: 0,\n\t\tagreementCount: 0,\n\t\thintActiveSampleCount: 0,\n\t\thintActiveAgreementCount: 0,\n\t\tlastUpdatedAt: at,\n\t};\n}\n\nfunction finiteNonNegative(value: number | undefined): number | undefined {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0 ? value : undefined;\n}\n\nfunction updateEwma(previous: number | undefined, next: number | undefined): number | undefined {\n\tif (next === undefined) return previous;\n\treturn previous === undefined ? next : previous + EWMA_ALPHA * (next - previous);\n}\n\nfunction updateDeviation(\n\tpreviousValue: number | undefined,\n\tpreviousDeviation: number | undefined,\n\tnext: number | undefined,\n): number | undefined {\n\tif (next === undefined) return previousDeviation;\n\tconst deviation = previousValue === undefined ? 0 : Math.abs(next - previousValue);\n\treturn updateEwma(previousDeviation, deviation);\n}\n\nfunction parseHost(value: unknown, hostId: string): HostToolPerformanceData | undefined {\n\tif (\n\t\t!isRecordObject(value) ||\n\t\t!isHostFingerprint(value.host) ||\n\t\tvalue.host.id !== hostId ||\n\t\t!isRecordObject(value.stats) ||\n\t\t!Array.isArray(value.observations)\n\t)\n\t\treturn undefined;\n\tconst host = value.host;\n\t// intentAgreement is a purely additive field (older store files predate it) — tolerate absence\n\t// rather than bumping STORE_VERSION, same as any other backward-compatible default-empty field.\n\tconst intentAgreementRaw = isRecordObject(value.intentAgreement) ? value.intentAgreement : {};\n\treturn {\n\t\thost,\n\t\tstats: Object.fromEntries(\n\t\t\tObject.entries(value.stats).filter((entry): entry is [string, ToolPerformanceStats] => isStats(entry[1])),\n\t\t),\n\t\tobservations: value.observations.filter(isObservation),\n\t\tintentAgreement: Object.fromEntries(\n\t\t\tObject.entries(intentAgreementRaw).filter((entry): entry is [string, ToolSelectionIntentAgreement] =>\n\t\t\t\tisIntentAgreement(entry[1]),\n\t\t\t),\n\t\t),\n\t};\n}\n\nfunction trimStats(stats: Record<string, ToolPerformanceStats>): Record<string, ToolPerformanceStats> {\n\tconst entries = Object.entries(stats);\n\tif (entries.length <= MAX_STATS_PER_HOST) return stats;\n\treturn Object.fromEntries(\n\t\tentries\n\t\t\t.sort(([, left], [, right]) => Date.parse(right.lastUsedAt) - Date.parse(left.lastUsedAt))\n\t\t\t.slice(0, MAX_STATS_PER_HOST),\n\t);\n}\n\nfunction trimIntentAgreement(\n\trecords: Record<string, ToolSelectionIntentAgreement>,\n): Record<string, ToolSelectionIntentAgreement> {\n\tconst entries = Object.entries(records);\n\tif (entries.length <= MAX_INTENT_AGREEMENT_PER_HOST) return records;\n\treturn Object.fromEntries(\n\t\tentries\n\t\t\t.sort(([, left], [, right]) => Date.parse(right.lastUpdatedAt) - Date.parse(left.lastUpdatedAt))\n\t\t\t.slice(0, MAX_INTENT_AGREEMENT_PER_HOST),\n\t);\n}\n\nexport class ToolPerformanceStore {\n\tprivate readonly storage: HostStateStore<HostToolPerformanceData>;\n\n\tconstructor(filePath: string, options: { fingerprint?: () => HostFingerprint; readOnly?: boolean } = {}) {\n\t\tthis.storage = new HostStateStore({\n\t\t\tfilePath,\n\t\t\tversion: STORE_VERSION,\n\t\t\tfingerprint: options.fingerprint,\n\t\t\treadOnly: options.readOnly ?? isWorkerSession(),\n\t\t\tparseHost,\n\t\t});\n\t}\n\n\tstatic forAgentDir(\n\t\tagentDir: string,\n\t\toptions: { fingerprint?: () => HostFingerprint; readOnly?: boolean } = {},\n\t): ToolPerformanceStore {\n\t\treturn new ToolPerformanceStore(stateFile(agentDir, \"tool-performance.json\"), options);\n\t}\n\n\tprivate createHostData(host: HostFingerprint): HostToolPerformanceData {\n\t\treturn { host, stats: {}, observations: [], intentAgreement: {} };\n\t}\n\n\tget(key: ToolPerformanceKey): ToolPerformanceStats {\n\t\tconst host = this.storage.getHost();\n\t\tconst stats = host?.stats[statKey(key)];\n\t\treturn stats ? { ...stats } : emptyStats(key, new Date(0).toISOString());\n\t}\n\n\t/** Every per-tool track record recorded for a (model,intent) bucket — the promotion.ts input. */\n\tgetStatsForIntent(modelRef: string, intentClass: ToolSelectionIntentClass): ToolPerformanceStats[] {\n\t\tconst host = this.storage.getHost();\n\t\tif (!host) return [];\n\t\treturn Object.values(host.stats)\n\t\t\t.filter((stats) => stats.modelRef === modelRef && stats.intentClass === intentClass)\n\t\t\t.map((stats) => ({ ...stats }));\n\t}\n\n\t/** Durable observe-mode agreement for one (model,intent) bucket (see {@link ToolSelectionIntentAgreement}). */\n\tgetIntentAgreement(modelRef: string, intentClass: ToolSelectionIntentClass): ToolSelectionIntentAgreement {\n\t\tconst host = this.storage.getHost();\n\t\tconst record = host?.intentAgreement[intentAgreementKey(modelRef, intentClass)];\n\t\treturn record ? { ...record } : emptyIntentAgreement(modelRef, intentClass, new Date(0).toISOString());\n\t}\n\n\t/** All recorded (model,intent) agreement buckets, optionally scoped to one model — report input. */\n\tgetAllIntentAgreements(modelRef?: string): ToolSelectionIntentAgreement[] {\n\t\tconst host = this.storage.getHost();\n\t\treturn Object.values(host?.intentAgreement ?? {})\n\t\t\t.filter((record) => modelRef === undefined || record.modelRef === modelRef)\n\t\t\t.map((record) => ({ ...record }));\n\t}\n\n\trecordValidation(\n\t\tkey: ToolPerformanceKey,\n\t\toutcome: \"repaired\" | \"bounced\",\n\t\tat = new Date().toISOString(),\n\t): ToolPerformanceStats {\n\t\treturn this.storage.mutateCurrentHost(\n\t\t\t(host) => this.createHostData(host),\n\t\t\t(host) => {\n\t\t\t\tconst storageKey = statKey(key);\n\t\t\t\tconst current = host.stats[storageKey] ?? emptyStats(key, at);\n\t\t\t\tconst next: ToolPerformanceStats = {\n\t\t\t\t\t...current,\n\t\t\t\t\trepairCount: current.repairCount + (outcome === \"repaired\" ? 1 : 0),\n\t\t\t\t\tbounceCount: current.bounceCount + (outcome === \"bounced\" ? 1 : 0),\n\t\t\t\t\tlastUsedAt: at,\n\t\t\t\t};\n\t\t\t\thost.stats[storageKey] = next;\n\t\t\t\thost.stats = trimStats(host.stats);\n\t\t\t\treturn { result: { ...next }, changed: true };\n\t\t\t},\n\t\t);\n\t}\n\n\trecordExecution(observation: ToolExecutionObservation): ToolPerformanceStats {\n\t\tconst at = observation.at ?? new Date().toISOString();\n\t\treturn this.storage.mutateCurrentHost(\n\t\t\t(host) => this.createHostData(host),\n\t\t\t(host) => {\n\t\t\t\tconst storageKey = statKey(observation.key);\n\t\t\t\tconst current = host.stats[storageKey] ?? emptyStats(observation.key, at);\n\t\t\t\tconst latencyMs = finiteNonNegative(observation.latencyMs);\n\t\t\t\tconst inputTokenEstimate = finiteNonNegative(observation.inputTokenEstimate);\n\t\t\t\tconst outputTokenEstimate = finiteNonNegative(observation.outputTokenEstimate);\n\t\t\t\tconst next: ToolPerformanceStats = {\n\t\t\t\t\t...current,\n\t\t\t\t\talpha: current.alpha + (observation.success ? 1 : 0),\n\t\t\t\t\tbeta: current.beta + (observation.success ? 0 : 1),\n\t\t\t\t\tsampleCount: current.sampleCount + 1,\n\t\t\t\t\tlatencyEwmaMs: updateEwma(current.latencyEwmaMs, latencyMs),\n\t\t\t\t\tlatencyDeviationEwmaMs: updateDeviation(\n\t\t\t\t\t\tcurrent.latencyEwmaMs,\n\t\t\t\t\t\tcurrent.latencyDeviationEwmaMs,\n\t\t\t\t\t\tlatencyMs,\n\t\t\t\t\t),\n\t\t\t\t\tinputTokenEstimateEwma: updateEwma(current.inputTokenEstimateEwma, inputTokenEstimate),\n\t\t\t\t\toutputTokenEstimateEwma: updateEwma(current.outputTokenEstimateEwma, outputTokenEstimate),\n\t\t\t\t\tfailureCount: current.failureCount + (observation.success ? 0 : 1),\n\t\t\t\t\tlastUsedAt: at,\n\t\t\t\t};\n\t\t\t\thost.stats[storageKey] = next;\n\t\t\t\thost.stats = trimStats(host.stats);\n\t\t\t\thost.observations.push({\n\t\t\t\t\t...observation.selection,\n\t\t\t\t\tat,\n\t\t\t\t\tmodelRef: observation.key.modelRef,\n\t\t\t\t\tintentClass: observation.key.intentClass,\n\t\t\t\t\tactualTool: observation.key.tool,\n\t\t\t\t\tsucceeded: observation.success,\n\t\t\t\t\tranked: observation.selection.ranked.slice(0, 6),\n\t\t\t\t\tshortlist: observation.selection.shortlist.slice(0, 3),\n\t\t\t\t\tlatencyMs,\n\t\t\t\t\tinputTokenEstimate,\n\t\t\t\t\toutputTokenEstimate,\n\t\t\t\t});\n\t\t\t\tif (host.observations.length > MAX_OBSERVATIONS_PER_HOST) {\n\t\t\t\t\thost.observations = host.observations.slice(-MAX_OBSERVATIONS_PER_HOST);\n\t\t\t\t}\n\n\t\t\t\t// Observe-mode agreement: did the RAW ranking's top pick (before any actual-tool-only\n\t\t\t\t// eligibility gating) match what the model actually called? Recorded durably per\n\t\t\t\t// (model,intent), separate from the capped `observations` log above, so it survives trimming.\n\t\t\t\tconst predictedBest = observation.selection.ranked[0]?.tool;\n\t\t\t\tconst agreed = predictedBest !== undefined && predictedBest === observation.key.tool;\n\t\t\t\tconst agreementKey = intentAgreementKey(observation.key.modelRef, observation.key.intentClass);\n\t\t\t\tconst currentAgreement =\n\t\t\t\t\thost.intentAgreement[agreementKey] ??\n\t\t\t\t\temptyIntentAgreement(observation.key.modelRef, observation.key.intentClass, at);\n\t\t\t\thost.intentAgreement[agreementKey] = {\n\t\t\t\t\t...currentAgreement,\n\t\t\t\t\tsampleCount: currentAgreement.sampleCount + 1,\n\t\t\t\t\tagreementCount: currentAgreement.agreementCount + (agreed ? 1 : 0),\n\t\t\t\t\thintActiveSampleCount:\n\t\t\t\t\t\tcurrentAgreement.hintActiveSampleCount + (observation.hintActiveAtCallTime ? 1 : 0),\n\t\t\t\t\thintActiveAgreementCount:\n\t\t\t\t\t\tcurrentAgreement.hintActiveAgreementCount + (observation.hintActiveAtCallTime && agreed ? 1 : 0),\n\t\t\t\t\tlastUpdatedAt: at,\n\t\t\t\t};\n\t\t\t\thost.intentAgreement = trimIntentAgreement(host.intentAgreement);\n\n\t\t\t\treturn { result: { ...next }, changed: true };\n\t\t\t},\n\t\t);\n\t}\n\n\tgetMetrics(modelRef?: string): ToolSelectionMetrics {\n\t\tconst host = this.storage.getHost();\n\t\tconst observations = (host?.observations ?? []).filter(\n\t\t\t(observation) => modelRef === undefined || observation.modelRef === modelRef,\n\t\t);\n\t\tconst firstTools = observations.filter((observation) => observation.firstTool);\n\t\tconst recommended = observations.filter((observation) => observation.disposition === \"recommend\");\n\t\tconst average = (values: Array<number | undefined>): number | undefined => {\n\t\t\tconst present = values.filter((value): value is number => value !== undefined);\n\t\t\treturn present.length > 0 ? present.reduce((sum, value) => sum + value, 0) / present.length : undefined;\n\t\t};\n\t\treturn {\n\t\t\tfirstToolAttempts: firstTools.length,\n\t\t\tfirstToolSuccesses: firstTools.filter((observation) => observation.succeeded).length,\n\t\t\twrongToolOrFailureCount: observations.filter(\n\t\t\t\t(observation) =>\n\t\t\t\t\t!observation.succeeded ||\n\t\t\t\t\t(observation.disposition === \"recommend\" && observation.recommendation !== observation.actualTool),\n\t\t\t).length,\n\t\t\trecommendationCount: recommended.length,\n\t\t\trecommendationMatchedCount: recommended.filter(\n\t\t\t\t(observation) => observation.recommendation === observation.actualTool,\n\t\t\t).length,\n\t\t\tshortlistCount: observations.filter((observation) => observation.disposition === \"shortlist\").length,\n\t\t\tabstentionCount: observations.filter((observation) => observation.disposition === \"abstain\").length,\n\t\t\taverageLatencyMs: average(observations.map((observation) => observation.latencyMs)),\n\t\t\taverageInputTokenEstimate: average(observations.map((observation) => observation.inputTokenEstimate)),\n\t\t\taverageOutputTokenEstimate: average(observations.map((observation) => observation.outputTokenEstimate)),\n\t\t};\n\t}\n\n\tgetObservations(modelRef?: string): ToolSelectionObservation[] {\n\t\tconst host = this.storage.getHost();\n\t\treturn (host?.observations ?? [])\n\t\t\t.filter((observation) => modelRef === undefined || observation.modelRef === modelRef)\n\t\t\t.map((observation) => ({\n\t\t\t\t...observation,\n\t\t\t\tshortlist: [...observation.shortlist],\n\t\t\t\tranked: observation.ranked.map((candidate) => ({ ...candidate })),\n\t\t\t}));\n\t}\n}\n"]}
|