@code-yeongyu/senpi 2026.11.10 → 2026.11.11
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 +95 -0
- package/dist/bundle/{SKILL-B4R7BVOT.md → SKILL-R7FEIQKG.md} +1 -1
- package/dist/bundle/chunks/{SKILL-AZ6ONO52.js → SKILL-5O2UKORG.js} +1 -1
- package/dist/bundle/chunks/{SKILL-B4R7BVOT.md → SKILL-R7FEIQKG.md} +1 -1
- package/dist/bundle/chunks/{args-77GYOPEO.js → args-HFYB6URH.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-YFZ734T3.js → azure-openai-responses-MNN2TINI.js} +1 -1
- package/dist/bundle/chunks/{chunk-ZUQCYIRY.js → chunk-2ODGHBUD.js} +1 -1
- package/dist/bundle/chunks/chunk-3IYEGHBI.js +2 -0
- package/dist/bundle/chunks/{chunk-I5ASHSLZ.js → chunk-4JMGWVRH.js} +1 -1
- package/dist/bundle/chunks/{chunk-YKYWL2NO.js → chunk-5F2XC6UC.js} +3 -3
- package/dist/bundle/chunks/{chunk-MSDBBOB2.js → chunk-5H43O4MA.js} +1 -1
- package/dist/bundle/chunks/{chunk-R3OP7IA4.js → chunk-5PIZWSNG.js} +4 -4
- package/dist/bundle/chunks/{chunk-33MZJTQ3.js → chunk-B4WD5XHP.js} +1 -1
- package/dist/bundle/chunks/{chunk-Q63YLZMN.js → chunk-BPEA5SWW.js} +2 -2
- package/dist/bundle/chunks/{chunk-MOVJQVMC.js → chunk-BUDJLVMF.js} +3 -3
- package/dist/bundle/chunks/{chunk-V5FSENW6.js → chunk-COKX65TE.js} +1 -1
- package/dist/bundle/chunks/{chunk-2EJ4BGBM.js → chunk-DHORIIVQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-NH7SYIGN.js → chunk-DLPV4B3R.js} +1 -1
- package/dist/bundle/chunks/{chunk-RCHIMH7N.js → chunk-DQY26AX3.js} +1 -1
- package/dist/bundle/chunks/{chunk-Y7Z7XPUF.js → chunk-DZQA5LVN.js} +1 -1
- package/dist/bundle/chunks/{chunk-2CNSCMYC.js → chunk-E5O4SP5I.js} +1 -1
- package/dist/bundle/chunks/{chunk-3Q5ZENSD.js → chunk-E6ZBTSC6.js} +1 -1
- package/dist/bundle/chunks/{chunk-GVPZPVVO.js → chunk-IBDAV2AL.js} +3 -3
- package/dist/bundle/chunks/chunk-IREUIMFE.js +11 -0
- package/dist/bundle/chunks/{chunk-KU7OCWJF.js → chunk-J4ADZ2OK.js} +1 -1
- package/dist/bundle/chunks/{chunk-T2SMQPRE.js → chunk-K3GAGIPX.js} +1 -1
- package/dist/bundle/chunks/{chunk-BELNOPAI.js → chunk-L3KVP7VJ.js} +3 -3
- package/dist/bundle/chunks/{chunk-IYSJFQUU.js → chunk-L6DF5G6K.js} +1 -1
- package/dist/bundle/chunks/{chunk-7MN7YNO5.js → chunk-L7DGTA3L.js} +1 -1
- package/dist/bundle/chunks/chunk-LJFQYCFH.js +2 -0
- package/dist/bundle/chunks/{chunk-J2NGJKXL.js → chunk-LXINMDMX.js} +1 -1
- package/dist/bundle/chunks/{chunk-H33A33M4.js → chunk-M2VJVJMK.js} +1 -1
- package/dist/bundle/chunks/{chunk-2U6HXWXS.js → chunk-NNQ34ZDW.js} +1 -1
- package/dist/bundle/chunks/chunk-NQKCJQHB.js +2 -0
- package/dist/bundle/chunks/{chunk-EJB5E2JK.js → chunk-NRZAJUUO.js} +2 -2
- package/dist/bundle/chunks/{chunk-R2Z7CX77.js → chunk-OSNR3IRD.js} +1 -1
- package/dist/bundle/chunks/{chunk-O3FG6HML.js → chunk-PJI5GT7U.js} +1 -1
- package/dist/bundle/chunks/{chunk-FDNM2DAE.js → chunk-PUZDKFRT.js} +164 -164
- package/dist/bundle/chunks/{chunk-BPNSOZ2C.js → chunk-QUVSIW2R.js} +1 -1
- package/dist/bundle/chunks/{chunk-WXYMAUFX.js → chunk-QX7WD3IM.js} +1 -1
- package/dist/bundle/chunks/{chunk-Y4ONXQMR.js → chunk-RGHVPUUX.js} +1 -1
- package/dist/bundle/chunks/{chunk-RYPM5BZQ.js → chunk-S7NAJQB3.js} +1 -1
- package/dist/bundle/chunks/{chunk-2BH54YQR.js → chunk-SANWO37B.js} +1 -1
- package/dist/bundle/chunks/{chunk-YQZNARTX.js → chunk-SS5VTBAV.js} +1 -1
- package/dist/bundle/chunks/{chunk-LT353NSF.js → chunk-T4CUD7RF.js} +1 -1
- package/dist/bundle/chunks/{chunk-J7FW7MED.js → chunk-TCZORL3V.js} +1 -1
- package/dist/bundle/chunks/{chunk-KU72IKV5.js → chunk-VGSWOLIY.js} +1 -1
- package/dist/bundle/chunks/{chunk-DBQBJTMF.js → chunk-VUY4BZDI.js} +1 -1
- package/dist/bundle/chunks/chunk-XI6THO4F.js +2 -0
- package/dist/bundle/chunks/{chunk-FAFIGBUD.js → chunk-XUDKT4UH.js} +3 -3
- package/dist/bundle/chunks/{cli-main-BX5AFWJQ.js → cli-main-7II7GCIR.js} +1 -1
- package/dist/bundle/chunks/{credential-accounts-LVVPKFEY.js → credential-accounts-N3B5YJS7.js} +1 -1
- package/dist/bundle/chunks/{dispatch-EP35KKJ3.js → dispatch-YUYZQXRP.js} +1 -1
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{hand-entry-F6PWKNPJ.js → hand-entry-ONOLRMVB.js} +3 -3
- package/dist/bundle/chunks/{headless-host-HKGNJGYT.js → headless-host-53UMJMM6.js} +1 -1
- package/dist/bundle/chunks/{health-write-FBF74QJ7.js → health-write-JLSF5EVV.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-5SCPY3OH.js → help-fast-path-552QLMWT.js} +1 -1
- package/dist/bundle/chunks/{host-command-47QQKJEY.js → host-command-KWMJLPBS.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-VSAH4M3R.js → host-lifecycle-4WQDCN3Y.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +5 -5
- package/dist/bundle/chunks/{host-session-command-SL4AN5WD.js → host-session-command-ZDYEKCUB.js} +1 -1
- package/dist/bundle/chunks/{host-socket-request-DMYXC56U.js → host-socket-request-QN4Q2P5E.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-JDMIHJMQ.js → interactive-mode-EPE4M32G.js} +1 -1
- package/dist/bundle/chunks/{login-health-EVXVLHB2.js → login-health-TOSQT5RG.js} +1 -1
- package/dist/bundle/chunks/{main-4RITUAQF.js → main-OM7BKVZG.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-SKDD4OWM.js → multi-session-host-DB6XMY53.js} +11 -8
- package/dist/bundle/chunks/openai-codex-responses-VRGOAFEG.js +10 -0
- package/dist/bundle/chunks/{openai-responses-NIVBWE2H.js → openai-responses-I7PXRWCM.js} +2 -2
- package/dist/bundle/chunks/{package-manager-cli-B5VA4KFO.js → package-manager-cli-GLU5Q2KV.js} +1 -1
- package/dist/bundle/chunks/{role-HQUN4XXK.js → role-AEOLJRTP.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-F3BEMXBE.js → rotation-stream-E3FJFHXJ.js} +1 -1
- package/dist/bundle/chunks/rpc-mode-SDJVBT36.js +2 -0
- package/dist/bundle/chunks/{rpc-monitor-source-C6VQ3BC4.js → rpc-monitor-source-PGTDSGWP.js} +1 -1
- package/dist/bundle/chunks/{run-attached-tui-R3RB5P7G.js → run-attached-tui-4AENRP7P.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-FPEQCX33.js → schedule-command-5SQD7M5N.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-R25A2QGS.js +3 -0
- package/dist/bundle/chunks/{session-picker-2FZSNFS7.js → session-picker-GZM5CVQL.js} +1 -1
- package/dist/bundle/chunks/{session-slot-CZGQQCOC.js → session-slot-RH7JLO3F.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +335 -332
- package/dist/bundle/chunks/{state-store-S7QAESIF.js → state-store-IECVTYXC.js} +1 -1
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +5 -5
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/cli.js +9 -3
- package/dist/core/agent-session-runtime.d.ts +2 -0
- package/dist/core/agent-session-runtime.js +5 -0
- package/dist/core/agent-session.d.ts +15 -3
- package/dist/core/agent-session.js +91 -18
- package/dist/core/assistant-error-redaction.d.ts +9 -0
- package/dist/core/assistant-error-redaction.js +27 -0
- package/dist/core/config-reference-redaction.js +90 -10
- package/dist/core/context-files.d.ts +10 -0
- package/dist/core/context-files.js +58 -12
- package/dist/core/credential-accounts.d.ts +2 -0
- package/dist/core/credential-accounts.js +10 -1
- package/dist/core/dynamic-prompt/intent-gate.js +2 -2
- package/dist/core/dynamic-prompt/style.js +2 -2
- package/dist/core/dynamic-prompt/verification.js +2 -2
- package/dist/core/egress/wire.d.ts +13 -0
- package/dist/core/extensions/builtin/anthropic-subscription/accounts.d.ts +3 -0
- package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.js +3 -2
- package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-account-test.js +3 -1
- package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-connection-test.d.ts +3 -1
- package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-connection-test.js +47 -16
- package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-login-slots.d.ts +1 -1
- package/dist/core/extensions/builtin/anthropic-subscription/claude-cli-login-slots.js +4 -2
- package/dist/core/extensions/builtin/anthropic-subscription/claude-settings-env.d.ts +20 -0
- package/dist/core/extensions/builtin/anthropic-subscription/claude-settings-env.js +39 -0
- package/dist/core/extensions/builtin/anthropic-subscription/context-window.d.ts +17 -0
- package/dist/core/extensions/builtin/anthropic-subscription/context-window.js +23 -0
- package/dist/core/extensions/builtin/anthropic-subscription/errors.d.ts +1 -0
- package/dist/core/extensions/builtin/anthropic-subscription/errors.js +14 -5
- package/dist/core/extensions/builtin/anthropic-subscription/oauth-login.js +3 -3
- package/dist/core/extensions/builtin/anthropic-subscription/prompt-cache-ttl.d.ts +10 -4
- package/dist/core/extensions/builtin/anthropic-subscription/prompt-cache-ttl.js +14 -5
- package/dist/core/extensions/builtin/anthropic-subscription/query-environment.d.ts +3 -2
- package/dist/core/extensions/builtin/anthropic-subscription/query-environment.js +5 -4
- package/dist/core/extensions/builtin/anthropic-subscription/sdk-boundary.lazy.d.ts +2 -1
- package/dist/core/extensions/builtin/anthropic-subscription/sdk-boundary.lazy.js +1 -0
- package/dist/core/extensions/builtin/anthropic-subscription/stream.js +11 -1
- package/dist/core/extensions/builtin/config-reload/change-groups.js +6 -2
- package/dist/core/extensions/builtin/goal/continuation.d.ts +6 -0
- package/dist/core/extensions/builtin/goal/continuation.js +3 -2
- package/dist/core/extensions/builtin/goal/index.js +14 -26
- package/dist/core/extensions/builtin/goal/lifecycle-helpers.d.ts +8 -6
- package/dist/core/extensions/builtin/goal/lifecycle-helpers.js +77 -39
- package/dist/core/extensions/builtin/goal/monitor-continuation.js +66 -7
- package/dist/core/extensions/builtin/goal/persistence.js +20 -0
- package/dist/core/extensions/builtin/goal/provider-retry.d.ts +9 -0
- package/dist/core/extensions/builtin/goal/provider-retry.js +16 -0
- package/dist/core/extensions/builtin/goal/reload-reengagement.d.ts +3 -2
- package/dist/core/extensions/builtin/goal/reload-reengagement.js +4 -4
- package/dist/core/extensions/builtin/goal/session-start-continuation.d.ts +28 -0
- package/dist/core/extensions/builtin/goal/session-start-continuation.js +75 -0
- package/dist/core/extensions/builtin/goal/store.d.ts +3 -2
- package/dist/core/extensions/builtin/goal/store.js +9 -2
- package/dist/core/extensions/builtin/goal/types.d.ts +9 -0
- package/dist/core/extensions/builtin/handoff-hint/index.js +15 -11
- package/dist/core/extensions/builtin/handoff-hint/replacement-relay.d.ts +16 -0
- package/dist/core/extensions/builtin/handoff-hint/replacement-relay.js +17 -0
- package/dist/core/extensions/builtin/html-render/tool.js +13 -3
- package/dist/core/extensions/builtin/imagegen/skill/SKILL.md +1 -1
- package/dist/core/extensions/builtin/imagegen/tool.js +4 -14
- package/dist/core/extensions/builtin/mcp/auth/catalog-identity.js +32 -8
- package/dist/core/extensions/builtin/mcp/auth/commands-auth.js +2 -1
- package/dist/core/extensions/builtin/mcp/auth/context.js +3 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-grant.d.ts +43 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-grant.js +196 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-issuer.d.ts +7 -1
- package/dist/core/extensions/builtin/mcp/auth/oauth-issuer.js +13 -0
- package/dist/core/extensions/builtin/mcp/auth/oauth-provider.d.ts +6 -17
- package/dist/core/extensions/builtin/mcp/auth/oauth-provider.js +67 -88
- package/dist/core/extensions/builtin/mcp/auth/oauth-refresh.d.ts +1 -1
- package/dist/core/extensions/builtin/mcp/auth/oauth-refresh.js +25 -4
- package/dist/core/extensions/builtin/mcp/auth/oauth.js +10 -7
- package/dist/core/extensions/builtin/mcp/auth/registered-redirect.d.ts +19 -0
- package/dist/core/extensions/builtin/mcp/auth/registered-redirect.js +55 -0
- package/dist/core/extensions/builtin/mcp/auth/token-store.d.ts +23 -1
- package/dist/core/extensions/builtin/mcp/auth/token-store.js +3 -0
- package/dist/core/extensions/builtin/mcp/catalog-cache.js +7 -6
- package/dist/core/extensions/builtin/mcp/catalog.js +3 -2
- package/dist/core/extensions/builtin/mcp/invocation.js +6 -0
- package/dist/core/extensions/builtin/mcp/service-register.js +16 -2
- package/dist/core/extensions/builtin/mcp/service-tools-changed.js +61 -54
- package/dist/core/extensions/builtin/mcp/startup-race.d.ts +2 -0
- package/dist/core/extensions/builtin/mcp/startup-race.js +25 -7
- package/dist/core/extensions/builtin/permission-system/parsers.js +1 -0
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js +3 -3
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-2.js +9 -8
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +3 -3
- package/dist/core/extensions/builtin/prompt-preset/claude-haiku-5-5.js +3 -3
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-5-5.js +3 -3
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-5.js +4 -4
- package/dist/core/extensions/builtin/prompt-preset/claude-sonnet-5-5.js +3 -3
- package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.js +3 -3
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +3 -3
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +2 -2
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +3 -3
- package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/grok-4.6.js +4 -4
- package/dist/core/extensions/builtin/prompt-preset/grok-4.7.js +5 -5
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3-1.js +4 -4
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js +7 -6
- package/dist/core/extensions/loader.js +24 -4
- package/dist/core/extensions/runner.d.ts +9 -1
- package/dist/core/extensions/runner.js +9 -4
- package/dist/core/extensions/types.d.ts +19 -3
- package/dist/core/hand/hook-advertise.d.ts +41 -0
- package/dist/core/hand/hook-advertise.js +98 -0
- package/dist/core/hand/hook-contract.d.ts +66 -0
- package/dist/core/hand/hook-contract.js +138 -0
- package/dist/core/open-timing.d.ts +2 -0
- package/dist/core/open-timing.js +7 -1
- package/dist/core/resource-loader.js +21 -3
- package/dist/core/retry-fallback/controller-types.d.ts +2 -0
- package/dist/core/retry-fallback/controller.js +9 -2
- package/dist/core/retry-fallback/cooldown.d.ts +7 -0
- package/dist/core/retry-fallback/cooldown.js +13 -1
- package/dist/core/retry-fallback/credential-recovery.d.ts +7 -0
- package/dist/core/retry-fallback/credential-recovery.js +24 -0
- package/dist/core/retry-fallback/log.d.ts +7 -1
- package/dist/core/retry-fallback/log.js +82 -5
- package/dist/core/retry-fallback/model-config-error.js +2 -1
- package/dist/core/retry-fallback/settings.d.ts +8 -5
- package/dist/core/retry-fallback/settings.js +9 -6
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.js +15 -1
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.js +8 -0
- package/dist/core/turn-origin.d.ts +18 -10
- package/dist/core/turn-origin.js +34 -30
- package/dist/core/ultrafast-lanes.d.ts +1 -0
- package/dist/core/ultrafast-lanes.js +4 -2
- package/dist/modes/interactive/components/footer.d.ts +23 -5
- package/dist/modes/interactive/components/footer.js +45 -16
- package/dist/modes/interactive/interactive-mode.js +9 -1
- package/dist/modes/interactive/session-control-rpc-commands.d.ts +1 -1
- package/dist/modes/interactive/session-control-rpc-commands.js +5 -0
- package/dist/modes/rpc/admit-external-message-command.d.ts +2 -0
- package/dist/modes/rpc/admit-external-message-command.js +5 -1
- package/dist/modes/rpc/compact-admission-validation.js +4 -1
- package/dist/modes/rpc/connection-authority.d.ts +2 -1
- package/dist/modes/rpc/connection-authority.js +11 -9
- package/dist/modes/rpc/connection-handler.d.ts +2 -0
- package/dist/modes/rpc/connection-handler.js +33 -7
- package/dist/modes/rpc/connection-roles.d.ts +7 -0
- package/dist/modes/rpc/connection-roles.js +15 -0
- package/dist/modes/rpc/custom-capability.d.ts +6 -0
- package/dist/modes/rpc/custom-capability.js +6 -0
- package/dist/modes/rpc/delegated-drive-origin.d.ts +6 -6
- package/dist/modes/rpc/delegated-drive-origin.js +7 -8
- package/dist/modes/rpc/delegation-declaration.d.ts +2 -0
- package/dist/modes/rpc/delegation-declaration.js +7 -3
- package/dist/modes/rpc/effect-commands.d.ts +33 -0
- package/dist/modes/rpc/host-capabilities.d.ts +1 -0
- package/dist/modes/rpc/host-capabilities.js +7 -1
- package/dist/modes/rpc/host-gc-evidence.d.ts +1 -1
- package/dist/modes/rpc/host-gc-evidence.js +9 -3
- package/dist/modes/rpc/host-gc.js +4 -1
- package/dist/modes/rpc/host-observe-request.d.ts +2 -0
- package/dist/modes/rpc/host-observe-request.js +6 -1
- package/dist/modes/rpc/host-park-ledger.d.ts +19 -0
- package/dist/modes/rpc/host-park-ledger.js +110 -0
- package/dist/modes/rpc/lifecycle-delivery.js +4 -1
- package/dist/modes/rpc/loopless-tool-handlers.d.ts +6 -0
- package/dist/modes/rpc/loopless-tool-handlers.js +14 -1
- package/dist/modes/rpc/media-placeholders.js +1 -0
- package/dist/modes/rpc/method-classes-schema-host.d.ts +42 -1
- package/dist/modes/rpc/method-classes-schema-host.js +24 -21
- package/dist/modes/rpc/method-classes-schema-session.d.ts +20 -0
- package/dist/modes/rpc/method-classes-schema-session.js +6 -0
- package/dist/modes/rpc/method-classes-schema.d.ts +62 -1
- package/dist/modes/rpc/method-classes-schema.js +5 -2
- package/dist/modes/rpc/method-classes.d.ts +4 -0
- package/dist/modes/rpc/method-classes.js +6 -0
- package/dist/modes/rpc/multi-session-host.js +1 -1
- package/dist/modes/rpc/project-file-commands.d.ts +32 -0
- package/dist/modes/rpc/project-file-commands.js +195 -0
- package/dist/modes/rpc/project-file-path.d.ts +34 -0
- package/dist/modes/rpc/project-file-path.js +93 -0
- package/dist/modes/rpc/rpc-error-types.d.ts +9 -1
- package/dist/modes/rpc/rpc-error-types.js +8 -0
- package/dist/modes/rpc/rpc-host-command-types.d.ts +14 -1
- package/dist/modes/rpc/rpc-host-response-types.d.ts +21 -0
- package/dist/modes/rpc/rpc-mutation-response-types.d.ts +7 -0
- package/dist/modes/rpc/rpc-read-response-types.d.ts +7 -0
- package/dist/modes/rpc/rpc-session-command-types.d.ts +10 -0
- package/dist/modes/rpc/rpc-session-state-types.d.ts +2 -0
- package/dist/modes/rpc/session-attachment-gate.js +6 -0
- package/dist/modes/rpc/session-binding.d.ts +1 -0
- package/dist/modes/rpc/session-binding.js +6 -1
- package/dist/modes/rpc/session-command-activity.js +1 -0
- package/dist/modes/rpc/session-connection-context.d.ts +2 -0
- package/dist/modes/rpc/session-connection-context.js +4 -0
- package/dist/modes/rpc/session-registry-attach.d.ts +2 -0
- package/dist/modes/rpc/session-registry-attach.js +15 -11
- package/dist/modes/rpc/session-registry-claims.js +2 -0
- package/dist/modes/rpc/session-registry-open.js +13 -7
- package/dist/modes/rpc/session-registry-opening.js +2 -1
- package/dist/modes/rpc/session-registry-types.d.ts +4 -0
- package/dist/modes/rpc/session-registry.d.ts +3 -0
- package/dist/modes/rpc/session-registry.js +27 -3
- package/dist/modes/rpc/session-router-close.js +1 -0
- package/dist/modes/rpc/session-router-context.d.ts +4 -2
- package/dist/modes/rpc/session-router-context.js +3 -0
- package/dist/modes/rpc/session-router-host-reads.js +1 -0
- package/dist/modes/rpc/session-router-occupancy.js +10 -1
- package/dist/modes/rpc/session-router-open-result.d.ts +12 -0
- package/dist/modes/rpc/session-router-open-result.js +63 -0
- package/dist/modes/rpc/session-router-open.d.ts +3 -0
- package/dist/modes/rpc/session-router-open.js +15 -63
- package/dist/modes/rpc/session-router-park.d.ts +15 -0
- package/dist/modes/rpc/session-router-park.js +176 -0
- package/dist/modes/rpc/session-router-routing.d.ts +1 -1
- package/dist/modes/rpc/session-router-routing.js +7 -0
- package/dist/modes/rpc/session-status-source.js +2 -2
- package/dist/private-fd-startup-fillers.d.ts +2 -2
- package/dist/private-fd-startup-fillers.js +34 -4
- package/dist/senpi +9 -3
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/rpc-inbound-samples.json +44 -2
- package/docs/extensions.md +11 -1
- package/docs/rpc.md +106 -2
- package/docs/settings.md +5 -3
- package/docs/skills.md +1 -1
- package/docs/usage.md +1 -1
- package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
- package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-436DNN4Z.js +0 -2
- package/dist/bundle/chunks/chunk-DLAY7CIU.js +0 -2
- package/dist/bundle/chunks/chunk-SJI6UB23.js +0 -2
- package/dist/bundle/chunks/chunk-XH2MWTXA.js +0 -11
- package/dist/bundle/chunks/chunk-YK3ZZCHI.js +0 -2
- package/dist/bundle/chunks/openai-codex-responses-ABB2J43U.js +0 -10
- package/dist/bundle/chunks/rpc-mode-ZDUGW2IM.js +0 -2
- package/dist/bundle/chunks/session-control-endpoint-MEDV66PS.js +0 -3
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
import { longContextAvailable } from "./long-context.js";
|
|
2
2
|
/** Claude Code's default window when a request does not ask for the long context. */
|
|
3
3
|
export const CLAUDE_CODE_DEFAULT_CONTEXT_WINDOW = 200_000;
|
|
4
|
+
/** The most of a request's output budget Claude Code holds back from its window (`zoo` in Claude Code 2.1.321). */
|
|
5
|
+
const CLAUDE_CODE_OUTPUT_RESERVE_CAP = 20_000;
|
|
6
|
+
/** The margin Claude Code keeps below its reserved window before it refuses a request (`Woo` in Claude Code 2.1.321). */
|
|
7
|
+
const CLAUDE_CODE_BLOCKING_BUFFER = 3_000;
|
|
8
|
+
/**
|
|
9
|
+
* The `CLAUDE_CODE_MAX_CONTEXT_TOKENS` that makes Claude Code accept a conversation up to `window`.
|
|
10
|
+
*
|
|
11
|
+
* With `DISABLE_COMPACT` set, Claude Code takes that variable as the model's window, then refuses a
|
|
12
|
+
* request on its own, with no API call, once the conversation passes the window minus its output reserve
|
|
13
|
+
* (the request's output budget, capped at 20k) minus a 3k buffer. Handing it the bare planned window put
|
|
14
|
+
* that limit 23k below the window senpi compacts against, so every turn between the two failed in
|
|
15
|
+
* milliseconds with "Prompt is too long", and so did the summarization request of the recovery
|
|
16
|
+
* compaction. senpi keeps its own output reserve below `window`, so the variable carries the window plus
|
|
17
|
+
* Claude Code's reserve and Claude Code's limit lands on `window` itself.
|
|
18
|
+
*
|
|
19
|
+
* `outputTokens` is the output budget Claude Code reserves for the request. Without an explicit
|
|
20
|
+
* `CLAUDE_CODE_MAX_OUTPUT_TOKENS` it is the model's own default, which is at least the cap for every
|
|
21
|
+
* Claude model, so the cap is the default here; a larger addition only lets a request reach the API's own
|
|
22
|
+
* window check, whose error senpi's overflow recovery already parses.
|
|
23
|
+
*/
|
|
24
|
+
export function claudeCodeMaxContextTokens(window, outputTokens = CLAUDE_CODE_OUTPUT_RESERVE_CAP) {
|
|
25
|
+
return window + Math.min(outputTokens, CLAUDE_CODE_OUTPUT_RESERVE_CAP) + CLAUDE_CODE_BLOCKING_BUFFER;
|
|
26
|
+
}
|
|
4
27
|
/**
|
|
5
28
|
* Models whose 1M window is reachable only through Claude Code's `[1m]` opt-in, which sends the legacy
|
|
6
29
|
* `context-1m-2025-08-07` beta that a subscription without extra usage refuses. These are the rows of
|
|
@@ -10,6 +10,7 @@ export type SdkErrorClassification = {
|
|
|
10
10
|
/** Set on an auth failure that proves the login itself is gone, so the account needs a new sign-in (senpi#5350). */
|
|
11
11
|
signInRequired?: "login_expired";
|
|
12
12
|
};
|
|
13
|
+
export declare function errorText(error: unknown): string;
|
|
13
14
|
export declare function isExtraUsageExhausted(error: unknown): boolean;
|
|
14
15
|
export type SdkResultUsage = Extract<SDKMessage, {
|
|
15
16
|
type: "result";
|
|
@@ -21,21 +21,30 @@ function record(value) {
|
|
|
21
21
|
? value
|
|
22
22
|
: undefined;
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
/** `String()` throws for a null-prototype object or a throwing `toString`; the classifiers must never throw. */
|
|
25
|
+
function safeString(value) {
|
|
26
|
+
try {
|
|
27
|
+
return String(value);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return Object.prototype.toString.call(value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function errorText(error) {
|
|
25
34
|
if (typeof error === "string")
|
|
26
35
|
return error;
|
|
27
|
-
if (error instanceof Error)
|
|
28
|
-
return error.message;
|
|
29
36
|
const value = record(error);
|
|
30
37
|
if (!value)
|
|
31
|
-
return
|
|
38
|
+
return safeString(error);
|
|
32
39
|
const message = value.message;
|
|
33
40
|
if (typeof message === "string")
|
|
34
41
|
return message;
|
|
42
|
+
if (error instanceof Error)
|
|
43
|
+
return safeString(message);
|
|
35
44
|
const code = value.error;
|
|
36
45
|
if (typeof code === "string")
|
|
37
46
|
return code;
|
|
38
|
-
return
|
|
47
|
+
return safeString(error);
|
|
39
48
|
}
|
|
40
49
|
export function isExtraUsageExhausted(error) {
|
|
41
50
|
return EXTRA_USAGE_EXHAUSTED.test(errorText(error).toLowerCase());
|
|
@@ -306,17 +306,17 @@ export function createOAuthConfig(deps) {
|
|
|
306
306
|
cancelled();
|
|
307
307
|
callbacks.onProgress?.(check.outcome === "ok"
|
|
308
308
|
? `Connection test passed on ${model}`
|
|
309
|
-
: `Connection test failed on ${model}
|
|
309
|
+
: `Connection test failed on ${model}: ${check.status === undefined ? "" : `HTTP ${check.status}: `}${check.message ?? check.reason ?? "No provider response was retained"}; the account was kept. Retry from the account list.`);
|
|
310
310
|
// The slot stays written: the caller's commit merges onto it, so the account owns its dir throughout.
|
|
311
311
|
let tested = slot;
|
|
312
312
|
const saved = await credentials.modify(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, async (stored) => {
|
|
313
313
|
const base = storedSubscription(stored) ?? withSlot(current, slot);
|
|
314
314
|
tested = base.accounts?.find((candidate) => candidate.name === name) ?? slot;
|
|
315
|
-
return withCheck(base, name, check);
|
|
315
|
+
return withCheck(base, name, check, dirId);
|
|
316
316
|
});
|
|
317
317
|
if (callbacks.signal !== undefined)
|
|
318
318
|
recordClaudeCliLoginOutcome(callbacks.signal, { account: { name }, check });
|
|
319
|
-
signedInCredential = withCheck(withSlot(storedSubscription(saved) ?? current, tested), name, check);
|
|
319
|
+
signedInCredential = withCheck(withSlot(storedSubscription(saved) ?? current, tested), name, check, dirId);
|
|
320
320
|
}
|
|
321
321
|
catch (error) {
|
|
322
322
|
try {
|
|
@@ -11,11 +11,17 @@ type QueryEnvironment = {
|
|
|
11
11
|
* Pin Claude Code's prompt-cache lifetime for a one-shot query and return it, so senpi's history breakpoint uses the
|
|
12
12
|
* same lifetime (senpi#2982). The Messages API rejects a 1-hour breakpoint that follows a 5-minute one, and Claude Code
|
|
13
13
|
* otherwise picks its lifetime per request: 1 hour on a subscription within its usage limits, 5 minutes on an API key
|
|
14
|
-
* or after the limits. `FORCE_PROMPT_CACHING_5M` wins, as it does in Claude Code; then
|
|
15
|
-
*
|
|
14
|
+
* or after the limits. `FORCE_PROMPT_CACHING_5M` wins, as it does in Claude Code; then a lifetime from a loaded
|
|
15
|
+
* settings file. The managed subscription lanes pin 1 hour,
|
|
16
16
|
* Claude Code's subscription default; so does the `claude-cli` lane, whose account is a verified first-party claude.ai login. The ambient lane can be an API key or a subscription login, so nothing is
|
|
17
|
-
* pinned there and
|
|
17
|
+
* pinned there unless a lifetime is set explicitly — and a lifetime set in a loaded settings file counts as explicit
|
|
18
|
+
* (senpi#2988): Claude Code applies the `env` block of the settings files it loads, so `settingsEnv` carries the
|
|
19
|
+
* effective settings env for the sources this attempt loads. Precedence is settings env, then explicit env, then the
|
|
20
|
+
* lane default: Claude Code writes each settings source's env over the process env, and launch-env keys are only
|
|
21
|
+
* protected when the session is host-orchestrated (a desktop host, or `CLAUDE_CODE_ENVIRONMENT_KIND=byoc`); an SDK
|
|
22
|
+
* spawn is neither, so a settings value wins over the process env and over `options.env`, and a settings value
|
|
23
|
+
* wins over senpi's assumption about Claude Code's default.
|
|
18
24
|
*/
|
|
19
|
-
export declare function pinOneShotPromptCacheTtl(options: QueryEnvironment, authLane: AnthropicSubscriptionAuthLane, environment: Readonly<Record<string, string | undefined>>): PromptCacheTtl | undefined;
|
|
25
|
+
export declare function pinOneShotPromptCacheTtl(options: QueryEnvironment, authLane: AnthropicSubscriptionAuthLane, environment: Readonly<Record<string, string | undefined>>, settingsEnv?: Readonly<Record<string, string | undefined>>): PromptCacheTtl | undefined;
|
|
20
26
|
export {};
|
|
21
27
|
//# sourceMappingURL=prompt-cache-ttl.d.ts.map
|
|
@@ -11,14 +11,23 @@ function parsePromptCacheTtl(value) {
|
|
|
11
11
|
* Pin Claude Code's prompt-cache lifetime for a one-shot query and return it, so senpi's history breakpoint uses the
|
|
12
12
|
* same lifetime (senpi#2982). The Messages API rejects a 1-hour breakpoint that follows a 5-minute one, and Claude Code
|
|
13
13
|
* otherwise picks its lifetime per request: 1 hour on a subscription within its usage limits, 5 minutes on an API key
|
|
14
|
-
* or after the limits. `FORCE_PROMPT_CACHING_5M` wins, as it does in Claude Code; then
|
|
15
|
-
*
|
|
14
|
+
* or after the limits. `FORCE_PROMPT_CACHING_5M` wins, as it does in Claude Code; then a lifetime from a loaded
|
|
15
|
+
* settings file. The managed subscription lanes pin 1 hour,
|
|
16
16
|
* Claude Code's subscription default; so does the `claude-cli` lane, whose account is a verified first-party claude.ai login. The ambient lane can be an API key or a subscription login, so nothing is
|
|
17
|
-
* pinned there and
|
|
17
|
+
* pinned there unless a lifetime is set explicitly — and a lifetime set in a loaded settings file counts as explicit
|
|
18
|
+
* (senpi#2988): Claude Code applies the `env` block of the settings files it loads, so `settingsEnv` carries the
|
|
19
|
+
* effective settings env for the sources this attempt loads. Precedence is settings env, then explicit env, then the
|
|
20
|
+
* lane default: Claude Code writes each settings source's env over the process env, and launch-env keys are only
|
|
21
|
+
* protected when the session is host-orchestrated (a desktop host, or `CLAUDE_CODE_ENVIRONMENT_KIND=byoc`); an SDK
|
|
22
|
+
* spawn is neither, so a settings value wins over the process env and over `options.env`, and a settings value
|
|
23
|
+
* wins over senpi's assumption about Claude Code's default.
|
|
18
24
|
*/
|
|
19
|
-
export function pinOneShotPromptCacheTtl(options, authLane, environment) {
|
|
20
|
-
const forced5m = isTruthy(options.env?.[FORCE_PROMPT_CACHING_5M_ENV]) ||
|
|
25
|
+
export function pinOneShotPromptCacheTtl(options, authLane, environment, settingsEnv) {
|
|
26
|
+
const forced5m = isTruthy(options.env?.[FORCE_PROMPT_CACHING_5M_ENV]) ||
|
|
27
|
+
isTruthy(environment[FORCE_PROMPT_CACHING_5M_ENV]) ||
|
|
28
|
+
isTruthy(settingsEnv?.[FORCE_PROMPT_CACHING_5M_ENV]);
|
|
21
29
|
const ttl = (forced5m ? "5m" : undefined) ??
|
|
30
|
+
parsePromptCacheTtl(settingsEnv?.[PROMPT_CACHE_TTL_ENV]) ??
|
|
22
31
|
parsePromptCacheTtl(options.env?.[PROMPT_CACHE_TTL_ENV]) ??
|
|
23
32
|
parsePromptCacheTtl(environment[PROMPT_CACHE_TTL_ENV]) ??
|
|
24
33
|
(authLane === "ambient" ? undefined : "1h");
|
|
@@ -5,8 +5,9 @@ import type { Api, Model } from "@earendil-works/pi-ai";
|
|
|
5
5
|
*
|
|
6
6
|
* - Compaction (senpi owner): Claude Code's per-turn token-budget reminder changes the prompt every turn and defeats
|
|
7
7
|
* prompt-cache reuse; senpi's compaction carries its own budget reminder. With DISABLE_COMPACT set, Claude Code takes
|
|
8
|
-
* CLAUDE_CODE_MAX_CONTEXT_TOKENS over every model rule of its own
|
|
9
|
-
*
|
|
8
|
+
* CLAUDE_CODE_MAX_CONTEXT_TOKENS over every model rule of its own (senpi#3801) and its native compaction stays off.
|
|
9
|
+
* The variable carries the planned window plus the output reserve Claude Code holds back from it, so Claude Code
|
|
10
|
+
* refuses a request only past the window senpi plans, not 23k below the window senpi compacts against.
|
|
10
11
|
* - Base URL: the registration baseUrl is the api-id sentinel. Any other value is the user's models.json baseUrl
|
|
11
12
|
* (senpi#4765); Claude Code sends its requests to `ANTHROPIC_BASE_URL` and keeps the selected login as the credential.
|
|
12
13
|
*/
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { CLAUDE_SDK_OAUTH_API_ID } from "./api-id.js";
|
|
2
|
-
import { plannedContextWindow } from "./context-window.js";
|
|
2
|
+
import { claudeCodeMaxContextTokens, plannedContextWindow } from "./context-window.js";
|
|
3
3
|
/**
|
|
4
4
|
* Variables the lane layers over the Claude Code subprocess environment the auth lane builds; they win over the
|
|
5
5
|
* host's, including the managed lanes' stripped `ANTHROPIC_BASE_URL`.
|
|
6
6
|
*
|
|
7
7
|
* - Compaction (senpi owner): Claude Code's per-turn token-budget reminder changes the prompt every turn and defeats
|
|
8
8
|
* prompt-cache reuse; senpi's compaction carries its own budget reminder. With DISABLE_COMPACT set, Claude Code takes
|
|
9
|
-
* CLAUDE_CODE_MAX_CONTEXT_TOKENS over every model rule of its own
|
|
10
|
-
*
|
|
9
|
+
* CLAUDE_CODE_MAX_CONTEXT_TOKENS over every model rule of its own (senpi#3801) and its native compaction stays off.
|
|
10
|
+
* The variable carries the planned window plus the output reserve Claude Code holds back from it, so Claude Code
|
|
11
|
+
* refuses a request only past the window senpi plans, not 23k below the window senpi compacts against.
|
|
11
12
|
* - Base URL: the registration baseUrl is the api-id sentinel. Any other value is the user's models.json baseUrl
|
|
12
13
|
* (senpi#4765); Claude Code sends its requests to `ANTHROPIC_BASE_URL` and keeps the selected login as the credential.
|
|
13
14
|
*/
|
|
@@ -15,7 +16,7 @@ export function claudeCodeQueryEnvironment(model, senpiOwnsCompaction) {
|
|
|
15
16
|
const environment = {};
|
|
16
17
|
if (senpiOwnsCompaction) {
|
|
17
18
|
environment.CLAUDE_CODE_TOTAL_TOKENS_REMINDER = "off";
|
|
18
|
-
environment.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(plannedContextWindow(model));
|
|
19
|
+
environment.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(claudeCodeMaxContextTokens(plannedContextWindow(model)));
|
|
19
20
|
environment.DISABLE_COMPACT = "1";
|
|
20
21
|
}
|
|
21
22
|
if (model.baseUrl !== CLAUDE_SDK_OAUTH_API_ID)
|
|
@@ -20,11 +20,12 @@
|
|
|
20
20
|
* (`packages/ai/src/api/*.lazy.ts`); `test/startup-import-graph.test.ts` fails
|
|
21
21
|
* if a static edge to the SDK reappears.
|
|
22
22
|
*/
|
|
23
|
-
import type { createSdkMcpServer, getSessionMessages, query } from "@anthropic-ai/claude-agent-sdk";
|
|
23
|
+
import type { createSdkMcpServer, getSessionMessages, query, resolveSettings } from "@anthropic-ai/claude-agent-sdk";
|
|
24
24
|
export type ClaudeAgentSdkModule = {
|
|
25
25
|
query: typeof query;
|
|
26
26
|
createSdkMcpServer: typeof createSdkMcpServer;
|
|
27
27
|
getSessionMessages: typeof getSessionMessages;
|
|
28
|
+
resolveSettings: typeof resolveSettings;
|
|
28
29
|
};
|
|
29
30
|
/**
|
|
30
31
|
* Loads the SDK once and caches it. Concurrent callers share the in-flight
|
|
@@ -5,6 +5,7 @@ import { queryWithAuthLane } from "./auth-lane.js";
|
|
|
5
5
|
import { markColdSeedOverflow } from "./cold-seed-budget.js";
|
|
6
6
|
import { CLAUDE_CODE_DEFAULT_CONTEXT_WINDOW } from "./context-window.js";
|
|
7
7
|
import { buildCustomToolServers } from "./custom-tools.js";
|
|
8
|
+
import { resolveQuerySettingsEnv } from "./claude-settings-env.js";
|
|
8
9
|
import { sdkAssistantFailure, sdkResultFailure, sdkResultFailureUsage } from "./errors.js";
|
|
9
10
|
import { defaultExecutableDeps, resolveClaudeCodeRun } from "./executable.js";
|
|
10
11
|
import { estimateLongContextFallbackTokens } from "./long-context-budget.js";
|
|
@@ -79,6 +80,10 @@ export function streamAnthropicSubscription(model, context, options) {
|
|
|
79
80
|
toolWatch.reconcileWithContext(sessionKey, context);
|
|
80
81
|
const toolWatchNote = toolWatch.buildPromptNote(sessionKey, context, resolvedTools.customToolNameToSdk);
|
|
81
82
|
const providerSettings = loadAnthropicSubscriptionProviderSettingsFromDisk(cwd);
|
|
83
|
+
// The effective `env` block of the settings files this stream's queries load (senpi#2988 item 4): a
|
|
84
|
+
// lifetime set there is what Claude Code will actually use, so the pin must see it. Resolved once per
|
|
85
|
+
// stream; the pin only receives it for attempts whose settingSources are non-empty.
|
|
86
|
+
const settingsEnv = await resolveQuerySettingsEnv(cwd, providerSettings);
|
|
82
87
|
const senpiOwnsCompaction = resolveCompactionOwner(providerSettings) === "senpi";
|
|
83
88
|
const toolLessRequest = options?.toolChoice === "none";
|
|
84
89
|
const mcpServers = toolLessRequest ? undefined : await buildCustomToolServers(resolvedTools.customTools);
|
|
@@ -107,7 +112,12 @@ export function streamAnthropicSubscription(model, context, options) {
|
|
|
107
112
|
queryOptions.mcpServers = mcpServers;
|
|
108
113
|
// The one-shot prompt is built after this, for the lane this attempt resolved (senpi#2982).
|
|
109
114
|
if (!useResidentSession) {
|
|
110
|
-
oneShotCacheTtl = pinOneShotPromptCacheTtl(queryOptions, authLane ?? providerSettings.tokenInjection ?? "ambient", { ...process.env, ...options?.env }
|
|
115
|
+
oneShotCacheTtl = pinOneShotPromptCacheTtl(queryOptions, authLane ?? providerSettings.tokenInjection ?? "ambient", { ...process.env, ...options?.env },
|
|
116
|
+
// Only the settings files this attempt loads can set its lifetime: managed lanes load
|
|
117
|
+
// none, so nothing is passed there (senpi#2988).
|
|
118
|
+
queryOptions.settingSources !== undefined && queryOptions.settingSources.length > 0
|
|
119
|
+
? settingsEnv
|
|
120
|
+
: undefined);
|
|
111
121
|
}
|
|
112
122
|
return queryOptions;
|
|
113
123
|
};
|
|
@@ -7,8 +7,12 @@ export function groupChangedPaths(paths, targets, rearmedContainers) {
|
|
|
7
7
|
if (!targetMatchesPath(activeTarget.target, path))
|
|
8
8
|
continue;
|
|
9
9
|
matched = true;
|
|
10
|
-
//
|
|
11
|
-
|
|
10
|
+
// Discovery containers only rearm their watches; discovered files carry the change.
|
|
11
|
+
// An extensions directory may contain only runtime state (e.g. a park's goal/no-session).
|
|
12
|
+
if (rearmedContainers.includes(resolve(path)) &&
|
|
13
|
+
(activeTarget.target.id === "builtin-project-presence" ||
|
|
14
|
+
activeTarget.target.id === "builtin-global-extensions" ||
|
|
15
|
+
activeTarget.target.id === "builtin-project-extensions"))
|
|
12
16
|
continue;
|
|
13
17
|
const group = groups.get(activeTarget.registrationId) ?? [];
|
|
14
18
|
if (!group.includes(path))
|
|
@@ -33,6 +33,12 @@ export type GoalContinuationInput = {
|
|
|
33
33
|
readonly continuationPending: boolean;
|
|
34
34
|
/** The last turn was rejected (or silently starved) by context size and recovery did not shrink it. */
|
|
35
35
|
readonly lastTurnStuckOnContextOverflow: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The wake re-checks a provider that refused for a usage or rate limit, either on the armed provider retry or as
|
|
38
|
+
* the first wake of a session opened in the middle of that wait. Waiting out a limit is not a stall, so it spends
|
|
39
|
+
* neither the continuation cap nor the no-progress budget (senpi#4085).
|
|
40
|
+
*/
|
|
41
|
+
readonly limitWait?: boolean;
|
|
36
42
|
};
|
|
37
43
|
export type GoalContinuationVerdict = {
|
|
38
44
|
kind: "continue";
|
|
@@ -67,9 +67,10 @@ export function evaluateGoalContinuation(input) {
|
|
|
67
67
|
return { kind: "deny", reason: "single-flight" };
|
|
68
68
|
if (hasRepeatedNormalizedOutputHash(input.recentNormalizedOutputHashes))
|
|
69
69
|
return { kind: "deny", reason: "repetition" };
|
|
70
|
-
|
|
70
|
+
const limitWait = (input.path === "providerRecovery" || input.path === "sessionStart") && input.limitWait === true;
|
|
71
|
+
if (!limitWait && isNoProgressBudgetExhausted(input))
|
|
71
72
|
return { kind: "deny", reason: "no-progress" };
|
|
72
|
-
if (input.consecutiveContinuations >= GOAL_CONTINUATION_CAP) {
|
|
73
|
+
if (!limitWait && input.consecutiveContinuations >= GOAL_CONTINUATION_CAP) {
|
|
73
74
|
return { kind: "deny", reason: "cap" };
|
|
74
75
|
}
|
|
75
76
|
if ((input.path === "immediate" || input.path === "userGrace") &&
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { MANUAL_CONTINUE_CUSTOM_TYPE } from "../../../manual-continue.js";
|
|
2
|
-
import { GOAL_CONTINUATION_MESSAGE_TYPE } from "../../../messages.js";
|
|
3
2
|
import { buildDeadlineStopNotice, deadlineStopPendingSinceLastTurn, TURN_DEADLINE_ENTRY_TYPE, } from "../../../turn-deadline.js";
|
|
4
3
|
import { noticeEntryRenderer } from "../../notice/index.js";
|
|
5
4
|
import { continueGoalAfterAgentEnd } from "./agent-end-continuation.js";
|
|
@@ -11,10 +10,11 @@ import { GoalDirectInputLifecycle } from "./direct-input-lifecycle.js";
|
|
|
11
10
|
import { GoalElapsedTicker } from "./elapsed-ticker.js";
|
|
12
11
|
import { formatGoalForTool, goalStatusLabel } from "./format.js";
|
|
13
12
|
import { goalLifecycleChanged, registerGoalLifecycleCollector } from "./lifecycle-facts.js";
|
|
14
|
-
import { GOAL_STALE_STOP_NOTICE, isResumeOfStoppedGoal,
|
|
13
|
+
import { GOAL_STALE_STOP_NOTICE, isResumeOfStoppedGoal, recoverMissingGoalContinuationStop, } from "./lifecycle-helpers.js";
|
|
15
14
|
import { GOAL_CONTINUATION_SCHEDULED_EVENT, MonitorAwareGoalContinuation } from "./monitor-continuation.js";
|
|
16
15
|
import { reengageGoalAfterReload } from "./reload-reengagement.js";
|
|
17
16
|
import { registerGoalFireNowRequest } from "./rpc-wait-surface.js";
|
|
17
|
+
import { queueGoalContinuation, readTrailingGoalContinuations } from "./session-start-continuation.js";
|
|
18
18
|
import { isStaleExtensionContextError } from "./stale-context.js";
|
|
19
19
|
import { interruptedRunHeld, markStopPaused, markStopResumed, pausedByStop, stopHoldLive } from "./stop-pause.js";
|
|
20
20
|
import { accountGoalUsage, migrateLegacyGoal, readGoal, updateGoal } from "./store.js";
|
|
@@ -156,6 +156,10 @@ export default function goalExtension(pi) {
|
|
|
156
156
|
const ref = goalStoreRef(ctx);
|
|
157
157
|
await migrateLegacyGoal(ref);
|
|
158
158
|
let goal = await readGoal(goalStoreRef(ctx));
|
|
159
|
+
// senpi#3015: a crash between the stop claim and the session append leaves the claim
|
|
160
|
+
// without its entries; re-append the missing ones once on reopen.
|
|
161
|
+
if (goal)
|
|
162
|
+
await recoverMissingGoalContinuationStop(pi, ctx, goal);
|
|
159
163
|
// A process that died mid-turn never ran the quit-time abort that stops an active goal (senpi#5753). Stop it the
|
|
160
164
|
// same way here, so the resume prompt below asks before any continuation runs (senpi#5755). Opening that session
|
|
161
165
|
// at launch (`--continue`, `--session`) is the same resume, so it asks too.
|
|
@@ -202,26 +206,26 @@ export default function goalExtension(pi) {
|
|
|
202
206
|
ctx,
|
|
203
207
|
goal,
|
|
204
208
|
monitor: monitorContinuation,
|
|
205
|
-
|
|
206
|
-
queueContinuation: () => queueGoalContinuationForCurrentSession(pi, ctx, goal),
|
|
209
|
+
readTrailingContinuations: () => readTrailingGoalContinuations(ctx.sessionManager.getBranch()),
|
|
210
|
+
queueContinuation: (limitWait) => queueGoalContinuationForCurrentSession(pi, ctx, goal, limitWait),
|
|
207
211
|
});
|
|
208
212
|
}
|
|
209
213
|
else if (goal) {
|
|
210
214
|
// Migration-lite admission: a resumed session carrying a trailing flood of
|
|
211
215
|
// historical continuations must not reignite on load. Skip the auto-queue,
|
|
212
216
|
// leave the goal active (no status rewrite), and tell the user how to resume.
|
|
213
|
-
const
|
|
214
|
-
if (
|
|
217
|
+
const trailing = readTrailingGoalContinuations(ctx.sessionManager.getBranch());
|
|
218
|
+
if (trailing.counted >= GOAL_CONTINUATION_CAP) {
|
|
215
219
|
// The load-time flood suppression parks the goal without rewriting its
|
|
216
220
|
// status, so the only resume signal left is the user's next message.
|
|
217
221
|
// Arm the one-shot latch the direct-input lifecycle fires when that
|
|
218
222
|
// message is accepted; without it the promise in the notice is a lie
|
|
219
223
|
// and the resumed session sits idle until the goal is recreated.
|
|
220
224
|
directInputLifecycle.armSuppressedLoadResume();
|
|
221
|
-
ctx.ui.notify(`Goal auto-continuation suppressed for this resumed session (${
|
|
225
|
+
ctx.ui.notify(`Goal auto-continuation suppressed for this resumed session (${trailing.counted} historical continuations). Send a message to resume.`, "info");
|
|
222
226
|
}
|
|
223
227
|
else {
|
|
224
|
-
await queueGoalContinuationForCurrentSession(pi, ctx, goal);
|
|
228
|
+
await queueGoalContinuationForCurrentSession(pi, ctx, goal, trailing.waitingOutLimit);
|
|
225
229
|
}
|
|
226
230
|
}
|
|
227
231
|
});
|
|
@@ -407,12 +411,13 @@ export default function goalExtension(pi) {
|
|
|
407
411
|
await queueGoalContinuationForCurrentSession(pi, ctx, resumed);
|
|
408
412
|
return true;
|
|
409
413
|
}
|
|
410
|
-
async function queueGoalContinuationForCurrentSession(extensionApi, ctx, goal) {
|
|
414
|
+
async function queueGoalContinuationForCurrentSession(extensionApi, ctx, goal, limitWait = false) {
|
|
411
415
|
const continuedGoal = await queueGoalContinuation(extensionApi, ctx, goal, {
|
|
412
416
|
continuationPending,
|
|
413
417
|
markContinuationPending: () => {
|
|
414
418
|
continuationPending = true;
|
|
415
419
|
},
|
|
420
|
+
limitWait,
|
|
416
421
|
});
|
|
417
422
|
if (continuedGoal === null) {
|
|
418
423
|
clearAgentGoalAccounting();
|
|
@@ -533,23 +538,6 @@ export default function goalExtension(pi) {
|
|
|
533
538
|
return goal;
|
|
534
539
|
}
|
|
535
540
|
}
|
|
536
|
-
/**
|
|
537
|
-
* Counts goal-continuation entries queued since the most recent real user message
|
|
538
|
-
* in the current branch (mirrors the todo-gate / todo-bridge backward branch read).
|
|
539
|
-
* A real user message is the only reset: the assistant turns in between are exactly
|
|
540
|
-
* the unattended loop this admission guard exists to stop.
|
|
541
|
-
*/
|
|
542
|
-
function countTrailingGoalContinuationEntries(entries) {
|
|
543
|
-
let count = 0;
|
|
544
|
-
for (let index = entries.length - 1; index >= 0; index--) {
|
|
545
|
-
const entry = entries[index];
|
|
546
|
-
if (entry?.type === "message" && entry.message.role === "user")
|
|
547
|
-
break;
|
|
548
|
-
if (entry?.type === "custom_message" && entry.customType === GOAL_CONTINUATION_MESSAGE_TYPE)
|
|
549
|
-
count += 1;
|
|
550
|
-
}
|
|
551
|
-
return count;
|
|
552
|
-
}
|
|
553
541
|
function goalStoreRef(ctx) {
|
|
554
542
|
return buildGoalStoreRef(ctx.sessionManager, ctx.cwd);
|
|
555
543
|
}
|
|
@@ -11,10 +11,6 @@ type GoalContinuationDeliveryOptions = {
|
|
|
11
11
|
readonly content: (verdict: ContinuingGoalContinuationVerdict) => string;
|
|
12
12
|
readonly markContinuationPending: () => void;
|
|
13
13
|
};
|
|
14
|
-
export type SessionStartContinuationOptions = {
|
|
15
|
-
readonly continuationPending: boolean;
|
|
16
|
-
readonly markContinuationPending: () => void;
|
|
17
|
-
};
|
|
18
14
|
/**
|
|
19
15
|
* Mirrors codex `maybe_prompt_resume_paused_goal_after_resume`
|
|
20
16
|
* (codex-rs/tui/src/app/thread_goal_actions.rs), which prompts on resume for every
|
|
@@ -24,13 +20,19 @@ export type SessionStartContinuationOptions = {
|
|
|
24
20
|
export declare function isResumeOfStoppedGoal(ctx: ExtensionContext, sessionStartReason: string, goal: Goal | null): goal is Goal;
|
|
25
21
|
/** Evaluates and delivers a continuation only after all guardrail checks admit it. */
|
|
26
22
|
export declare function admitAndQueueGoalContinuation(pi: ExtensionAPI, ctx: ExtensionContext, goal: Goal, options: GoalContinuationDeliveryOptions): Promise<Goal | null>;
|
|
27
|
-
/** Routes startup and resume continuations through the same verdict and delivery accounting as agent-end paths. */
|
|
28
|
-
export declare function queueGoalContinuation(pi: ExtensionAPI, ctx: ExtensionContext, goal: Goal, options: SessionStartContinuationOptions): Promise<Goal | null>;
|
|
29
23
|
export declare function buildCurrentGoalContinuationSignature(ctx: ExtensionContext, goal: Goal, lastAssistantText: string): string;
|
|
30
24
|
export declare function lastAssistantText(messages: readonly AgentMessage[]): string;
|
|
31
25
|
export declare function isLastTurnStuckOnContextOverflow(ctx: ExtensionContext, lastAssistant: Extract<AgentMessage, {
|
|
32
26
|
role: "assistant";
|
|
33
27
|
}> | undefined): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* senpi#3015: the stop claim and the session entries are two separate writes, so a crash
|
|
30
|
+
* between them leaves the claim without its entries. On session start the claim still
|
|
31
|
+
* stands, so re-append the missing entries once from the payload the claim captured.
|
|
32
|
+
* A claim whose entries already landed is left alone; a claim recorded before the
|
|
33
|
+
* payload existed cannot be rebuilt and is left alone too.
|
|
34
|
+
*/
|
|
35
|
+
export declare function recoverMissingGoalContinuationStop(pi: ExtensionAPI, ctx: ExtensionContext, goal: Goal): Promise<void>;
|
|
34
36
|
export declare function queueHiddenGoalPrompt(pi: ExtensionAPI, content: string): void;
|
|
35
37
|
export {};
|
|
36
38
|
//# sourceMappingURL=lifecycle-helpers.d.ts.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isTurnStuckOnContextOverflow } from "../../../compaction/stuck-overflow.js";
|
|
2
|
-
import { enginePauseSinceLastTurn } from "../../../engine-paused.js";
|
|
2
|
+
import { ENGINE_PAUSED_ENTRY_TYPE, enginePauseSinceLastTurn } from "../../../engine-paused.js";
|
|
3
3
|
import { GOAL_CONTINUATION_MESSAGE_TYPE } from "../../../messages.js";
|
|
4
4
|
import { createSessionLogger } from "../../../session-log.js";
|
|
5
|
+
import { isRecord } from "../../../work-custody-record.js";
|
|
5
6
|
import { getLatestPhasesFromBranchEntries } from "../todotools/state.js";
|
|
6
7
|
import { buildGoalContinuationSignature, evaluateGoalContinuation, hashAssistantText, } from "./continuation.js";
|
|
7
8
|
import { CONTEXT_OVERFLOW_BLOCKED_REASON, CONTINUATION_CAP_BLOCKED_REASON, continuationCapRecoveryHint, LENGTH_EXHAUSTED_BLOCKED_REASON, NO_PROGRESS_BLOCKED_REASON, REPETITION_BLOCKED_REASON, } from "./continuation-recovery.js";
|
|
8
|
-
import { buildContinuationPrompt } from "./prompt.js";
|
|
9
9
|
import { recordContinuationDelivered, recordGoalContinuationStopped } from "./store.js";
|
|
10
10
|
import { goalStoreRef } from "./store-ref.js";
|
|
11
11
|
import { openTodoTaskContents } from "./todo-gate.js";
|
|
@@ -41,36 +41,15 @@ export async function admitAndQueueGoalContinuation(pi, ctx, goal, options) {
|
|
|
41
41
|
if (options.input.currentSignature === undefined) {
|
|
42
42
|
throw new Error("Cannot queue a goal continuation without a progress signature");
|
|
43
43
|
}
|
|
44
|
-
const recordedGoal = await recordContinuationDelivered(goalStoreRef(ctx.sessionManager, ctx.cwd), options.input.currentSignature, goal.id,
|
|
44
|
+
const recordedGoal = await recordContinuationDelivered(goalStoreRef(ctx.sessionManager, ctx.cwd), options.input.currentSignature, goal.id, options.input.limitWait === true
|
|
45
|
+
? { countUnattended: false, countStreak: false }
|
|
46
|
+
: { countUnattended: options.input.path !== "monitorDelayed" });
|
|
45
47
|
if (recordedGoal === null)
|
|
46
48
|
return null;
|
|
47
49
|
options.markContinuationPending();
|
|
48
50
|
queueHiddenGoalPrompt(pi, options.content(verdict));
|
|
49
51
|
return recordedGoal;
|
|
50
52
|
}
|
|
51
|
-
/** Routes startup and resume continuations through the same verdict and delivery accounting as agent-end paths. */
|
|
52
|
-
export async function queueGoalContinuation(pi, ctx, goal, options) {
|
|
53
|
-
const signature = buildCurrentGoalContinuationSignature(ctx, goal, lastAssistantTextFromEntries(ctx.sessionManager.getBranch()));
|
|
54
|
-
return admitAndQueueGoalContinuation(pi, ctx, goal, {
|
|
55
|
-
input: {
|
|
56
|
-
isIdle: ctx.isIdle(),
|
|
57
|
-
hasPendingMessages: ctx.hasPendingMessages(),
|
|
58
|
-
path: "sessionStart",
|
|
59
|
-
lastStopReason: undefined,
|
|
60
|
-
lastTurnWasMalformedToolUse: false,
|
|
61
|
-
consecutiveContinuations: goal.consecutiveContinuations ?? 0,
|
|
62
|
-
lastContinuationSignature: goal.lastContinuationSignature,
|
|
63
|
-
currentSignature: signature,
|
|
64
|
-
consecutiveLengthRecoveries: 0,
|
|
65
|
-
recentNormalizedOutputHashes: [],
|
|
66
|
-
toollessContinuationStreak: 0,
|
|
67
|
-
continuationPending: options.continuationPending,
|
|
68
|
-
lastTurnStuckOnContextOverflow: isLastTurnStuckOnContextOverflow(ctx, lastAssistantFromEntries(ctx.sessionManager.getBranch())),
|
|
69
|
-
},
|
|
70
|
-
content: () => buildContinuationPrompt(goal, { modelId: ctx.model?.id }),
|
|
71
|
-
markContinuationPending: options.markContinuationPending,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
53
|
export function buildCurrentGoalContinuationSignature(ctx, goal, lastAssistantText) {
|
|
75
54
|
const entries = ctx.sessionManager.getBranch();
|
|
76
55
|
const openTodos = openTodoTaskContents(entries).length;
|
|
@@ -85,18 +64,6 @@ export function lastAssistantText(messages) {
|
|
|
85
64
|
}
|
|
86
65
|
return "";
|
|
87
66
|
}
|
|
88
|
-
function lastAssistantTextFromEntries(entries) {
|
|
89
|
-
const assistant = lastAssistantFromEntries(entries);
|
|
90
|
-
return assistant === undefined ? "" : textContent(assistant);
|
|
91
|
-
}
|
|
92
|
-
function lastAssistantFromEntries(entries) {
|
|
93
|
-
for (let index = entries.length - 1; index >= 0; index--) {
|
|
94
|
-
const entry = entries[index];
|
|
95
|
-
if (entry?.type === "message" && entry.message.role === "assistant")
|
|
96
|
-
return entry.message;
|
|
97
|
-
}
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
67
|
export function isLastTurnStuckOnContextOverflow(ctx, lastAssistant) {
|
|
101
68
|
return lastAssistant !== undefined && isTurnStuckOnContextOverflow(lastAssistant, ctx.model?.contextWindow ?? 0);
|
|
102
69
|
}
|
|
@@ -112,7 +79,12 @@ async function handleDeniedContinuation(pi, ctx, goal, input, reason) {
|
|
|
112
79
|
const logger = createSessionLogger(ctx.agentDir);
|
|
113
80
|
const at = Date.now();
|
|
114
81
|
const blockedReason = blockedReasonForContinuationGuard(reason);
|
|
115
|
-
const stopped = await recordGoalContinuationStopped(goalStoreRef(ctx.sessionManager, ctx.cwd), goal, at, blockedReason
|
|
82
|
+
const stopped = await recordGoalContinuationStopped(goalStoreRef(ctx.sessionManager, ctx.cwd), goal, at, blockedReason, {
|
|
83
|
+
reason,
|
|
84
|
+
consecutiveContinuations: input.consecutiveContinuations,
|
|
85
|
+
unattendedContinuations: goal.unattendedContinuations ?? 0,
|
|
86
|
+
noProgressContinuations: goal.noProgressContinuations ?? 0,
|
|
87
|
+
});
|
|
116
88
|
if (!stopped.recorded)
|
|
117
89
|
return stopped.goal;
|
|
118
90
|
// Preserve the guard's existing side effects even if publishing the additive entries fails.
|
|
@@ -164,6 +136,72 @@ async function handleDeniedContinuation(pi, ctx, goal, input, reason) {
|
|
|
164
136
|
}
|
|
165
137
|
return stopped.goal;
|
|
166
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* senpi#3015: the stop claim and the session entries are two separate writes, so a crash
|
|
141
|
+
* between them leaves the claim without its entries. On session start the claim still
|
|
142
|
+
* stands, so re-append the missing entries once from the payload the claim captured.
|
|
143
|
+
* A claim whose entries already landed is left alone; a claim recorded before the
|
|
144
|
+
* payload existed cannot be rebuilt and is left alone too.
|
|
145
|
+
*/
|
|
146
|
+
export async function recoverMissingGoalContinuationStop(pi, ctx, goal) {
|
|
147
|
+
const at = goal.continuationStoppedAt;
|
|
148
|
+
const detail = goal.continuationStoppedDetail;
|
|
149
|
+
if (at === undefined || detail === undefined)
|
|
150
|
+
return;
|
|
151
|
+
const branch = ctx.sessionManager.getBranch();
|
|
152
|
+
const logger = createSessionLogger(ctx.agentDir);
|
|
153
|
+
if (!hasStopEntrySince(branch, goal.id, at)) {
|
|
154
|
+
try {
|
|
155
|
+
pi.appendEntry("goal-continuation-stopped", {
|
|
156
|
+
goalId: goal.id,
|
|
157
|
+
reason: detail.reason,
|
|
158
|
+
consecutiveContinuations: detail.consecutiveContinuations,
|
|
159
|
+
unattendedContinuations: detail.unattendedContinuations,
|
|
160
|
+
noProgressContinuations: detail.noProgressContinuations,
|
|
161
|
+
at,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
logger.warn("goal_continuation_record_write_failed", {
|
|
166
|
+
kind: "goal-continuation-stopped",
|
|
167
|
+
error: error instanceof Error ? error.message : String(error),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (detail.reason !== "stale" && detail.reason !== "repetition")
|
|
172
|
+
return;
|
|
173
|
+
if (hasEnginePausedEntrySince(branch, at) || enginePauseSinceLastTurn(branch))
|
|
174
|
+
return;
|
|
175
|
+
try {
|
|
176
|
+
pi.appendEntry(ENGINE_PAUSED_ENTRY_TYPE, {
|
|
177
|
+
reason: detail.reason === "stale" ? "goal-stale" : "goal-repeat",
|
|
178
|
+
customType: GOAL_CONTINUATION_MESSAGE_TYPE,
|
|
179
|
+
count: detail.consecutiveContinuations,
|
|
180
|
+
at,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
logger.warn("goal_continuation_record_write_failed", {
|
|
185
|
+
kind: ENGINE_PAUSED_ENTRY_TYPE,
|
|
186
|
+
error: error instanceof Error ? error.message : String(error),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function hasStopEntrySince(branch, goalId, sinceAt) {
|
|
191
|
+
return branch.some((entry) => entry?.type === "custom" &&
|
|
192
|
+
entry.customType === "goal-continuation-stopped" &&
|
|
193
|
+
isRecord(entry.data) &&
|
|
194
|
+
entry.data.goalId === goalId &&
|
|
195
|
+
typeof entry.data.at === "number" &&
|
|
196
|
+
entry.data.at >= sinceAt);
|
|
197
|
+
}
|
|
198
|
+
function hasEnginePausedEntrySince(branch, sinceAt) {
|
|
199
|
+
return branch.some((entry) => entry?.type === "custom" &&
|
|
200
|
+
entry.customType === ENGINE_PAUSED_ENTRY_TYPE &&
|
|
201
|
+
isRecord(entry.data) &&
|
|
202
|
+
typeof entry.data.at === "number" &&
|
|
203
|
+
entry.data.at >= sinceAt);
|
|
204
|
+
}
|
|
167
205
|
function blockedReasonForContinuationGuard(reason) {
|
|
168
206
|
switch (reason) {
|
|
169
207
|
case "cap":
|