@assemblyline-agents/runtime 1.0.0 → 3.0.0
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/LICENSE +1 -1
- package/dist/a2a-client.d.ts +22 -0
- package/dist/a2a-client.d.ts.map +1 -0
- package/dist/a2a-client.js +211 -0
- package/dist/a2a-client.js.map +1 -0
- package/dist/agent-capability-snapshot.d.ts +32 -0
- package/dist/agent-capability-snapshot.d.ts.map +1 -0
- package/dist/agent-capability-snapshot.js +77 -0
- package/dist/agent-capability-snapshot.js.map +1 -0
- package/dist/agent-event-handlers.d.ts +21 -0
- package/dist/agent-event-handlers.d.ts.map +1 -0
- package/dist/agent-event-handlers.js +64 -0
- package/dist/agent-event-handlers.js.map +1 -0
- package/dist/agent-hook-context.d.ts +8 -0
- package/dist/agent-hook-context.d.ts.map +1 -0
- package/dist/agent-hook-context.js +29 -0
- package/dist/agent-hook-context.js.map +1 -0
- package/dist/agent-hook-evaluation.d.ts +61 -0
- package/dist/agent-hook-evaluation.d.ts.map +1 -0
- package/dist/agent-hook-evaluation.js +197 -0
- package/dist/agent-hook-evaluation.js.map +1 -0
- package/dist/agent-hook-run-lifecycle.d.ts +44 -0
- package/dist/agent-hook-run-lifecycle.d.ts.map +1 -0
- package/dist/agent-hook-run-lifecycle.js +76 -0
- package/dist/agent-hook-run-lifecycle.js.map +1 -0
- package/dist/agent-state.d.ts +31 -0
- package/dist/agent-state.d.ts.map +1 -0
- package/dist/agent-state.js +80 -0
- package/dist/agent-state.js.map +1 -0
- package/dist/agent-surface.d.ts +32 -0
- package/dist/agent-surface.d.ts.map +1 -0
- package/dist/agent-surface.js +85 -0
- package/dist/agent-surface.js.map +1 -0
- package/dist/attachments.d.ts +5 -1
- package/dist/attachments.d.ts.map +1 -1
- package/dist/attachments.js +58 -32
- package/dist/attachments.js.map +1 -1
- package/dist/audience.d.ts +30 -0
- package/dist/audience.d.ts.map +1 -0
- package/dist/audience.js +68 -0
- package/dist/audience.js.map +1 -0
- package/dist/authored-hooks.d.ts +6 -0
- package/dist/authored-hooks.d.ts.map +1 -0
- package/dist/authored-hooks.js +17 -0
- package/dist/authored-hooks.js.map +1 -0
- package/dist/automation-event-match.d.ts +8 -0
- package/dist/automation-event-match.d.ts.map +1 -0
- package/dist/automation-event-match.js +25 -0
- package/dist/automation-event-match.js.map +1 -0
- package/dist/background-review-trigger.d.ts +9 -0
- package/dist/background-review-trigger.d.ts.map +1 -0
- package/dist/background-review-trigger.js +72 -0
- package/dist/background-review-trigger.js.map +1 -0
- package/dist/background-review-types.d.ts +60 -0
- package/dist/background-review-types.d.ts.map +1 -0
- package/dist/background-review-types.js +2 -0
- package/dist/background-review-types.js.map +1 -0
- package/dist/background-review-worker.d.ts +14 -0
- package/dist/background-review-worker.d.ts.map +1 -0
- package/dist/background-review-worker.js +61 -0
- package/dist/background-review-worker.js.map +1 -0
- package/dist/background-review.d.ts +5 -0
- package/dist/background-review.d.ts.map +1 -0
- package/dist/background-review.js +332 -0
- package/dist/background-review.js.map +1 -0
- package/dist/builtin-tool-executors.d.ts +50 -27
- package/dist/builtin-tool-executors.d.ts.map +1 -1
- package/dist/builtin-tool-executors.js +332 -124
- package/dist/builtin-tool-executors.js.map +1 -1
- package/dist/builtin-tools.d.ts +16 -9
- package/dist/builtin-tools.d.ts.map +1 -1
- package/dist/builtin-tools.js +308 -116
- package/dist/builtin-tools.js.map +1 -1
- package/dist/capability-catalog.d.ts +3 -2
- package/dist/capability-catalog.d.ts.map +1 -1
- package/dist/capability-catalog.js +12 -7
- package/dist/capability-catalog.js.map +1 -1
- package/dist/capability-inspection.d.ts +31 -0
- package/dist/capability-inspection.d.ts.map +1 -0
- package/dist/capability-inspection.js +58 -0
- package/dist/capability-inspection.js.map +1 -0
- package/dist/channel-http-util.d.ts.map +1 -1
- package/dist/channel-http-util.js +6 -5
- package/dist/channel-http-util.js.map +1 -1
- package/dist/channel-ingress.d.ts +16 -1
- package/dist/channel-ingress.d.ts.map +1 -1
- package/dist/channel-ingress.js +152 -14
- package/dist/channel-ingress.js.map +1 -1
- package/dist/channel.d.ts +73 -3
- package/dist/channel.d.ts.map +1 -1
- package/dist/checkpoints.d.ts +1 -1
- package/dist/checkpoints.d.ts.map +1 -1
- package/dist/checkpoints.js +6 -6
- package/dist/checkpoints.js.map +1 -1
- package/dist/child-process-env.d.ts +7 -0
- package/dist/child-process-env.d.ts.map +1 -0
- package/dist/child-process-env.js +41 -0
- package/dist/child-process-env.js.map +1 -0
- package/dist/computer-relay-protocol.d.ts.map +1 -1
- package/dist/computer-relay-protocol.js +4 -4
- package/dist/computer-relay-protocol.js.map +1 -1
- package/dist/concurrency.d.ts +1 -1
- package/dist/concurrency.js +1 -1
- package/dist/connection-auth-util.d.ts +1 -0
- package/dist/connection-auth-util.d.ts.map +1 -1
- package/dist/connection-auth-util.js +3 -1
- package/dist/connection-auth-util.js.map +1 -1
- package/dist/connection-clients.d.ts +11 -3
- package/dist/connection-clients.d.ts.map +1 -1
- package/dist/connection-clients.js +71 -8
- package/dist/connection-clients.js.map +1 -1
- package/dist/connection-event-store.d.ts +98 -0
- package/dist/connection-event-store.d.ts.map +1 -0
- package/dist/connection-event-store.js +162 -0
- package/dist/connection-event-store.js.map +1 -0
- package/dist/connection-events.d.ts +51 -0
- package/dist/connection-events.d.ts.map +1 -0
- package/dist/connection-events.js +343 -0
- package/dist/connection-events.js.map +1 -0
- package/dist/connection-stores.d.ts +6 -0
- package/dist/connection-stores.d.ts.map +1 -1
- package/dist/connection-stores.js +20 -1
- package/dist/connection-stores.js.map +1 -1
- package/dist/connection-util.d.ts +3 -2
- package/dist/connection-util.d.ts.map +1 -1
- package/dist/connection-util.js +18 -1
- package/dist/connection-util.js.map +1 -1
- package/dist/connections.d.ts +60 -5
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +390 -57
- package/dist/connections.js.map +1 -1
- package/dist/context-policy-util.d.ts.map +1 -1
- package/dist/context-policy-util.js +1 -3
- package/dist/context-policy-util.js.map +1 -1
- package/dist/conversation-context.d.ts +9 -4
- package/dist/conversation-context.d.ts.map +1 -1
- package/dist/conversation-context.js +65 -19
- package/dist/conversation-context.js.map +1 -1
- package/dist/conversation-transcript.d.ts +8 -5
- package/dist/conversation-transcript.d.ts.map +1 -1
- package/dist/conversation-transcript.js +24 -5
- package/dist/conversation-transcript.js.map +1 -1
- package/dist/conversation-turn-coalescing.d.ts +22 -0
- package/dist/conversation-turn-coalescing.d.ts.map +1 -0
- package/dist/conversation-turn-coalescing.js +121 -0
- package/dist/conversation-turn-coalescing.js.map +1 -0
- package/dist/conversation-turn-dispatch.d.ts +5 -2
- package/dist/conversation-turn-dispatch.d.ts.map +1 -1
- package/dist/conversation-turn-dispatch.js +59 -22
- package/dist/conversation-turn-dispatch.js.map +1 -1
- package/dist/default-outbound-route.d.ts +29 -0
- package/dist/default-outbound-route.d.ts.map +1 -0
- package/dist/default-outbound-route.js +105 -0
- package/dist/default-outbound-route.js.map +1 -0
- package/dist/delivery-artifacts.d.ts +2 -0
- package/dist/delivery-artifacts.d.ts.map +1 -0
- package/dist/delivery-artifacts.js +34 -0
- package/dist/delivery-artifacts.js.map +1 -0
- package/dist/delivery-files.d.ts +5 -0
- package/dist/delivery-files.d.ts.map +1 -0
- package/dist/delivery-files.js +33 -0
- package/dist/delivery-files.js.map +1 -0
- package/dist/delivery-queue.d.ts +21 -1
- package/dist/delivery-queue.d.ts.map +1 -1
- package/dist/delivery-queue.js +144 -1
- package/dist/delivery-queue.js.map +1 -1
- package/dist/delivery-send.d.ts +2 -2
- package/dist/delivery-send.d.ts.map +1 -1
- package/dist/delivery-send.js +256 -100
- package/dist/delivery-send.js.map +1 -1
- package/dist/durable-files.d.ts +37 -0
- package/dist/durable-files.d.ts.map +1 -0
- package/dist/durable-files.js +63 -0
- package/dist/durable-files.js.map +1 -0
- package/dist/harness-loop.d.ts +18 -9
- package/dist/harness-loop.d.ts.map +1 -1
- package/dist/harness-loop.js +245 -50
- package/dist/harness-loop.js.map +1 -1
- package/dist/heic-transcode-worker.d.ts +2 -0
- package/dist/heic-transcode-worker.d.ts.map +1 -0
- package/dist/heic-transcode-worker.js +59 -0
- package/dist/heic-transcode-worker.js.map +1 -0
- package/dist/heic-transcode.d.ts +18 -0
- package/dist/heic-transcode.d.ts.map +1 -0
- package/dist/heic-transcode.js +99 -0
- package/dist/heic-transcode.js.map +1 -0
- package/dist/human-input-routing.d.ts +22 -0
- package/dist/human-input-routing.d.ts.map +1 -0
- package/dist/human-input-routing.js +26 -0
- package/dist/human-input-routing.js.map +1 -0
- package/dist/in-memory-agent-state-store.d.ts +21 -0
- package/dist/in-memory-agent-state-store.d.ts.map +1 -0
- package/dist/in-memory-agent-state-store.js +97 -0
- package/dist/in-memory-agent-state-store.js.map +1 -0
- package/dist/in-memory-conversation-turn-store.d.ts +3 -1
- package/dist/in-memory-conversation-turn-store.d.ts.map +1 -1
- package/dist/in-memory-conversation-turn-store.js +41 -2
- package/dist/in-memory-conversation-turn-store.js.map +1 -1
- package/dist/in-memory-run-store.d.ts +8 -0
- package/dist/in-memory-run-store.d.ts.map +1 -1
- package/dist/in-memory-run-store.js +28 -5
- package/dist/in-memory-run-store.js.map +1 -1
- package/dist/in-memory-sandbox-session-store.d.ts +2 -1
- package/dist/in-memory-sandbox-session-store.d.ts.map +1 -1
- package/dist/in-memory-sandbox-session-store.js +65 -1
- package/dist/in-memory-sandbox-session-store.js.map +1 -1
- package/dist/in-memory-small-stores.d.ts +18 -1
- package/dist/in-memory-small-stores.d.ts.map +1 -1
- package/dist/in-memory-small-stores.js +107 -1
- package/dist/in-memory-small-stores.js.map +1 -1
- package/dist/in-memory-workspace-store.d.ts +40 -0
- package/dist/in-memory-workspace-store.d.ts.map +1 -0
- package/dist/in-memory-workspace-store.js +370 -0
- package/dist/in-memory-workspace-store.js.map +1 -0
- package/dist/index.d.ts +116 -45
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +637 -566
- package/dist/index.js.map +1 -1
- package/dist/json-util.d.ts +8 -0
- package/dist/json-util.d.ts.map +1 -1
- package/dist/json-util.js +8 -0
- package/dist/json-util.js.map +1 -1
- package/dist/learning-store.d.ts +111 -0
- package/dist/learning-store.d.ts.map +1 -0
- package/dist/learning-store.js +193 -0
- package/dist/learning-store.js.map +1 -0
- package/dist/local-sandbox.d.ts +3 -2
- package/dist/local-sandbox.d.ts.map +1 -1
- package/dist/local-sandbox.js +69 -25
- package/dist/local-sandbox.js.map +1 -1
- package/dist/mcp-client.d.ts.map +1 -1
- package/dist/mcp-client.js +3 -2
- package/dist/mcp-client.js.map +1 -1
- package/dist/media-processor.d.ts +42 -0
- package/dist/media-processor.d.ts.map +1 -0
- package/dist/media-processor.js +2 -0
- package/dist/media-processor.js.map +1 -0
- package/dist/model-media.d.ts +13 -1
- package/dist/model-media.d.ts.map +1 -1
- package/dist/model-media.js +81 -18
- package/dist/model-media.js.map +1 -1
- package/dist/model-visible-interrupts.d.ts +10 -0
- package/dist/model-visible-interrupts.d.ts.map +1 -0
- package/dist/model-visible-interrupts.js +41 -0
- package/dist/model-visible-interrupts.js.map +1 -0
- package/dist/operator-controls.d.ts.map +1 -1
- package/dist/operator-controls.js +16 -3
- package/dist/operator-controls.js.map +1 -1
- package/dist/outbound-http-policy.d.ts +7 -0
- package/dist/outbound-http-policy.d.ts.map +1 -0
- package/dist/outbound-http-policy.js +155 -0
- package/dist/outbound-http-policy.js.map +1 -0
- package/dist/principals.d.ts +18 -0
- package/dist/principals.d.ts.map +1 -0
- package/dist/principals.js +90 -0
- package/dist/principals.js.map +1 -0
- package/dist/public-api.d.ts +21 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +19 -0
- package/dist/public-api.js.map +1 -0
- package/dist/replay-resume.d.ts +15 -3
- package/dist/replay-resume.d.ts.map +1 -1
- package/dist/replay-resume.js +256 -24
- package/dist/replay-resume.js.map +1 -1
- package/dist/resource-projection-util.d.ts +1 -1
- package/dist/resource-projection-util.d.ts.map +1 -1
- package/dist/resource-projection-util.js +21 -10
- package/dist/resource-projection-util.js.map +1 -1
- package/dist/resource-projection.d.ts +8 -1
- package/dist/resource-projection.d.ts.map +1 -1
- package/dist/resource-projection.js +230 -26
- package/dist/resource-projection.js.map +1 -1
- package/dist/run-heartbeat.d.ts +12 -2
- package/dist/run-heartbeat.d.ts.map +1 -1
- package/dist/run-heartbeat.js +31 -4
- package/dist/run-heartbeat.js.map +1 -1
- package/dist/run-outcome.d.ts +9 -5
- package/dist/run-outcome.d.ts.map +1 -1
- package/dist/run-outcome.js +16 -5
- package/dist/run-outcome.js.map +1 -1
- package/dist/run-recovery.d.ts +31 -2
- package/dist/run-recovery.d.ts.map +1 -1
- package/dist/run-recovery.js +211 -32
- package/dist/run-recovery.js.map +1 -1
- package/dist/run-replay.d.ts +35 -0
- package/dist/run-replay.d.ts.map +1 -0
- package/dist/run-replay.js +193 -0
- package/dist/run-replay.js.map +1 -0
- package/dist/run-result.d.ts +4 -0
- package/dist/run-result.d.ts.map +1 -0
- package/dist/run-result.js +18 -0
- package/dist/run-result.js.map +1 -0
- package/dist/run-timeline-query.d.ts +38 -0
- package/dist/run-timeline-query.d.ts.map +1 -0
- package/dist/run-timeline-query.js +99 -0
- package/dist/run-timeline-query.js.map +1 -0
- package/dist/runs-query.d.ts.map +1 -1
- package/dist/runs-query.js +12 -4
- package/dist/runs-query.js.map +1 -1
- package/dist/runtime-bundle.d.ts.map +1 -1
- package/dist/runtime-bundle.js +2 -0
- package/dist/runtime-bundle.js.map +1 -1
- package/dist/runtime-learning.d.ts +88 -0
- package/dist/runtime-learning.d.ts.map +1 -0
- package/dist/runtime-learning.js +260 -0
- package/dist/runtime-learning.js.map +1 -0
- package/dist/runtime-types.d.ts +79 -10
- package/dist/runtime-types.d.ts.map +1 -1
- package/dist/sandbox-fs.d.ts +9 -5
- package/dist/sandbox-fs.d.ts.map +1 -1
- package/dist/sandbox-fs.js +50 -33
- package/dist/sandbox-fs.js.map +1 -1
- package/dist/sandbox-handle.d.ts +25 -0
- package/dist/sandbox-handle.d.ts.map +1 -0
- package/dist/sandbox-handle.js +120 -0
- package/dist/sandbox-handle.js.map +1 -0
- package/dist/sandbox-session-identity.d.ts +14 -0
- package/dist/sandbox-session-identity.d.ts.map +1 -0
- package/dist/sandbox-session-identity.js +33 -0
- package/dist/sandbox-session-identity.js.map +1 -0
- package/dist/sandbox-session-key.d.ts.map +1 -1
- package/dist/sandbox-session-key.js +14 -10
- package/dist/sandbox-session-key.js.map +1 -1
- package/dist/sandbox-session-lifecycle.d.ts +12 -0
- package/dist/sandbox-session-lifecycle.d.ts.map +1 -0
- package/dist/sandbox-session-lifecycle.js +261 -0
- package/dist/sandbox-session-lifecycle.js.map +1 -0
- package/dist/sandbox-snapshot-policy.js +3 -3
- package/dist/sandbox-snapshot-policy.js.map +1 -1
- package/dist/sandbox-state-sync.d.ts +22 -0
- package/dist/sandbox-state-sync.d.ts.map +1 -0
- package/dist/sandbox-state-sync.js +147 -0
- package/dist/sandbox-state-sync.js.map +1 -0
- package/dist/sandbox-sync-worker.d.ts +11 -2
- package/dist/sandbox-sync-worker.d.ts.map +1 -1
- package/dist/sandbox-sync-worker.js +143 -31
- package/dist/sandbox-sync-worker.js.map +1 -1
- package/dist/schedule-execution.d.ts.map +1 -1
- package/dist/schedule-execution.js +187 -57
- package/dist/schedule-execution.js.map +1 -1
- package/dist/sdk-api-client.d.ts +17 -0
- package/dist/sdk-api-client.d.ts.map +1 -0
- package/dist/sdk-api-client.js +55 -0
- package/dist/sdk-api-client.js.map +1 -0
- package/dist/security.js +2 -2
- package/dist/security.js.map +1 -1
- package/dist/self-improvement.d.ts +34 -6
- package/dist/self-improvement.d.ts.map +1 -1
- package/dist/self-improvement.js +140 -34
- package/dist/self-improvement.js.map +1 -1
- package/dist/skill-bundles.d.ts +55 -0
- package/dist/skill-bundles.d.ts.map +1 -0
- package/dist/skill-bundles.js +134 -0
- package/dist/skill-bundles.js.map +1 -0
- package/dist/source-loader.d.ts +8 -0
- package/dist/source-loader.d.ts.map +1 -1
- package/dist/source-loader.js +41 -10
- package/dist/source-loader.js.map +1 -1
- package/dist/state-store-helpers.d.ts +2 -0
- package/dist/state-store-helpers.d.ts.map +1 -1
- package/dist/state-store-helpers.js +11 -1
- package/dist/state-store-helpers.js.map +1 -1
- package/dist/state-stores.d.ts +2 -0
- package/dist/state-stores.d.ts.map +1 -1
- package/dist/state-stores.js +40 -7
- package/dist/state-stores.js.map +1 -1
- package/dist/state.d.ts +344 -5
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +44 -2
- package/dist/state.js.map +1 -1
- package/dist/storage.d.ts +59 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +183 -6
- package/dist/storage.js.map +1 -1
- package/dist/subagent-execution.d.ts +7 -6
- package/dist/subagent-execution.d.ts.map +1 -1
- package/dist/subagent-execution.js +58 -19
- package/dist/subagent-execution.js.map +1 -1
- package/dist/target-instructions.d.ts +14 -0
- package/dist/target-instructions.d.ts.map +1 -0
- package/dist/target-instructions.js +18 -0
- package/dist/target-instructions.js.map +1 -0
- package/dist/tool-apis.d.ts.map +1 -1
- package/dist/tool-apis.js +55 -10
- package/dist/tool-apis.js.map +1 -1
- package/dist/tool-execution.d.ts +26 -13
- package/dist/tool-execution.d.ts.map +1 -1
- package/dist/tool-execution.js +368 -239
- package/dist/tool-execution.js.map +1 -1
- package/dist/turn-media.d.ts +29 -0
- package/dist/turn-media.d.ts.map +1 -0
- package/dist/turn-media.js +233 -0
- package/dist/turn-media.js.map +1 -0
- package/dist/usage-reconciliation.d.ts +1 -1
- package/dist/usage-reconciliation.js +1 -1
- package/dist/workspace-id.d.ts +10 -0
- package/dist/workspace-id.d.ts.map +1 -0
- package/dist/workspace-id.js +55 -0
- package/dist/workspace-id.js.map +1 -0
- package/dist/workspace-manifest.d.ts +24 -0
- package/dist/workspace-manifest.d.ts.map +1 -0
- package/dist/workspace-manifest.js +111 -0
- package/dist/workspace-manifest.js.map +1 -0
- package/dist/workspace-operation-limiter.d.ts +16 -0
- package/dist/workspace-operation-limiter.d.ts.map +1 -0
- package/dist/workspace-operation-limiter.js +31 -0
- package/dist/workspace-operation-limiter.js.map +1 -0
- package/dist/workspace-operations.d.ts +145 -0
- package/dist/workspace-operations.d.ts.map +1 -0
- package/dist/workspace-operations.js +420 -0
- package/dist/workspace-operations.js.map +1 -0
- package/dist/workspace-runtime.d.ts +110 -0
- package/dist/workspace-runtime.d.ts.map +1 -0
- package/dist/workspace-runtime.js +240 -0
- package/dist/workspace-runtime.js.map +1 -0
- package/dist/workspace-search.d.ts +55 -0
- package/dist/workspace-search.d.ts.map +1 -0
- package/dist/workspace-search.js +262 -0
- package/dist/workspace-search.js.map +1 -0
- package/dist/workspace-service.d.ts +173 -0
- package/dist/workspace-service.d.ts.map +1 -0
- package/dist/workspace-service.js +619 -0
- package/dist/workspace-service.js.map +1 -0
- package/dist/workspace.d.ts +7 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +7 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +7 -4
- package/dist/agent-harness.d.ts +0 -108
- package/dist/agent-harness.d.ts.map +0 -1
- package/dist/agent-harness.js +0 -2
- package/dist/agent-harness.js.map +0 -1
- package/dist/attachments-legacy.d.ts +0 -17
- package/dist/attachments-legacy.d.ts.map +0 -1
- package/dist/attachments-legacy.js +0 -273
- package/dist/attachments-legacy.js.map +0 -1
- package/dist/code-mode.d.ts +0 -20
- package/dist/code-mode.d.ts.map +0 -1
- package/dist/code-mode.js +0 -658
- package/dist/code-mode.js.map +0 -1
- package/dist/hook-dispatch.d.ts +0 -19
- package/dist/hook-dispatch.d.ts.map +0 -1
- package/dist/hook-dispatch.js +0 -37
- package/dist/hook-dispatch.js.map +0 -1
- package/dist/pi-agent-harness.d.ts +0 -40
- package/dist/pi-agent-harness.d.ts.map +0 -1
- package/dist/pi-agent-harness.js +0 -222
- package/dist/pi-agent-harness.js.map +0 -1
- package/dist/pi-harness.d.ts +0 -42
- package/dist/pi-harness.d.ts.map +0 -1
- package/dist/pi-harness.js +0 -142
- package/dist/pi-harness.js.map +0 -1
- package/dist/run-resolver.d.ts +0 -35
- package/dist/run-resolver.d.ts.map +0 -1
- package/dist/run-resolver.js +0 -84
- package/dist/run-resolver.js.map +0 -1
- package/dist/usage-budget.d.ts +0 -29
- package/dist/usage-budget.d.ts.map +0 -1
- package/dist/usage-budget.js +0 -145
- package/dist/usage-budget.js.map +0 -1
package/dist/connections.js
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { ConnectionAuthorizationFailedError, ConnectionAuthorizationRequiredError, isConnectionAuthorizationFailedError, isConnectionAuthorizationRequiredError } from "@assemblyline-agents/core";
|
|
3
|
+
import { ConnectionAuthorizationFailedError, ConnectionAuthorizationRequiredError, isConnectionAuthorizationFailedError, isConnectionAuthorizationRequiredError, resolveSandboxPath, shellQuote } from "@assemblyline-agents/core";
|
|
3
4
|
import { OAUTH_STANDARD_TOKEN_FIELDS, buildOAuthChallenge, connectionPrincipalFor, connectionPrincipalKey, grantToTokenResult, isTokenExpired, normalizeAuthorization, randomUrlToken, resolveHeadersDefinition, storedGrantExpired, tokenCacheKey } from "./connection-auth-util.js";
|
|
4
|
-
import { HttpApiConnectionClient, McpConnectionClient, OpenApiConnectionClient, RelayMcpConnectionClient, readResponseBody } from "./connection-clients.js";
|
|
5
|
+
import { HttpApiConnectionClient, A2AConnectionClient, CredentialConnectionClient, McpConnectionClient, OpenApiConnectionClient, RelayMcpConnectionClient, SdkApiConnectionClient, readResponseBody } from "./connection-clients.js";
|
|
5
6
|
import { SandboxCliConnectionClient } from "./sandbox-cli-client.js";
|
|
7
|
+
import { audienceAllowsConnectionAccess } from "./audience.js";
|
|
6
8
|
import { InMemoryConnectionAuthorizationSessionStore, InMemoryConnectionGrantStore } from "./connection-stores.js";
|
|
7
|
-
import { connectionToolAccess, isLiveConnection, isRecord, liveDefinitionUrl, parseQualifiedName, scoreMatch, stringValue, timestamp, tokenize } from "./connection-util.js";
|
|
9
|
+
import { connectionToolAccess, connectionToolApproval, isLiveConnection, isRecord, liveDefinitionUrl, parseQualifiedName, scoreMatch, stringValue, timestamp, tokenize } from "./connection-util.js";
|
|
8
10
|
export * from "./connection-auth-util.js";
|
|
9
11
|
export * from "./connection-clients.js";
|
|
10
12
|
export * from "./connection-stores.js";
|
|
11
13
|
export * from "./connection-util.js";
|
|
12
14
|
export * from "./computer-relay-protocol.js";
|
|
15
|
+
export class ConnectionConfigurationError extends Error {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "ConnectionConfigurationError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function isConnectionConfigurationError(error) {
|
|
22
|
+
return error instanceof ConnectionConfigurationError;
|
|
23
|
+
}
|
|
24
|
+
const MATERIALIZED_CREDENTIAL_ROOT = "/workspace/.assembly-line/credentials/";
|
|
13
25
|
// Compose the channel-visible response for a run parked on connection
|
|
14
26
|
// authorization. The generic "authorization required" string is useless to the
|
|
15
27
|
// human — the challenge URL is the thing they need to click.
|
|
@@ -33,23 +45,55 @@ export async function connectionAuthorizationPrompt(store, authorizationSessionI
|
|
|
33
45
|
export async function materializeConnectionCredentialsIntoSandbox(run, registry, sandbox, appendEvent) {
|
|
34
46
|
if (run.input.channel === "subagent" || typeof run.input.parentRunId === "string")
|
|
35
47
|
return;
|
|
36
|
-
const { materialized, pending } = await registry.materializeCredentials(
|
|
48
|
+
const { materialized, pending } = await registry.materializeCredentials({
|
|
49
|
+
id: run.id,
|
|
50
|
+
input: run.input
|
|
51
|
+
});
|
|
37
52
|
if (materialized.length === 0 && pending.length === 0)
|
|
38
53
|
return;
|
|
39
54
|
for (const credential of materialized) {
|
|
40
55
|
for (const file of credential.files) {
|
|
56
|
+
assertMaterializedCredentialPath(credential.connection, file.path);
|
|
41
57
|
await sandbox.writeFile(file.path, file.content);
|
|
42
|
-
|
|
58
|
+
const physicalPath = resolveSandboxPath(sandbox.root, file.path);
|
|
59
|
+
await sandbox.shell(`chmod ${file.mode.toString(8)} -- ${shellQuote(physicalPath)}`);
|
|
60
|
+
}
|
|
61
|
+
for (const command of credential.commands ?? []) {
|
|
62
|
+
await sandbox.shell(command);
|
|
43
63
|
}
|
|
44
64
|
}
|
|
45
65
|
await appendEvent("connections.credentials_materialized", {
|
|
46
66
|
materialized: materialized.map((credential) => ({
|
|
47
67
|
connection: credential.connection,
|
|
48
|
-
files: credential.files.map((file) => file.path)
|
|
68
|
+
files: credential.files.map((file) => file.path),
|
|
69
|
+
...(credential.audit ? { audit: credential.audit } : {})
|
|
49
70
|
})),
|
|
50
71
|
pending
|
|
51
72
|
});
|
|
52
73
|
}
|
|
74
|
+
function assertMaterializedCredentialPath(connectionName, path) {
|
|
75
|
+
const normalized = path.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
76
|
+
if (normalized.split("/").includes("..") || !normalized.startsWith(MATERIALIZED_CREDENTIAL_ROOT)) {
|
|
77
|
+
throw new ConnectionConfigurationError(`Connection ${connectionName} materialize files must be under ${MATERIALIZED_CREDENTIAL_ROOT}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function assertRedactedAuditMetadata(connectionName, audit) {
|
|
81
|
+
const visit = (value, path) => {
|
|
82
|
+
if (Array.isArray(value)) {
|
|
83
|
+
value.forEach((item, index) => visit(item, `${path}[${index}]`));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (!value || typeof value !== "object")
|
|
87
|
+
return;
|
|
88
|
+
for (const [key, item] of Object.entries(value)) {
|
|
89
|
+
if (/(?:token|secret|password|authorization|credential)/iu.test(key)) {
|
|
90
|
+
throw new ConnectionConfigurationError(`Connection ${connectionName} audit metadata contains forbidden secret-like key ${path}.${key}.`);
|
|
91
|
+
}
|
|
92
|
+
visit(item, `${path}.${key}`);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
visit(audit, "audit");
|
|
96
|
+
}
|
|
53
97
|
export const CONNECTION_PAIR_TOOL_NAME = "pair";
|
|
54
98
|
// The synthetic host-side pairing tool advertised for connections that define
|
|
55
99
|
// redeemPairingCode. The input field is named `secret` so tool-call event
|
|
@@ -59,7 +103,7 @@ function pairingToolItem(connection) {
|
|
|
59
103
|
connection: connection.name,
|
|
60
104
|
qualifiedName: `${connection.name}__${CONNECTION_PAIR_TOOL_NAME}`,
|
|
61
105
|
tool: CONNECTION_PAIR_TOOL_NAME,
|
|
62
|
-
description: `Pair ${connection.name} by redeeming a one-time pairing packet or claim code. When the user pastes binding/pairing instructions for ${connection.name}, call this with the FULL pasted text as \`secret\`; the host exchanges it and stores the credential durably.
|
|
106
|
+
description: `Pair ${connection.name} by redeeming a one-time pairing packet or claim code. When the user pastes binding/pairing instructions for ${connection.name}, call this with the FULL pasted text as \`secret\`; the host exchanges it and stores the credential durably. Only call this for a supplied packet; the tool's presence does not mean an existing grant is missing.`,
|
|
63
107
|
inputSchema: {
|
|
64
108
|
type: "object",
|
|
65
109
|
additionalProperties: false,
|
|
@@ -94,6 +138,8 @@ export class RuntimeConnectionRegistry {
|
|
|
94
138
|
clients = new Map();
|
|
95
139
|
tokenCache = new Map();
|
|
96
140
|
executionContext;
|
|
141
|
+
authorizationIntent = new AsyncLocalStorage();
|
|
142
|
+
pendingAuthorizationCreations = new Map();
|
|
97
143
|
grantStore;
|
|
98
144
|
authorizationSessionStore;
|
|
99
145
|
constructor(options) {
|
|
@@ -109,8 +155,48 @@ export class RuntimeConnectionRegistry {
|
|
|
109
155
|
.filter(isLiveConnection)
|
|
110
156
|
.map((connection) => connection.name);
|
|
111
157
|
}
|
|
158
|
+
/** Resolve the host-only event adapter without exposing it as a model tool. */
|
|
159
|
+
async eventBindingContext(connectionName) {
|
|
160
|
+
const compiled = this.options.connections.find((connection) => connection.name === connectionName);
|
|
161
|
+
if (!compiled || !isLiveConnection(compiled)) {
|
|
162
|
+
throw new ConnectionConfigurationError(`Connection ${connectionName} is not registered as a live connection.`);
|
|
163
|
+
}
|
|
164
|
+
const definition = (await this.resolveConnection(compiled)).definition;
|
|
165
|
+
if (!definition.events)
|
|
166
|
+
throw new ConnectionConfigurationError(`Connection ${connectionName} does not accept provider events.`);
|
|
167
|
+
const context = this.resolverContext();
|
|
168
|
+
let principal;
|
|
169
|
+
if (definition.events.scope === "connection") {
|
|
170
|
+
principal = { type: "app" };
|
|
171
|
+
}
|
|
172
|
+
else if (definition.auth) {
|
|
173
|
+
const authorization = await normalizeAuthorization(definition.auth, context);
|
|
174
|
+
principal = connectionPrincipalFor(compiled, authorization, context);
|
|
175
|
+
}
|
|
176
|
+
else if (compiled.subject === "user") {
|
|
177
|
+
const sessionPrincipal = context.session.principal;
|
|
178
|
+
if (!sessionPrincipal || sessionPrincipal.type !== "user") {
|
|
179
|
+
throw new ConnectionConfigurationError(`Connection ${connectionName} events require an authenticated user principal.`);
|
|
180
|
+
}
|
|
181
|
+
principal = sessionPrincipal;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
principal = { type: "app" };
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
compiled,
|
|
188
|
+
events: definition.events,
|
|
189
|
+
principal,
|
|
190
|
+
principalKey: connectionPrincipalKey(principal),
|
|
191
|
+
getToken: async () => {
|
|
192
|
+
if (!definition.auth)
|
|
193
|
+
throw new ConnectionConfigurationError(`Connection ${connectionName} event adapter requested a token without connection auth.`);
|
|
194
|
+
return this.resolveToken(compiled, definition.auth, context, liveDefinitionUrl(definition));
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
112
198
|
async search(input, execution) {
|
|
113
|
-
return this.withExecutionContext(execution, () => this.searchWithContext(input));
|
|
199
|
+
return this.authorizationIntent.run("discover", () => this.withExecutionContext(execution, () => this.searchWithContext(input)));
|
|
114
200
|
}
|
|
115
201
|
async searchWithContext(input) {
|
|
116
202
|
const keywords = input.keywords ?? "";
|
|
@@ -119,15 +205,27 @@ export class RuntimeConnectionRegistry {
|
|
|
119
205
|
const queryTokens = tokenize(keywords);
|
|
120
206
|
const scored = [];
|
|
121
207
|
const failures = [];
|
|
208
|
+
const privateOnly = [];
|
|
122
209
|
// Pairing tools surface even when the connection cannot authenticate yet —
|
|
123
210
|
// redeeming a pasted packet is exactly how an unauthorized connection
|
|
124
211
|
// becomes authorized, so it must not hide behind the failure path.
|
|
125
212
|
const pairable = [];
|
|
126
213
|
for (const connection of target) {
|
|
127
|
-
|
|
128
|
-
|
|
214
|
+
// A personal connection stays registered in a shared run, but its tool
|
|
215
|
+
// catalog, pairing, and authorization state are private-surface only.
|
|
216
|
+
if (!this.connectionAccessible(connection)) {
|
|
217
|
+
privateOnly.push({
|
|
218
|
+
connection: connection.name,
|
|
219
|
+
description: `${connection.name} is registered. Its personal tools, pairing, and authorization status are available only on a private surface such as a direct message; this does not mean a durable grant is missing.`,
|
|
220
|
+
requiresPrivateAudience: true
|
|
221
|
+
});
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
129
224
|
let metadata;
|
|
130
225
|
try {
|
|
226
|
+
if (await this.supportsPairing(connection)) {
|
|
227
|
+
pairable.push(pairingToolItem(connection));
|
|
228
|
+
}
|
|
131
229
|
metadata = await this.getClient(connection.name).getToolMetadata();
|
|
132
230
|
}
|
|
133
231
|
catch (error) {
|
|
@@ -156,23 +254,52 @@ export class RuntimeConnectionRegistry {
|
|
|
156
254
|
scored.sort((a, b) => b.score - a.score);
|
|
157
255
|
const matches = scored.slice(0, limit).map((entry) => entry.item);
|
|
158
256
|
if (matches.length > 0)
|
|
159
|
-
return [...pairable, ...matches, ...failures];
|
|
257
|
+
return [...pairable, ...matches, ...privateOnly, ...failures];
|
|
258
|
+
const privateConnectionNames = new Set(privateOnly.map((item) => item.connection));
|
|
160
259
|
return [
|
|
161
260
|
...pairable,
|
|
261
|
+
...privateOnly,
|
|
162
262
|
...target.map((connection) => ({
|
|
163
263
|
connection: connection.name,
|
|
164
264
|
description: connection.description ?? `${connection.name} connection`
|
|
165
|
-
})),
|
|
265
|
+
})).filter((item) => !privateConnectionNames.has(item.connection)),
|
|
166
266
|
...failures
|
|
167
267
|
];
|
|
168
268
|
}
|
|
269
|
+
// Deliberately does not swallow load errors: a definition module that fails
|
|
270
|
+
// to resolve (for example a deployed artifact missing the connection's
|
|
271
|
+
// package) must surface the real cause instead of silently hiding the
|
|
272
|
+
// pairing tool that would otherwise be the recovery path.
|
|
169
273
|
async supportsPairing(connection) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
274
|
+
return typeof (await this.resolveConnection(connection)).definition.redeemPairingCode === "function";
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Report which live connections can redeem a pairing code right now, and
|
|
278
|
+
* which cannot because their definition failed to resolve (missing package,
|
|
279
|
+
* unset env, platform mismatch). Backs the core `pair` tool: a connection
|
|
280
|
+
* that cannot even load must still be *diagnosable* from the model — the
|
|
281
|
+
* resolve failure is the answer the user needs, not a hidden tool.
|
|
282
|
+
*/
|
|
283
|
+
async pairingStatus() {
|
|
284
|
+
return this.authorizationIntent.run("discover", async () => {
|
|
285
|
+
const pairable = [];
|
|
286
|
+
const unavailable = [];
|
|
287
|
+
for (const connection of this.options.connections) {
|
|
288
|
+
if (!this.toolAllowed(connection))
|
|
289
|
+
continue;
|
|
290
|
+
try {
|
|
291
|
+
if (await this.supportsPairing(connection))
|
|
292
|
+
pairable.push(connection.name);
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
unavailable.push({
|
|
296
|
+
connection: connection.name,
|
|
297
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return { pairable, unavailable };
|
|
302
|
+
});
|
|
176
303
|
}
|
|
177
304
|
/**
|
|
178
305
|
* Redeem a user-provided one-time pairing code host-side and persist the
|
|
@@ -184,6 +311,9 @@ export class RuntimeConnectionRegistry {
|
|
|
184
311
|
if (!compiled || !isLiveConnection(compiled)) {
|
|
185
312
|
throw new Error(`Connection ${connectionName} is not registered as a live connection.`);
|
|
186
313
|
}
|
|
314
|
+
if (!this.connectionAccessible(compiled)) {
|
|
315
|
+
throw new Error(`Connection ${connectionName} is personal and pairs only on a private surface such as a direct message.`);
|
|
316
|
+
}
|
|
187
317
|
const definition = (await this.resolveConnection(compiled)).definition;
|
|
188
318
|
const redeem = definition.redeemPairingCode;
|
|
189
319
|
if (!redeem)
|
|
@@ -206,21 +336,29 @@ export class RuntimeConnectionRegistry {
|
|
|
206
336
|
};
|
|
207
337
|
}
|
|
208
338
|
async metadataForQualifiedName(qualifiedName) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
339
|
+
return this.authorizationIntent.run("discover", async () => {
|
|
340
|
+
const parsed = parseQualifiedName(qualifiedName);
|
|
341
|
+
if (!parsed)
|
|
342
|
+
return undefined;
|
|
343
|
+
const compiled = this.options.connections.find((connection) => connection.name === parsed.connectionName);
|
|
344
|
+
if (!compiled || !this.toolAllowed(compiled))
|
|
345
|
+
return undefined;
|
|
346
|
+
const metadata = await this.getClient(parsed.connectionName).getToolMetadata();
|
|
347
|
+
return metadata.find((tool) => tool.name === parsed.toolName);
|
|
348
|
+
});
|
|
214
349
|
}
|
|
215
350
|
async executeQualifiedTool(qualifiedName, input, execution) {
|
|
216
351
|
const parsed = parseQualifiedName(qualifiedName);
|
|
217
352
|
if (!parsed)
|
|
218
353
|
throw new Error(`Invalid connection tool name: ${qualifiedName}`);
|
|
354
|
+
const compiled = this.options.connections.find((connection) => connection.name === parsed.connectionName);
|
|
355
|
+
if (!compiled || !this.toolAllowed(compiled)) {
|
|
356
|
+
throw new Error(`Connection tool ${qualifiedName} is unavailable here: personal connections work only on a private surface such as a direct message.`);
|
|
357
|
+
}
|
|
219
358
|
// "<connection>__pair" is the synthetic host-side pairing tool; it must
|
|
220
359
|
// run before any client/auth resolution (the whole point is that the
|
|
221
360
|
// connection is not authorized yet).
|
|
222
361
|
if (parsed.toolName === CONNECTION_PAIR_TOOL_NAME) {
|
|
223
|
-
const compiled = this.options.connections.find((connection) => connection.name === parsed.connectionName);
|
|
224
362
|
if (compiled && await this.supportsPairing(compiled)) {
|
|
225
363
|
const secret = isRecord(input) && typeof input.secret === "string" ? input.secret : "";
|
|
226
364
|
return this.withExecutionContext(execution, () => this.redeemPairingCode(parsed.connectionName, secret));
|
|
@@ -232,12 +370,27 @@ export class RuntimeConnectionRegistry {
|
|
|
232
370
|
const compiled = this.options.connections.find((connection) => connection.name === connectionName);
|
|
233
371
|
if (!compiled || !isLiveConnection(compiled))
|
|
234
372
|
return undefined;
|
|
373
|
+
if (!this.toolAllowed(compiled)) {
|
|
374
|
+
throw new Error(`Connection tool ${connectionName}__${toolName} is unavailable here: personal connections work only on a private surface such as a direct message.`);
|
|
375
|
+
}
|
|
376
|
+
// Pairing is a synthetic host-side bootstrap operation, not a provider
|
|
377
|
+
// tool. It must bypass the provider connection's ordinary read/write
|
|
378
|
+
// classification or discovery will advertise a tool that execution then
|
|
379
|
+
// rejects before the redeemer can run.
|
|
380
|
+
if (toolName === CONNECTION_PAIR_TOOL_NAME) {
|
|
381
|
+
if (!await this.supportsPairing(compiled)) {
|
|
382
|
+
throw new Error(`Connection ${connectionName} does not support pairing codes.`);
|
|
383
|
+
}
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
235
386
|
const resolved = await this.resolveConnection(compiled);
|
|
387
|
+
if (!("access" in resolved.definition) || !resolved.definition.access)
|
|
388
|
+
return undefined;
|
|
236
389
|
const access = connectionToolAccess(toolName, resolved.definition.access);
|
|
237
390
|
if (access === "none")
|
|
238
391
|
throw new Error(`Tool ${toolName} is not allowed by connection ${connectionName}.`);
|
|
239
392
|
if (access === "write" && resolved.definition.access.write !== false) {
|
|
240
|
-
return resolved.definition.access
|
|
393
|
+
return connectionToolApproval(toolName, resolved.definition.access);
|
|
241
394
|
}
|
|
242
395
|
return resolved.definition.approval;
|
|
243
396
|
}
|
|
@@ -247,18 +400,24 @@ export class RuntimeConnectionRegistry {
|
|
|
247
400
|
return existing;
|
|
248
401
|
const compiled = this.options.connections.find((connection) => connection.name === connectionName);
|
|
249
402
|
if (!compiled || !isLiveConnection(compiled)) {
|
|
250
|
-
throw new
|
|
403
|
+
throw new ConnectionConfigurationError(`Connection ${connectionName} is not registered as a live connection.`);
|
|
251
404
|
}
|
|
252
405
|
const resolved = () => this.resolveConnection(compiled);
|
|
253
|
-
const client = compiled.protocol === "
|
|
254
|
-
? new
|
|
255
|
-
: compiled.protocol === "
|
|
256
|
-
? compiled
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
:
|
|
406
|
+
const client = compiled.protocol === "credential"
|
|
407
|
+
? new CredentialConnectionClient()
|
|
408
|
+
: compiled.protocol === "cli"
|
|
409
|
+
? new SandboxCliConnectionClient(compiled, resolved, this)
|
|
410
|
+
: compiled.protocol === "mcp"
|
|
411
|
+
? compiled.transport === "relay"
|
|
412
|
+
? new RelayMcpConnectionClient(compiled, resolved, this)
|
|
413
|
+
: new McpConnectionClient(compiled, resolved, this)
|
|
414
|
+
: compiled.protocol === "openapi"
|
|
415
|
+
? new OpenApiConnectionClient(compiled, resolved, this)
|
|
416
|
+
: compiled.protocol === "sdk"
|
|
417
|
+
? new SdkApiConnectionClient(compiled, resolved)
|
|
418
|
+
: compiled.protocol === "a2a"
|
|
419
|
+
? new A2AConnectionClient(compiled, resolved, this)
|
|
420
|
+
: new HttpApiConnectionClient(compiled, resolved, this);
|
|
262
421
|
this.clients.set(connectionName, client);
|
|
263
422
|
return client;
|
|
264
423
|
}
|
|
@@ -299,6 +458,9 @@ export class RuntimeConnectionRegistry {
|
|
|
299
458
|
* session's challenge is reused.
|
|
300
459
|
*/
|
|
301
460
|
async beginAuthorization(connectionName) {
|
|
461
|
+
return this.authorizationIntent.run("authorize", () => this.beginAuthorizationWithContext(connectionName));
|
|
462
|
+
}
|
|
463
|
+
async beginAuthorizationWithContext(connectionName) {
|
|
302
464
|
const compiled = this.options.connections.find((connection) => connection.name === connectionName);
|
|
303
465
|
if (!compiled || !isLiveConnection(compiled))
|
|
304
466
|
return { status: "unavailable", reason: "unknown_connection" };
|
|
@@ -330,29 +492,38 @@ export class RuntimeConnectionRegistry {
|
|
|
330
492
|
* that persists the rotated grant to the grant store BEFORE anything is
|
|
331
493
|
* rendered — so the sandbox only ever sees the short-lived access token.
|
|
332
494
|
*
|
|
333
|
-
* A connection that cannot resolve
|
|
334
|
-
*
|
|
335
|
-
*
|
|
495
|
+
* A normal connection that cannot resolve is reported as pending. An
|
|
496
|
+
* required or explicitly requested credential-protocol connection throws
|
|
497
|
+
* instead, so a run can never continue after a missing, revoked, or
|
|
498
|
+
* mismatched sandbox credential.
|
|
336
499
|
*/
|
|
337
|
-
async materializeCredentials() {
|
|
500
|
+
async materializeCredentials(run) {
|
|
501
|
+
return this.authorizationIntent.run("discover", () => this.materializeCredentialsWithContext(run));
|
|
502
|
+
}
|
|
503
|
+
async materializeCredentialsWithContext(run) {
|
|
338
504
|
const materialized = [];
|
|
339
505
|
const pending = [];
|
|
340
506
|
const context = this.resolverContext();
|
|
341
507
|
for (const compiled of this.options.connections) {
|
|
342
|
-
if (!
|
|
508
|
+
if (!this.toolAllowed(compiled))
|
|
343
509
|
continue;
|
|
510
|
+
const failClosed = compiled.protocol === "credential"
|
|
511
|
+
&& (compiled.required || sandboxCredentialWasRequested(run, compiled.name));
|
|
344
512
|
let definition;
|
|
345
513
|
try {
|
|
346
514
|
definition = (await this.resolveConnection(compiled)).definition;
|
|
347
515
|
}
|
|
348
516
|
catch (error) {
|
|
517
|
+
if (failClosed)
|
|
518
|
+
throw error;
|
|
349
519
|
pending.push({ connection: compiled.name, reason: error instanceof Error ? error.message : String(error) });
|
|
350
520
|
continue;
|
|
351
521
|
}
|
|
352
522
|
const spec = definition.materialize;
|
|
353
|
-
if (!spec || spec.files
|
|
523
|
+
if (!spec || ((spec.files?.length ?? 0) === 0 && !spec.resolve))
|
|
354
524
|
continue;
|
|
355
|
-
const
|
|
525
|
+
const staticFiles = spec.files ?? [];
|
|
526
|
+
const needsToken = staticFiles.some((file) => templateUsesToken(file.path) || templateUsesToken(file.content));
|
|
356
527
|
let resolvedToken = { token: "" };
|
|
357
528
|
if (needsToken) {
|
|
358
529
|
if (!definition.auth) {
|
|
@@ -363,6 +534,64 @@ export class RuntimeConnectionRegistry {
|
|
|
363
534
|
resolvedToken = await this.resolveToken(compiled, definition.auth, context, liveDefinitionUrl(definition));
|
|
364
535
|
}
|
|
365
536
|
catch (error) {
|
|
537
|
+
if (failClosed)
|
|
538
|
+
throw error;
|
|
539
|
+
if (isConnectionAuthorizationRequiredError(error)) {
|
|
540
|
+
const authorizeUrl = typeof error.challenge?.url === "string" ? error.challenge.url : undefined;
|
|
541
|
+
pending.push({ connection: compiled.name, reason: `authorization_required: ${error.reason}`, ...(authorizeUrl ? { authorizeUrl } : {}) });
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
const reason = isConnectionAuthorizationFailedError(error)
|
|
545
|
+
? `${error.reason}: ${error.message}`
|
|
546
|
+
: error instanceof Error
|
|
547
|
+
? error.message
|
|
548
|
+
: String(error);
|
|
549
|
+
pending.push({ connection: compiled.name, reason });
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
let files = staticFiles;
|
|
554
|
+
let commands = [];
|
|
555
|
+
let audit;
|
|
556
|
+
if (spec.resolve) {
|
|
557
|
+
if (!run) {
|
|
558
|
+
pending.push({ connection: compiled.name, reason: "run_context_required" });
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
let lazyToken;
|
|
562
|
+
try {
|
|
563
|
+
const authorization = definition.auth
|
|
564
|
+
? await normalizeAuthorization(definition.auth, context)
|
|
565
|
+
: undefined;
|
|
566
|
+
const principal = authorization
|
|
567
|
+
? connectionPrincipalFor(compiled, authorization, context)
|
|
568
|
+
: { type: "app" };
|
|
569
|
+
const resolved = await spec.resolve({
|
|
570
|
+
connectionName: compiled.name,
|
|
571
|
+
agentId: this.options.agentId ?? "",
|
|
572
|
+
run,
|
|
573
|
+
principal,
|
|
574
|
+
session: context.session,
|
|
575
|
+
env: this.options.env,
|
|
576
|
+
fetch: this.options.fetch,
|
|
577
|
+
getToken: async () => {
|
|
578
|
+
if (!definition.auth)
|
|
579
|
+
throw new Error(`Connection ${compiled.name} materialization requested a token without auth.`);
|
|
580
|
+
lazyToken ??= this.resolveToken(compiled, definition.auth, context, liveDefinitionUrl(definition));
|
|
581
|
+
return lazyToken;
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
if (!resolved)
|
|
585
|
+
continue;
|
|
586
|
+
files = resolved.files;
|
|
587
|
+
commands = resolved.commands ?? [];
|
|
588
|
+
audit = resolved.audit;
|
|
589
|
+
if (audit)
|
|
590
|
+
assertRedactedAuditMetadata(compiled.name, audit);
|
|
591
|
+
}
|
|
592
|
+
catch (error) {
|
|
593
|
+
if (failClosed)
|
|
594
|
+
throw error;
|
|
366
595
|
if (isConnectionAuthorizationRequiredError(error)) {
|
|
367
596
|
const authorizeUrl = typeof error.challenge?.url === "string" ? error.challenge.url : undefined;
|
|
368
597
|
pending.push({ connection: compiled.name, reason: `authorization_required: ${error.reason}`, ...(authorizeUrl ? { authorizeUrl } : {}) });
|
|
@@ -389,14 +618,18 @@ export class RuntimeConnectionRegistry {
|
|
|
389
618
|
try {
|
|
390
619
|
materialized.push({
|
|
391
620
|
connection: compiled.name,
|
|
392
|
-
files:
|
|
621
|
+
files: files.map((file) => ({
|
|
393
622
|
path: renderCredentialTemplate(file.path, values, compiled.name),
|
|
394
623
|
content: renderCredentialTemplate(file.content, values, compiled.name),
|
|
395
624
|
mode: file.mode ?? 0o600
|
|
396
|
-
}))
|
|
625
|
+
})),
|
|
626
|
+
...(commands.length > 0 ? { commands } : {}),
|
|
627
|
+
...(audit ? { audit } : {})
|
|
397
628
|
});
|
|
398
629
|
}
|
|
399
630
|
catch (error) {
|
|
631
|
+
if (failClosed)
|
|
632
|
+
throw error;
|
|
400
633
|
pending.push({ connection: compiled.name, reason: error instanceof Error ? error.message : String(error) });
|
|
401
634
|
}
|
|
402
635
|
}
|
|
@@ -424,6 +657,11 @@ export class RuntimeConnectionRegistry {
|
|
|
424
657
|
const session = await this.authorizationSessionStore.getSessionByState(state);
|
|
425
658
|
if (!session)
|
|
426
659
|
throw new ConnectionAuthorizationFailedError("unknown", { reason: "unknown_state", retryable: false });
|
|
660
|
+
// Provider callbacks are routinely retried. Once the grant was saved and
|
|
661
|
+
// the session completed, return the durable result without attempting to
|
|
662
|
+
// exchange the one-time authorization code again.
|
|
663
|
+
if (session.status === "completed")
|
|
664
|
+
return session;
|
|
427
665
|
if (session.expiresAt <= Date.now()) {
|
|
428
666
|
await this.authorizationSessionStore.updateSession(session.id, { status: "expired" });
|
|
429
667
|
throw new ConnectionAuthorizationFailedError(session.connectionName, { reason: "authorization_expired", retryable: true });
|
|
@@ -444,7 +682,11 @@ export class RuntimeConnectionRegistry {
|
|
|
444
682
|
if (!resolved.definition.auth) {
|
|
445
683
|
throw new ConnectionAuthorizationFailedError(session.connectionName, { reason: "auth_not_configured", retryable: false });
|
|
446
684
|
}
|
|
447
|
-
const authorization = await normalizeAuthorization(resolved.definition.auth, {
|
|
685
|
+
const authorization = await normalizeAuthorization(resolved.definition.auth, {
|
|
686
|
+
env: this.options.env,
|
|
687
|
+
fetch: this.options.fetch,
|
|
688
|
+
session: session.session
|
|
689
|
+
});
|
|
448
690
|
const connectionContext = { url: compiled.url ?? "" };
|
|
449
691
|
let token;
|
|
450
692
|
if (authorization.kind === "oauth" && authorization.oauth) {
|
|
@@ -533,6 +775,15 @@ export class RuntimeConnectionRegistry {
|
|
|
533
775
|
throw new Error(`OpenAPI connection ${compiled.name} must export description.`);
|
|
534
776
|
return { compiled, definition: raw };
|
|
535
777
|
}
|
|
778
|
+
if (compiled.protocol === "a2a") {
|
|
779
|
+
if (typeof raw.agentCardUrl !== "string")
|
|
780
|
+
throw new Error(`A2A connection ${compiled.name} must export agentCardUrl.`);
|
|
781
|
+
if (typeof raw.description !== "string")
|
|
782
|
+
throw new Error(`A2A connection ${compiled.name} must export description.`);
|
|
783
|
+
if (!raw.access || typeof raw.access !== "object")
|
|
784
|
+
throw new Error(`A2A connection ${compiled.name} must export access.`);
|
|
785
|
+
return { compiled, definition: raw };
|
|
786
|
+
}
|
|
536
787
|
if (compiled.protocol === "http") {
|
|
537
788
|
if (typeof raw.baseUrl !== "string")
|
|
538
789
|
throw new Error(`HTTP API connection ${compiled.name} must export baseUrl.`);
|
|
@@ -542,6 +793,18 @@ export class RuntimeConnectionRegistry {
|
|
|
542
793
|
throw new Error(`HTTP API connection ${compiled.name} must export operations.`);
|
|
543
794
|
return { compiled, definition: raw };
|
|
544
795
|
}
|
|
796
|
+
if (compiled.protocol === "sdk") {
|
|
797
|
+
if (compiled.source.path.startsWith("dynamic://")) {
|
|
798
|
+
throw new Error(`Dynamic SDK API connection ${compiled.name} is not allowed.`);
|
|
799
|
+
}
|
|
800
|
+
if (typeof raw.description !== "string" || !Array.isArray(raw.operations) || typeof raw.execute !== "function") {
|
|
801
|
+
throw new Error(`SDK API connection ${compiled.name} must export description, operations, and execute.`);
|
|
802
|
+
}
|
|
803
|
+
if (!raw.access || typeof raw.access !== "object") {
|
|
804
|
+
throw new Error(`SDK API connection ${compiled.name} must export access.`);
|
|
805
|
+
}
|
|
806
|
+
return { compiled, definition: raw };
|
|
807
|
+
}
|
|
545
808
|
if (compiled.protocol === "cli") {
|
|
546
809
|
if (compiled.source.path.startsWith("dynamic://")) {
|
|
547
810
|
throw new Error(`Dynamic CLI connection ${compiled.name} is not allowed.`);
|
|
@@ -554,6 +817,12 @@ export class RuntimeConnectionRegistry {
|
|
|
554
817
|
}
|
|
555
818
|
return { compiled, definition: raw };
|
|
556
819
|
}
|
|
820
|
+
if (compiled.protocol === "credential") {
|
|
821
|
+
if (typeof raw.description !== "string" || !raw.auth || !raw.materialize || typeof raw.materialize !== "object") {
|
|
822
|
+
throw new Error(`Credential connection ${compiled.name} must export description, auth, and materialize.`);
|
|
823
|
+
}
|
|
824
|
+
return { compiled, definition: raw };
|
|
825
|
+
}
|
|
557
826
|
throw new Error(`Connection ${compiled.name} is declaration-only.`);
|
|
558
827
|
}
|
|
559
828
|
targetConnections(name) {
|
|
@@ -563,6 +832,18 @@ export class RuntimeConnectionRegistry {
|
|
|
563
832
|
return !name || connection.name === name;
|
|
564
833
|
});
|
|
565
834
|
}
|
|
835
|
+
/**
|
|
836
|
+
* The single audience rule: personal (user-subject) connections exist only
|
|
837
|
+
* on private surfaces. Everything else — discovery, execution, pairing,
|
|
838
|
+
* and credential materialization — derives from this one predicate.
|
|
839
|
+
*/
|
|
840
|
+
connectionAccessible(connection) {
|
|
841
|
+
const audience = this.options.audience ?? { private: true };
|
|
842
|
+
return audienceAllowsConnectionAccess(audience, connection.subject);
|
|
843
|
+
}
|
|
844
|
+
toolAllowed(connection) {
|
|
845
|
+
return isLiveConnection(connection) && this.connectionAccessible(connection);
|
|
846
|
+
}
|
|
566
847
|
connectionFailure(connection, error) {
|
|
567
848
|
if (isConnectionAuthorizationRequiredError(error)) {
|
|
568
849
|
return {
|
|
@@ -594,14 +875,14 @@ export class RuntimeConnectionRegistry {
|
|
|
594
875
|
if (cached && !isTokenExpired(cached.token))
|
|
595
876
|
return cached.token;
|
|
596
877
|
const connectionContext = { url: resolvedUrl ?? connection.url ?? "" };
|
|
597
|
-
if (authorization.kind === "oauth") {
|
|
878
|
+
if (authorization.kind === "oauth" || authorization.kind === "interactive") {
|
|
598
879
|
const stored = await this.grantStore.getGrant(connection.name, principalKey);
|
|
599
880
|
if (stored && !storedGrantExpired(stored)) {
|
|
600
881
|
const token = grantToTokenResult(stored);
|
|
601
882
|
this.tokenCache.set(cacheKey, { token, authorization, principal, connection: connectionContext });
|
|
602
883
|
return token;
|
|
603
884
|
}
|
|
604
|
-
if (stored?.refreshToken && authorization.oauth) {
|
|
885
|
+
if (stored?.refreshToken && authorization.kind === "oauth" && authorization.oauth) {
|
|
605
886
|
const refreshed = await this.refreshOAuthGrant(authorization.oauth, connection.name, principal, principalKey, stored.refreshToken);
|
|
606
887
|
// saveGrantFromToken preserved the credential bag on the grant; mirror
|
|
607
888
|
// that on the returned token so template rendering sees it too.
|
|
@@ -610,7 +891,9 @@ export class RuntimeConnectionRegistry {
|
|
|
610
891
|
this.tokenCache.set(cacheKey, { token: refreshed, authorization, principal, connection: connectionContext });
|
|
611
892
|
return refreshed;
|
|
612
893
|
}
|
|
613
|
-
|
|
894
|
+
if (authorization.kind === "oauth") {
|
|
895
|
+
throw await this.createAuthorizationRequiredError(connection, authorization, principal, principalKey, context, connectionContext);
|
|
896
|
+
}
|
|
614
897
|
}
|
|
615
898
|
try {
|
|
616
899
|
const token = await authorization.getToken({ principal, connection: connectionContext });
|
|
@@ -619,6 +902,9 @@ export class RuntimeConnectionRegistry {
|
|
|
619
902
|
}
|
|
620
903
|
catch (error) {
|
|
621
904
|
if (isConnectionAuthorizationRequiredError(error) && authorization.kind === "interactive") {
|
|
905
|
+
if (this.authorizationIntent.getStore() === "discover") {
|
|
906
|
+
throw this.authorizationRequiredWithoutSession(connection, error);
|
|
907
|
+
}
|
|
622
908
|
throw await this.createAuthorizationRequiredError(connection, authorization, principal, principalKey, context, connectionContext, error);
|
|
623
909
|
}
|
|
624
910
|
if (isConnectionAuthorizationRequiredError(error) || isConnectionAuthorizationFailedError(error))
|
|
@@ -629,6 +915,7 @@ export class RuntimeConnectionRegistry {
|
|
|
629
915
|
resolverContext() {
|
|
630
916
|
return {
|
|
631
917
|
env: this.options.env,
|
|
918
|
+
fetch: this.options.fetch,
|
|
632
919
|
session: this.options.session
|
|
633
920
|
};
|
|
634
921
|
}
|
|
@@ -644,6 +931,36 @@ export class RuntimeConnectionRegistry {
|
|
|
644
931
|
}
|
|
645
932
|
}
|
|
646
933
|
async createAuthorizationRequiredError(connection, authorization, principal, principalKey, context, connectionContext, cause) {
|
|
934
|
+
if (this.authorizationIntent.getStore() === "discover") {
|
|
935
|
+
return this.authorizationRequiredWithoutSession(connection, cause);
|
|
936
|
+
}
|
|
937
|
+
const key = `${connection.name}\0${principalKey}`;
|
|
938
|
+
const pending = this.pendingAuthorizationCreations.get(key);
|
|
939
|
+
if (pending)
|
|
940
|
+
return pending;
|
|
941
|
+
const creation = this.createAuthorizationRequiredErrorWithContext(connection, authorization, principal, principalKey, context, connectionContext, cause);
|
|
942
|
+
this.pendingAuthorizationCreations.set(key, creation);
|
|
943
|
+
try {
|
|
944
|
+
return await creation;
|
|
945
|
+
}
|
|
946
|
+
finally {
|
|
947
|
+
if (this.pendingAuthorizationCreations.get(key) === creation) {
|
|
948
|
+
this.pendingAuthorizationCreations.delete(key);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
authorizationRequiredWithoutSession(connection, cause) {
|
|
953
|
+
const options = {
|
|
954
|
+
reason: cause?.reason ?? "authorization_required"
|
|
955
|
+
};
|
|
956
|
+
if (cause?.message)
|
|
957
|
+
options.message = cause.message;
|
|
958
|
+
if (cause?.challenge)
|
|
959
|
+
options.challenge = cause.challenge;
|
|
960
|
+
return new ConnectionAuthorizationRequiredError(connection.name, options);
|
|
961
|
+
}
|
|
962
|
+
async createAuthorizationRequiredErrorWithContext(connection, authorization, principal, principalKey, context, connectionContext, cause) {
|
|
963
|
+
await this.authorizationSessionStore.deleteExpiredSessions?.(Date.now());
|
|
647
964
|
const existing = await this.authorizationSessionStore.findPendingSession(connection.name, principalKey);
|
|
648
965
|
if (existing) {
|
|
649
966
|
const options = {
|
|
@@ -675,7 +992,7 @@ export class RuntimeConnectionRegistry {
|
|
|
675
992
|
challenge = buildOAuthChallenge(authorization.oauth, oauthChallengeOptions);
|
|
676
993
|
}
|
|
677
994
|
else if (authorization.startAuthorization) {
|
|
678
|
-
const started = await authorization.startAuthorization({ principal, connection: connectionContext, callbackUrl });
|
|
995
|
+
const started = await authorization.startAuthorization({ principal, connection: connectionContext, callbackUrl, state });
|
|
679
996
|
challenge = started.challenge;
|
|
680
997
|
resume = started.resume;
|
|
681
998
|
if (!challenge.url && cause?.challenge?.url)
|
|
@@ -725,7 +1042,7 @@ export class RuntimeConnectionRegistry {
|
|
|
725
1042
|
return new ConnectionAuthorizationRequiredError(connection.name, errorOptions);
|
|
726
1043
|
}
|
|
727
1044
|
callbackUrl() {
|
|
728
|
-
const base = (this.options.callbackBaseUrl ?? this.options.env.
|
|
1045
|
+
const base = (this.options.callbackBaseUrl ?? this.options.env.ASSEMBLY_LINE_PUBLIC_URL ?? "http://localhost").replace(/\/+$/u, "");
|
|
729
1046
|
return `${base}/assembly-line/connections/callback`;
|
|
730
1047
|
}
|
|
731
1048
|
async exchangeOAuthAuthorizationCode(oauth, session, callback) {
|
|
@@ -752,9 +1069,21 @@ export class RuntimeConnectionRegistry {
|
|
|
752
1069
|
}
|
|
753
1070
|
async requestOAuthToken(oauth, fields) {
|
|
754
1071
|
const body = new URLSearchParams();
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
1072
|
+
const headers = {
|
|
1073
|
+
accept: "application/json",
|
|
1074
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
1075
|
+
};
|
|
1076
|
+
if (oauth.tokenEndpointAuthMethod === "client_secret_basic") {
|
|
1077
|
+
if (!oauth.clientSecret) {
|
|
1078
|
+
throw new ConnectionAuthorizationFailedError("oauth", { reason: "missing_client_secret" });
|
|
1079
|
+
}
|
|
1080
|
+
headers.authorization = `Basic ${Buffer.from(`${oauth.clientId}:${oauth.clientSecret}`).toString("base64")}`;
|
|
1081
|
+
}
|
|
1082
|
+
else {
|
|
1083
|
+
body.set("client_id", oauth.clientId);
|
|
1084
|
+
if (oauth.clientSecret)
|
|
1085
|
+
body.set("client_secret", oauth.clientSecret);
|
|
1086
|
+
}
|
|
758
1087
|
for (const [key, value] of Object.entries(oauth.tokenParams ?? {}))
|
|
759
1088
|
body.set(key, value);
|
|
760
1089
|
for (const [key, value] of Object.entries(fields)) {
|
|
@@ -763,10 +1092,7 @@ export class RuntimeConnectionRegistry {
|
|
|
763
1092
|
}
|
|
764
1093
|
const response = await this.request(oauth.tokenUrl, {
|
|
765
1094
|
method: "POST",
|
|
766
|
-
headers
|
|
767
|
-
accept: "application/json",
|
|
768
|
-
"content-type": "application/x-www-form-urlencoded"
|
|
769
|
-
},
|
|
1095
|
+
headers,
|
|
770
1096
|
body
|
|
771
1097
|
});
|
|
772
1098
|
const payload = await readResponseBody(response);
|
|
@@ -835,4 +1161,11 @@ export class RuntimeConnectionRegistry {
|
|
|
835
1161
|
await this.grantStore.saveGrant(grant);
|
|
836
1162
|
}
|
|
837
1163
|
}
|
|
1164
|
+
function sandboxCredentialWasRequested(run, connectionName) {
|
|
1165
|
+
const requests = run?.input.sandboxCredentials;
|
|
1166
|
+
return Boolean(requests
|
|
1167
|
+
&& typeof requests === "object"
|
|
1168
|
+
&& !Array.isArray(requests)
|
|
1169
|
+
&& Object.prototype.hasOwnProperty.call(requests, connectionName));
|
|
1170
|
+
}
|
|
838
1171
|
//# sourceMappingURL=connections.js.map
|