comisai 1.0.27 → 1.0.30
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/node_modules/@comis/agent/dist/bootstrap/sections/tool-descriptions.js +62 -8
- package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.js +3 -1
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +7 -0
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +26 -0
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.d.ts +21 -0
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.js +29 -9
- package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.d.ts +10 -2
- package/node_modules/@comis/agent/dist/context-engine/signature-surrogate-guard.js +15 -9
- package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.d.ts +17 -2
- package/node_modules/@comis/agent/dist/context-engine/thinking-block-cleaner.js +19 -8
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +28 -0
- package/node_modules/@comis/agent/dist/executor/executor-response-filter.js +3 -0
- package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +3 -1
- package/node_modules/@comis/agent/dist/executor/phase-filter.d.ts +20 -4
- package/node_modules/@comis/agent/dist/executor/phase-filter.js +62 -19
- package/node_modules/@comis/agent/dist/executor/pi-executor.js +6 -0
- package/node_modules/@comis/agent/dist/executor/stream-wrappers/config-resolver.js +2 -3
- package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.js +2 -3
- package/node_modules/@comis/agent/dist/executor/ttl-guard.js +2 -3
- package/node_modules/@comis/agent/dist/index.d.ts +4 -2
- package/node_modules/@comis/agent/dist/index.js +3 -2
- package/node_modules/@comis/agent/dist/model/compaction-model-resolver.d.ts +41 -0
- package/node_modules/@comis/agent/dist/model/compaction-model-resolver.js +51 -0
- package/node_modules/@comis/agent/dist/model/model-registry-adapter.js +113 -26
- package/node_modules/@comis/agent/dist/model/model-scanner.d.ts +27 -0
- package/node_modules/@comis/agent/dist/model/model-scanner.js +64 -23
- package/node_modules/@comis/agent/dist/model/operation-model-defaults.d.ts +37 -15
- package/node_modules/@comis/agent/dist/model/operation-model-defaults.js +70 -25
- package/node_modules/@comis/agent/dist/model/operation-model-resolver.d.ts +2 -2
- package/node_modules/@comis/agent/dist/model/operation-model-resolver.js +12 -8
- package/node_modules/@comis/agent/dist/provider/capabilities.d.ts +21 -0
- package/node_modules/@comis/agent/dist/provider/capabilities.js +28 -0
- package/node_modules/@comis/agent/dist/session/orphaned-message-repair.js +61 -1
- package/node_modules/@comis/agent/dist/workspace/templates.js +1 -1
- package/node_modules/@comis/agent/package.json +1 -1
- package/node_modules/@comis/channels/dist/shared/channel-manager.d.ts +19 -1
- package/node_modules/@comis/channels/dist/shared/channel-manager.js +59 -3
- package/node_modules/@comis/channels/dist/shared/deliver-to-channel.d.ts +10 -0
- package/node_modules/@comis/channels/dist/shared/deliver-to-channel.js +25 -10
- package/node_modules/@comis/channels/dist/shared/execution-deliver.d.ts +1 -1
- package/node_modules/@comis/channels/dist/shared/execution-deliver.js +1 -1
- package/node_modules/@comis/channels/dist/shared/execution-pipeline.d.ts +8 -0
- package/node_modules/@comis/channels/dist/shared/inbound-gate.js +21 -3
- package/node_modules/@comis/channels/dist/shared/inbound-pipeline.d.ts +8 -0
- package/node_modules/@comis/channels/dist/shared/inbound-route.d.ts +1 -1
- package/node_modules/@comis/channels/dist/shared/inbound-route.js +1 -0
- package/node_modules/@comis/channels/dist/telegram/message-mapper.d.ts +18 -1
- package/node_modules/@comis/channels/dist/telegram/message-mapper.js +95 -1
- package/node_modules/@comis/channels/dist/telegram/telegram-adapter.js +7 -1
- package/node_modules/@comis/channels/package.json +1 -1
- package/node_modules/@comis/cli/package.json +1 -1
- package/node_modules/@comis/core/dist/config/schema-agent.d.ts +15 -3
- package/node_modules/@comis/core/dist/config/schema-agent.js +6 -2
- package/node_modules/@comis/core/dist/config/schema-integrations.d.ts +4 -4
- package/node_modules/@comis/core/dist/config/schema-integrations.js +3 -3
- package/node_modules/@comis/core/dist/config/schema-models.d.ts +4 -2
- package/node_modules/@comis/core/dist/config/schema-models.js +4 -2
- package/node_modules/@comis/core/package.json +1 -1
- package/node_modules/@comis/daemon/dist/daemon.js +74 -9
- package/node_modules/@comis/daemon/dist/rpc/agent-handlers.js +40 -9
- package/node_modules/@comis/daemon/dist/rpc/builtin-provider-guard.d.ts +16 -0
- package/node_modules/@comis/daemon/dist/rpc/builtin-provider-guard.js +60 -0
- package/node_modules/@comis/daemon/dist/rpc/config-handlers.js +59 -0
- package/node_modules/@comis/daemon/dist/rpc/credential-resolver.d.ts +17 -0
- package/node_modules/@comis/daemon/dist/rpc/credential-resolver.js +99 -0
- package/node_modules/@comis/daemon/dist/rpc/message-handlers.d.ts +5 -0
- package/node_modules/@comis/daemon/dist/rpc/message-handlers.js +25 -4
- package/node_modules/@comis/daemon/dist/rpc/model-handlers.d.ts +4 -3
- package/node_modules/@comis/daemon/dist/rpc/model-handlers.js +21 -3
- package/node_modules/@comis/daemon/dist/rpc/provider-handlers.js +82 -6
- package/node_modules/@comis/daemon/dist/rpc/rpc-dispatch.d.ts +4 -0
- package/node_modules/@comis/daemon/dist/wiring/inbound-message-id-resolver.d.ts +48 -0
- package/node_modules/@comis/daemon/dist/wiring/inbound-message-id-resolver.js +58 -0
- package/node_modules/@comis/daemon/dist/wiring/restart-continuation.d.ts +10 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.d.ts +18 -6
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +98 -46
- package/node_modules/@comis/daemon/dist/wiring/setup-channels.d.ts +13 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +2 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-gateway-rpc.js +1 -1
- package/node_modules/@comis/daemon/package.json +2 -2
- package/node_modules/@comis/gateway/package.json +1 -1
- package/node_modules/@comis/infra/package.json +1 -1
- package/node_modules/@comis/memory/package.json +1 -1
- package/node_modules/@comis/scheduler/package.json +1 -1
- package/node_modules/@comis/shared/package.json +1 -1
- package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.d.ts +1 -1
- package/node_modules/@comis/skills/dist/bridge/mcp-tool-bridge.js +1 -1
- package/node_modules/@comis/skills/dist/bridge/tool-audit.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/exec-tool.d.ts +12 -11
- package/node_modules/@comis/skills/dist/builtin/exec-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/file/apply-patch-tool.d.ts +3 -2
- package/node_modules/@comis/skills/dist/builtin/file/apply-patch-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/file-tools/edit-tool.d.ts +7 -6
- package/node_modules/@comis/skills/dist/builtin/file-tools/edit-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/file-tools/find-tool.d.ts +6 -5
- package/node_modules/@comis/skills/dist/builtin/file-tools/find-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/file-tools/grep-tool.d.ts +16 -15
- package/node_modules/@comis/skills/dist/builtin/file-tools/grep-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/file-tools/ls-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/file-tools/ls-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/file-tools/notebook-edit-tool.d.ts +7 -6
- package/node_modules/@comis/skills/dist/builtin/file-tools/notebook-edit-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/file-tools/read-tool.d.ts +6 -5
- package/node_modules/@comis/skills/dist/builtin/file-tools/read-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/file-tools/write-tool.d.ts +5 -4
- package/node_modules/@comis/skills/dist/builtin/file-tools/write-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/admin-manage-factory.d.ts +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +28 -27
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/background-tasks-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/background-tasks-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/browser-tool-schema.d.ts +67 -66
- package/node_modules/@comis/skills/dist/builtin/platform/browser-tool-schema.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/channels-manage-tool.d.ts +6 -5
- package/node_modules/@comis/skills/dist/builtin/platform/channels-manage-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/cron-tool.d.ts +20 -19
- package/node_modules/@comis/skills/dist/builtin/platform/cron-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/ctx-expand-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/ctx-expand-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/ctx-inspect-tool.d.ts +3 -2
- package/node_modules/@comis/skills/dist/builtin/platform/ctx-inspect-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/ctx-recall-tool.d.ts +6 -5
- package/node_modules/@comis/skills/dist/builtin/platform/ctx-recall-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/ctx-search-tool.d.ts +6 -5
- package/node_modules/@comis/skills/dist/builtin/platform/ctx-search-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/describe-video-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/describe-video-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/discord-action-tool.d.ts +2 -1
- package/node_modules/@comis/skills/dist/builtin/platform/discord-action-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/extract-document-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/extract-document-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.d.ts +12 -11
- package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/heartbeat-manage-tool.d.ts +23 -22
- package/node_modules/@comis/skills/dist/builtin/platform/heartbeat-manage-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/image-generate-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/image-generate-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/image-tool.d.ts +8 -7
- package/node_modules/@comis/skills/dist/builtin/platform/image-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/mcp-manage-tool.d.ts +9 -8
- package/node_modules/@comis/skills/dist/builtin/platform/mcp-manage-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/memory-get-tool.d.ts +5 -4
- package/node_modules/@comis/skills/dist/builtin/platform/memory-get-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/memory-manage-tool.d.ts +12 -11
- package/node_modules/@comis/skills/dist/builtin/platform/memory-manage-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/memory-search-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/memory-search-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/memory-store-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/memory-store-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/message-tool.d.ts +32 -31
- package/node_modules/@comis/skills/dist/builtin/platform/message-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/messaging-factory.d.ts +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/models-manage-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/models-manage-tool.js +11 -4
- package/node_modules/@comis/skills/dist/builtin/platform/notify-tool.d.ts +6 -5
- package/node_modules/@comis/skills/dist/builtin/platform/notify-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/obs-query-tool.d.ts +11 -10
- package/node_modules/@comis/skills/dist/builtin/platform/obs-query-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/pipeline-tool.d.ts +37 -36
- package/node_modules/@comis/skills/dist/builtin/platform/pipeline-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/platform-action-tool.d.ts +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/providers-manage-tool.d.ts +21 -20
- package/node_modules/@comis/skills/dist/builtin/platform/providers-manage-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/session-search-tool.d.ts +6 -5
- package/node_modules/@comis/skills/dist/builtin/platform/session-search-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/session-status-tool.d.ts +3 -2
- package/node_modules/@comis/skills/dist/builtin/platform/session-status-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-history-tool.d.ts +5 -4
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-history-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-list-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-list-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-manage-tool.d.ts +5 -4
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-manage-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-send-tool.d.ts +7 -6
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-send-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-spawn-tool.d.ts +15 -14
- package/node_modules/@comis/skills/dist/builtin/platform/sessions-spawn-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/skills-manage-tool.d.ts +8 -7
- package/node_modules/@comis/skills/dist/builtin/platform/skills-manage-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/slack-action-tool.d.ts +2 -1
- package/node_modules/@comis/skills/dist/builtin/platform/slack-action-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/subagents-tool.d.ts +7 -6
- package/node_modules/@comis/skills/dist/builtin/platform/subagents-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/telegram-action-tool.d.ts +2 -1
- package/node_modules/@comis/skills/dist/builtin/platform/telegram-action-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/tokens-manage-tool.d.ts +5 -4
- package/node_modules/@comis/skills/dist/builtin/platform/tokens-manage-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/transcribe-audio-tool.d.ts +4 -3
- package/node_modules/@comis/skills/dist/builtin/platform/transcribe-audio-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/tts-tool.d.ts +6 -5
- package/node_modules/@comis/skills/dist/builtin/platform/tts-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/unified-context-tool.d.ts +13 -12
- package/node_modules/@comis/skills/dist/builtin/platform/unified-context-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/unified-memory-tool.d.ts +18 -17
- package/node_modules/@comis/skills/dist/builtin/platform/unified-memory-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/unified-session-tool.d.ts +11 -10
- package/node_modules/@comis/skills/dist/builtin/platform/unified-session-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/whatsapp-action-tool.d.ts +2 -1
- package/node_modules/@comis/skills/dist/builtin/platform/whatsapp-action-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/process-tool.d.ts +6 -5
- package/node_modules/@comis/skills/dist/builtin/process-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/web-fetch-tool.d.ts +5 -4
- package/node_modules/@comis/skills/dist/builtin/web-fetch-tool.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/web-search-tool.d.ts +9 -8
- package/node_modules/@comis/skills/dist/builtin/web-search-tool.js +1 -1
- package/node_modules/@comis/skills/package.json +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-detail-DqL6Artv.js → agent-detail-71BSbSfD.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-editor-CNM_h94Y.js → agent-editor-CTSDZhwT.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-list-Dbh-xD_F.js → agent-list-BEhni2ea.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{billing-view-C1DmtyzK.js → billing-view-DVP1IvVs.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{channel-detail-CtCH22N1.js → channel-detail-N_YK74xC.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{channel-list-C7xXn-60.js → channel-list-DRk6ZJaF.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{chat-console-C51pjFwk.js → chat-console-Dm-GtSf9.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{config-editor-BLArYRB7.js → config-editor-CIferYX6.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{context-dag-browser-fuyMinNI.js → context-dag-browser-CL84rXXM.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{context-engine-Bngf2bH0.js → context-engine-B1HOTEZv.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{delivery-view-C80hucxX.js → delivery-view-Y6JKYVFw.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{diagnostics-view-Cl4VbHZ6.js → diagnostics-view-DWV1UQjz.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-chat-message-ByFUoMm6.js → ic-chat-message-DfSERzzg.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-connection-dot-C4nDHgY2.js → ic-connection-dot-CXyhlJup.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-tool-call-Bh5kq-yY.js → ic-tool-call-DNmwTjek.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{index-BBkuC-EU.js → index-CBr0Tm9_.js} +2 -2
- package/node_modules/@comis/web/dist/assets/{mcp-management-DB-phOo7.js → mcp-management-BaH2-vox.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{media-config-CRqZ1ZUH.js → media-config-CZLshJoN.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{media-test-C9vE20Oy.js → media-test-C9NUWgo_.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{memory-inspector-CeqfnxMZ.js → memory-inspector-D_fmTcRN.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{message-center-Daup7Mof.js → message-center-BBFlNCZn.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{models-DLYnEU8E.js → models-BytGLm99.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{observe-view-BTSt_PO5.js → observe-view-VXtHqaqq.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-builder-DknfzyLt.js → pipeline-builder-CfXczlfJ.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-history-JnHZdeU_.js → pipeline-history-CPmXFnbe.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-history-detail-Dg4knsEb.js → pipeline-history-detail-DcueTMs9.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-list-AEnibjsp.js → pipeline-list-B-xG5WZh.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-monitor-DG7RbIOO.js → pipeline-monitor-pnIOYaSY.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{scheduler-uL1fYKAT.js → scheduler-BtUIFHhA.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{security-C3DywRLH.js → security-C8mWRq2y.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{session-detail-BtqCNWXV.js → session-detail-DgdkO5ka.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{session-list-CJXWa2XT.js → session-list-DcylcfTn.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{setup-wizard-ywn7oJvu.js → setup-wizard-BP5yjsuL.js} +75 -39
- package/node_modules/@comis/web/dist/assets/{skills-DX0KYnWD.js → skills-DXt1bX8Z.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{subagents-B8p5YJEB.js → subagents-C7YbUHXY.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{workspace-manager-CgzNIrw1.js → workspace-manager-DP6pW4wa.js} +1 -1
- package/node_modules/@comis/web/dist/index.html +1 -1
- package/node_modules/@comis/web/package.json +1 -1
- package/npm-shrinkwrap.json +6126 -0
- package/package.json +74 -74
|
@@ -18,6 +18,15 @@
|
|
|
18
18
|
* @module
|
|
19
19
|
*/
|
|
20
20
|
import { getToolMetadata } from "@comis/core";
|
|
21
|
+
import { getProviders } from "@mariozechner/pi-ai";
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Layer 1D (260430-vwt) -- live native-catalog provider list
|
|
24
|
+
//
|
|
25
|
+
// Computed once at module load time. Used by the providers_manage TOOL_GUIDE
|
|
26
|
+
// "Built-in vs Custom Provider Check" block below so the text reflects
|
|
27
|
+
// pi-ai's current native catalog without per-version source patches.
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
const _builtInProvidersList = [...getProviders()].sort().join(", ");
|
|
21
30
|
// ---------------------------------------------------------------------------
|
|
22
31
|
// TOOL_SUMMARIES: 5-8 word terse summaries (system prompt orientation)
|
|
23
32
|
// ---------------------------------------------------------------------------
|
|
@@ -272,24 +281,68 @@ Present a plan to the user before creating agents in batch.
|
|
|
272
281
|
Multiple agents can be created in one turn. Customize ALL workspace files for each agent after creation — or use single-call creation above to inline ROLE.md/IDENTITY.md and skip the post-create writes entirely.`,
|
|
273
282
|
providers_manage: `## Provider Configuration Guide
|
|
274
283
|
|
|
284
|
+
### Credential Pre-Check (MANDATORY before any provider switch)
|
|
285
|
+
BEFORE storing or switching, you MUST verify the credential exists. Never patch agents.*.provider, agents.*.model, call agents_manage update, call providers_manage create, or use gateway.patch on any agents.*.{provider,model} key without first running this 4-step flow:
|
|
286
|
+
|
|
287
|
+
1. **List existing keys** — gateway({ action: "env_list", filter: "<PROVIDER>*" })
|
|
288
|
+
Examples: filter "OPENROUTER*" / "ANTHROPIC*" / "GROQ*" / "DEEPSEEK*".
|
|
289
|
+
env_list returns only NAMES, never values — safe to call proactively.
|
|
290
|
+
Use the canonical name: <PROVIDER_UPPER>_API_KEY for cloud providers
|
|
291
|
+
(OPENROUTER_API_KEY, ANTHROPIC_API_KEY, GROQ_API_KEY, DEEPSEEK_API_KEY,
|
|
292
|
+
GEMINI_API_KEY for google, etc.). If env_list returns a non-canonical
|
|
293
|
+
name (e.g. "OR_KEY", "MY_OPENROUTER_KEY"), use that matched name verbatim
|
|
294
|
+
as apiKeyName. Local providers (ollama, lm-studio, vLLM) skip this step
|
|
295
|
+
entirely (no API key needed).
|
|
296
|
+
|
|
297
|
+
2. **Decide based on env_list result:**
|
|
298
|
+
a. **Match found** — use the matching env name as apiKeyName. Skip to step 4.
|
|
299
|
+
b. **No match** — ASK THE USER for the API key. Phrase it explicitly:
|
|
300
|
+
"I don't see a <KEY_NAME> configured. Please share your <Provider>
|
|
301
|
+
API key (signup link if relevant) and I'll store it before switching."
|
|
302
|
+
Do NOT proceed without the key. Do NOT invent a fake key. Do NOT
|
|
303
|
+
silently skip the switch.
|
|
304
|
+
|
|
305
|
+
3. **Store the key (only after the user supplies it)** —
|
|
306
|
+
gateway({ action: "env_set", env_key: "<KEY_NAME>", env_value: "<USER_PROVIDED_KEY>" })
|
|
307
|
+
|
|
308
|
+
4. **Now safe to switch** — call providers_manage create (for non-built-in)
|
|
309
|
+
or proceed directly to agents_manage update (for built-in). See the
|
|
310
|
+
"Built-in vs Custom Provider Check" and "Switching an Agent's Provider
|
|
311
|
+
or Model" sections below.
|
|
312
|
+
|
|
313
|
+
This rule applies UNCONDITIONALLY across ALL provider-switch paths:
|
|
314
|
+
- agents_manage update with new {provider, model}
|
|
315
|
+
- providers_manage create (the apiKeyName must reference a key already in env)
|
|
316
|
+
- gateway.patch agents.*.provider or agents.*.model
|
|
317
|
+
- providers_manage update changing apiKeyName
|
|
318
|
+
|
|
319
|
+
If the agent's primary will use a credential, you verify the credential exists FIRST. Skipping this check is the bug that causes "No API key found for <provider>" failures at the next chat turn — the user sees a generic "An error occurred" message and the bot silently breaks.
|
|
320
|
+
|
|
275
321
|
### Built-in vs Custom Provider Check (MANDATORY first step)
|
|
276
|
-
Before creating a custom provider, check if the model already exists in the built-in catalog. Built-in providers (
|
|
322
|
+
Before creating a custom provider, check if the model already exists in the built-in catalog. Built-in providers (${_builtInProvidersList}) already have their models registered — creating a redundant custom entry is wrong and will be ignored. Call models_manage({ action: "list_providers" }) for the live native-catalog list, or models_manage({ action: "list" }) for available models. Prefer list_providers over the static list above when you need an up-to-date roster.
|
|
277
323
|
|
|
278
|
-
If the model IS built-in: skip provider creation.
|
|
324
|
+
If the model IS built-in: skip provider creation. After credential pre-check passes (above), go straight to agents_manage update with the new provider/model pair (the credential is already in env from pre-check step 3, so apiKeyName resolution succeeds at the next session).
|
|
279
325
|
If the model is NOT built-in: you need a custom provider. Proceed to the steps below, but first gather ALL required configuration.
|
|
280
326
|
|
|
327
|
+
### Choosing the \`type\` Field (POST AUTO-PROMOTE FLOW)
|
|
328
|
+
After Layer 1C of the catalog-driven providers redesign, the \`type\` field follows two distinct rules depending on the provider name:
|
|
329
|
+
- **If \`provider_id\` matches a built-in name** (use models_manage list_providers to verify): OMIT \`type\` entirely from the create config. The daemon auto-promotes \`type\` to the native catalog name when \`provider_id\` matches a native entry AND no custom \`baseUrl\` is supplied. Setting \`type:"openai"\` for a built-in name still works (auto-promoted), but omitting it is cleaner.
|
|
330
|
+
- **If \`provider_id\` is a custom OpenAI-compatible proxy** (NVIDIA NIM, Together, Fireworks, etc.) NOT in the native catalog: set \`type:"openai"\` (or whatever wire-format API matches). Auto-promotion does not fire for non-catalog names.
|
|
331
|
+
- **If \`baseUrl\` differs from the native catalog URL** for a built-in name: this signals you want the OpenAI-passthrough shape (custom proxy that masquerades as the built-in). Auto-promotion is suppressed; the entry stays as \`type:"openai"\`.
|
|
332
|
+
|
|
281
333
|
### Information Gathering for Custom Providers
|
|
282
334
|
When creating a non-built-in provider, you MUST have: (1) the API base URL, (2) the exact model ID string, (3) the API protocol type. If the user did not supply all three:
|
|
283
335
|
1. Use web_search to look up the provider's API documentation (search for "<provider name> API base URL" or "<provider name> API docs").
|
|
284
336
|
2. If web search finds the information, use it to fill in the missing fields.
|
|
285
337
|
3. If web search does NOT find the information, ask the user to supply the missing fields before proceeding. Do NOT guess or invent URLs.
|
|
286
338
|
|
|
287
|
-
### Credential Workflow
|
|
288
|
-
API keys are NEVER stored in provider config
|
|
289
|
-
|
|
290
|
-
|
|
339
|
+
### Credential Workflow Summary
|
|
340
|
+
API keys are NEVER stored in provider config — they live in env (set via Credential Pre-Check step 3 above) and are referenced by name via apiKeyName. The Credential Pre-Check above is the canonical entry point; this section just documents what gets stored where:
|
|
341
|
+
- Env (~/.comis/.env): the API key value, keyed by name (e.g. OPENROUTER_API_KEY=sk-or-v1-...)
|
|
342
|
+
- providers.entries.<id>.apiKeyName: the env NAME (not the value)
|
|
343
|
+
- SecretManager / setRuntimeApiKey: comis populates this from the env at daemon boot and on hot-reload after env_set; agents never set it directly.
|
|
291
344
|
|
|
292
|
-
For local providers (Ollama, LM Studio, vLLM) that don't need API keys,
|
|
345
|
+
For local providers (Ollama, LM Studio, vLLM) that don't need API keys, the Credential Pre-Check is skipped (step 1 noted local providers skip); just call providers_manage create with \`apiKeyName\` omitted.
|
|
293
346
|
|
|
294
347
|
### After Creating a Provider
|
|
295
348
|
Switch an agent to use the new provider:
|
|
@@ -301,9 +354,10 @@ To switch an agent to a different provider/model, call agents_manage update with
|
|
|
301
354
|
|
|
302
355
|
\`agents.*.model\` and \`agents.*.provider\` are listed in MUTABLE_CONFIG_OVERRIDES, so the immutability guard does not block the patch.
|
|
303
356
|
|
|
304
|
-
**
|
|
357
|
+
**Three preconditions the LLM MUST verify before issuing the update:**
|
|
305
358
|
1. The target provider exists as a \`providers.entries.<provider_id>\` key. If it does not, call providers_manage create FIRST (and gateway env_set for the API key if needed). Patching an agent to a provider that has no entry resolves under the wrong provider family at the next session — the original bug.
|
|
306
359
|
2. The model id matches a \`models[].id\` in that provider entry (or is a built-in known to the pi-ai catalog for that provider type). Otherwise \`registry.find(provider, model)\` returns undefined and the next session falls back with a "Model not found" message.
|
|
360
|
+
3. **Credential pre-check passed** (see top of this guide). The target provider's apiKeyName is non-empty AND \`gateway env_list filter:"<PROVIDER>*"\` confirmed the named secret exists in env. Skipping this step is the bug that causes "No API key found" failures at the next chat turn — verified production repro on 2026-05-01.
|
|
307
361
|
|
|
308
362
|
**Timing — the change is NOT hot-applied to the active session.**
|
|
309
363
|
agents_manage update writes through persistToConfig WITHOUT a hot-update callback, which triggers a SIGUSR2 daemon restart (2-second debounce). The new provider/model takes effect on the next session, not the currently-running prompt. Tell the user the switch is queued and will take effect after the daemon settles.
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* and compacted output recovery.
|
|
5
5
|
*/
|
|
6
6
|
import { TOOL_SUMMARIES, TOOL_ORDER } from "./tool-descriptions.js";
|
|
7
|
+
import { getProviders } from "@mariozechner/pi-ai";
|
|
7
8
|
export function buildToolingSection(toolNames, _modelTier, toolSummaries) {
|
|
8
9
|
if (toolNames.length === 0)
|
|
9
10
|
return [];
|
|
@@ -360,7 +361,8 @@ export function buildPrivilegedToolsSection(toolNames, isMinimal, deferred) {
|
|
|
360
361
|
"- **Reset vs delete session**: Reset clears messages but keeps the session identity (good for \"start fresh\"). Delete archives the transcript and removes the session entirely.",
|
|
361
362
|
"- **Memory delete vs flush**: Delete removes specific entries by ID (surgical). Flush removes all entries for a scope (nuclear -- use with caution, requires approval).",
|
|
362
363
|
"- **Token rotation**: Prefer rotate over revoke+create -- rotation is atomic and prevents downtime.",
|
|
363
|
-
|
|
364
|
+
`- **Built-in first**: Before creating a custom provider, check if the model is already built-in (models_manage list). Built-in providers (${[...getProviders()].sort().join(", ")}) need only an API key — no custom provider entry. Only create a custom provider for models NOT in the built-in catalog.`,
|
|
365
|
+
`- **Discover providers at runtime**: Call \`models_manage({ action: "list_providers" })\` for the live native-catalog list — preferred over relying on the static text above when the SDK is upgraded.`,
|
|
364
366
|
"- **Provider then agent**: When adding a custom (non-built-in) provider, first create the provider entry (providers_manage create), store the API key if needed (gateway env_set -- skip for keyless providers like Ollama), then switch the agent (agents_manage update). Never set an agent's model to a name that has no matching provider. If you lack the provider's base URL or model ID, use web_search to find it; if that fails, ask the user.",
|
|
365
367
|
"- **Failover chain**: After creating multiple providers, configure automatic model failover on the agent (agents_manage update with modelFailover.fallbackModels). Each fallback entry is a {provider, modelId} pair referencing a configured provider. Failover order: primary > cache-aware retry > auth key rotation > fallback models in order. Never add a fallback model whose provider does not exist.",
|
|
366
368
|
"- **Add vs replace fallback**: modelFailover.fallbackModels and authProfiles are REPLACED wholesale on update (scalar fields deep-merge; arrays do not). When the user says 'add' / 'also' / 'in addition', call agents_manage get FIRST to read the current array, append, then update with the full list. When the user says 'set' / 'use' / 'switch to', overwrite directly.",
|
|
@@ -49,6 +49,13 @@ export interface PiEventBridgeDeps {
|
|
|
49
49
|
onDelta?: (delta: string) => void;
|
|
50
50
|
/** Called when a safety control triggers -- PiExecutor uses this to call session.abort(). */
|
|
51
51
|
onAbort?: () => void;
|
|
52
|
+
/** Called when a `rate_limited` error fires inside the SDK's auto-retry loop --
|
|
53
|
+
* PiExecutor wires this to `session.abortRetry()` to cancel the SDK's
|
|
54
|
+
* internal retry. Rate-limit windows are per-minute (longer than the SDK's
|
|
55
|
+
* ~30s retry budget), so retrying within the window cannot succeed.
|
|
56
|
+
* Non-`rate_limited` retryable errors (overloaded, network, 5xx) bypass this
|
|
57
|
+
* hook -- the SDK's normal retry-with-backoff proceeds. (260501-dkl) */
|
|
58
|
+
onAbortRetry?: () => void;
|
|
52
59
|
/** SDK context usage accessor -- returns live context metrics from AgentSession. */
|
|
53
60
|
getContextUsage?: () => ContextUsageData | undefined;
|
|
54
61
|
/** Context window guard for percent-based warn/block checks. */
|
|
@@ -16,6 +16,7 @@ import { randomUUID } from "node:crypto";
|
|
|
16
16
|
import { resolveModelPricing } from "../model/model-catalog.js";
|
|
17
17
|
import { getCacheProviderInfo } from "../executor/cache-usage-helpers.js";
|
|
18
18
|
import { sanitizeMcpToolNameForAnalytics } from "../executor/cache-break-detection.js";
|
|
19
|
+
import { classifyError } from "../executor/error-classifier.js";
|
|
19
20
|
import { extractPlanFromResponse } from "../planner/plan-extractor.js";
|
|
20
21
|
import { extractMcpServerName, classifyMcpErrorType, sanitizeToolArgs, extractErrorText } from "./bridge-event-handlers.js";
|
|
21
22
|
import { createBridgeMetrics, buildBridgeResult } from "./bridge-metrics.js";
|
|
@@ -843,6 +844,31 @@ export function createPiEventBridge(deps) {
|
|
|
843
844
|
break;
|
|
844
845
|
}
|
|
845
846
|
// -----------------------------------------------------------------
|
|
847
|
+
// SDK auto-retry loop: abort on rate_limited (260501-dkl)
|
|
848
|
+
// -----------------------------------------------------------------
|
|
849
|
+
case "auto_retry_start": {
|
|
850
|
+
const errorMessage = event.errorMessage ?? "";
|
|
851
|
+
const attempt = event.attempt;
|
|
852
|
+
const maxAttempts = event.maxAttempts;
|
|
853
|
+
const delayMs = event.delayMs;
|
|
854
|
+
const classification = classifyError(new Error(errorMessage));
|
|
855
|
+
if (classification.category === "rate_limited") {
|
|
856
|
+
deps.logger.info({
|
|
857
|
+
module: "agent.bridge.auto-retry-abort",
|
|
858
|
+
attempt,
|
|
859
|
+
maxAttempts,
|
|
860
|
+
delayMs,
|
|
861
|
+
errorMessage,
|
|
862
|
+
hint: "Rate-limit windows are per-minute; SDK retry budget cannot bridge the window -- aborting retry to surface terminal failure",
|
|
863
|
+
errorKind: "rate_limited",
|
|
864
|
+
}, "Aborting SDK auto-retry on rate-limited error");
|
|
865
|
+
deps.onAbortRetry?.();
|
|
866
|
+
}
|
|
867
|
+
// Non-rate_limited categories (overloaded, network, server_error, etc.)
|
|
868
|
+
// fall through -- let the SDK's normal retry-with-backoff proceed.
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
// -----------------------------------------------------------------
|
|
846
872
|
// Default: ignore unknown event types (future SDK events)
|
|
847
873
|
// -----------------------------------------------------------------
|
|
848
874
|
default:
|
|
@@ -20,6 +20,27 @@
|
|
|
20
20
|
* guarantees the surrounding context changes turn-to-turn. So the latest's
|
|
21
21
|
* signatures get invalidated too. Drop them all.
|
|
22
22
|
*
|
|
23
|
+
* 260430-anthropic-400-thinking-block: the prior cache-fence skip
|
|
24
|
+
* (`if (i <= budget.cacheFenceIndex) preserve`) caused a per-execution
|
|
25
|
+
* regression. In iteration 1 of an execution the fence is -1 so all signed
|
|
26
|
+
* thinking blocks are stripped and the wire body establishes a cached
|
|
27
|
+
* prefix WITHOUT signatures. In subsequent iterations the fence becomes
|
|
28
|
+
* positive (= the breakpoint placed in iter 1) and the skip preserved
|
|
29
|
+
* messages 0…fence as-is. But `buildSessionContext()` reloads from on-disk
|
|
30
|
+
* JSONL where signatures are intact, so the wire body re-introduced signed
|
|
31
|
+
* thinking blocks at fence-protected positions that Anthropic had cached
|
|
32
|
+
* as unsigned. The cache-prefix validator detected the divergence and
|
|
33
|
+
* rejected with `400 invalid_request_error: ... blocks cannot be modified`.
|
|
34
|
+
*
|
|
35
|
+
* Fix: scrub uniformly across the array, regardless of cacheFenceIndex.
|
|
36
|
+
* The scrubber is pure/deterministic — input messages → same scrubbed
|
|
37
|
+
* output every time — so iter 1 strips, Anthropic caches the stripped
|
|
38
|
+
* prefix, iter 2 strips identically, and the cache hits. There is NO
|
|
39
|
+
* per-iteration cache penalty: the rebuild only happens once per session
|
|
40
|
+
* (when iter 1 first establishes the cached prefix). The cacheFenceIndex
|
|
41
|
+
* is read from the budget for diagnostic stats only and never gates
|
|
42
|
+
* stripping.
|
|
43
|
+
*
|
|
23
44
|
* Provider coverage: NOT gated on `model.reasoning` because Gemini's
|
|
24
45
|
* `thoughtSignature` lives on toolCall blocks even when the model itself
|
|
25
46
|
* is not flagged as reasoning. Cost is one walk over assistant messages,
|
|
@@ -21,6 +21,27 @@
|
|
|
21
21
|
* guarantees the surrounding context changes turn-to-turn. So the latest's
|
|
22
22
|
* signatures get invalidated too. Drop them all.
|
|
23
23
|
*
|
|
24
|
+
* 260430-anthropic-400-thinking-block: the prior cache-fence skip
|
|
25
|
+
* (`if (i <= budget.cacheFenceIndex) preserve`) caused a per-execution
|
|
26
|
+
* regression. In iteration 1 of an execution the fence is -1 so all signed
|
|
27
|
+
* thinking blocks are stripped and the wire body establishes a cached
|
|
28
|
+
* prefix WITHOUT signatures. In subsequent iterations the fence becomes
|
|
29
|
+
* positive (= the breakpoint placed in iter 1) and the skip preserved
|
|
30
|
+
* messages 0…fence as-is. But `buildSessionContext()` reloads from on-disk
|
|
31
|
+
* JSONL where signatures are intact, so the wire body re-introduced signed
|
|
32
|
+
* thinking blocks at fence-protected positions that Anthropic had cached
|
|
33
|
+
* as unsigned. The cache-prefix validator detected the divergence and
|
|
34
|
+
* rejected with `400 invalid_request_error: ... blocks cannot be modified`.
|
|
35
|
+
*
|
|
36
|
+
* Fix: scrub uniformly across the array, regardless of cacheFenceIndex.
|
|
37
|
+
* The scrubber is pure/deterministic — input messages → same scrubbed
|
|
38
|
+
* output every time — so iter 1 strips, Anthropic caches the stripped
|
|
39
|
+
* prefix, iter 2 strips identically, and the cache hits. There is NO
|
|
40
|
+
* per-iteration cache penalty: the rebuild only happens once per session
|
|
41
|
+
* (when iter 1 first establishes the cached prefix). The cacheFenceIndex
|
|
42
|
+
* is read from the budget for diagnostic stats only and never gates
|
|
43
|
+
* stripping.
|
|
44
|
+
*
|
|
24
45
|
* Provider coverage: NOT gated on `model.reasoning` because Gemini's
|
|
25
46
|
* `thoughtSignature` lives on toolCall blocks even when the model itself
|
|
26
47
|
* is not flagged as reasoning. Cost is one walk over assistant messages,
|
|
@@ -43,7 +64,7 @@
|
|
|
43
64
|
export function createSignatureReplayScrubber(deps) {
|
|
44
65
|
return {
|
|
45
66
|
name: "signature-replay-scrubber",
|
|
46
|
-
async apply(messages,
|
|
67
|
+
async apply(messages, _budget) {
|
|
47
68
|
if (messages.length === 0)
|
|
48
69
|
return messages;
|
|
49
70
|
// Find the latest assistant message index. If none, no scrub.
|
|
@@ -64,20 +85,19 @@ export function createSignatureReplayScrubber(deps) {
|
|
|
64
85
|
for (let i = 0; i < messages.length; i++) {
|
|
65
86
|
// eslint-disable-next-line security/detect-object-injection -- numeric index
|
|
66
87
|
const original = messages[i];
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
88
|
+
// 260430-anthropic-400-thinking-block: cacheFenceIndex is intentionally
|
|
89
|
+
// NOT consulted here. Stripping uniformly across the array keeps the
|
|
90
|
+
// scrubbed prefix identical across iterations of the same execution,
|
|
91
|
+
// which is what Anthropic's prompt-cache validator requires. See
|
|
92
|
+
// module docstring for the full rationale.
|
|
73
93
|
const msg = original;
|
|
74
94
|
if (msg.role !== "assistant" || !Array.isArray(msg.content)) {
|
|
75
95
|
// eslint-disable-next-line security/detect-object-injection -- numeric index
|
|
76
96
|
result[i] = original;
|
|
77
97
|
continue;
|
|
78
98
|
}
|
|
79
|
-
//
|
|
80
|
-
//
|
|
99
|
+
// Walk content blocks. Latest included: cross-turn signature
|
|
100
|
+
// validation invalidates it too.
|
|
81
101
|
const content = msg.content;
|
|
82
102
|
let messageChanged = false;
|
|
83
103
|
const newContent = new Array(content.length);
|
|
@@ -21,8 +21,16 @@
|
|
|
21
21
|
* plain text rather than sending sanitized-text + original-signature
|
|
22
22
|
* mismatch. Skips `redacted: true` blocks (no readable text to taint).
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* 260430-anthropic-400-thinking-block: cacheFenceIndex is intentionally
|
|
25
|
+
* NOT consulted to gate guarding. The guard is pure/deterministic — input
|
|
26
|
+
* messages → same guarded output every time — so iter 1 strips,
|
|
27
|
+
* Anthropic caches the guarded prefix, iter 2 strips identically, and the
|
|
28
|
+
* cache hits. The prior fence-skip caused per-execution divergence
|
|
29
|
+
* symmetric to the bug found in `signature-replay-scrubber.ts` and
|
|
30
|
+
* `thinking-block-cleaner.ts`: iter 1 stripped (fence=-1) and built a
|
|
31
|
+
* surrogate-safe cached prefix, iter 2 preserved fence-protected messages
|
|
32
|
+
* (fence>0) and re-introduced surrogate-tainted-with-original-signature
|
|
33
|
+
* blocks at positions Anthropic had cached without them.
|
|
26
34
|
*
|
|
27
35
|
* Immutability: never mutates input; shallow-copies the block and the
|
|
28
36
|
* containing message only when scrubbing is needed. When no scrub fires,
|
|
@@ -22,8 +22,16 @@
|
|
|
22
22
|
* plain text rather than sending sanitized-text + original-signature
|
|
23
23
|
* mismatch. Skips `redacted: true` blocks (no readable text to taint).
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* 260430-anthropic-400-thinking-block: cacheFenceIndex is intentionally
|
|
26
|
+
* NOT consulted to gate guarding. The guard is pure/deterministic — input
|
|
27
|
+
* messages → same guarded output every time — so iter 1 strips,
|
|
28
|
+
* Anthropic caches the guarded prefix, iter 2 strips identically, and the
|
|
29
|
+
* cache hits. The prior fence-skip caused per-execution divergence
|
|
30
|
+
* symmetric to the bug found in `signature-replay-scrubber.ts` and
|
|
31
|
+
* `thinking-block-cleaner.ts`: iter 1 stripped (fence=-1) and built a
|
|
32
|
+
* surrogate-safe cached prefix, iter 2 preserved fence-protected messages
|
|
33
|
+
* (fence>0) and re-introduced surrogate-tainted-with-original-signature
|
|
34
|
+
* blocks at positions Anthropic had cached without them.
|
|
27
35
|
*
|
|
28
36
|
* Immutability: never mutates input; shallow-copies the block and the
|
|
29
37
|
* containing message only when scrubbing is needed. When no scrub fires,
|
|
@@ -50,7 +58,7 @@ const UNPAIRED_LOW_SURROGATE = /(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
|
|
|
50
58
|
export function createSignatureSurrogateGuard(deps) {
|
|
51
59
|
return {
|
|
52
60
|
name: "signature-surrogate-guard",
|
|
53
|
-
async apply(messages,
|
|
61
|
+
async apply(messages, _budget) {
|
|
54
62
|
if (messages.length === 0) {
|
|
55
63
|
deps?.onGuarded?.({ signaturesStripped: 0 });
|
|
56
64
|
return messages;
|
|
@@ -61,12 +69,10 @@ export function createSignatureSurrogateGuard(deps) {
|
|
|
61
69
|
for (let i = 0; i < messages.length; i++) {
|
|
62
70
|
// eslint-disable-next-line security/detect-object-injection -- numeric index
|
|
63
71
|
const original = messages[i];
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
72
|
+
// 260430-anthropic-400-thinking-block: cacheFenceIndex is intentionally
|
|
73
|
+
// NOT consulted here. Stripping uniformly across the array keeps the
|
|
74
|
+
// guarded prefix identical across iterations of the same execution,
|
|
75
|
+
// which is what Anthropic's prompt-cache validator requires.
|
|
70
76
|
const msg = original;
|
|
71
77
|
if (msg.role !== "assistant" || !Array.isArray(msg.content)) {
|
|
72
78
|
// eslint-disable-next-line security/detect-object-injection -- numeric index
|
|
@@ -5,6 +5,18 @@
|
|
|
5
5
|
* keep-window, measured in assistant turns (not turn pairs). Redacted thinking
|
|
6
6
|
* blocks (containing encrypted signatures for API continuity) are always preserved.
|
|
7
7
|
*
|
|
8
|
+
* 260430-anthropic-400-thinking-block: cacheFenceIndex is intentionally NOT
|
|
9
|
+
* consulted to gate stripping. The cleaner is pure/deterministic — input
|
|
10
|
+
* messages → same cleaned output every time — so iteration 1 strips,
|
|
11
|
+
* Anthropic caches the cleaned prefix, iteration 2 strips identically, and
|
|
12
|
+
* the cache hits. The prior fence-skip caused per-execution divergence:
|
|
13
|
+
* iter 1 stripped (fence=-1) and built a thinking-free cached prefix,
|
|
14
|
+
* iter 2 preserved fence-protected messages (fence>0) and re-introduced
|
|
15
|
+
* thinking blocks at positions Anthropic had cached without them, which
|
|
16
|
+
* the prompt-cache validator rejected with `400 ... blocks cannot be
|
|
17
|
+
* modified`. The cacheFenceIndex on the budget is read for diagnostic
|
|
18
|
+
* stats only and never gates the strip decision.
|
|
19
|
+
*
|
|
8
20
|
* Immutability: never mutates input messages or arrays. Returns new arrays and
|
|
9
21
|
* shallow-copied messages only when changes are needed. When no changes are
|
|
10
22
|
* required, returns the original array reference (zero allocation).
|
|
@@ -26,9 +38,12 @@ import type { ContextLayer } from "./types.js";
|
|
|
26
38
|
*/
|
|
27
39
|
export declare function createThinkingBlockCleaner(keepTurns: number, onCleaned?: (stats: {
|
|
28
40
|
blocksRemoved: number;
|
|
29
|
-
/** Cache fence index when
|
|
41
|
+
/** Cache fence index when present on the budget; reported for diagnostics
|
|
42
|
+
* only. Stripping is no longer gated on the fence (260430-anthropic-400-
|
|
43
|
+
* thinking-block). */
|
|
30
44
|
cacheFenceIndex?: number;
|
|
31
|
-
/** Number of messages protected by the cache fence.
|
|
45
|
+
/** Number of messages protected by the cache fence. Always undefined now
|
|
46
|
+
* because the fence does not protect any messages from stripping. */
|
|
32
47
|
messagesProtected?: number;
|
|
33
48
|
/** Total messages in the conversation. */
|
|
34
49
|
totalMessages?: number;
|
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
* keep-window, measured in assistant turns (not turn pairs). Redacted thinking
|
|
7
7
|
* blocks (containing encrypted signatures for API continuity) are always preserved.
|
|
8
8
|
*
|
|
9
|
+
* 260430-anthropic-400-thinking-block: cacheFenceIndex is intentionally NOT
|
|
10
|
+
* consulted to gate stripping. The cleaner is pure/deterministic — input
|
|
11
|
+
* messages → same cleaned output every time — so iteration 1 strips,
|
|
12
|
+
* Anthropic caches the cleaned prefix, iteration 2 strips identically, and
|
|
13
|
+
* the cache hits. The prior fence-skip caused per-execution divergence:
|
|
14
|
+
* iter 1 stripped (fence=-1) and built a thinking-free cached prefix,
|
|
15
|
+
* iter 2 preserved fence-protected messages (fence>0) and re-introduced
|
|
16
|
+
* thinking blocks at positions Anthropic had cached without them, which
|
|
17
|
+
* the prompt-cache validator rejected with `400 ... blocks cannot be
|
|
18
|
+
* modified`. The cacheFenceIndex on the budget is read for diagnostic
|
|
19
|
+
* stats only and never gates the strip decision.
|
|
20
|
+
*
|
|
9
21
|
* Immutability: never mutates input messages or arrays. Returns new arrays and
|
|
10
22
|
* shallow-copied messages only when changes are needed. When no changes are
|
|
11
23
|
* required, returns the original array reference (zero allocation).
|
|
@@ -65,11 +77,10 @@ export function createThinkingBlockCleaner(keepTurns, onCleaned, getKeepTurnsOve
|
|
|
65
77
|
let blocksRemoved = 0;
|
|
66
78
|
const result = new Array(messages.length);
|
|
67
79
|
for (let i = 0; i < messages.length; i++) {
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
80
|
+
// 260430-anthropic-400-thinking-block: cacheFenceIndex is intentionally
|
|
81
|
+
// NOT consulted here. Stripping uniformly across the array keeps the
|
|
82
|
+
// cleaned prefix identical across iterations of the same execution,
|
|
83
|
+
// which is what Anthropic's prompt-cache validator requires.
|
|
73
84
|
const msg = messages[i];
|
|
74
85
|
if (!oldAssistantIndices.has(i)) {
|
|
75
86
|
// Within keep-window or not an assistant message -- pass through unchanged
|
|
@@ -103,13 +114,13 @@ export function createThinkingBlockCleaner(keepTurns, onCleaned, getKeepTurnsOve
|
|
|
103
114
|
// If no changes were made to any message, return original array reference
|
|
104
115
|
if (!anyChanged)
|
|
105
116
|
return messages;
|
|
106
|
-
// Report cleaning stats via callback
|
|
107
|
-
//
|
|
117
|
+
// Report cleaning stats via callback. cacheFenceIndex is reported for
|
|
118
|
+
// diagnostic visibility but is no longer gating stripping. messagesProtected
|
|
119
|
+
// is intentionally omitted because no messages are fence-protected anymore.
|
|
108
120
|
onCleaned?.({
|
|
109
121
|
blocksRemoved,
|
|
110
122
|
...(budget.cacheFenceIndex >= 0 && blocksRemoved > 0 && {
|
|
111
123
|
cacheFenceIndex: budget.cacheFenceIndex,
|
|
112
|
-
messagesProtected: budget.cacheFenceIndex + 1,
|
|
113
124
|
totalMessages: messages.length,
|
|
114
125
|
}),
|
|
115
126
|
});
|
|
@@ -363,6 +363,34 @@ export async function runPrompt(params) {
|
|
|
363
363
|
// eslint-disable-next-line no-useless-assignment
|
|
364
364
|
silentRetryAttempted = true;
|
|
365
365
|
}
|
|
366
|
+
else if (earlyClassification.category === "rate_limited") {
|
|
367
|
+
// Provider-side time-based throttle (429/529). Retrying within the
|
|
368
|
+
// same runPrompt invocation cannot succeed — the rate-limit window
|
|
369
|
+
// hasn't rolled. The model-retry layer's cache-aware short retry
|
|
370
|
+
// (model-retry.ts:261-294) is the correct retry point for 429 with
|
|
371
|
+
// a parseable Retry-After header < SHORT_RETRY_THRESHOLD_MS. If we
|
|
372
|
+
// got here, that retry was either skipped (no Retry-After) or
|
|
373
|
+
// exhausted, AND the SDK didn't throw the 429 out (caught inside
|
|
374
|
+
// pi-ai's stream wrapper, surfaced as empty response). Re-entering
|
|
375
|
+
// runWithModelRetry from this layer would do another N retries that
|
|
376
|
+
// all hit the same rate-limit window — observed in production as
|
|
377
|
+
// 1 user message → 8 LLM calls (daemon.1.log:23:35:06-23:35:52,
|
|
378
|
+
// OpenRouter qwen/qwen3-coder:free 8 RPM cap). Short-circuit.
|
|
379
|
+
deps.logger.warn({
|
|
380
|
+
llmCalls: earlyBridgeResult.llmCalls,
|
|
381
|
+
finishReason: earlyBridgeResult.finishReason,
|
|
382
|
+
providerError: llmErrSource,
|
|
383
|
+
hint: "Provider returned a rate-limit error; retrying within the same window cannot succeed — surfacing terminal failure to caller",
|
|
384
|
+
errorKind: "rate_limited",
|
|
385
|
+
}, "Rate-limit error — skipping silent-retry and declaring terminal failure");
|
|
386
|
+
promptSucceeded = false;
|
|
387
|
+
const llmDetail = llmErrSource ? ` — ${llmErrSource}` : "";
|
|
388
|
+
promptError = new Error(`Rate limit exceeded: ${earlyBridgeResult.llmCalls} LLM call(s) produced empty response (finishReason: ${earlyBridgeResult.finishReason ?? "unknown"})${llmDetail}`);
|
|
389
|
+
// Defensive invariant: close the gate so a future refactor that
|
|
390
|
+
// re-enters this region cannot run a second silent-retry cycle.
|
|
391
|
+
// eslint-disable-next-line no-useless-assignment
|
|
392
|
+
silentRetryAttempted = true;
|
|
393
|
+
}
|
|
366
394
|
else if (earlyClassification.category === "client_request") {
|
|
367
395
|
// Plain client_request: deterministic failure (e.g. unprocessable_entity,
|
|
368
396
|
// bare "cannot be modified" without signature noun). Retrying would
|
|
@@ -274,6 +274,9 @@ function summarizeToolCall(call) {
|
|
|
274
274
|
case "gateway": {
|
|
275
275
|
const action = typeof args.action === "string" ? args.action : undefined;
|
|
276
276
|
const section = typeof args.section === "string" ? args.section : undefined;
|
|
277
|
+
const key = typeof args.key === "string" ? args.key : undefined;
|
|
278
|
+
if (action && section && key)
|
|
279
|
+
return `gateway({action: "${action}", section: "${section}", key: "${key}"})`;
|
|
277
280
|
if (action && section)
|
|
278
281
|
return `gateway({action: "${action}", section: "${section}"})`;
|
|
279
282
|
if (action)
|
|
@@ -93,7 +93,9 @@ export async function assembleTools(params) {
|
|
|
93
93
|
enabled: config.sdkRetry?.enabled ?? true,
|
|
94
94
|
maxRetries: config.sdkRetry?.maxRetries ?? 5,
|
|
95
95
|
baseDelayMs: config.sdkRetry?.baseDelayMs ?? 4000,
|
|
96
|
-
|
|
96
|
+
provider: {
|
|
97
|
+
maxRetryDelayMs: config.sdkRetry?.maxDelayMs ?? 60000,
|
|
98
|
+
},
|
|
97
99
|
},
|
|
98
100
|
};
|
|
99
101
|
// Selective override: directive takes precedence over config
|
|
@@ -12,10 +12,26 @@ export declare function parsePhase(textSignature: unknown): string | undefined;
|
|
|
12
12
|
/** True if a content block is user-visible text (not commentary). */
|
|
13
13
|
export declare function isVisibleTextBlock(block: any): boolean;
|
|
14
14
|
/**
|
|
15
|
-
* Extract user-visible text from the last assistant message
|
|
15
|
+
* Extract user-visible text from the last "real" assistant message.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Filters non-real assistants from the tail walk:
|
|
18
|
+
* - aborted-empty (stopReason "aborted" + empty content) — original.
|
|
19
|
+
* - error-empty (stopReason "error" + empty content) — sibling of
|
|
20
|
+
* aborted-empty, marks failed LLM calls (e.g. 429 / 5xx swallowed
|
|
21
|
+
* inside pi-ai's stream wrapper, surfaced as empty content).
|
|
22
|
+
* - synthetic-injected (model === "synthetic") — appended by
|
|
23
|
+
* orphaned-message-repair.ts to restore role alternation after a
|
|
24
|
+
* daemon restart; not user-visible LLM output.
|
|
25
|
+
* - cross-turn boundary (role === "user" encountered before a
|
|
26
|
+
* qualifying assistant) — return "" because the user message marks
|
|
27
|
+
* the start of the current execution window; assistants before it
|
|
28
|
+
* belong to prior turns (260501-gyy).
|
|
29
|
+
*
|
|
30
|
+
* When the resulting last assistant contains commentary-phase text
|
|
31
|
+
* blocks, drops them and returns only visible text. Otherwise returns
|
|
32
|
+
* the visible (non-commentary) text blocks of the last assistant
|
|
33
|
+
* directly — does NOT delegate to session.getLastAssistantText(),
|
|
34
|
+
* which walks past empty messages and would re-introduce the
|
|
35
|
+
* synthetic-leak (260501-egj).
|
|
20
36
|
*/
|
|
21
37
|
export declare function getVisibleAssistantText(session: any): string;
|
|
@@ -28,28 +28,61 @@ export function isVisibleTextBlock(block) {
|
|
|
28
28
|
parsePhase(block.textSignature) !== "commentary");
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* Extract user-visible text from the last assistant message
|
|
31
|
+
* Extract user-visible text from the last "real" assistant message.
|
|
32
32
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
33
|
+
* Filters non-real assistants from the tail walk:
|
|
34
|
+
* - aborted-empty (stopReason "aborted" + empty content) — original.
|
|
35
|
+
* - error-empty (stopReason "error" + empty content) — sibling of
|
|
36
|
+
* aborted-empty, marks failed LLM calls (e.g. 429 / 5xx swallowed
|
|
37
|
+
* inside pi-ai's stream wrapper, surfaced as empty content).
|
|
38
|
+
* - synthetic-injected (model === "synthetic") — appended by
|
|
39
|
+
* orphaned-message-repair.ts to restore role alternation after a
|
|
40
|
+
* daemon restart; not user-visible LLM output.
|
|
41
|
+
* - cross-turn boundary (role === "user" encountered before a
|
|
42
|
+
* qualifying assistant) — return "" because the user message marks
|
|
43
|
+
* the start of the current execution window; assistants before it
|
|
44
|
+
* belong to prior turns (260501-gyy).
|
|
45
|
+
*
|
|
46
|
+
* When the resulting last assistant contains commentary-phase text
|
|
47
|
+
* blocks, drops them and returns only visible text. Otherwise returns
|
|
48
|
+
* the visible (non-commentary) text blocks of the last assistant
|
|
49
|
+
* directly — does NOT delegate to session.getLastAssistantText(),
|
|
50
|
+
* which walks past empty messages and would re-introduce the
|
|
51
|
+
* synthetic-leak (260501-egj).
|
|
36
52
|
*/
|
|
37
53
|
export function getVisibleAssistantText(session) {
|
|
38
54
|
const messages = session?.messages;
|
|
39
|
-
// Find last
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
// Find last "real" assistant message in the CURRENT execution window —
|
|
56
|
+
// skip aborted-empty, error-empty, and synthetic-injected; stop at the
|
|
57
|
+
// first user message (turn boundary) to avoid leaking prior-turn text
|
|
58
|
+
// (260501-gyy).
|
|
59
|
+
const lastAssistant = (() => {
|
|
60
|
+
if (!Array.isArray(messages))
|
|
61
|
+
return undefined;
|
|
62
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
63
|
+
const m = messages[i]; // eslint-disable-line security/detect-object-injection
|
|
64
|
+
// Crossed turn boundary — assistants before this user message belong
|
|
65
|
+
// to a prior turn and must not be returned.
|
|
66
|
+
if (m?.role === "user")
|
|
67
|
+
return undefined;
|
|
68
|
+
// toolResult / tool / other roles — keep walking within current turn.
|
|
69
|
+
if (m?.role !== "assistant")
|
|
70
|
+
continue;
|
|
71
|
+
// Skip aborted-empty (existing behavior — preserved).
|
|
47
72
|
if (m.stopReason === "aborted" && m.content?.length === 0)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
73
|
+
continue;
|
|
74
|
+
// Skip error-empty — failed LLM calls (e.g. 429 swallowed inside
|
|
75
|
+
// pi-ai's stream wrapper).
|
|
76
|
+
if (m.stopReason === "error" && m.content?.length === 0)
|
|
77
|
+
continue;
|
|
78
|
+
// Skip synthetic-injected — orphaned-message-repair scaffolding.
|
|
79
|
+
if (m.model === "synthetic")
|
|
80
|
+
continue;
|
|
81
|
+
return m;
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
})();
|
|
85
|
+
// Only activate phase filtering when commentary blocks are present.
|
|
53
86
|
const hasCommentary = lastAssistant?.content?.some((b) => b?.type === "text" && parsePhase(b.textSignature) === "commentary") ?? false;
|
|
54
87
|
if (hasCommentary) {
|
|
55
88
|
return lastAssistant.content
|
|
@@ -57,7 +90,17 @@ export function getVisibleAssistantText(session) {
|
|
|
57
90
|
.map((b) => b.text)
|
|
58
91
|
.join("");
|
|
59
92
|
}
|
|
60
|
-
// No commentary —
|
|
61
|
-
|
|
93
|
+
// No commentary — return lastAssistant's visible text directly.
|
|
94
|
+
// Do NOT delegate to session.getLastAssistantText() because it walks
|
|
95
|
+
// past empty messages (aborted/error/etc.) and re-introduces the
|
|
96
|
+
// synthetic-leak (production bug 260501-egj: post-restart-resumption
|
|
97
|
+
// rate-limit returned synthetic placeholder instead of the
|
|
98
|
+
// 260501-cur "Rate limit exceeded" terminal error).
|
|
99
|
+
if (!lastAssistant?.content || !Array.isArray(lastAssistant.content))
|
|
100
|
+
return "";
|
|
101
|
+
return lastAssistant.content
|
|
102
|
+
.filter(isVisibleTextBlock)
|
|
103
|
+
.map((b) => b.text)
|
|
104
|
+
.join("");
|
|
62
105
|
}
|
|
63
106
|
/* eslint-enable @typescript-eslint/no-explicit-any */
|