apex-code 0.0.1-alpha.0 → 0.0.1-alpha.2
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 +24 -0
- package/README.md +66 -681
- package/dist/cli/args.d.ts +5 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +45 -6
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-command.d.ts.map +1 -1
- package/dist/cli/auth-command.js +3 -3
- package/dist/cli/auth-command.js.map +1 -1
- package/dist/cli/cost-command.d.ts +19 -0
- package/dist/cli/cost-command.d.ts.map +1 -0
- package/dist/cli/cost-command.js +107 -0
- package/dist/cli/cost-command.js.map +1 -0
- package/dist/cli/startup-ui.d.ts +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -2
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +45 -16
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -7
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +2 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +9 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +30 -4
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +46 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +137 -19
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +6 -6
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +1 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/context/deferred-schemas.d.ts +92 -0
- package/dist/core/context/deferred-schemas.d.ts.map +1 -0
- package/dist/core/context/deferred-schemas.js +74 -0
- package/dist/core/context/deferred-schemas.js.map +1 -0
- package/dist/core/context/eviction.d.ts +47 -0
- package/dist/core/context/eviction.d.ts.map +1 -0
- package/dist/core/context/eviction.js +83 -0
- package/dist/core/context/eviction.js.map +1 -0
- package/dist/core/context/pipeline.d.ts +90 -0
- package/dist/core/context/pipeline.d.ts.map +1 -0
- package/dist/core/context/pipeline.js +109 -0
- package/dist/core/context/pipeline.js.map +1 -0
- package/dist/core/credential-failover.d.ts +30 -0
- package/dist/core/credential-failover.d.ts.map +1 -0
- package/dist/core/credential-failover.js +46 -0
- package/dist/core/credential-failover.js.map +1 -0
- package/dist/core/credential-pool.d.ts +60 -0
- package/dist/core/credential-pool.d.ts.map +1 -0
- package/dist/core/credential-pool.js +84 -0
- package/dist/core/credential-pool.js.map +1 -0
- package/dist/core/delegation/agents.d.ts +15 -0
- package/dist/core/delegation/agents.d.ts.map +1 -0
- package/dist/core/delegation/agents.js +55 -0
- package/dist/core/delegation/agents.js.map +1 -0
- package/dist/core/delegation/ceiling.d.ts +29 -0
- package/dist/core/delegation/ceiling.d.ts.map +1 -0
- package/dist/core/delegation/ceiling.js +34 -0
- package/dist/core/delegation/ceiling.js.map +1 -0
- package/dist/core/delegation/runtime.d.ts +94 -0
- package/dist/core/delegation/runtime.d.ts.map +1 -0
- package/dist/core/delegation/runtime.js +117 -0
- package/dist/core/delegation/runtime.js.map +1 -0
- package/dist/core/durable-state/daemon.d.ts +37 -0
- package/dist/core/durable-state/daemon.d.ts.map +1 -0
- package/dist/core/durable-state/daemon.js +62 -0
- package/dist/core/durable-state/daemon.js.map +1 -0
- package/dist/core/durable-state/provenance.d.ts +7 -0
- package/dist/core/durable-state/provenance.d.ts.map +1 -0
- package/dist/core/durable-state/provenance.js +24 -0
- package/dist/core/durable-state/provenance.js.map +1 -0
- package/dist/core/durable-state/sqlite.d.ts +84 -0
- package/dist/core/durable-state/sqlite.d.ts.map +1 -0
- package/dist/core/durable-state/sqlite.js +331 -0
- package/dist/core/durable-state/sqlite.js.map +1 -0
- package/dist/core/environment.d.ts +12 -0
- package/dist/core/environment.d.ts.map +1 -0
- package/dist/core/environment.js +69 -0
- package/dist/core/environment.js.map +1 -0
- package/dist/core/evidence-policy.d.ts +17 -0
- package/dist/core/evidence-policy.d.ts.map +1 -0
- package/dist/core/evidence-policy.js +25 -0
- package/dist/core/evidence-policy.js.map +1 -0
- package/dist/core/evidence.d.ts +16 -0
- package/dist/core/evidence.d.ts.map +1 -0
- package/dist/core/evidence.js +51 -0
- package/dist/core/evidence.js.map +1 -0
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js +2 -1
- package/dist/core/experimental.js.map +1 -1
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/model-config.d.ts +8 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +21 -5
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-resolver.d.ts +20 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +59 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +73 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +225 -8
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/observability/aggregate.d.ts +21 -0
- package/dist/core/observability/aggregate.d.ts.map +1 -0
- package/dist/core/observability/aggregate.js +36 -0
- package/dist/core/observability/aggregate.js.map +1 -0
- package/dist/core/observability/otlp.d.ts +66 -0
- package/dist/core/observability/otlp.d.ts.map +1 -0
- package/dist/core/observability/otlp.js +95 -0
- package/dist/core/observability/otlp.js.map +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +3 -2
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/permissions/gate.d.ts +35 -0
- package/dist/core/permissions/gate.d.ts.map +1 -0
- package/dist/core/permissions/gate.js +72 -0
- package/dist/core/permissions/gate.js.map +1 -0
- package/dist/core/permissions/modes.d.ts +18 -0
- package/dist/core/permissions/modes.d.ts.map +1 -0
- package/dist/core/permissions/modes.js +57 -0
- package/dist/core/permissions/modes.js.map +1 -0
- package/dist/core/permissions/responder.d.ts +30 -0
- package/dist/core/permissions/responder.d.ts.map +1 -0
- package/dist/core/permissions/responder.js +32 -0
- package/dist/core/permissions/responder.js.map +1 -0
- package/dist/core/permissions/rules.d.ts +34 -0
- package/dist/core/permissions/rules.d.ts.map +1 -0
- package/dist/core/permissions/rules.js +74 -0
- package/dist/core/permissions/rules.js.map +1 -0
- package/dist/core/permissions/startup.d.ts +33 -0
- package/dist/core/permissions/startup.d.ts.map +1 -0
- package/dist/core/permissions/startup.js +55 -0
- package/dist/core/permissions/startup.js.map +1 -0
- package/dist/core/permissions/store.d.ts +114 -0
- package/dist/core/permissions/store.d.ts.map +1 -0
- package/dist/core/permissions/store.js +229 -0
- package/dist/core/permissions/store.js.map +1 -0
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +1 -1
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/provider-attribution.d.ts.map +1 -1
- package/dist/core/provider-attribution.js +6 -7
- package/dist/core/provider-attribution.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +2 -2
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +20 -16
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/sandbox/child-entry.d.ts +2 -0
- package/dist/core/sandbox/child-entry.d.ts.map +1 -0
- package/dist/core/sandbox/child-entry.js +11 -0
- package/dist/core/sandbox/child-entry.js.map +1 -0
- package/dist/core/sandbox/cli-launch.d.ts +27 -0
- package/dist/core/sandbox/cli-launch.d.ts.map +1 -0
- package/dist/core/sandbox/cli-launch.js +133 -0
- package/dist/core/sandbox/cli-launch.js.map +1 -0
- package/dist/core/sandbox/cli-supervisor.d.ts +25 -0
- package/dist/core/sandbox/cli-supervisor.d.ts.map +1 -0
- package/dist/core/sandbox/cli-supervisor.js +57 -0
- package/dist/core/sandbox/cli-supervisor.js.map +1 -0
- package/dist/core/sandbox/linux-backend.d.ts +18 -0
- package/dist/core/sandbox/linux-backend.d.ts.map +1 -0
- package/dist/core/sandbox/linux-backend.js +186 -0
- package/dist/core/sandbox/linux-backend.js.map +1 -0
- package/dist/core/sandbox/macos-backend.d.ts +18 -0
- package/dist/core/sandbox/macos-backend.d.ts.map +1 -0
- package/dist/core/sandbox/macos-backend.js +195 -0
- package/dist/core/sandbox/macos-backend.js.map +1 -0
- package/dist/core/sandbox/network-proxy.d.ts +19 -0
- package/dist/core/sandbox/network-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/network-proxy.js +79 -0
- package/dist/core/sandbox/network-proxy.js.map +1 -0
- package/dist/core/sandbox/policy.d.ts +32 -0
- package/dist/core/sandbox/policy.d.ts.map +1 -0
- package/dist/core/sandbox/policy.js +38 -0
- package/dist/core/sandbox/policy.js.map +1 -0
- package/dist/core/sandbox/supervisor.d.ts +31 -0
- package/dist/core/sandbox/supervisor.d.ts.map +1 -0
- package/dist/core/sandbox/supervisor.js +18 -0
- package/dist/core/sandbox/supervisor.js.map +1 -0
- package/dist/core/sandbox/violations.d.ts +23 -0
- package/dist/core/sandbox/violations.d.ts.map +1 -0
- package/dist/core/sandbox/violations.js +30 -0
- package/dist/core/sandbox/violations.js.map +1 -0
- package/dist/core/sdk.d.ts +20 -36
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +129 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +41 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +57 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-share.d.ts +16 -0
- package/dist/core/session-share.d.ts.map +1 -0
- package/dist/core/session-share.js +22 -0
- package/dist/core/session-share.js.map +1 -0
- package/dist/core/settings-manager.d.ts +38 -9
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +39 -24
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +5 -5
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/timings.d.ts +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +3 -2
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/ask-user.d.ts +25 -0
- package/dist/core/tools/ask-user.d.ts.map +1 -0
- package/dist/core/tools/ask-user.js +49 -0
- package/dist/core/tools/ask-user.js.map +1 -0
- package/dist/core/tools/bash-command-segments.d.ts +22 -0
- package/dist/core/tools/bash-command-segments.d.ts.map +1 -0
- package/dist/core/tools/bash-command-segments.js +128 -0
- package/dist/core/tools/bash-command-segments.js.map +1 -0
- package/dist/core/tools/bash.d.ts +26 -3
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +105 -16
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/contract.d.ts +156 -0
- package/dist/core/tools/contract.d.ts.map +1 -0
- package/dist/core/tools/contract.js +48 -0
- package/dist/core/tools/contract.js.map +1 -0
- package/dist/core/tools/delegate.d.ts +38 -0
- package/dist/core/tools/delegate.d.ts.map +1 -0
- package/dist/core/tools/delegate.js +66 -0
- package/dist/core/tools/delegate.js.map +1 -0
- package/dist/core/tools/edit.d.ts +2 -2
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +24 -0
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts +2 -2
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +12 -0
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +2 -2
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +12 -0
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +29 -4
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +118 -2
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +2 -2
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +12 -0
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +1 -1
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/path-permission.d.ts +18 -0
- package/dist/core/tools/path-permission.d.ts.map +1 -0
- package/dist/core/tools/path-permission.js +28 -0
- package/dist/core/tools/path-permission.js.map +1 -0
- package/dist/core/tools/plan-present.d.ts +27 -0
- package/dist/core/tools/plan-present.d.ts.map +1 -0
- package/dist/core/tools/plan-present.js +55 -0
- package/dist/core/tools/plan-present.js.map +1 -0
- package/dist/core/tools/read.d.ts +2 -2
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +12 -0
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/test.d.ts +34 -0
- package/dist/core/tools/test.d.ts.map +1 -0
- package/dist/core/tools/test.js +75 -0
- package/dist/core/tools/test.js.map +1 -0
- package/dist/core/tools/todo-write.d.ts +31 -0
- package/dist/core/tools/todo-write.d.ts.map +1 -0
- package/dist/core/tools/todo-write.js +51 -0
- package/dist/core/tools/todo-write.js.map +1 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts +13 -2
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +11 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/tool-schema.d.ts +22 -0
- package/dist/core/tools/tool-schema.d.ts.map +1 -0
- package/dist/core/tools/tool-schema.js +45 -0
- package/dist/core/tools/tool-schema.js.map +1 -0
- package/dist/core/tools/web-fetch.d.ts +26 -0
- package/dist/core/tools/web-fetch.d.ts.map +1 -0
- package/dist/core/tools/web-fetch.js +62 -0
- package/dist/core/tools/web-fetch.js.map +1 -0
- package/dist/core/tools/web-search.d.ts +26 -0
- package/dist/core/tools/web-search.d.ts.map +1 -0
- package/dist/core/tools/web-search.js +53 -0
- package/dist/core/tools/web-search.js.map +1 -0
- package/dist/core/tools/write.d.ts +6 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +32 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/usage-performance-store.d.ts +56 -0
- package/dist/core/usage-performance-store.d.ts.map +1 -0
- package/dist/core/usage-performance-store.js +85 -0
- package/dist/core/usage-performance-store.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +48 -6
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +2 -2
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +9 -6
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +1 -4
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.js +11 -39
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +8 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +49 -20
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +6 -6
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +2 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +58 -9
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -3
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +92 -104
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +2 -2
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +15 -10
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/rpc-entry.d.ts.map +1 -1
- package/dist/rpc-entry.js +2 -1
- package/dist/rpc-entry.js.map +1 -1
- package/dist/server/create-harness.d.ts +1 -1
- package/dist/server/create-harness.d.ts.map +1 -1
- package/dist/server/create-harness.js +6 -5
- package/dist/server/create-harness.js.map +1 -1
- package/dist/testing/replay/metrics.d.ts +24 -0
- package/dist/testing/replay/metrics.d.ts.map +1 -0
- package/dist/testing/replay/metrics.js +35 -0
- package/dist/testing/replay/metrics.js.map +1 -0
- package/dist/testing/replay/recorded-provider.d.ts +10 -0
- package/dist/testing/replay/recorded-provider.d.ts.map +1 -0
- package/dist/testing/replay/recorded-provider.js +108 -0
- package/dist/testing/replay/recorded-provider.js.map +1 -0
- package/dist/testing/replay/runner.d.ts +56 -0
- package/dist/testing/replay/runner.d.ts.map +1 -0
- package/dist/testing/replay/runner.js +406 -0
- package/dist/testing/replay/runner.js.map +1 -0
- package/dist/utils/apex-code-user-agent.d.ts +2 -0
- package/dist/utils/apex-code-user-agent.d.ts.map +1 -0
- package/dist/utils/apex-code-user-agent.js +5 -0
- package/dist/utils/apex-code-user-agent.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +32 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +198 -100
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +5 -5
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +23 -14
- package/dist/utils/version-check.js.map +1 -1
- package/dist/utils/windows-self-update.d.ts.map +1 -1
- package/dist/utils/windows-self-update.js +1 -1
- package/dist/utils/windows-self-update.js.map +1 -1
- package/docs/compaction.md +21 -21
- package/docs/containerization.md +24 -21
- package/docs/custom-provider.md +9 -9
- package/docs/development.md +11 -11
- package/docs/environment-variables.md +36 -77
- package/docs/extensions.md +47 -47
- package/docs/index.md +12 -24
- package/docs/json.md +6 -6
- package/docs/keybindings.md +3 -3
- package/docs/llama-cpp.md +7 -7
- package/docs/models.md +11 -11
- package/docs/packages.md +46 -42
- package/docs/prompt-templates.md +3 -3
- package/docs/providers.md +10 -10
- package/docs/quickstart.md +49 -32
- package/docs/rpc.md +11 -11
- package/docs/sdk.md +4 -4
- package/docs/security.md +18 -18
- package/docs/session-format.md +9 -9
- package/docs/sessions.md +13 -13
- package/docs/settings.md +10 -14
- package/docs/shell-aliases.md +1 -1
- package/docs/skills.md +8 -8
- package/docs/terminal-setup.md +12 -12
- package/docs/termux.md +4 -4
- package/docs/themes.md +8 -8
- package/docs/tmux.md +4 -4
- package/docs/tui.md +3 -3
- package/docs/usage.md +54 -51
- package/docs/windows.md +1 -1
- package/npm-shrinkwrap.json +5 -5
- package/package.json +2 -3
- package/dist/core/telemetry.d.ts +0 -3
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js +0 -9
- package/dist/core/telemetry.js.map +0 -1
- package/dist/utils/pi-user-agent.d.ts +0 -2
- package/dist/utils/pi-user-agent.d.ts.map +0 -1
- package/dist/utils/pi-user-agent.js +0 -5
- package/dist/utils/pi-user-agent.js.map +0 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface SandboxPolicy {
|
|
2
|
+
readonly workspace: string;
|
|
3
|
+
readonly allowedHosts: readonly string[];
|
|
4
|
+
}
|
|
5
|
+
export type SandboxPolicyResult = {
|
|
6
|
+
readonly kind: "valid";
|
|
7
|
+
readonly policy: SandboxPolicy;
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: "invalid";
|
|
10
|
+
readonly reason: string;
|
|
11
|
+
};
|
|
12
|
+
export type SandboxStatus = {
|
|
13
|
+
readonly kind: "enforced";
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: "unavailable";
|
|
16
|
+
readonly reason: string;
|
|
17
|
+
};
|
|
18
|
+
export declare class SandboxUnavailableError extends Error {
|
|
19
|
+
constructor(reason: string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validate the single writable boundary before any platform backend runs. We accept
|
|
23
|
+
* no relative, missing, or non-directory workspace because a backend must never
|
|
24
|
+
* silently broaden an ambiguous path into host authority.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createSandboxPolicy(options: {
|
|
27
|
+
workspace: string;
|
|
28
|
+
allowedHosts?: readonly string[];
|
|
29
|
+
}): SandboxPolicyResult;
|
|
30
|
+
/** Throws rather than returning an executable fallback when OS enforcement is absent. */
|
|
31
|
+
export declare function requireSandboxEnforcement(status: SandboxStatus): void;
|
|
32
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/policy.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,MAAM,MAAM,mBAAmB,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtH,qBAAa,uBAAwB,SAAQ,KAAK;IACjD,YAAY,MAAM,EAAE,MAAM,EAGzB;CACD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC,GAAG,mBAAmB,CAiBtB;AAED,yFAAyF;AACzF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAGrE","sourcesContent":["import { existsSync, realpathSync, statSync } from \"node:fs\";\nimport { isAbsolute } from \"node:path\";\n\nexport interface SandboxPolicy {\n\treadonly workspace: string;\n\treadonly allowedHosts: readonly string[];\n}\n\nexport type SandboxPolicyResult =\n\t| { readonly kind: \"valid\"; readonly policy: SandboxPolicy }\n\t| { readonly kind: \"invalid\"; readonly reason: string };\n\nexport type SandboxStatus = { readonly kind: \"enforced\" } | { readonly kind: \"unavailable\"; readonly reason: string };\n\nexport class SandboxUnavailableError extends Error {\n\tconstructor(reason: string) {\n\t\tsuper(`OS sandbox is not enforcing this agent session: ${reason}`);\n\t\tthis.name = \"SandboxUnavailableError\";\n\t}\n}\n\n/**\n * Validate the single writable boundary before any platform backend runs. We accept\n * no relative, missing, or non-directory workspace because a backend must never\n * silently broaden an ambiguous path into host authority.\n */\nexport function createSandboxPolicy(options: {\n\tworkspace: string;\n\tallowedHosts?: readonly string[];\n}): SandboxPolicyResult {\n\tif (!isAbsolute(options.workspace)) {\n\t\treturn { kind: \"invalid\", reason: \"Sandbox workspace must be an absolute path.\" };\n\t}\n\tif (!existsSync(options.workspace)) {\n\t\treturn { kind: \"invalid\", reason: `Sandbox workspace does not exist: ${options.workspace}` };\n\t}\n\tif (!statSync(options.workspace).isDirectory()) {\n\t\treturn { kind: \"invalid\", reason: `Sandbox workspace is not a directory: ${options.workspace}` };\n\t}\n\treturn {\n\t\tkind: \"valid\",\n\t\tpolicy: {\n\t\t\tworkspace: realpathSync(options.workspace),\n\t\t\tallowedHosts: options.allowedHosts ?? [],\n\t\t},\n\t};\n}\n\n/** Throws rather than returning an executable fallback when OS enforcement is absent. */\nexport function requireSandboxEnforcement(status: SandboxStatus): void {\n\tif (status.kind === \"enforced\") return;\n\tthrow new SandboxUnavailableError(status.reason);\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { isAbsolute } from "node:path";
|
|
3
|
+
export class SandboxUnavailableError extends Error {
|
|
4
|
+
constructor(reason) {
|
|
5
|
+
super(`OS sandbox is not enforcing this agent session: ${reason}`);
|
|
6
|
+
this.name = "SandboxUnavailableError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Validate the single writable boundary before any platform backend runs. We accept
|
|
11
|
+
* no relative, missing, or non-directory workspace because a backend must never
|
|
12
|
+
* silently broaden an ambiguous path into host authority.
|
|
13
|
+
*/
|
|
14
|
+
export function createSandboxPolicy(options) {
|
|
15
|
+
if (!isAbsolute(options.workspace)) {
|
|
16
|
+
return { kind: "invalid", reason: "Sandbox workspace must be an absolute path." };
|
|
17
|
+
}
|
|
18
|
+
if (!existsSync(options.workspace)) {
|
|
19
|
+
return { kind: "invalid", reason: `Sandbox workspace does not exist: ${options.workspace}` };
|
|
20
|
+
}
|
|
21
|
+
if (!statSync(options.workspace).isDirectory()) {
|
|
22
|
+
return { kind: "invalid", reason: `Sandbox workspace is not a directory: ${options.workspace}` };
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
kind: "valid",
|
|
26
|
+
policy: {
|
|
27
|
+
workspace: realpathSync(options.workspace),
|
|
28
|
+
allowedHosts: options.allowedHosts ?? [],
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Throws rather than returning an executable fallback when OS enforcement is absent. */
|
|
33
|
+
export function requireSandboxEnforcement(status) {
|
|
34
|
+
if (status.kind === "enforced")
|
|
35
|
+
return;
|
|
36
|
+
throw new SandboxUnavailableError(status.reason);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../src/core/sandbox/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAavC,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACjD,YAAY,MAAc,EAAE;QAC3B,KAAK,CAAC,mDAAmD,MAAM,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IAAA,CACtC;CACD;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAGnC,EAAuB;IACvB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;IACnF,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,qCAAqC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;IAC9F,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAChD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,yCAAyC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;IAClG,CAAC;IACD,OAAO;QACN,IAAI,EAAE,OAAO;QACb,MAAM,EAAE;YACP,SAAS,EAAE,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC;YAC1C,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,EAAE;SACxC;KACD,CAAC;AAAA,CACF;AAED,yFAAyF;AACzF,MAAM,UAAU,yBAAyB,CAAC,MAAqB,EAAQ;IACtE,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO;IACvC,MAAM,IAAI,uBAAuB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAAA,CACjD","sourcesContent":["import { existsSync, realpathSync, statSync } from \"node:fs\";\nimport { isAbsolute } from \"node:path\";\n\nexport interface SandboxPolicy {\n\treadonly workspace: string;\n\treadonly allowedHosts: readonly string[];\n}\n\nexport type SandboxPolicyResult =\n\t| { readonly kind: \"valid\"; readonly policy: SandboxPolicy }\n\t| { readonly kind: \"invalid\"; readonly reason: string };\n\nexport type SandboxStatus = { readonly kind: \"enforced\" } | { readonly kind: \"unavailable\"; readonly reason: string };\n\nexport class SandboxUnavailableError extends Error {\n\tconstructor(reason: string) {\n\t\tsuper(`OS sandbox is not enforcing this agent session: ${reason}`);\n\t\tthis.name = \"SandboxUnavailableError\";\n\t}\n}\n\n/**\n * Validate the single writable boundary before any platform backend runs. We accept\n * no relative, missing, or non-directory workspace because a backend must never\n * silently broaden an ambiguous path into host authority.\n */\nexport function createSandboxPolicy(options: {\n\tworkspace: string;\n\tallowedHosts?: readonly string[];\n}): SandboxPolicyResult {\n\tif (!isAbsolute(options.workspace)) {\n\t\treturn { kind: \"invalid\", reason: \"Sandbox workspace must be an absolute path.\" };\n\t}\n\tif (!existsSync(options.workspace)) {\n\t\treturn { kind: \"invalid\", reason: `Sandbox workspace does not exist: ${options.workspace}` };\n\t}\n\tif (!statSync(options.workspace).isDirectory()) {\n\t\treturn { kind: \"invalid\", reason: `Sandbox workspace is not a directory: ${options.workspace}` };\n\t}\n\treturn {\n\t\tkind: \"valid\",\n\t\tpolicy: {\n\t\t\tworkspace: realpathSync(options.workspace),\n\t\t\tallowedHosts: options.allowedHosts ?? [],\n\t\t},\n\t};\n}\n\n/** Throws rather than returning an executable fallback when OS enforcement is absent. */\nexport function requireSandboxEnforcement(status: SandboxStatus): void {\n\tif (status.kind === \"enforced\") return;\n\tthrow new SandboxUnavailableError(status.reason);\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type SandboxPolicy, type SandboxStatus } from "./policy.ts";
|
|
2
|
+
export interface SandboxLaunch {
|
|
3
|
+
readonly command: string;
|
|
4
|
+
readonly args: readonly string[];
|
|
5
|
+
readonly policy: SandboxPolicy;
|
|
6
|
+
readonly environment?: NodeJS.ProcessEnv;
|
|
7
|
+
/** Application/runtime directories needed by the child but never writable by it. */
|
|
8
|
+
readonly readOnlyPaths?: readonly string[];
|
|
9
|
+
/** Individual read-only files, such as a host-owned credential file. */
|
|
10
|
+
readonly readOnlyFiles?: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
/** A platform adapter. Its sole job is to launch a normal Apex child inside an OS boundary. */
|
|
13
|
+
export interface SandboxBackend {
|
|
14
|
+
readonly status: SandboxStatus;
|
|
15
|
+
launch(launch: SandboxLaunch): Promise<number>;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export interface SandboxSupervisor {
|
|
19
|
+
readonly status: SandboxStatus;
|
|
20
|
+
launch(options: Omit<SandboxLaunch, "policy">): Promise<number>;
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Owns fail-closed policy propagation and lifecycle; OS details remain behind the
|
|
25
|
+
* backend so all testable security semantics are Apex-owned.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createSandboxSupervisor(options: {
|
|
28
|
+
backend: SandboxBackend;
|
|
29
|
+
policy: SandboxPolicy;
|
|
30
|
+
}): SandboxSupervisor;
|
|
31
|
+
//# sourceMappingURL=supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhG,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACzC,oFAAoF;IACpF,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,wEAAwE;IACxE,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C;AAED,+FAA+F;AAC/F,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAChD,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC;CACtB,GAAG,iBAAiB,CAWpB","sourcesContent":["import { requireSandboxEnforcement, type SandboxPolicy, type SandboxStatus } from \"./policy.ts\";\n\nexport interface SandboxLaunch {\n\treadonly command: string;\n\treadonly args: readonly string[];\n\treadonly policy: SandboxPolicy;\n\treadonly environment?: NodeJS.ProcessEnv;\n\t/** Application/runtime directories needed by the child but never writable by it. */\n\treadonly readOnlyPaths?: readonly string[];\n\t/** Individual read-only files, such as a host-owned credential file. */\n\treadonly readOnlyFiles?: readonly string[];\n}\n\n/** A platform adapter. Its sole job is to launch a normal Apex child inside an OS boundary. */\nexport interface SandboxBackend {\n\treadonly status: SandboxStatus;\n\tlaunch(launch: SandboxLaunch): Promise<number>;\n\tclose(): Promise<void>;\n}\n\nexport interface SandboxSupervisor {\n\treadonly status: SandboxStatus;\n\tlaunch(options: Omit<SandboxLaunch, \"policy\">): Promise<number>;\n\tclose(): Promise<void>;\n}\n\n/**\n * Owns fail-closed policy propagation and lifecycle; OS details remain behind the\n * backend so all testable security semantics are Apex-owned.\n */\nexport function createSandboxSupervisor(options: {\n\tbackend: SandboxBackend;\n\tpolicy: SandboxPolicy;\n}): SandboxSupervisor {\n\treturn {\n\t\tstatus: options.backend.status,\n\t\tasync launch(launch) {\n\t\t\trequireSandboxEnforcement(options.backend.status);\n\t\t\treturn options.backend.launch({ ...launch, policy: options.policy });\n\t\t},\n\t\tasync close() {\n\t\t\tawait options.backend.close();\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { requireSandboxEnforcement } from "./policy.js";
|
|
2
|
+
/**
|
|
3
|
+
* Owns fail-closed policy propagation and lifecycle; OS details remain behind the
|
|
4
|
+
* backend so all testable security semantics are Apex-owned.
|
|
5
|
+
*/
|
|
6
|
+
export function createSandboxSupervisor(options) {
|
|
7
|
+
return {
|
|
8
|
+
status: options.backend.status,
|
|
9
|
+
async launch(launch) {
|
|
10
|
+
requireSandboxEnforcement(options.backend.status);
|
|
11
|
+
return options.backend.launch({ ...launch, policy: options.policy });
|
|
12
|
+
},
|
|
13
|
+
async close() {
|
|
14
|
+
await options.backend.close();
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=supervisor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../../src/core/sandbox/supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAA0C,MAAM,aAAa,CAAC;AA0BhG;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAGvC,EAAqB;IACrB,OAAO;QACN,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;QAC9B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE;YACpB,yBAAyB,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAClD,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAAA,CACrE;QACD,KAAK,CAAC,KAAK,GAAG;YACb,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAAA,CAC9B;KACD,CAAC;AAAA,CACF","sourcesContent":["import { requireSandboxEnforcement, type SandboxPolicy, type SandboxStatus } from \"./policy.ts\";\n\nexport interface SandboxLaunch {\n\treadonly command: string;\n\treadonly args: readonly string[];\n\treadonly policy: SandboxPolicy;\n\treadonly environment?: NodeJS.ProcessEnv;\n\t/** Application/runtime directories needed by the child but never writable by it. */\n\treadonly readOnlyPaths?: readonly string[];\n\t/** Individual read-only files, such as a host-owned credential file. */\n\treadonly readOnlyFiles?: readonly string[];\n}\n\n/** A platform adapter. Its sole job is to launch a normal Apex child inside an OS boundary. */\nexport interface SandboxBackend {\n\treadonly status: SandboxStatus;\n\tlaunch(launch: SandboxLaunch): Promise<number>;\n\tclose(): Promise<void>;\n}\n\nexport interface SandboxSupervisor {\n\treadonly status: SandboxStatus;\n\tlaunch(options: Omit<SandboxLaunch, \"policy\">): Promise<number>;\n\tclose(): Promise<void>;\n}\n\n/**\n * Owns fail-closed policy propagation and lifecycle; OS details remain behind the\n * backend so all testable security semantics are Apex-owned.\n */\nexport function createSandboxSupervisor(options: {\n\tbackend: SandboxBackend;\n\tpolicy: SandboxPolicy;\n}): SandboxSupervisor {\n\treturn {\n\t\tstatus: options.backend.status,\n\t\tasync launch(launch) {\n\t\t\trequireSandboxEnforcement(options.backend.status);\n\t\t\treturn options.backend.launch({ ...launch, policy: options.policy });\n\t\t},\n\t\tasync close() {\n\t\t\tawait options.backend.close();\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type SandboxViolationKind = "filesystem" | "network" | "unknown";
|
|
2
|
+
export interface SandboxViolation {
|
|
3
|
+
readonly kind: SandboxViolationKind;
|
|
4
|
+
readonly command: string;
|
|
5
|
+
readonly detail: string;
|
|
6
|
+
readonly timestamp: Date;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Apex-owned bounded violation tail. It intentionally does not depend on a platform
|
|
10
|
+
* runtime's monitor, because Linux does not provide that monitor consistently.
|
|
11
|
+
*/
|
|
12
|
+
export declare class SandboxViolationStore {
|
|
13
|
+
private readonly capacity;
|
|
14
|
+
private readonly violations;
|
|
15
|
+
private _totalCount;
|
|
16
|
+
constructor(options?: {
|
|
17
|
+
capacity?: number;
|
|
18
|
+
});
|
|
19
|
+
get totalCount(): number;
|
|
20
|
+
add(violation: SandboxViolation): void;
|
|
21
|
+
list(): readonly SandboxViolation[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=violations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"violations.d.ts","sourceRoot":"","sources":["../../../src/core/sandbox/violations.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CACzB;AAED;;;GAGG;AACH,qBAAa,qBAAqB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,OAAO,CAAC,WAAW,CAAK;IAExB,YAAY,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAM1C;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,GAAG,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAMrC;IAED,IAAI,IAAI,SAAS,gBAAgB,EAAE,CAElC;CACD","sourcesContent":["export type SandboxViolationKind = \"filesystem\" | \"network\" | \"unknown\";\n\nexport interface SandboxViolation {\n\treadonly kind: SandboxViolationKind;\n\treadonly command: string;\n\treadonly detail: string;\n\treadonly timestamp: Date;\n}\n\n/**\n * Apex-owned bounded violation tail. It intentionally does not depend on a platform\n * runtime's monitor, because Linux does not provide that monitor consistently.\n */\nexport class SandboxViolationStore {\n\tprivate readonly capacity: number;\n\tprivate readonly violations: SandboxViolation[] = [];\n\tprivate _totalCount = 0;\n\n\tconstructor(options?: { capacity?: number }) {\n\t\tconst capacity = options?.capacity ?? 100;\n\t\tif (!Number.isSafeInteger(capacity) || capacity < 1) {\n\t\t\tthrow new Error(\"Sandbox violation capacity must be a positive safe integer.\");\n\t\t}\n\t\tthis.capacity = capacity;\n\t}\n\n\tget totalCount(): number {\n\t\treturn this._totalCount;\n\t}\n\n\tadd(violation: SandboxViolation): void {\n\t\tthis._totalCount += 1;\n\t\tthis.violations.push(violation);\n\t\tif (this.violations.length > this.capacity) {\n\t\t\tthis.violations.splice(0, this.violations.length - this.capacity);\n\t\t}\n\t}\n\n\tlist(): readonly SandboxViolation[] {\n\t\treturn [...this.violations];\n\t}\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apex-owned bounded violation tail. It intentionally does not depend on a platform
|
|
3
|
+
* runtime's monitor, because Linux does not provide that monitor consistently.
|
|
4
|
+
*/
|
|
5
|
+
export class SandboxViolationStore {
|
|
6
|
+
capacity;
|
|
7
|
+
violations = [];
|
|
8
|
+
_totalCount = 0;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
const capacity = options?.capacity ?? 100;
|
|
11
|
+
if (!Number.isSafeInteger(capacity) || capacity < 1) {
|
|
12
|
+
throw new Error("Sandbox violation capacity must be a positive safe integer.");
|
|
13
|
+
}
|
|
14
|
+
this.capacity = capacity;
|
|
15
|
+
}
|
|
16
|
+
get totalCount() {
|
|
17
|
+
return this._totalCount;
|
|
18
|
+
}
|
|
19
|
+
add(violation) {
|
|
20
|
+
this._totalCount += 1;
|
|
21
|
+
this.violations.push(violation);
|
|
22
|
+
if (this.violations.length > this.capacity) {
|
|
23
|
+
this.violations.splice(0, this.violations.length - this.capacity);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
list() {
|
|
27
|
+
return [...this.violations];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=violations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"violations.js","sourceRoot":"","sources":["../../../src/core/sandbox/violations.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,MAAM,OAAO,qBAAqB;IAChB,QAAQ,CAAS;IACjB,UAAU,GAAuB,EAAE,CAAC;IAC7C,WAAW,GAAG,CAAC,CAAC;IAExB,YAAY,OAA+B,EAAE;QAC5C,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,GAAG,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;QAChF,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAAA,CACzB;IAED,IAAI,UAAU,GAAW;QACxB,OAAO,IAAI,CAAC,WAAW,CAAC;IAAA,CACxB;IAED,GAAG,CAAC,SAA2B,EAAQ;QACtC,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAChC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnE,CAAC;IAAA,CACD;IAED,IAAI,GAAgC;QACnC,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;IAAA,CAC5B;CACD","sourcesContent":["export type SandboxViolationKind = \"filesystem\" | \"network\" | \"unknown\";\n\nexport interface SandboxViolation {\n\treadonly kind: SandboxViolationKind;\n\treadonly command: string;\n\treadonly detail: string;\n\treadonly timestamp: Date;\n}\n\n/**\n * Apex-owned bounded violation tail. It intentionally does not depend on a platform\n * runtime's monitor, because Linux does not provide that monitor consistently.\n */\nexport class SandboxViolationStore {\n\tprivate readonly capacity: number;\n\tprivate readonly violations: SandboxViolation[] = [];\n\tprivate _totalCount = 0;\n\n\tconstructor(options?: { capacity?: number }) {\n\t\tconst capacity = options?.capacity ?? 100;\n\t\tif (!Number.isSafeInteger(capacity) || capacity < 1) {\n\t\t\tthrow new Error(\"Sandbox violation capacity must be a positive safe integer.\");\n\t\t}\n\t\tthis.capacity = capacity;\n\t}\n\n\tget totalCount(): number {\n\t\treturn this._totalCount;\n\t}\n\n\tadd(violation: SandboxViolation): void {\n\t\tthis._totalCount += 1;\n\t\tthis.violations.push(violation);\n\t\tif (this.violations.length > this.capacity) {\n\t\t\tthis.violations.splice(0, this.violations.length - this.capacity);\n\t\t}\n\t}\n\n\tlist(): readonly SandboxViolation[] {\n\t\treturn [...this.violations];\n\t}\n}\n"]}
|
package/dist/core/sdk.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type Model } from "@earendil-works/pi-ai/compat";
|
|
2
2
|
import { type ThinkingLevel } from "apex-code-agent-core";
|
|
3
|
-
import { AgentSession } from "./agent-session.ts";
|
|
3
|
+
import { AgentSession, type AgentSessionConfig } from "./agent-session.ts";
|
|
4
|
+
import type { AgentDefinitionResolver } from "./delegation/runtime.ts";
|
|
4
5
|
import type { LoadExtensionsResult, SessionStartEvent, ToolDefinition } from "./extensions/index.ts";
|
|
5
6
|
import { ModelRuntime } from "./model-runtime.ts";
|
|
6
7
|
import type { ResourceLoader } from "./resource-loader.ts";
|
|
7
8
|
import { SessionManager } from "./session-manager.ts";
|
|
8
9
|
import { SettingsManager } from "./settings-manager.ts";
|
|
10
|
+
import type { EvidenceSink } from "./tools/contract.ts";
|
|
9
11
|
import { createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue } from "./tools/index.ts";
|
|
10
12
|
export interface CreateAgentSessionOptions {
|
|
11
13
|
/** Working directory for project-local discovery. Default: process.cwd() */
|
|
@@ -51,6 +53,23 @@ export interface CreateAgentSessionOptions {
|
|
|
51
53
|
settingsManager?: SettingsManager;
|
|
52
54
|
/** Session start event metadata for extension runtime startup. */
|
|
53
55
|
sessionStartEvent?: SessionStartEvent;
|
|
56
|
+
/** Authorization configuration for every registered tool call. */
|
|
57
|
+
permissionGate?: AgentSessionConfig["permissionGate"];
|
|
58
|
+
/** Optional destination for source-level evidence; defaults to the durable session sink. */
|
|
59
|
+
evidenceSink?: EvidenceSink;
|
|
60
|
+
/**
|
|
61
|
+
* Delegation entry point (roadmap Phase 5, ADR 0008). When set, `delegate`
|
|
62
|
+
* executes real child sessions through `resolveAgent`, with the child's
|
|
63
|
+
* authority derived from this session's live active tools and permission
|
|
64
|
+
* store -- never reconstructed. When omitted, `delegate` stays inert (no agent
|
|
65
|
+
* types resolve). Agent discovery is injected here as a caller-supplied
|
|
66
|
+
* resolver rather than built in, until Phase 5 task 5.5 lands real
|
|
67
|
+
* markdown/frontmatter discovery. Requires `permissionGate` to be set too: a
|
|
68
|
+
* child's authority has nothing to derive from otherwise.
|
|
69
|
+
*/
|
|
70
|
+
delegation?: {
|
|
71
|
+
resolveAgent?: AgentDefinitionResolver;
|
|
72
|
+
};
|
|
54
73
|
}
|
|
55
74
|
/** Result from createAgentSession */
|
|
56
75
|
export interface CreateAgentSessionResult {
|
|
@@ -67,40 +86,5 @@ export type { PromptTemplate } from "./prompt-templates.ts";
|
|
|
67
86
|
export type { Skill } from "./skills.ts";
|
|
68
87
|
export type { Tool } from "./tools/index.ts";
|
|
69
88
|
export { withFileMutationQueue, createCodingTools, createReadOnlyTools, createReadTool, createBashTool, createEditTool, createWriteTool, createGrepTool, createFindTool, createLsTool, };
|
|
70
|
-
/**
|
|
71
|
-
* Create an AgentSession with the specified options.
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* ```typescript
|
|
75
|
-
* // Minimal - uses defaults
|
|
76
|
-
* const { session } = await createAgentSession();
|
|
77
|
-
*
|
|
78
|
-
* // With explicit model
|
|
79
|
-
* import { getModel } from '@earendil-works/pi-ai';
|
|
80
|
-
* const { session } = await createAgentSession({
|
|
81
|
-
* model: getModel('anthropic', 'claude-opus-4-5'),
|
|
82
|
-
* thinkingLevel: 'high',
|
|
83
|
-
* });
|
|
84
|
-
*
|
|
85
|
-
* // Continue previous session
|
|
86
|
-
* const { session, modelFallbackMessage } = await createAgentSession({
|
|
87
|
-
* continueSession: true,
|
|
88
|
-
* });
|
|
89
|
-
*
|
|
90
|
-
* // Full control
|
|
91
|
-
* const loader = new DefaultResourceLoader({
|
|
92
|
-
* cwd: process.cwd(),
|
|
93
|
-
* agentDir: getAgentDir(),
|
|
94
|
-
* settingsManager: SettingsManager.create(),
|
|
95
|
-
* });
|
|
96
|
-
* await loader.reload();
|
|
97
|
-
* const { session } = await createAgentSession({
|
|
98
|
-
* model: myModel,
|
|
99
|
-
* tools: ["read", "bash"],
|
|
100
|
-
* resourceLoader: loader,
|
|
101
|
-
* sessionManager: SessionManager.inMemory(),
|
|
102
|
-
* });
|
|
103
|
-
* ```
|
|
104
|
-
*/
|
|
105
89
|
export declare function createAgentSession(options?: CreateAgentSessionOptions): Promise<CreateAgentSessionResult>;
|
|
106
90
|
//# sourceMappingURL=sdk.d.ts.map
|
package/dist/core/sdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { clampThinkingLevel, type Message, type Model, streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport { Agent, type AgentMessage, setDefaultStreamFn, type ThinkingLevel } from \"apex-code-agent-core\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession } from \"./agent-session.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport type { ExtensionRunner, LoadExtensionsResult, SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { findInitialModel } from \"./model-resolver.ts\";\nimport { ModelRuntime } from \"./model-runtime.ts\";\nimport { mergeProviderAttributionHeaders } from \"./provider-attribution.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport { time } from \"./timings.ts\";\nimport {\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\ttype ToolName,\n\twithFileMutationQueue,\n} from \"./tools/index.ts\";\n\n// Preserve the pre-0.81 fallback for extensions that construct Agent instances\n// or invoke low-level agent loops without supplying streamFn. Agent core remains\n// provider-agnostic and does not import pi-ai/compat itself.\nsetDefaultStreamFn(streamSimple);\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.apex-code/agent */\n\tagentDir?: string;\n\n\t/** Canonical model/auth runtime. Defaults to a runtime using agentDir/auth.json and models.json. */\n\tmodelRuntime?: ModelRuntime;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted, pi enables the default built-in tools (read, bash, edit, write)\n\t * and leaves extension/custom tools enabled unless `noTools` changes that default.\n\t * When provided, only the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start event metadata for extension runtime startup. */\n\tsessionStartEvent?: SessionStartEvent;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tInlineExtension,\n\tSlashCommandInfo,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { Tool } from \"./tools/index.ts\";\n\nexport {\n\twithFileMutationQueue,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from '@earendil-works/pi-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst modelRuntime = options.modelRuntime ?? (await ModelRuntime.create({ authPath, modelsPath }));\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRuntime.getModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRuntime.hasConfiguredAuth(restoredModel.provider)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRuntime,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\tconst initialActiveToolNames: string[] = (\n\t\toptions.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: async (model, context, options) => {\n\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\tconst headerRunner = extensionRunnerRef.current;\n\t\t\treturn modelRuntime.streamSimple(model, context, {\n\t\t\t\t...options,\n\t\t\t\ttimeoutMs,\n\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\tmaxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\ttransformHeaders: async (requestHeaders) => {\n\t\t\t\t\tconst headers = mergeProviderAttributionHeaders(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tsettingsManager,\n\t\t\t\t\t\toptions?.sessionId,\n\t\t\t\t\t\trequestHeaders,\n\t\t\t\t\t);\n\t\t\t\t\treturn headerRunner?.hasHandlers(\"before_provider_headers\")\n\t\t\t\t\t\t? headerRunner.emitBeforeProviderHeaders(headers ?? {})\n\t\t\t\t\t\t: (headers ?? {});\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\tonPayload: async (payload, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload);\n\t\t},\n\t\tonResponse: async (response, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"after_provider_response\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait runner.emit({\n\t\t\t\ttype: \"after_provider_response\",\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: response.headers,\n\t\t\t});\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = existingSession.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRuntime,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\textensionRunnerRef,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t});\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { clampThinkingLevel, type Message, type Model, streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport { Agent, type AgentMessage, setDefaultStreamFn, type ThinkingLevel } from \"apex-code-agent-core\";\nimport { getAgentDir } from \"../config.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession, type AgentSessionConfig } from \"./agent-session.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport { createAgentDefinitionResolver } from \"./delegation/agents.ts\";\nimport type { AgentDefinitionResolver, DelegationRuntimeOptions } from \"./delegation/runtime.ts\";\nimport type { ExtensionRunner, LoadExtensionsResult, SessionStartEvent, ToolDefinition } from \"./extensions/index.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { findInitialModel } from \"./model-resolver.ts\";\nimport { ModelRuntime } from \"./model-runtime.ts\";\nimport { DerivedPermissionRuleStore } from \"./permissions/store.ts\";\nimport { mergeProviderAttributionHeaders } from \"./provider-attribution.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, SessionManager } from \"./session-manager.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport { time } from \"./timings.ts\";\nimport type { ApexToolDefinition, Capability, EvidenceSink } from \"./tools/contract.ts\";\nimport {\n\tcreateAllToolDefinitions,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateDelegateToolDefinition,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\ttype ToolName,\n\twithFileMutationQueue,\n} from \"./tools/index.ts\";\n\n// Preserve the pre-0.81 fallback for extensions that construct Agent instances\n// or invoke low-level agent loops without supplying streamFn. Agent core remains\n// provider-agnostic and does not import pi-ai/compat itself.\nsetDefaultStreamFn(streamSimple);\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.apex-code/agent */\n\tagentDir?: string;\n\n\t/** Canonical model/auth runtime. Defaults to a runtime using agentDir/auth.json and models.json. */\n\tmodelRuntime?: ModelRuntime;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted, pi enables the default built-in tools (read, bash, edit, write)\n\t * and leaves extension/custom tools enabled unless `noTools` changes that default.\n\t * When provided, only the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start event metadata for extension runtime startup. */\n\tsessionStartEvent?: SessionStartEvent;\n\t/** Authorization configuration for every registered tool call. */\n\tpermissionGate?: AgentSessionConfig[\"permissionGate\"];\n\t/** Optional destination for source-level evidence; defaults to the durable session sink. */\n\tevidenceSink?: EvidenceSink;\n\t/**\n\t * Delegation entry point (roadmap Phase 5, ADR 0008). When set, `delegate`\n\t * executes real child sessions through `resolveAgent`, with the child's\n\t * authority derived from this session's live active tools and permission\n\t * store -- never reconstructed. When omitted, `delegate` stays inert (no agent\n\t * types resolve). Agent discovery is injected here as a caller-supplied\n\t * resolver rather than built in, until Phase 5 task 5.5 lands real\n\t * markdown/frontmatter discovery. Requires `permissionGate` to be set too: a\n\t * child's authority has nothing to derive from otherwise.\n\t */\n\tdelegation?: { resolveAgent?: AgentDefinitionResolver };\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tInlineExtension,\n\tSlashCommandInfo,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { Tool } from \"./tools/index.ts\";\n\nexport {\n\twithFileMutationQueue,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from '@earendil-works/pi-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\n/** The most recent assistant text in a completed session -- what a delegated child returns to its parent as its result. */\nfunction extractFinalAssistantText(session: AgentSession): string {\n\tconst messages = session.agent.state.messages;\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst message = messages[i];\n\t\tif (message.role !== \"assistant\") continue;\n\t\tconst text = message.content\n\t\t\t.filter(\n\t\t\t\t(content): content is Extract<AgentMessage, { role: \"assistant\" }>[\"content\"][number] & { type: \"text\" } =>\n\t\t\t\t\tcontent.type === \"text\",\n\t\t\t)\n\t\t\t.map((content) => content.text)\n\t\t\t.join(\"\\n\");\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst modelRuntime = options.modelRuntime ?? (await ModelRuntime.create({ authPath, modelsPath }));\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRuntime.getModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRuntime.hasConfiguredAuth(restoredModel.provider)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRuntime,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\tconst initialActiveToolNames: string[] = (\n\t\toptions.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: async (model, context, options) => {\n\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\tconst headerRunner = extensionRunnerRef.current;\n\t\t\treturn modelRuntime.streamSimple(model, context, {\n\t\t\t\t...options,\n\t\t\t\ttimeoutMs,\n\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\tmaxRetries: options?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\tmaxRetryDelayMs: options?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\ttransformHeaders: async (requestHeaders) => {\n\t\t\t\t\tconst headers = mergeProviderAttributionHeaders(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tsettingsManager,\n\t\t\t\t\t\toptions?.sessionId,\n\t\t\t\t\t\trequestHeaders,\n\t\t\t\t\t);\n\t\t\t\t\treturn headerRunner?.hasHandlers(\"before_provider_headers\")\n\t\t\t\t\t\t? headerRunner.emitBeforeProviderHeaders(headers ?? {})\n\t\t\t\t\t\t: (headers ?? {});\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\tonPayload: async (payload, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload);\n\t\t},\n\t\tonResponse: async (response, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"after_provider_response\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait runner.emit({\n\t\t\t\ttype: \"after_provider_response\",\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: response.headers,\n\t\t\t});\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = existingSession.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\t// Forward ref, mirroring extensionRunnerRef above: the delegation runtime's\n\t// closures are needed to build `customTools` before `session` exists, but they\n\t// must read the *live* session (active tools can change after construction),\n\t// not a snapshot frozen at this point.\n\tconst parentSessionRef: { current?: AgentSession } = {};\n\tconst customTools: ToolDefinition[] = options.customTools ? [...options.customTools] : [];\n\t// A configured permission gate supplies the authority a child must derive, so\n\t// discovery is enabled by default in real sessions. Callers that need fixture\n\t// definitions may still provide an explicit resolver.\n\tconst delegation = options.delegation ?? (options.permissionGate ? {} : undefined);\n\tif (delegation) {\n\t\tconst parentPermissionGate = options.permissionGate;\n\t\tconst resolveAgent =\n\t\t\tdelegation.resolveAgent ??\n\t\t\tcreateAgentDefinitionResolver({\n\t\t\t\tcwd,\n\t\t\t\tagentDir,\n\t\t\t\tisProjectTrusted: () => settingsManager.isProjectTrusted(),\n\t\t\t});\n\t\tconst delegationRuntime: DelegationRuntimeOptions = {\n\t\t\tresolveAgent,\n\t\t\tgetParentCapabilities: () => {\n\t\t\t\tconst capabilities = new Set<Capability>();\n\t\t\t\tfor (const name of parentSessionRef.current?.getActiveToolNames() ?? []) {\n\t\t\t\t\tconst contract = (\n\t\t\t\t\t\tparentSessionRef.current?.getToolDefinition(name) as Partial<ApexToolDefinition> | undefined\n\t\t\t\t\t)?.contract;\n\t\t\t\t\tif (contract) for (const capability of contract.capabilities) capabilities.add(capability);\n\t\t\t\t}\n\t\t\t\treturn capabilities;\n\t\t\t},\n\t\t\tgetToolCapabilities: (toolName) => {\n\t\t\t\t// Prefer the parent's own live registry first (it also covers\n\t\t\t\t// extension/custom tools an agent definition might name), but fall back\n\t\t\t\t// to the canonical built-in registry: \"what capability does tool X\n\t\t\t\t// need\" is a property of the tool itself, independent of whether the\n\t\t\t\t// parent's own session restricted it out of its active/allowed set via\n\t\t\t\t// `tools`/`excludeTools` -- that restriction affects the parent's own\n\t\t\t\t// *authority* (getParentCapabilities, above), not what a named tool is.\n\t\t\t\tconst fromParent = (\n\t\t\t\t\tparentSessionRef.current?.getToolDefinition(toolName) as Partial<ApexToolDefinition> | undefined\n\t\t\t\t)?.contract?.capabilities;\n\t\t\t\tif (fromParent) return fromParent;\n\t\t\t\treturn (createAllToolDefinitions(cwd)[toolName as ToolName] as ApexToolDefinition | undefined)?.contract\n\t\t\t\t\t?.capabilities;\n\t\t\t},\n\t\t\t// Read fresh each call, not captured once: depth is a live property of\n\t\t\t// the (possibly delegated) session this createAgentSession call is\n\t\t\t// building, via the same sessionManager this closure already captures.\n\t\t\tgetDelegationDepth: () => sessionManager.getDelegationDepth(),\n\t\t\tmaxDelegationDepth: settingsManager.getDelegationMaxDepth(),\n\t\t\tgetParentSessionDir: () => sessionManager.getSessionDir(),\n\t\t\tbuildChildSession: async ({ definition, toolNames, depth, sessionId, artifactDir }) => {\n\t\t\t\tif (!parentPermissionGate) {\n\t\t\t\t\tthrow new Error(\"delegate requires a permission gate configured on the parent session (ADR 0008).\");\n\t\t\t\t}\n\t\t\t\tconst childModel =\n\t\t\t\t\t(definition.model && modelRuntime.getAvailableSnapshot().find((m) => m.id === definition.model)) ||\n\t\t\t\t\tmodel;\n\t\t\t\tif (!childModel) {\n\t\t\t\t\tthrow new Error(`Cannot delegate to \"${definition.name}\": no model is available for the child session.`);\n\t\t\t\t}\n\t\t\t\tconst childSessionManager = artifactDir\n\t\t\t\t\t? SessionManager.create(cwd, artifactDir, {\n\t\t\t\t\t\t\tid: sessionId,\n\t\t\t\t\t\t\tparentSession: sessionManager.getSessionId(),\n\t\t\t\t\t\t\tdelegationDepth: depth,\n\t\t\t\t\t\t})\n\t\t\t\t\t: SessionManager.inMemory(cwd, {\n\t\t\t\t\t\t\tparentSession: sessionManager.getSessionId(),\n\t\t\t\t\t\t\tdelegationDepth: depth,\n\t\t\t\t\t\t});\n\t\t\t\tconst derivedStore = new DerivedPermissionRuleStore({ parent: parentPermissionGate.store });\n\t\t\t\tconst { session: childSession } = await createAgentSession({\n\t\t\t\t\tcwd,\n\t\t\t\t\tagentDir,\n\t\t\t\t\tmodel: childModel,\n\t\t\t\t\tmodelRuntime,\n\t\t\t\t\tsettingsManager,\n\t\t\t\t\tsessionManager: childSessionManager,\n\t\t\t\t\tresourceLoader,\n\t\t\t\t\ttools: toolNames,\n\t\t\t\t\t// No responder: a child's `ask` fails closed rather than prompting the\n\t\t\t\t\t// human for a call the human did not make (ADR 0008, \"Who answers a\n\t\t\t\t\t// child's ask\").\n\t\t\t\t\tpermissionGate: { store: derivedStore, getMode: parentPermissionGate.getMode },\n\t\t\t\t\t// Forwarded so a child that itself holds `delegate` can delegate again\n\t\t\t\t\t// (bounded by the depth guard above, read fresh from its own session\n\t\t\t\t\t// header on its next createAgentSession call) -- otherwise recursion\n\t\t\t\t\t// would be silently capped at one level regardless of maxDelegationDepth.\n\t\t\t\t\tdelegation,\n\t\t\t\t});\n\t\t\t\tawait childSession.bindExtensions({});\n\t\t\t\treturn {\n\t\t\t\t\tasync run(task: string) {\n\t\t\t\t\t\tconst prompt = definition.systemPrompt\n\t\t\t\t\t\t\t? `${definition.systemPrompt}\\n\\nTask: ${task}`\n\t\t\t\t\t\t\t: `Task: ${task}`;\n\t\t\t\t\t\tawait childSession.prompt(prompt);\n\t\t\t\t\t\treturn { output: extractFinalAssistantText(childSession) };\n\t\t\t\t\t},\n\t\t\t\t\tdispose() {\n\t\t\t\t\t\tchildSession.dispose();\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t},\n\t\t};\n\t\tcustomTools.push(createDelegateToolDefinition(delegationRuntime) as ToolDefinition<any, any>);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools,\n\t\tmodelRuntime,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\textensionRunnerRef,\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t\tpermissionGate: options.permissionGate,\n\t\tevidenceSink: options.evidenceSink,\n\t});\n\tparentSessionRef.current = session;\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
package/dist/core/sdk.js
CHANGED
|
@@ -6,15 +6,17 @@ import { resolvePath } from "../utils/paths.js";
|
|
|
6
6
|
import { AgentSession } from "./agent-session.js";
|
|
7
7
|
import { formatNoModelsAvailableMessage } from "./auth-guidance.js";
|
|
8
8
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
9
|
+
import { createAgentDefinitionResolver } from "./delegation/agents.js";
|
|
9
10
|
import { convertToLlm } from "./messages.js";
|
|
10
11
|
import { findInitialModel } from "./model-resolver.js";
|
|
11
12
|
import { ModelRuntime } from "./model-runtime.js";
|
|
13
|
+
import { DerivedPermissionRuleStore } from "./permissions/store.js";
|
|
12
14
|
import { mergeProviderAttributionHeaders } from "./provider-attribution.js";
|
|
13
15
|
import { DefaultResourceLoader } from "./resource-loader.js";
|
|
14
16
|
import { getDefaultSessionDir, SessionManager } from "./session-manager.js";
|
|
15
17
|
import { SettingsManager } from "./settings-manager.js";
|
|
16
18
|
import { time } from "./timings.js";
|
|
17
|
-
import { createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue, } from "./tools/index.js";
|
|
19
|
+
import { createAllToolDefinitions, createBashTool, createCodingTools, createDelegateToolDefinition, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue, } from "./tools/index.js";
|
|
18
20
|
// Preserve the pre-0.81 fallback for extensions that construct Agent instances
|
|
19
21
|
// or invoke low-level agent loops without supplying streamFn. Agent core remains
|
|
20
22
|
// provider-agnostic and does not import pi-ai/compat itself.
|
|
@@ -63,6 +65,22 @@ function getDefaultAgentDir() {
|
|
|
63
65
|
* });
|
|
64
66
|
* ```
|
|
65
67
|
*/
|
|
68
|
+
/** The most recent assistant text in a completed session -- what a delegated child returns to its parent as its result. */
|
|
69
|
+
function extractFinalAssistantText(session) {
|
|
70
|
+
const messages = session.agent.state.messages;
|
|
71
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
72
|
+
const message = messages[i];
|
|
73
|
+
if (message.role !== "assistant")
|
|
74
|
+
continue;
|
|
75
|
+
const text = message.content
|
|
76
|
+
.filter((content) => content.type === "text")
|
|
77
|
+
.map((content) => content.text)
|
|
78
|
+
.join("\n");
|
|
79
|
+
if (text)
|
|
80
|
+
return text;
|
|
81
|
+
}
|
|
82
|
+
return "";
|
|
83
|
+
}
|
|
66
84
|
export async function createAgentSession(options = {}) {
|
|
67
85
|
const cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());
|
|
68
86
|
const agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();
|
|
@@ -242,6 +260,112 @@ export async function createAgentSession(options = {}) {
|
|
|
242
260
|
}
|
|
243
261
|
sessionManager.appendThinkingLevelChange(thinkingLevel);
|
|
244
262
|
}
|
|
263
|
+
// Forward ref, mirroring extensionRunnerRef above: the delegation runtime's
|
|
264
|
+
// closures are needed to build `customTools` before `session` exists, but they
|
|
265
|
+
// must read the *live* session (active tools can change after construction),
|
|
266
|
+
// not a snapshot frozen at this point.
|
|
267
|
+
const parentSessionRef = {};
|
|
268
|
+
const customTools = options.customTools ? [...options.customTools] : [];
|
|
269
|
+
// A configured permission gate supplies the authority a child must derive, so
|
|
270
|
+
// discovery is enabled by default in real sessions. Callers that need fixture
|
|
271
|
+
// definitions may still provide an explicit resolver.
|
|
272
|
+
const delegation = options.delegation ?? (options.permissionGate ? {} : undefined);
|
|
273
|
+
if (delegation) {
|
|
274
|
+
const parentPermissionGate = options.permissionGate;
|
|
275
|
+
const resolveAgent = delegation.resolveAgent ??
|
|
276
|
+
createAgentDefinitionResolver({
|
|
277
|
+
cwd,
|
|
278
|
+
agentDir,
|
|
279
|
+
isProjectTrusted: () => settingsManager.isProjectTrusted(),
|
|
280
|
+
});
|
|
281
|
+
const delegationRuntime = {
|
|
282
|
+
resolveAgent,
|
|
283
|
+
getParentCapabilities: () => {
|
|
284
|
+
const capabilities = new Set();
|
|
285
|
+
for (const name of parentSessionRef.current?.getActiveToolNames() ?? []) {
|
|
286
|
+
const contract = parentSessionRef.current?.getToolDefinition(name)?.contract;
|
|
287
|
+
if (contract)
|
|
288
|
+
for (const capability of contract.capabilities)
|
|
289
|
+
capabilities.add(capability);
|
|
290
|
+
}
|
|
291
|
+
return capabilities;
|
|
292
|
+
},
|
|
293
|
+
getToolCapabilities: (toolName) => {
|
|
294
|
+
// Prefer the parent's own live registry first (it also covers
|
|
295
|
+
// extension/custom tools an agent definition might name), but fall back
|
|
296
|
+
// to the canonical built-in registry: "what capability does tool X
|
|
297
|
+
// need" is a property of the tool itself, independent of whether the
|
|
298
|
+
// parent's own session restricted it out of its active/allowed set via
|
|
299
|
+
// `tools`/`excludeTools` -- that restriction affects the parent's own
|
|
300
|
+
// *authority* (getParentCapabilities, above), not what a named tool is.
|
|
301
|
+
const fromParent = parentSessionRef.current?.getToolDefinition(toolName)?.contract?.capabilities;
|
|
302
|
+
if (fromParent)
|
|
303
|
+
return fromParent;
|
|
304
|
+
return createAllToolDefinitions(cwd)[toolName]?.contract
|
|
305
|
+
?.capabilities;
|
|
306
|
+
},
|
|
307
|
+
// Read fresh each call, not captured once: depth is a live property of
|
|
308
|
+
// the (possibly delegated) session this createAgentSession call is
|
|
309
|
+
// building, via the same sessionManager this closure already captures.
|
|
310
|
+
getDelegationDepth: () => sessionManager.getDelegationDepth(),
|
|
311
|
+
maxDelegationDepth: settingsManager.getDelegationMaxDepth(),
|
|
312
|
+
getParentSessionDir: () => sessionManager.getSessionDir(),
|
|
313
|
+
buildChildSession: async ({ definition, toolNames, depth, sessionId, artifactDir }) => {
|
|
314
|
+
if (!parentPermissionGate) {
|
|
315
|
+
throw new Error("delegate requires a permission gate configured on the parent session (ADR 0008).");
|
|
316
|
+
}
|
|
317
|
+
const childModel = (definition.model && modelRuntime.getAvailableSnapshot().find((m) => m.id === definition.model)) ||
|
|
318
|
+
model;
|
|
319
|
+
if (!childModel) {
|
|
320
|
+
throw new Error(`Cannot delegate to "${definition.name}": no model is available for the child session.`);
|
|
321
|
+
}
|
|
322
|
+
const childSessionManager = artifactDir
|
|
323
|
+
? SessionManager.create(cwd, artifactDir, {
|
|
324
|
+
id: sessionId,
|
|
325
|
+
parentSession: sessionManager.getSessionId(),
|
|
326
|
+
delegationDepth: depth,
|
|
327
|
+
})
|
|
328
|
+
: SessionManager.inMemory(cwd, {
|
|
329
|
+
parentSession: sessionManager.getSessionId(),
|
|
330
|
+
delegationDepth: depth,
|
|
331
|
+
});
|
|
332
|
+
const derivedStore = new DerivedPermissionRuleStore({ parent: parentPermissionGate.store });
|
|
333
|
+
const { session: childSession } = await createAgentSession({
|
|
334
|
+
cwd,
|
|
335
|
+
agentDir,
|
|
336
|
+
model: childModel,
|
|
337
|
+
modelRuntime,
|
|
338
|
+
settingsManager,
|
|
339
|
+
sessionManager: childSessionManager,
|
|
340
|
+
resourceLoader,
|
|
341
|
+
tools: toolNames,
|
|
342
|
+
// No responder: a child's `ask` fails closed rather than prompting the
|
|
343
|
+
// human for a call the human did not make (ADR 0008, "Who answers a
|
|
344
|
+
// child's ask").
|
|
345
|
+
permissionGate: { store: derivedStore, getMode: parentPermissionGate.getMode },
|
|
346
|
+
// Forwarded so a child that itself holds `delegate` can delegate again
|
|
347
|
+
// (bounded by the depth guard above, read fresh from its own session
|
|
348
|
+
// header on its next createAgentSession call) -- otherwise recursion
|
|
349
|
+
// would be silently capped at one level regardless of maxDelegationDepth.
|
|
350
|
+
delegation,
|
|
351
|
+
});
|
|
352
|
+
await childSession.bindExtensions({});
|
|
353
|
+
return {
|
|
354
|
+
async run(task) {
|
|
355
|
+
const prompt = definition.systemPrompt
|
|
356
|
+
? `${definition.systemPrompt}\n\nTask: ${task}`
|
|
357
|
+
: `Task: ${task}`;
|
|
358
|
+
await childSession.prompt(prompt);
|
|
359
|
+
return { output: extractFinalAssistantText(childSession) };
|
|
360
|
+
},
|
|
361
|
+
dispose() {
|
|
362
|
+
childSession.dispose();
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
customTools.push(createDelegateToolDefinition(delegationRuntime));
|
|
368
|
+
}
|
|
245
369
|
const session = new AgentSession({
|
|
246
370
|
agent,
|
|
247
371
|
sessionManager,
|
|
@@ -249,14 +373,17 @@ export async function createAgentSession(options = {}) {
|
|
|
249
373
|
cwd,
|
|
250
374
|
scopedModels: options.scopedModels,
|
|
251
375
|
resourceLoader,
|
|
252
|
-
customTools
|
|
376
|
+
customTools,
|
|
253
377
|
modelRuntime,
|
|
254
378
|
initialActiveToolNames,
|
|
255
379
|
allowedToolNames,
|
|
256
380
|
excludedToolNames,
|
|
257
381
|
extensionRunnerRef,
|
|
258
382
|
sessionStartEvent: options.sessionStartEvent,
|
|
383
|
+
permissionGate: options.permissionGate,
|
|
384
|
+
evidenceSink: options.evidenceSink,
|
|
259
385
|
});
|
|
386
|
+
parentSessionRef.current = session;
|
|
260
387
|
const extensionsResult = resourceLoader.getExtensions();
|
|
261
388
|
return {
|
|
262
389
|
session,
|