@code-yeongyu/senpi 2026.9.10 → 2026.9.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 +83 -0
- package/dist/core/agent-session.d.ts +57 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +130 -20
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +2 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +49 -17
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/brand.d.ts +5 -0
- package/dist/core/brand.d.ts.map +1 -1
- package/dist/core/brand.js +13 -0
- package/dist/core/brand.js.map +1 -1
- package/dist/core/changelog-source.d.ts +8 -0
- package/dist/core/changelog-source.d.ts.map +1 -0
- package/dist/core/changelog-source.js +19 -0
- package/dist/core/changelog-source.js.map +1 -0
- package/dist/core/credential-accounts.d.ts +3 -0
- package/dist/core/credential-accounts.d.ts.map +1 -1
- package/dist/core/credential-accounts.js +20 -1
- package/dist/core/credential-accounts.js.map +1 -1
- package/dist/core/credential-pool/classify.d.ts.map +1 -1
- package/dist/core/credential-pool/classify.js +8 -0
- package/dist/core/credential-pool/classify.js.map +1 -1
- package/dist/core/extensions/builtin/account/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/account/index.js +7 -3
- package/dist/core/extensions/builtin/account/index.js.map +1 -1
- package/dist/core/extensions/builtin/account-display-name.d.ts +7 -0
- package/dist/core/extensions/builtin/account-display-name.d.ts.map +1 -0
- package/dist/core/extensions/builtin/account-display-name.js +40 -0
- package/dist/core/extensions/builtin/account-display-name.js.map +1 -0
- package/dist/core/extensions/builtin/ask-user/format.d.ts.map +1 -1
- package/dist/core/extensions/builtin/ask-user/format.js +7 -2
- package/dist/core/extensions/builtin/ask-user/format.js.map +1 -1
- package/dist/core/extensions/builtin/ask-user/pending.d.ts.map +1 -1
- package/dist/core/extensions/builtin/ask-user/pending.js +3 -0
- package/dist/core/extensions/builtin/ask-user/pending.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/account-command.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/account-command.js +21 -9
- package/dist/core/extensions/builtin/claude-sdk-oauth/account-command.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.d.ts +1 -0
- package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.js +11 -6
- package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.d.ts +9 -0
- package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.js +10 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js +3 -0
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js +19 -10
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/settings.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js +3 -9
- package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js.map +1 -1
- package/dist/core/extensions/builtin/config-reload/routine-settings.d.ts.map +1 -1
- package/dist/core/extensions/builtin/config-reload/routine-settings.js +1 -0
- package/dist/core/extensions/builtin/config-reload/routine-settings.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.js +5 -3
- package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/accounts.d.ts +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/accounts.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/accounts.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/settings.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js +3 -9
- package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js.map +1 -1
- package/dist/core/extensions/builtin/goal/agent-end-continuation.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/agent-end-continuation.js +13 -1
- package/dist/core/extensions/builtin/goal/agent-end-continuation.js.map +1 -1
- package/dist/core/extensions/builtin/goal/prompt.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/prompt.js +11 -8
- package/dist/core/extensions/builtin/goal/prompt.js.map +1 -1
- package/dist/core/extensions/builtin/goal/terminal-provider-error.d.ts +1 -0
- package/dist/core/extensions/builtin/goal/terminal-provider-error.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/terminal-provider-error.js +28 -0
- package/dist/core/extensions/builtin/goal/terminal-provider-error.js.map +1 -1
- package/dist/core/extensions/builtin/goal/todo-gate.js +2 -2
- package/dist/core/extensions/builtin/goal/todo-gate.js.map +1 -1
- package/dist/core/extensions/builtin/goal/tool-registration.js +2 -2
- package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
- package/dist/core/extensions/builtin/gpt-account.d.ts.map +1 -1
- package/dist/core/extensions/builtin/gpt-account.js +19 -8
- package/dist/core/extensions/builtin/gpt-account.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.d.ts +3 -0
- package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.d.ts.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.js +19 -0
- package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.js.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts +6 -6
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +26 -7
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/presets.js +29 -0
- package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
- package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
- package/dist/core/high-reasoning-warning.d.ts.map +1 -1
- package/dist/core/high-reasoning-warning.js +5 -1
- package/dist/core/high-reasoning-warning.js.map +1 -1
- package/dist/core/manual-continue.d.ts +14 -0
- package/dist/core/manual-continue.d.ts.map +1 -1
- package/dist/core/manual-continue.js +13 -0
- package/dist/core/manual-continue.js.map +1 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +2 -2
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/remote-catalog-merge.d.ts +16 -0
- package/dist/core/remote-catalog-merge.d.ts.map +1 -0
- package/dist/core/remote-catalog-merge.js +75 -0
- package/dist/core/remote-catalog-merge.js.map +1 -0
- package/dist/core/remote-catalog-provider.d.ts +3 -0
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +12 -40
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/session-entry-materializer.d.ts +12 -0
- package/dist/core/session-entry-materializer.d.ts.map +1 -0
- package/dist/core/session-entry-materializer.js +26 -0
- package/dist/core/session-entry-materializer.js.map +1 -0
- package/dist/core/session-manager.d.ts +36 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +38 -8
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +10 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/modes/app-server/daemon/process.d.ts +6 -1
- package/dist/modes/app-server/daemon/process.d.ts.map +1 -1
- package/dist/modes/app-server/daemon/process.js +23 -4
- package/dist/modes/app-server/daemon/process.js.map +1 -1
- package/dist/modes/app-server/protocol/account.d.ts +2 -0
- package/dist/modes/app-server/protocol/account.d.ts.map +1 -1
- package/dist/modes/app-server/protocol/account.js.map +1 -1
- package/dist/modes/interactive/components/ask-user-question-keys.d.ts +1 -1
- package/dist/modes/interactive/components/ask-user-question-keys.d.ts.map +1 -1
- package/dist/modes/interactive/components/ask-user-question-keys.js +65 -17
- package/dist/modes/interactive/components/ask-user-question-keys.js.map +1 -1
- package/dist/modes/interactive/components/ask-user-question-render.d.ts +2 -1
- package/dist/modes/interactive/components/ask-user-question-render.d.ts.map +1 -1
- package/dist/modes/interactive/components/ask-user-question-render.js +39 -9
- package/dist/modes/interactive/components/ask-user-question-render.js.map +1 -1
- package/dist/modes/interactive/components/ask-user-question-state.d.ts +14 -4
- package/dist/modes/interactive/components/ask-user-question-state.d.ts.map +1 -1
- package/dist/modes/interactive/components/ask-user-question-state.js +63 -6
- package/dist/modes/interactive/components/ask-user-question-state.js.map +1 -1
- package/dist/modes/interactive/components/ask-user-question.d.ts +2 -0
- package/dist/modes/interactive/components/ask-user-question.d.ts.map +1 -1
- package/dist/modes/interactive/components/ask-user-question.js +27 -14
- package/dist/modes/interactive/components/ask-user-question.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +51 -19
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +11 -0
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +29 -9
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +7 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/help-content.d.ts.map +1 -1
- package/dist/modes/interactive/help-content.js +4 -0
- package/dist/modes/interactive/help-content.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +13 -4
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +44 -15
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/tips/catalog/input-tips.js +1 -1
- package/dist/modes/interactive/tips/catalog/input-tips.js.map +1 -1
- package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
- package/dist/modes/rpc/connection-handler.js +3 -1
- package/dist/modes/rpc/connection-handler.js.map +1 -1
- package/dist/modes/rpc/connection-question-bridge.js +1 -1
- package/dist/modes/rpc/connection-question-bridge.js.map +1 -1
- package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
- package/dist/modes/rpc/host-ensure.js +33 -11
- package/dist/modes/rpc/host-ensure.js.map +1 -1
- package/dist/modes/rpc/host-lifecycle.d.ts +14 -0
- package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
- package/dist/modes/rpc/host-lifecycle.js +31 -5
- package/dist/modes/rpc/host-lifecycle.js.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.js +2 -0
- package/dist/modes/rpc/rpc-input-validation.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/changelog.d.ts +3 -1
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +89 -23
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/paths.d.ts +5 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +14 -1
- package/dist/utils/paths.js.map +1 -1
- package/docs/app-server.md +6 -0
- package/docs/extensions.md +19 -3
- package/docs/rpc.md +10 -0
- package/docs/settings.md +2 -1
- package/docs/tui.md +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +28 -0
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +5 -4
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/output/streaming-output-buffer.ts +58 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/output/streaming-output.ts +9 -64
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts +17 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js +90 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.d.ts +23 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.js +71 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts +873 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js +303 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts +12 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js +35 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts +23 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js +23 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts +24 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js +116 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts +20 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js +153 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.d.ts +12 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.js +3 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts +14 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js +162 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.d.ts +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.js +23 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.d.ts +25 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.js +124 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.d.ts +18 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.js +101 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts +14 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js +111 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js +5 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.d.ts +24 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.js +86 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.d.ts +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts +51 -4
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js +196 -7
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts +8 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +10 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts +9 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/compat.js +3 -0
- package/node_modules/@earendil-works/pi-ai/dist/compat.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +4 -4
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.js +14 -5
- package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/all.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/all.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/all.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/baseten.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opengateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.d.ts +12 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js +62 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts +10 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js +28 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +3 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +4 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.js +55 -16
- package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
package/docs/extensions.md
CHANGED
|
@@ -2340,18 +2340,34 @@ pi.registerTool({
|
|
|
2340
2340
|
|
|
2341
2341
|
**Usage accounting:** If a tool makes nested LLM calls, return their combined `Usage` as `usage`. Senpi persists it on the tool result and includes it in footer, `/session`, and RPC session totals. `tool_result` handlers can inspect or replace this value.
|
|
2342
2342
|
|
|
2343
|
-
**Signaling errors:**
|
|
2343
|
+
**Signaling errors:** There are two ways to mark a tool execution as failed (sets `isError: true` on the result, the `tool_execution_end` event, and the `toolResult` message the LLM sees):
|
|
2344
|
+
|
|
2345
|
+
- Throw an error from `execute`. The thrown message becomes the result text and `details` is empty.
|
|
2346
|
+
- Return a normal result with `isError: true`. `content` and `details` are delivered unchanged, so the LLM can still branch on your typed `details` while every error surface (TUI row background, RPC `isError`, `tool_result` handlers) treats the call as a failure. Omitting `isError` or setting it to `false` is a success.
|
|
2344
2347
|
|
|
2345
2348
|
**Early termination:** Return `terminate: true` from `execute()` to hint that the automatic follow-up LLM call should be skipped after the current tool batch. This only takes effect when every finalized tool result in that batch is terminating. See [examples/extensions/structured-output.ts](../examples/extensions/structured-output.ts) for a minimal example where the agent ends on a final structured-output tool call.
|
|
2346
2349
|
|
|
2347
2350
|
```typescript
|
|
2348
|
-
//
|
|
2351
|
+
// Throw when there is nothing structured to report
|
|
2349
2352
|
async execute(toolCallId, params) {
|
|
2350
2353
|
if (!isValid(params.input)) {
|
|
2351
2354
|
throw new Error(`Invalid input: ${params.input}`);
|
|
2352
2355
|
}
|
|
2353
2356
|
return { content: [{ type: "text", text: "OK" }], details: {} };
|
|
2354
2357
|
}
|
|
2358
|
+
|
|
2359
|
+
// Return isError: true when the LLM should still see typed details
|
|
2360
|
+
async execute(toolCallId, params) {
|
|
2361
|
+
const outcome = await createTeam(params);
|
|
2362
|
+
if (outcome.kind === "member_start_rejected") {
|
|
2363
|
+
return {
|
|
2364
|
+
content: [{ type: "text", text: outcome.reason }],
|
|
2365
|
+
details: { kind: "runtime_error", code: outcome.kind },
|
|
2366
|
+
isError: true,
|
|
2367
|
+
};
|
|
2368
|
+
}
|
|
2369
|
+
return { content: [{ type: "text", text: "Created" }], details: { kind: "created" } };
|
|
2370
|
+
}
|
|
2355
2371
|
```
|
|
2356
2372
|
|
|
2357
2373
|
**Important:** Use `StringEnum` from `@earendil-works/pi-ai` for string enums. `Type.Union`/`Type.Literal` doesn't work with Google's API.
|
|
@@ -3270,7 +3286,7 @@ const highlighted = highlightCode(code, lang, theme);
|
|
|
3270
3286
|
|
|
3271
3287
|
- Extension errors are logged, agent continues
|
|
3272
3288
|
- `tool_call` errors block the tool (fail-safe)
|
|
3273
|
-
- Tool `execute` errors
|
|
3289
|
+
- Tool `execute` errors are signaled by throwing or by returning a result with `isError: true`; either way the result reaches the LLM with `isError: true` and execution continues (a returned result keeps its `content` and `details`)
|
|
3274
3290
|
|
|
3275
3291
|
## Mode Behavior
|
|
3276
3292
|
|
package/docs/rpc.md
CHANGED
|
@@ -8,6 +8,14 @@ RPC mode enables headless operation of the coding agent via a JSON protocol over
|
|
|
8
8
|
|
|
9
9
|
**Note for Node.js/TypeScript users**: If you're building a Node.js application, consider using `AgentSession` directly from `@code-yeongyu/senpi` instead of spawning a subprocess. See [`src/core/agent-session.ts`](../src/core/agent-session.ts) for the API. For a subprocess-based TypeScript client, see [`src/modes/rpc/rpc-client.ts`](../src/modes/rpc/rpc-client.ts).
|
|
10
10
|
|
|
11
|
+
## Account display names
|
|
12
|
+
|
|
13
|
+
`get_provider_accounts` returns secret-free descriptors containing `name`, `source`, `blocked`, `pinned`, and optional `displayName`. Render a named account as `displayName (name)`; keep using the immutable `name` for `account_pin`, `account_remove`, and comparisons. Legacy accounts omit `displayName`.
|
|
14
|
+
|
|
15
|
+
Use `/account <provider> rename <id> <display name...>` or the corresponding `/gpt-account` and `/claude-account` commands to name saved accounts; `clear-name <id>` removes only the label. `/gpt-account add` offers optional naming after login is saved, and only when Senpi generated the account ID itself; the Claude lane names accounts through its own login prompt and never asks twice. Blank input or cancellation keeps that login usable. Environment accounts cannot be renamed.
|
|
16
|
+
|
|
17
|
+
A label is stored NFC-normalized with internal whitespace collapsed, must contain at least one visible character, and may not exceed 32 terminal columns (measured in grapheme clusters, so CJK and emoji count two columns each). Uniqueness within a provider folds case, Unicode compatibility forms, invisible code points, and Cyrillic lookalikes, so two labels that render identically are refused.
|
|
18
|
+
|
|
11
19
|
## Starting RPC Mode
|
|
12
20
|
|
|
13
21
|
### RPC client lifecycle
|
|
@@ -147,6 +155,8 @@ The command response reports only `{ cancelled }`, so this event is the only pus
|
|
|
147
155
|
|
|
148
156
|
The lifecycle supervisor is also available to bundled/rebranded runtimes through the hidden internal launch route `--internal-rpc-host-supervisor`. This route is wire-invisible and intended only for desktop launchers: it receives the public socket, ownership directory, and the runtime command/arguments to wrap, then runs the same `host-lifecycle.ts` implementation used by `ensureHost()`. Normal CLI modes do not use or advertise this route. Compiled standalone binaries also re-enter themselves through this route automatically: a bun executable always boots its embedded entrypoint, so the script-path re-entry used under a JS runtime would be parsed as CLI arguments (`Unknown option: --socket`) and the host could never start.
|
|
149
157
|
|
|
158
|
+
On win32 the supervisor's internal hop lives under `<agentDir>/rpc-host-daemon/internal-<uuid>`, and that directory is created recursively. Before allocating the internal hop or spawning a child, the supervisor ensures `<publicSocket>.secret` exists, creating its parent directories and a 32-byte secret with mode `0600` when needed. An existing valid secret, including one written by `ensureHost()`, is reused unchanged. Direct launch therefore works on a fresh profile without caller-side secret provisioning. Provisioning failures identify the bootstrap step and secret path; the public endpoint still requires the secret handshake before forwarding RPC traffic.
|
|
159
|
+
|
|
150
160
|
Hosts started through `ensureHost()` are wrapped by a lifecycle supervisor that owns the public socket and spawns the
|
|
151
161
|
real RPC host on a private internal hop. The policy lives in `<agentDir>/rpc-host-daemon/settings.json`:
|
|
152
162
|
|
package/docs/settings.md
CHANGED
|
@@ -88,7 +88,7 @@ Permission rules are a confirmation policy, not a sandbox. Senpi, extensions, pa
|
|
|
88
88
|
| `modelThinkingLevels` | object | - | Per-model reasoning effort memory (`"provider/id": "level"`) |
|
|
89
89
|
| `modelLastOnThinkingLevels` | object | - | Per-model last non-off reasoning level, used by `/reasoning on` to restore the previous effort |
|
|
90
90
|
| `modelServiceTiers` | object | - | Per-model service tier memory (`"provider/id": "auto" \| "priority"`) |
|
|
91
|
-
| `promptPreset` | string | `"auto"` | Force a system prompt preset: `"auto"`, `"kimi-k2-6"`, `"kimi-k2-7"`, `"kimi-k3"`, `"glm-5.2"`, `"glm-5.3"`, `"grok-4.5"`, `"grok-4.6"`, `"claude-fable-5"`, `"claude-fable-5-1"`, `"claude-opus-5"`, `"claude-opus-4-5"`, `"claude-opus-4-6"`, `"claude-opus-4-7"`, `"claude-opus-4-8"`, `"deepseek-v4-flash"`, `"deepseek-v4-flash-0731"`, `"deepseek-v4-pro"`, `"gpt-5"`, `"gpt-5.2"`, `"gpt-5.3-codex"`, `"gpt-5.4"`, `"gpt-5.5"`, `"gpt-5.6"`, or `"gpt-6-astra"` |
|
|
91
|
+
| `promptPreset` | string | `"auto"` | Force a system prompt preset: `"auto"`, `"kimi-k2-6"`, `"kimi-k2-7"`, `"kimi-k3"`, `"glm-5.2"`, `"glm-5.3"`, `"grok-4.5"`, `"grok-4.6"`, `"claude-fable-5"`, `"claude-fable-5-1"`, `"claude-opus-5"`, `"claude-opus-4-5"`, `"claude-opus-4-6"`, `"claude-opus-4-7"`, `"claude-opus-4-8"`, `"deepseek-v4-flash"`, `"deepseek-v4-flash-0731"`, `"deepseek-v4-1-flash"`, `"deepseek-v4-pro"`, `"gpt-5"`, `"gpt-5.2"`, `"gpt-5.3-codex"`, `"gpt-5.4"`, `"gpt-5.5"`, `"gpt-5.6"`, or `"gpt-6-astra"` |
|
|
92
92
|
| `hideThinkingBlock` | boolean | `false` | Hide thinking blocks in output |
|
|
93
93
|
| `showCacheMissNotices` | boolean | `false` | Show transcript notices for significant prompt-cache misses, compaction or branch-summary usage, and provider recovery diagnostics such as dropped Anthropic thinking blocks |
|
|
94
94
|
| `thinkingBudgets` | object | - | Custom token budgets per thinking level. Anthropic, Google, and Bedrock use these natively. OpenAI-compatible models use them when `compat.thinkingTokenBudgetField` (or `supportsThinkingTokenBudget`) is set. |
|
|
@@ -130,6 +130,7 @@ When this value is anything other than `"auto"`, it overrides any model-level `p
|
|
|
130
130
|
| `tipsHistory` | object | - | Internal record of which tips were shown last (managed automatically) |
|
|
131
131
|
| `defaultProjectTrust` | string | `"ask"` | Fallback project trust behavior: `"ask"`, `"always"`, or `"never"`. Global setting only |
|
|
132
132
|
| `collapseChangelog` | boolean | `false` | Show condensed changelog after updates |
|
|
133
|
+
| `changelogSeen` | object | - | Internal per-source record of the latest changelog version acknowledged (managed automatically) |
|
|
133
134
|
| `enableInstallTelemetry` | boolean | `true` | Send an anonymous install/update version ping after first install or changelog-detected updates. This does not control update checks |
|
|
134
135
|
| `enableAnalytics` | boolean | `false` | Opt-in analytics data sharing. Currently only asked for during the experimental first-time setup (`PI_EXPERIMENTAL=1`) |
|
|
135
136
|
| `trackingId` | string | - | Analytics tracking identifier, generated when `enableAnalytics` is turned on |
|
package/docs/tui.md
CHANGED
|
@@ -178,7 +178,7 @@ Use `handle.unfocus()` when a visible overlay should stop owning input and let T
|
|
|
178
178
|
|
|
179
179
|
### Question Overlay and Async Widget
|
|
180
180
|
|
|
181
|
-
When the agent asks a blocking question (`waitForAnswer: true`), a full-screen overlay appears with a tab
|
|
181
|
+
When the agent asks a blocking question (`waitForAnswer: true`), a full-screen overlay appears with a tab for each question and a final Submit tab. Use digits or arrows to choose options, Space to toggle multi-select choices, and Enter to confirm and advance. The Submit tab contains the optional comment editor and accepts partial answers after confirmation; unanswered questions are reported back as unanswered. Esc backs out of an editor or asks for confirmation before discarding a draft.
|
|
182
182
|
|
|
183
183
|
For async questions (`waitForAnswer: false`), a one-line widget appears above the editor showing the question count and a countdown. The agent keeps working while you decide. Type your reply in the editor at any time and press Enter to send it as a comment, or open the full overlay with the shortcut shown in the widget.
|
|
184
184
|
|
|
@@ -12,6 +12,34 @@
|
|
|
12
12
|
|
|
13
13
|
### Removed
|
|
14
14
|
|
|
15
|
+
## [2026.9.11] - 2026-09-11
|
|
16
|
+
|
|
17
|
+
### Breaking Changes
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- The eval tool instructions now tell callers to emit large text in bounded chunks or through offset-based file reads, and to treat a truncation notice as incomplete data that must be recovered from the full-output path instead of being read as the whole result ([#1600](https://github.com/code-yeongyu/senpi/pull/1600)).
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Column-capped eval output now preserves a recoverable full-output artifact, so a cell whose output is clipped by a narrow terminal column cap still exposes the complete text through the artifact path ([#1600](https://github.com/code-yeongyu/senpi/pull/1600)).
|
|
28
|
+
|
|
29
|
+
### Removed
|
|
30
|
+
|
|
31
|
+
## [2026.9.10-2] - 2026-09-10
|
|
32
|
+
|
|
33
|
+
### Breaking Changes
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
### Removed
|
|
42
|
+
|
|
15
43
|
## [2026.9.10] - 2026-09-10
|
|
16
44
|
|
|
17
45
|
### Breaking Changes
|
|
@@ -218,10 +218,11 @@ empty pipe (`true | ( … )`) while a cell is active. Output, exit codes, `cwd`,
|
|
|
218
218
|
## Output and artifacts
|
|
219
219
|
|
|
220
220
|
Cell output is streamed while the cell runs. Large streams spill to an absolute
|
|
221
|
-
file after the default 50 KiB threshold
|
|
222
|
-
`/path/session.jsonl`, artifacts live in
|
|
223
|
-
without a file use a unique temporary
|
|
224
|
-
plain-path notice such as
|
|
221
|
+
file after the default 50 KiB threshold or when the output column cap drops
|
|
222
|
+
bytes. With a session file such as `/path/session.jsonl`, artifacts live in
|
|
223
|
+
`/path/session-artifacts/`; sessions without a file use a unique temporary
|
|
224
|
+
directory. Truncated results include a plain-path notice such as
|
|
225
|
+
`[Full output: /absolute/path/eval-….log]`.
|
|
225
226
|
|
|
226
227
|
## Deliberate differences from oh-my-pi
|
|
227
228
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi-codemode",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.11",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Source-only senpi extension package for codemode evaluation tools",
|
|
6
6
|
"type": "module",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@babel/parser": "8.0.4",
|
|
34
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.
|
|
34
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.11",
|
|
35
35
|
"typebox": "1.3.18"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@code-yeongyu/senpi": "2026.9.
|
|
38
|
+
"@code-yeongyu/senpi": "2026.9.11"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@code-yeongyu/senpi": "2026.9.
|
|
41
|
+
"@code-yeongyu/senpi": "2026.9.11"
|
|
42
42
|
},
|
|
43
43
|
"keywords": [
|
|
44
44
|
"senpi",
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
interface ByteSlice {
|
|
2
|
+
readonly text: string;
|
|
3
|
+
readonly bytes: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function truncateHeadBytes(text: string, maxBytes: number): ByteSlice {
|
|
7
|
+
if (maxBytes <= 0) return { text: "", bytes: 0 };
|
|
8
|
+
const buffer = Buffer.from(text, "utf8");
|
|
9
|
+
if (buffer.length <= maxBytes) return { text, bytes: buffer.length };
|
|
10
|
+
let end = maxBytes;
|
|
11
|
+
while (end > 0 && (buffer[end] & 0xc0) === 0x80) end--;
|
|
12
|
+
const slice = buffer.subarray(0, end);
|
|
13
|
+
return { text: slice.toString("utf8"), bytes: slice.length };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function truncateTailBytes(text: string, maxBytes: number): ByteSlice {
|
|
17
|
+
if (maxBytes <= 0) return { text: "", bytes: 0 };
|
|
18
|
+
const buffer = Buffer.from(text, "utf8");
|
|
19
|
+
if (buffer.length <= maxBytes) return { text, bytes: buffer.length };
|
|
20
|
+
let start = buffer.length - maxBytes;
|
|
21
|
+
while (start < buffer.length && (buffer[start] & 0xc0) === 0x80) start++;
|
|
22
|
+
const slice = buffer.subarray(start);
|
|
23
|
+
return { text: slice.toString("utf8"), bytes: slice.length };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class TailBuffer {
|
|
27
|
+
readonly #maxBytes: number;
|
|
28
|
+
#text = "";
|
|
29
|
+
#bytes = 0;
|
|
30
|
+
|
|
31
|
+
constructor(maxBytes: number) {
|
|
32
|
+
this.#maxBytes = Math.max(0, Math.floor(maxBytes));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
append(text: string): void {
|
|
36
|
+
if (text.length === 0) return;
|
|
37
|
+
if (this.#maxBytes === 0) {
|
|
38
|
+
this.#text = "";
|
|
39
|
+
this.#bytes = 0;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const incomingBytes = Buffer.byteLength(text, "utf8");
|
|
43
|
+
const next =
|
|
44
|
+
incomingBytes >= this.#maxBytes
|
|
45
|
+
? truncateTailBytes(text, this.#maxBytes)
|
|
46
|
+
: truncateTailBytes(this.#text + text, this.#maxBytes);
|
|
47
|
+
this.#text = next.text;
|
|
48
|
+
this.#bytes = next.bytes;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
text(): string {
|
|
52
|
+
return this.#text;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
bytes(): number {
|
|
56
|
+
return this.#bytes;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -2,9 +2,11 @@ import { createWriteStream, mkdirSync, type WriteStream } from "node:fs";
|
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateTail } from "../host-sdk.ts";
|
|
4
4
|
import { formatMiddleElisionMarker } from "./output-meta.ts";
|
|
5
|
+
import { TailBuffer, truncateHeadBytes } from "./streaming-output-buffer.ts";
|
|
5
6
|
|
|
6
7
|
export { artifactNotice, formatMiddleElisionMarker, resolveSessionArtifactsDir } from "./output-meta.ts";
|
|
7
|
-
export {
|
|
8
|
+
export { truncateHeadBytes, truncateTailBytes } from "./streaming-output-buffer.ts";
|
|
9
|
+
export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, TailBuffer, truncateTail };
|
|
8
10
|
|
|
9
11
|
export const ARTIFACT_DEFAULT_HEAD_BYTES = 3 * 1024 * 1024;
|
|
10
12
|
|
|
@@ -31,11 +33,6 @@ export interface OutputSinkOptions {
|
|
|
31
33
|
readonly chunkThrottleMs?: number;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
interface ByteSlice {
|
|
35
|
-
readonly text: string;
|
|
36
|
-
readonly bytes: number;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
36
|
function countNewlines(text: string): number {
|
|
40
37
|
let count = 0;
|
|
41
38
|
let cursor = text.indexOf("\n");
|
|
@@ -50,60 +47,6 @@ function lineCount(text: string): number {
|
|
|
50
47
|
return text.length === 0 ? 0 : countNewlines(text) + 1;
|
|
51
48
|
}
|
|
52
49
|
|
|
53
|
-
function truncateHeadBytes(text: string, maxBytes: number): ByteSlice {
|
|
54
|
-
if (maxBytes <= 0) return { text: "", bytes: 0 };
|
|
55
|
-
const buffer = Buffer.from(text, "utf8");
|
|
56
|
-
if (buffer.length <= maxBytes) return { text, bytes: buffer.length };
|
|
57
|
-
let end = maxBytes;
|
|
58
|
-
while (end > 0 && (buffer[end] & 0xc0) === 0x80) end--;
|
|
59
|
-
const slice = buffer.subarray(0, end);
|
|
60
|
-
return { text: slice.toString("utf8"), bytes: slice.length };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function truncateTailBytes(text: string, maxBytes: number): ByteSlice {
|
|
64
|
-
if (maxBytes <= 0) return { text: "", bytes: 0 };
|
|
65
|
-
const buffer = Buffer.from(text, "utf8");
|
|
66
|
-
if (buffer.length <= maxBytes) return { text, bytes: buffer.length };
|
|
67
|
-
let start = buffer.length - maxBytes;
|
|
68
|
-
while (start < buffer.length && (buffer[start] & 0xc0) === 0x80) start++;
|
|
69
|
-
const slice = buffer.subarray(start);
|
|
70
|
-
return { text: slice.toString("utf8"), bytes: slice.length };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export class TailBuffer {
|
|
74
|
-
readonly #maxBytes: number;
|
|
75
|
-
#text = "";
|
|
76
|
-
#bytes = 0;
|
|
77
|
-
|
|
78
|
-
constructor(maxBytes: number) {
|
|
79
|
-
this.#maxBytes = Math.max(0, Math.floor(maxBytes));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
append(text: string): void {
|
|
83
|
-
if (text.length === 0) return;
|
|
84
|
-
if (this.#maxBytes === 0) {
|
|
85
|
-
this.#text = "";
|
|
86
|
-
this.#bytes = 0;
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const incomingBytes = Buffer.byteLength(text, "utf8");
|
|
90
|
-
const next =
|
|
91
|
-
incomingBytes >= this.#maxBytes
|
|
92
|
-
? truncateTailBytes(text, this.#maxBytes)
|
|
93
|
-
: truncateTailBytes(this.#text + text, this.#maxBytes);
|
|
94
|
-
this.#text = next.text;
|
|
95
|
-
this.#bytes = next.bytes;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
text(): string {
|
|
99
|
-
return this.#text;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
bytes(): number {
|
|
103
|
-
return this.#bytes;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
50
|
export class OutputSink {
|
|
108
51
|
readonly #artifactPath: string | undefined;
|
|
109
52
|
readonly #spillThreshold: number;
|
|
@@ -146,8 +89,10 @@ export class OutputSink {
|
|
|
146
89
|
this.#totalBytes += rawBytes;
|
|
147
90
|
this.#totalNewlines += countNewlines(chunk);
|
|
148
91
|
this.#sawData = true;
|
|
149
|
-
this.#
|
|
150
|
-
this.#
|
|
92
|
+
const droppedBefore = this.#columnDroppedBytes;
|
|
93
|
+
const retained = this.#maxColumns > 0 ? this.#clampColumns(chunk) : chunk;
|
|
94
|
+
this.#mirrorRaw(chunk, this.#columnDroppedBytes > droppedBefore);
|
|
95
|
+
this.#retain(retained);
|
|
151
96
|
}
|
|
152
97
|
|
|
153
98
|
dump(notice?: string): Promise<OutputSummary> {
|
|
@@ -167,13 +112,13 @@ export class OutputSink {
|
|
|
167
112
|
this.#pendingChunk += chunk;
|
|
168
113
|
}
|
|
169
114
|
|
|
170
|
-
#mirrorRaw(chunk: string): void {
|
|
115
|
+
#mirrorRaw(chunk: string, columnCapDropped: boolean): void {
|
|
171
116
|
if (this.#artifactPath === undefined) return;
|
|
172
117
|
if (this.#file !== undefined) {
|
|
173
118
|
this.#file.write(chunk);
|
|
174
119
|
return;
|
|
175
120
|
}
|
|
176
|
-
if (this.#totalBytes <= this.#spillThreshold) {
|
|
121
|
+
if (!columnCapDropped && this.#totalBytes <= this.#spillThreshold) {
|
|
177
122
|
this.#beforeSpill += chunk;
|
|
178
123
|
return;
|
|
179
124
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const EVAL_PROMPT_TEMPLATE = `Run one step of code in a persistent kernel.
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
|
-
**One eval call = one cell = one logical step.** Top-level names persist per language across eval calls{{#if spawns}}, tool calls and \`task\` subagents{{else}} and tool calls{{/if}}: define helpers and clients once and reuse them instead of re-importing or re-reading. Rebuild state only after \`reset\`, a kernel restart, or a \`NameError\`/\`ReferenceError\`, and check a sentinel variable first so a re-run cannot duplicate side effects.
|
|
4
|
+
**One eval call = one cell = one logical step.** Top-level names persist per language across eval calls{{#if spawns}}, tool calls and \`task\` subagents{{else}} and tool calls{{/if}}: define helpers and clients once and reuse them instead of re-importing or re-reading. For large text, use bounded chunks or write it to a file and read it with offsets; treat truncation notices as incomplete data and follow the full-output path. Rebuild state only after \`reset\`, a kernel restart, or a \`NameError\`/\`ReferenceError\`, and check a sentinel variable first so a re-run cannot duplicate side effects.
|
|
5
5
|
|
|
6
6
|
{{#if styleClaude}}<eval_first_batching>
|
|
7
7
|
Batch a step's independent calls in one cell with \`parallel(thunks)\`; write real code around them - loops, branches, joins, a try/except per risky item - and keep every failed or missing item in the result verbatim; re-read truncated output before deciding.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-agent-core",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.11",
|
|
4
4
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"prepublishOnly": "npm run build"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.
|
|
39
|
-
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.9.
|
|
38
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.11",
|
|
39
|
+
"@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.9.11",
|
|
40
40
|
"diff": "9.0.0",
|
|
41
41
|
"ignore": "7.0.6",
|
|
42
42
|
"typebox": "1.3.18",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cascade model discovery.
|
|
3
|
+
*
|
|
4
|
+
* `GetCliModelConfigs` is credential-scoped: it reports the models the signed-in
|
|
5
|
+
* account may actually use, which differs per plan and per rollout. A failed or
|
|
6
|
+
* empty response therefore returns undefined so callers KEEP their static seed
|
|
7
|
+
* instead of publishing an empty catalog.
|
|
8
|
+
*/
|
|
9
|
+
import type { Model } from "../../types.ts";
|
|
10
|
+
export interface DevinDiscoveryOptions {
|
|
11
|
+
apiKey: string | undefined;
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
export declare function fetchDevinModels(options: DevinDiscoveryOptions): Promise<Model<"devin-agent">[] | undefined>;
|
|
17
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/api/devin-agent/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAS5C,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,GAAG,SAAS,CAAC,CAgClH"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cascade model discovery.
|
|
3
|
+
*
|
|
4
|
+
* `GetCliModelConfigs` is credential-scoped: it reports the models the signed-in
|
|
5
|
+
* account may actually use, which differs per plan and per rollout. A failed or
|
|
6
|
+
* empty response therefore returns undefined so callers KEEP their static seed
|
|
7
|
+
* instead of publishing an empty catalog.
|
|
8
|
+
*/
|
|
9
|
+
import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
|
|
10
|
+
import { GetCliModelConfigsRequestSchema, GetCliModelConfigsResponseSchema } from "./gen/cascade_pb.js";
|
|
11
|
+
import { devinCliMetadata, normalizeDevinSessionToken } from "./metadata.js";
|
|
12
|
+
import { DEVIN_CLI_MODEL_CONFIGS_PATH, DEVIN_DEFAULT_BASE_URL } from "./paths.js";
|
|
13
|
+
const DISCOVERY_TIMEOUT_MS = 5_000;
|
|
14
|
+
const DEFAULT_CONTEXT_WINDOW = 200_000;
|
|
15
|
+
const DEFAULT_MAX_TOKENS = 128_000;
|
|
16
|
+
export async function fetchDevinModels(options) {
|
|
17
|
+
const baseUrl = options.baseUrl ?? DEVIN_DEFAULT_BASE_URL;
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const onAbort = () => controller.abort();
|
|
20
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
21
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? DISCOVERY_TIMEOUT_MS);
|
|
22
|
+
try {
|
|
23
|
+
const request = create(GetCliModelConfigsRequestSchema, { metadata: devinCliMetadata(options.apiKey) });
|
|
24
|
+
const payload = toUnaryFrame(request);
|
|
25
|
+
const response = await fetch(baseUrl + DEVIN_CLI_MODEL_CONFIGS_PATH, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: {
|
|
28
|
+
"content-type": "application/connect+proto",
|
|
29
|
+
"connect-protocol-version": "1",
|
|
30
|
+
authorization: `Bearer ${normalizeDevinSessionToken(options.apiKey)}`,
|
|
31
|
+
},
|
|
32
|
+
body: payload,
|
|
33
|
+
signal: controller.signal,
|
|
34
|
+
});
|
|
35
|
+
if (!response.ok)
|
|
36
|
+
return undefined;
|
|
37
|
+
const body = new Uint8Array(await response.arrayBuffer());
|
|
38
|
+
const decoded = decodeUnary(body);
|
|
39
|
+
if (!decoded)
|
|
40
|
+
return undefined;
|
|
41
|
+
const models = decoded.clientModelConfigs.filter(usable).map(toModel);
|
|
42
|
+
return models.length > 0 ? models : undefined;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
clearTimeout(timeout);
|
|
49
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function usable(config) {
|
|
53
|
+
return config.modelUid.length > 0 && !config.disabled;
|
|
54
|
+
}
|
|
55
|
+
function toModel(config) {
|
|
56
|
+
return {
|
|
57
|
+
id: config.modelUid,
|
|
58
|
+
name: config.label || config.modelUid,
|
|
59
|
+
api: "devin-agent",
|
|
60
|
+
provider: "devin",
|
|
61
|
+
baseUrl: DEVIN_DEFAULT_BASE_URL,
|
|
62
|
+
reasoning: true,
|
|
63
|
+
input: config.supportsImages ? ["text", "image"] : ["text"],
|
|
64
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
65
|
+
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
|
66
|
+
maxTokens: config.maxTokens > 0 ? config.maxTokens : DEFAULT_MAX_TOKENS,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** Unary Connect bodies use the same 5-byte prefix, uncompressed. */
|
|
70
|
+
function toUnaryFrame(message) {
|
|
71
|
+
const payload = toBinary(GetCliModelConfigsRequestSchema, message);
|
|
72
|
+
const frame = new Uint8Array(5 + payload.byteLength);
|
|
73
|
+
new DataView(frame.buffer).setUint32(1, payload.byteLength, false);
|
|
74
|
+
frame.set(payload, 5);
|
|
75
|
+
return frame;
|
|
76
|
+
}
|
|
77
|
+
function decodeUnary(body) {
|
|
78
|
+
if (body.byteLength < 5)
|
|
79
|
+
return undefined;
|
|
80
|
+
const view = new DataView(body.buffer, body.byteOffset, body.byteLength);
|
|
81
|
+
const length = view.getUint32(1, false);
|
|
82
|
+
const payload = body.subarray(5, 5 + length);
|
|
83
|
+
try {
|
|
84
|
+
return fromBinary(GetCliModelConfigsResponseSchema, payload);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/api/devin-agent/discovery.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Cascade model discovery.\n *\n * `GetCliModelConfigs` is credential-scoped: it reports the models the signed-in\n * account may actually use, which differs per plan and per rollout. A failed or\n * empty response therefore returns undefined so callers KEEP their static seed\n * instead of publishing an empty catalog.\n */\n\nimport { create, fromBinary, toBinary } from \"@bufbuild/protobuf\";\nimport type { Model } from \"../../types.ts\";\nimport { GetCliModelConfigsRequestSchema, GetCliModelConfigsResponseSchema } from \"./gen/cascade_pb.ts\";\nimport { devinCliMetadata, normalizeDevinSessionToken } from \"./metadata.ts\";\nimport { DEVIN_CLI_MODEL_CONFIGS_PATH, DEVIN_DEFAULT_BASE_URL } from \"./paths.ts\";\n\nconst DISCOVERY_TIMEOUT_MS = 5_000;\nconst DEFAULT_CONTEXT_WINDOW = 200_000;\nconst DEFAULT_MAX_TOKENS = 128_000;\n\nexport interface DevinDiscoveryOptions {\n\tapiKey: string | undefined;\n\tbaseUrl?: string;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n}\n\nexport async function fetchDevinModels(options: DevinDiscoveryOptions): Promise<Model<\"devin-agent\">[] | undefined> {\n\tconst baseUrl = options.baseUrl ?? DEVIN_DEFAULT_BASE_URL;\n\tconst controller = new AbortController();\n\tconst onAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\tconst timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? DISCOVERY_TIMEOUT_MS);\n\n\ttry {\n\t\tconst request = create(GetCliModelConfigsRequestSchema, { metadata: devinCliMetadata(options.apiKey) });\n\t\tconst payload = toUnaryFrame(request);\n\t\tconst response = await fetch(baseUrl + DEVIN_CLI_MODEL_CONFIGS_PATH, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"content-type\": \"application/connect+proto\",\n\t\t\t\t\"connect-protocol-version\": \"1\",\n\t\t\t\tauthorization: `Bearer ${normalizeDevinSessionToken(options.apiKey)}`,\n\t\t\t},\n\t\t\tbody: payload,\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tif (!response.ok) return undefined;\n\t\tconst body = new Uint8Array(await response.arrayBuffer());\n\t\tconst decoded = decodeUnary(body);\n\t\tif (!decoded) return undefined;\n\t\tconst models = decoded.clientModelConfigs.filter(usable).map(toModel);\n\t\treturn models.length > 0 ? models : undefined;\n\t} catch {\n\t\treturn undefined;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\toptions.signal?.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\nfunction usable(config: { modelUid: string; disabled: boolean }): boolean {\n\treturn config.modelUid.length > 0 && !config.disabled;\n}\n\nfunction toModel(config: {\n\tmodelUid: string;\n\tlabel: string;\n\tmaxTokens: number;\n\tsupportsImages: boolean;\n}): Model<\"devin-agent\"> {\n\treturn {\n\t\tid: config.modelUid,\n\t\tname: config.label || config.modelUid,\n\t\tapi: \"devin-agent\",\n\t\tprovider: \"devin\",\n\t\tbaseUrl: DEVIN_DEFAULT_BASE_URL,\n\t\treasoning: true,\n\t\tinput: config.supportsImages ? [\"text\", \"image\"] : [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow: DEFAULT_CONTEXT_WINDOW,\n\t\tmaxTokens: config.maxTokens > 0 ? config.maxTokens : DEFAULT_MAX_TOKENS,\n\t};\n}\n\n/** Unary Connect bodies use the same 5-byte prefix, uncompressed. */\nfunction toUnaryFrame(\n\tmessage: ReturnType<typeof create<typeof GetCliModelConfigsRequestSchema>>,\n): Uint8Array<ArrayBuffer> {\n\tconst payload = toBinary(GetCliModelConfigsRequestSchema, message);\n\tconst frame = new Uint8Array(5 + payload.byteLength);\n\tnew DataView(frame.buffer).setUint32(1, payload.byteLength, false);\n\tframe.set(payload, 5);\n\treturn frame;\n}\n\nfunction decodeUnary(\n\tbody: Uint8Array,\n): ReturnType<typeof fromBinary<typeof GetCliModelConfigsResponseSchema>> | undefined {\n\tif (body.byteLength < 5) return undefined;\n\tconst view = new DataView(body.buffer, body.byteOffset, body.byteLength);\n\tconst length = view.getUint32(1, false);\n\tconst payload = body.subarray(5, 5 + length);\n\ttry {\n\t\treturn fromBinary(GetCliModelConfigsResponseSchema, payload);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connect streaming frame codec.
|
|
3
|
+
*
|
|
4
|
+
* Each frame is a 5-byte prefix - one flag byte plus a big-endian payload
|
|
5
|
+
* length - followed by the payload. Requests are gzipped (flag 0x01); the final
|
|
6
|
+
* response frame carries JSON trailers (flag 0x02) instead of a message.
|
|
7
|
+
*/
|
|
8
|
+
import { type DescMessage, type MessageShape } from "@bufbuild/protobuf";
|
|
9
|
+
export interface DevinFrame<TSchema extends DescMessage> {
|
|
10
|
+
/** Decoded message, absent on the end-of-stream trailer frame. */
|
|
11
|
+
message?: MessageShape<TSchema>;
|
|
12
|
+
/** Raw trailer JSON, present only on the end-of-stream frame. */
|
|
13
|
+
trailer?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Encodes one request message as a single gzipped Connect frame. */
|
|
16
|
+
export declare function encodeDevinFrame<TSchema extends DescMessage>(schema: TSchema, message: MessageShape<TSchema>): Uint8Array<ArrayBuffer>;
|
|
17
|
+
/**
|
|
18
|
+
* Decodes a Connect frame stream. Yields one entry per frame in arrival order
|
|
19
|
+
* so callers can map deltas as they land; the trailer frame yields its raw JSON
|
|
20
|
+
* instead of a message.
|
|
21
|
+
*/
|
|
22
|
+
export declare function decodeDevinFrames<TSchema extends DescMessage>(body: ReadableStream<Uint8Array>, schema: TSchema): AsyncGenerator<DevinFrame<TSchema>>;
|
|
23
|
+
//# sourceMappingURL=frames.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../../src/api/devin-agent/frames.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,KAAK,WAAW,EAAc,KAAK,YAAY,EAAY,MAAM,oBAAoB,CAAC;AAG/F,MAAM,WAAW,UAAU,CAAC,OAAO,SAAS,WAAW;IACtD,kEAAkE;IAClE,OAAO,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAChC,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,OAAO,SAAS,WAAW,EAC3D,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,GAC5B,UAAU,CAAC,WAAW,CAAC,CAOzB;AAED;;;;GAIG;AACH,wBAAuB,iBAAiB,CAAC,OAAO,SAAS,WAAW,EACnE,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,MAAM,EAAE,OAAO,GACb,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CA4BrC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connect streaming frame codec.
|
|
3
|
+
*
|
|
4
|
+
* Each frame is a 5-byte prefix - one flag byte plus a big-endian payload
|
|
5
|
+
* length - followed by the payload. Requests are gzipped (flag 0x01); the final
|
|
6
|
+
* response frame carries JSON trailers (flag 0x02) instead of a message.
|
|
7
|
+
*/
|
|
8
|
+
import { gunzipSync, gzipSync } from "node:zlib";
|
|
9
|
+
import { fromBinary, toBinary } from "@bufbuild/protobuf";
|
|
10
|
+
import { DEVIN_COMPRESSED_FLAG, DEVIN_MAX_FRAME_PAYLOAD, DEVIN_TRAILER_FLAG } from "./paths.js";
|
|
11
|
+
/** Encodes one request message as a single gzipped Connect frame. */
|
|
12
|
+
export function encodeDevinFrame(schema, message) {
|
|
13
|
+
const payload = gzipSync(toBinary(schema, message));
|
|
14
|
+
const frame = new Uint8Array(5 + payload.byteLength);
|
|
15
|
+
frame[0] = DEVIN_COMPRESSED_FLAG;
|
|
16
|
+
new DataView(frame.buffer).setUint32(1, payload.byteLength, false);
|
|
17
|
+
frame.set(payload, 5);
|
|
18
|
+
return frame;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Decodes a Connect frame stream. Yields one entry per frame in arrival order
|
|
22
|
+
* so callers can map deltas as they land; the trailer frame yields its raw JSON
|
|
23
|
+
* instead of a message.
|
|
24
|
+
*/
|
|
25
|
+
export async function* decodeDevinFrames(body, schema) {
|
|
26
|
+
let pending = new Uint8Array(0);
|
|
27
|
+
const reader = body.getReader();
|
|
28
|
+
try {
|
|
29
|
+
for (;;) {
|
|
30
|
+
const { done, value } = await reader.read();
|
|
31
|
+
if (value && value.byteLength > 0)
|
|
32
|
+
pending = append(pending, value);
|
|
33
|
+
while (pending.byteLength >= 5) {
|
|
34
|
+
const view = new DataView(pending.buffer, pending.byteOffset, pending.byteLength);
|
|
35
|
+
const length = view.getUint32(1, false);
|
|
36
|
+
if (length > DEVIN_MAX_FRAME_PAYLOAD) {
|
|
37
|
+
throw new Error(`Devin Connect frame length ${length} exceeds the ${DEVIN_MAX_FRAME_PAYLOAD}-byte cap`);
|
|
38
|
+
}
|
|
39
|
+
if (pending.byteLength < 5 + length)
|
|
40
|
+
break;
|
|
41
|
+
const flags = pending[0] ?? 0;
|
|
42
|
+
const raw = pending.subarray(5, 5 + length);
|
|
43
|
+
const payload = (flags & DEVIN_COMPRESSED_FLAG) === 0 ? copyOf(raw) : copyOf(gunzipSync(raw));
|
|
44
|
+
pending = pending.subarray(5 + length);
|
|
45
|
+
yield (flags & DEVIN_TRAILER_FLAG) === 0
|
|
46
|
+
? { message: fromBinary(schema, payload) }
|
|
47
|
+
: { trailer: new TextDecoder().decode(payload) };
|
|
48
|
+
}
|
|
49
|
+
if (done)
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
reader.releaseLock();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** protobuf-es requires an ArrayBuffer-backed view; Node buffers may be shared. */
|
|
58
|
+
function copyOf(source) {
|
|
59
|
+
const out = new Uint8Array(source.byteLength);
|
|
60
|
+
out.set(source);
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
function append(head, tail) {
|
|
64
|
+
if (head.byteLength === 0)
|
|
65
|
+
return tail;
|
|
66
|
+
const out = new Uint8Array(head.byteLength + tail.byteLength);
|
|
67
|
+
out.set(head, 0);
|
|
68
|
+
out.set(tail, head.byteLength);
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=frames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.js","sourceRoot":"","sources":["../../../src/api/devin-agent/frames.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Connect streaming frame codec.\n *\n * Each frame is a 5-byte prefix - one flag byte plus a big-endian payload\n * length - followed by the payload. Requests are gzipped (flag 0x01); the final\n * response frame carries JSON trailers (flag 0x02) instead of a message.\n */\n\nimport { gunzipSync, gzipSync } from \"node:zlib\";\nimport { type DescMessage, fromBinary, type MessageShape, toBinary } from \"@bufbuild/protobuf\";\nimport { DEVIN_COMPRESSED_FLAG, DEVIN_MAX_FRAME_PAYLOAD, DEVIN_TRAILER_FLAG } from \"./paths.ts\";\n\nexport interface DevinFrame<TSchema extends DescMessage> {\n\t/** Decoded message, absent on the end-of-stream trailer frame. */\n\tmessage?: MessageShape<TSchema>;\n\t/** Raw trailer JSON, present only on the end-of-stream frame. */\n\ttrailer?: string;\n}\n\n/** Encodes one request message as a single gzipped Connect frame. */\nexport function encodeDevinFrame<TSchema extends DescMessage>(\n\tschema: TSchema,\n\tmessage: MessageShape<TSchema>,\n): Uint8Array<ArrayBuffer> {\n\tconst payload = gzipSync(toBinary(schema, message));\n\tconst frame = new Uint8Array(5 + payload.byteLength);\n\tframe[0] = DEVIN_COMPRESSED_FLAG;\n\tnew DataView(frame.buffer).setUint32(1, payload.byteLength, false);\n\tframe.set(payload, 5);\n\treturn frame;\n}\n\n/**\n * Decodes a Connect frame stream. Yields one entry per frame in arrival order\n * so callers can map deltas as they land; the trailer frame yields its raw JSON\n * instead of a message.\n */\nexport async function* decodeDevinFrames<TSchema extends DescMessage>(\n\tbody: ReadableStream<Uint8Array>,\n\tschema: TSchema,\n): AsyncGenerator<DevinFrame<TSchema>> {\n\tlet pending: Uint8Array<ArrayBufferLike> = new Uint8Array(0);\n\tconst reader = body.getReader();\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (value && value.byteLength > 0) pending = append(pending, value);\n\t\t\twhile (pending.byteLength >= 5) {\n\t\t\t\tconst view = new DataView(pending.buffer, pending.byteOffset, pending.byteLength);\n\t\t\t\tconst length = view.getUint32(1, false);\n\t\t\t\tif (length > DEVIN_MAX_FRAME_PAYLOAD) {\n\t\t\t\t\tthrow new Error(`Devin Connect frame length ${length} exceeds the ${DEVIN_MAX_FRAME_PAYLOAD}-byte cap`);\n\t\t\t\t}\n\t\t\t\tif (pending.byteLength < 5 + length) break;\n\t\t\t\tconst flags = pending[0] ?? 0;\n\t\t\t\tconst raw = pending.subarray(5, 5 + length);\n\t\t\t\tconst payload: Uint8Array<ArrayBuffer> =\n\t\t\t\t\t(flags & DEVIN_COMPRESSED_FLAG) === 0 ? copyOf(raw) : copyOf(gunzipSync(raw));\n\t\t\t\tpending = pending.subarray(5 + length);\n\t\t\t\tyield (flags & DEVIN_TRAILER_FLAG) === 0\n\t\t\t\t\t? { message: fromBinary(schema, payload) }\n\t\t\t\t\t: { trailer: new TextDecoder().decode(payload) };\n\t\t\t}\n\t\t\tif (done) break;\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n}\n\n/** protobuf-es requires an ArrayBuffer-backed view; Node buffers may be shared. */\nfunction copyOf(source: Uint8Array<ArrayBufferLike>): Uint8Array<ArrayBuffer> {\n\tconst out = new Uint8Array(source.byteLength);\n\tout.set(source);\n\treturn out;\n}\n\nfunction append(head: Uint8Array<ArrayBufferLike>, tail: Uint8Array<ArrayBufferLike>): Uint8Array<ArrayBufferLike> {\n\tif (head.byteLength === 0) return tail;\n\tconst out = new Uint8Array(head.byteLength + tail.byteLength);\n\tout.set(head, 0);\n\tout.set(tail, head.byteLength);\n\treturn out;\n}\n"]}
|