@namzu/sdk 32.0.0 → 33.1.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/CHANGELOG.md +157 -0
- package/dist/authorization/gate.d.ts +1 -1
- package/dist/authorization/gate.js +1 -1
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +13 -0
- package/dist/bridge/a2a/mapper.js.map +1 -1
- package/dist/bridge/sse/mapper.d.ts.map +1 -1
- package/dist/bridge/sse/mapper.js +3 -0
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/connector/index.d.ts +1 -1
- package/dist/connector/index.d.ts.map +1 -1
- package/dist/connector/index.js +1 -1
- package/dist/connector/index.js.map +1 -1
- package/dist/connector/mcp/adapter.d.ts.map +1 -1
- package/dist/connector/mcp/adapter.js +71 -16
- package/dist/connector/mcp/adapter.js.map +1 -1
- package/dist/connector/mcp/client.d.ts.map +1 -1
- package/dist/connector/mcp/client.js +3 -2
- package/dist/connector/mcp/client.js.map +1 -1
- package/dist/connector/mcp/http-redirect.d.ts +17 -0
- package/dist/connector/mcp/http-redirect.d.ts.map +1 -0
- package/dist/connector/mcp/http-redirect.js +31 -0
- package/dist/connector/mcp/http-redirect.js.map +1 -0
- package/dist/connector/mcp/http-sse.d.ts.map +1 -1
- package/dist/connector/mcp/http-sse.js +5 -0
- package/dist/connector/mcp/http-sse.js.map +1 -1
- package/dist/connector/mcp/image-admission.d.ts +16 -0
- package/dist/connector/mcp/image-admission.d.ts.map +1 -0
- package/dist/connector/mcp/image-admission.js +288 -0
- package/dist/connector/mcp/image-admission.js.map +1 -0
- package/dist/connector/mcp/stdio.d.ts +13 -0
- package/dist/connector/mcp/stdio.d.ts.map +1 -1
- package/dist/connector/mcp/stdio.js +66 -23
- package/dist/connector/mcp/stdio.js.map +1 -1
- package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
- package/dist/connector/mcp/streamable-http.js +3 -0
- package/dist/connector/mcp/streamable-http.js.map +1 -1
- package/dist/constants/tools/index.js +1 -1
- package/dist/constants/tools/index.js.map +1 -1
- package/dist/execution/base.d.ts +13 -0
- package/dist/execution/base.d.ts.map +1 -1
- package/dist/execution/base.js +103 -8
- package/dist/execution/base.js.map +1 -1
- package/dist/execution/errors.d.ts +12 -0
- package/dist/execution/errors.d.ts.map +1 -0
- package/dist/execution/errors.js +21 -0
- package/dist/execution/errors.js.map +1 -0
- package/dist/execution/factory.d.ts.map +1 -1
- package/dist/execution/factory.js +1 -0
- package/dist/execution/factory.js.map +1 -1
- package/dist/execution/hybrid.d.ts +5 -0
- package/dist/execution/hybrid.d.ts.map +1 -1
- package/dist/execution/hybrid.js +36 -16
- package/dist/execution/hybrid.js.map +1 -1
- package/dist/execution/index.d.ts +1 -0
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +1 -0
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/local.d.ts +13 -0
- package/dist/execution/local.d.ts.map +1 -1
- package/dist/execution/local.js +145 -19
- package/dist/execution/local.js.map +1 -1
- package/dist/execution/output.d.ts +27 -0
- package/dist/execution/output.d.ts.map +1 -0
- package/dist/execution/output.js +105 -0
- package/dist/execution/output.js.map +1 -0
- package/dist/execution/remote.d.ts +26 -2
- package/dist/execution/remote.d.ts.map +1 -1
- package/dist/execution/remote.js +86 -15
- package/dist/execution/remote.js.map +1 -1
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +9 -3
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/process/kill-tree.d.ts +11 -13
- package/dist/process/kill-tree.d.ts.map +1 -1
- package/dist/process/kill-tree.js +11 -13
- package/dist/process/kill-tree.js.map +1 -1
- package/dist/provider/capabilities.d.ts +2 -0
- package/dist/provider/capabilities.d.ts.map +1 -1
- package/dist/provider/capabilities.js +6 -0
- package/dist/provider/capabilities.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +31 -0
- package/dist/provider/fallback.js.map +1 -1
- package/dist/provider/idle-timeout.d.ts.map +1 -1
- package/dist/provider/idle-timeout.js +5 -0
- package/dist/provider/idle-timeout.js.map +1 -1
- package/dist/provider/retry.d.ts.map +1 -1
- package/dist/provider/retry.js +5 -0
- package/dist/provider/retry.js.map +1 -1
- package/dist/public-runtime.d.ts +2 -2
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +2 -2
- package/dist/public-runtime.js.map +1 -1
- package/dist/registry/tool/execute.d.ts +7 -1
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +201 -54
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/run/command-gate.d.ts.map +1 -1
- package/dist/run/command-gate.js +11 -0
- package/dist/run/command-gate.js.map +1 -1
- package/dist/run/workspace-fingerprint.d.ts +4 -4
- package/dist/run/workspace-fingerprint.d.ts.map +1 -1
- package/dist/run/workspace-fingerprint.js +6 -4
- package/dist/run/workspace-fingerprint.js.map +1 -1
- package/dist/runtime/bidi/index.d.ts +1 -1
- package/dist/runtime/bidi/index.d.ts.map +1 -1
- package/dist/runtime/bidi/index.js +1 -1
- package/dist/runtime/bidi/index.js.map +1 -1
- package/dist/runtime/bidi/session.d.ts +19 -0
- package/dist/runtime/bidi/session.d.ts.map +1 -1
- package/dist/runtime/bidi/session.js +150 -26
- package/dist/runtime/bidi/session.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +43 -1
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +626 -161
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +3 -1
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +48 -4
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +10 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +67 -0
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +5 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +84 -22
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
- package/dist/runtime/query/request-rich-content.js +33 -13
- package/dist/runtime/query/request-rich-content.js.map +1 -1
- package/dist/runtime/query/result.d.ts.map +1 -1
- package/dist/runtime/query/result.js +25 -22
- package/dist/runtime/query/result.js.map +1 -1
- package/dist/runtime/query/resume-pending.d.ts +5 -1
- package/dist/runtime/query/resume-pending.d.ts.map +1 -1
- package/dist/runtime/query/resume-pending.js +66 -1
- package/dist/runtime/query/resume-pending.js.map +1 -1
- package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
- package/dist/runtime/query/tool-output-budget.js +45 -16
- package/dist/runtime/query/tool-output-budget.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +6 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +4 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/sandbox/provider/local.d.ts.map +1 -1
- package/dist/sandbox/provider/local.js +193 -41
- package/dist/sandbox/provider/local.js.map +1 -1
- package/dist/scheduler/delegating.d.ts +2 -1
- package/dist/scheduler/delegating.d.ts.map +1 -1
- package/dist/scheduler/delegating.js +6 -5
- package/dist/scheduler/delegating.js.map +1 -1
- package/dist/scheduler/local.d.ts +2 -1
- package/dist/scheduler/local.d.ts.map +1 -1
- package/dist/scheduler/local.js +2 -2
- package/dist/scheduler/local.js.map +1 -1
- package/dist/session/workspace/driver.d.ts +12 -4
- package/dist/session/workspace/driver.d.ts.map +1 -1
- package/dist/session/workspace/git-worktree.d.ts +17 -3
- package/dist/session/workspace/git-worktree.d.ts.map +1 -1
- package/dist/session/workspace/git-worktree.js +153 -34
- package/dist/session/workspace/git-worktree.js.map +1 -1
- package/dist/skills/registry.d.ts +15 -0
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +33 -0
- package/dist/skills/registry.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +76 -2
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/tools/builtins/run-code.d.ts.map +1 -1
- package/dist/tools/builtins/run-code.js +9 -11
- package/dist/tools/builtins/run-code.js.map +1 -1
- package/dist/tools/builtins/skill.d.ts +2 -1
- package/dist/tools/builtins/skill.d.ts.map +1 -1
- package/dist/tools/builtins/skill.js +250 -6
- package/dist/tools/builtins/skill.js.map +1 -1
- package/dist/tools/coordinator/agent.d.ts.map +1 -1
- package/dist/tools/coordinator/agent.js +100 -30
- package/dist/tools/coordinator/agent.js.map +1 -1
- package/dist/types/agent/manager.d.ts +1 -1
- package/dist/types/agent/manager.d.ts.map +1 -1
- package/dist/types/agent/scheduler.d.ts +10 -1
- package/dist/types/agent/scheduler.d.ts.map +1 -1
- package/dist/types/authorization/index.d.ts +12 -12
- package/dist/types/bidi/index.d.ts +19 -2
- package/dist/types/bidi/index.d.ts.map +1 -1
- package/dist/types/computer-use/index.d.ts +18 -0
- package/dist/types/computer-use/index.d.ts.map +1 -1
- package/dist/types/connector/execution-context.d.ts +3 -1
- package/dist/types/connector/execution-context.d.ts.map +1 -1
- package/dist/types/errors/catalog.d.ts.map +1 -1
- package/dist/types/errors/catalog.js +13 -6
- package/dist/types/errors/catalog.js.map +1 -1
- package/dist/types/errors/index.d.ts.map +1 -1
- package/dist/types/errors/index.js +21 -8
- package/dist/types/errors/index.js.map +1 -1
- package/dist/types/execution/index.d.ts +43 -1
- package/dist/types/execution/index.d.ts.map +1 -1
- package/dist/types/hitl/index.d.ts +11 -0
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/message/index.d.ts +1 -1
- package/dist/types/message/index.d.ts.map +1 -1
- package/dist/types/message/index.js +2 -1
- package/dist/types/message/index.js.map +1 -1
- package/dist/types/plugin/index.d.ts +14 -1
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/dist/types/plugin/index.js +1 -0
- package/dist/types/plugin/index.js.map +1 -1
- package/dist/types/provider/config.d.ts +9 -0
- package/dist/types/provider/config.d.ts.map +1 -1
- package/dist/types/provider/interface.d.ts +14 -0
- package/dist/types/provider/interface.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +17 -0
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/sandbox/index.d.ts +15 -10
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/tool/index.d.ts +77 -6
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/types/tool/presentation.d.ts +6 -2
- package/dist/types/tool/presentation.d.ts.map +1 -1
- package/dist/types/workspace/ref.d.ts +5 -0
- package/dist/types/workspace/ref.d.ts.map +1 -1
- package/dist/utils/abort.d.ts +8 -0
- package/dist/utils/abort.d.ts.map +1 -1
- package/dist/utils/abort.js +16 -0
- package/dist/utils/abort.js.map +1 -1
- package/package.json +4 -4
- package/src/authorization/gate.ts +1 -1
- package/src/bridge/a2a/mapper.ts +23 -4
- package/src/bridge/sse/mapper.ts +3 -0
- package/src/connector/index.ts +2 -0
- package/src/connector/mcp/adapter.ts +82 -21
- package/src/connector/mcp/client.ts +2 -1
- package/src/connector/mcp/http-redirect.ts +32 -0
- package/src/connector/mcp/http-sse.ts +5 -0
- package/src/connector/mcp/image-admission.ts +272 -0
- package/src/connector/mcp/stdio.ts +63 -21
- package/src/connector/mcp/streamable-http.ts +3 -0
- package/src/constants/tools/index.ts +1 -1
- package/src/execution/base.ts +124 -7
- package/src/execution/errors.ts +24 -0
- package/src/execution/factory.ts +1 -0
- package/src/execution/hybrid.ts +47 -16
- package/src/execution/index.ts +1 -0
- package/src/execution/local.ts +164 -19
- package/src/execution/output.ts +104 -0
- package/src/execution/remote.ts +122 -17
- package/src/plugin/lifecycle.ts +9 -3
- package/src/process/kill-tree.ts +11 -13
- package/src/provider/capabilities.ts +10 -0
- package/src/provider/fallback.ts +39 -0
- package/src/provider/idle-timeout.ts +8 -0
- package/src/provider/retry.ts +8 -0
- package/src/public-runtime.ts +7 -1
- package/src/registry/tool/execute.ts +230 -64
- package/src/run/command-gate.ts +12 -0
- package/src/run/workspace-fingerprint.ts +5 -4
- package/src/runtime/bidi/index.ts +1 -1
- package/src/runtime/bidi/session.ts +177 -28
- package/src/runtime/query/executor.ts +769 -163
- package/src/runtime/query/index.ts +58 -7
- package/src/runtime/query/iteration/index.ts +72 -0
- package/src/runtime/query/iteration/phases/context.ts +5 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +87 -23
- package/src/runtime/query/request-rich-content.ts +39 -14
- package/src/runtime/query/result.ts +25 -23
- package/src/runtime/query/resume-pending.ts +83 -1
- package/src/runtime/query/tool-output-budget.ts +52 -17
- package/src/runtime/query/tooling.ts +10 -0
- package/src/sandbox/provider/local.ts +213 -45
- package/src/scheduler/delegating.ts +6 -5
- package/src/scheduler/local.ts +3 -2
- package/src/session/workspace/driver.ts +12 -4
- package/src/session/workspace/git-worktree.ts +173 -34
- package/src/skills/registry.ts +47 -0
- package/src/tools/builtins/computer-use.ts +86 -2
- package/src/tools/builtins/run-code.ts +9 -11
- package/src/tools/builtins/skill.ts +325 -7
- package/src/tools/coordinator/agent.ts +108 -33
- package/src/types/agent/manager.ts +1 -1
- package/src/types/agent/scheduler.ts +10 -1
- package/src/types/bidi/index.ts +19 -2
- package/src/types/computer-use/index.ts +19 -0
- package/src/types/connector/execution-context.ts +3 -0
- package/src/types/errors/catalog.ts +14 -6
- package/src/types/errors/index.ts +22 -8
- package/src/types/execution/index.ts +46 -1
- package/src/types/hitl/index.ts +11 -0
- package/src/types/message/index.ts +3 -2
- package/src/types/plugin/index.ts +15 -0
- package/src/types/provider/config.ts +9 -0
- package/src/types/provider/interface.ts +18 -0
- package/src/types/run/events.ts +17 -3
- package/src/types/sandbox/index.ts +15 -10
- package/src/types/tool/index.ts +85 -6
- package/src/types/tool/presentation.ts +10 -3
- package/src/types/workspace/ref.ts +5 -0
- package/src/utils/abort.ts +18 -0
|
@@ -12,6 +12,32 @@ import { generateRunId } from '../../utils/id.js'
|
|
|
12
12
|
import { SCOPE_ATTRIBUTE } from '../../utils/log/types.js'
|
|
13
13
|
import { type Logger, resolveLogger } from '../../utils/logger.js'
|
|
14
14
|
|
|
15
|
+
const DEFAULT_CLOSE_TIMEOUT_MS = 5_000
|
|
16
|
+
const MAX_TIMER_DELAY_MS = 2_147_483_647
|
|
17
|
+
|
|
18
|
+
export class BidiSessionCloseTimeoutError extends Error {
|
|
19
|
+
constructor(readonly timeoutMs: number) {
|
|
20
|
+
super(
|
|
21
|
+
`Duplex provider session close did not settle within ${timeoutMs}ms. The local run is fenced and its tool authority was revoked, but provider cleanup is still unconfirmed.`,
|
|
22
|
+
)
|
|
23
|
+
this.name = 'BidiSessionCloseTimeoutError'
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function waitForProviderClose(pending: Promise<void>, timeoutMs: number): Promise<void> {
|
|
28
|
+
if (timeoutMs === 0) return await pending
|
|
29
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
30
|
+
const timeout = new Promise<never>((_, reject) => {
|
|
31
|
+
timer = setTimeout(() => reject(new BidiSessionCloseTimeoutError(timeoutMs)), timeoutMs)
|
|
32
|
+
timer.unref?.()
|
|
33
|
+
})
|
|
34
|
+
try {
|
|
35
|
+
await Promise.race([pending, timeout])
|
|
36
|
+
} finally {
|
|
37
|
+
if (timer) clearTimeout(timer)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
15
41
|
/**
|
|
16
42
|
* Run tools for a duplex session.
|
|
17
43
|
*
|
|
@@ -38,7 +64,17 @@ export interface BidiRunParams {
|
|
|
38
64
|
readonly connect: BidiConnectParams
|
|
39
65
|
readonly workingDirectory: string
|
|
40
66
|
readonly env?: Record<string, string>
|
|
67
|
+
/**
|
|
68
|
+
* Owns the complete run lifetime, not only connection establishment.
|
|
69
|
+
* Aborting it closes the provider session, ends local events and revokes
|
|
70
|
+
* every tool context without mutating the caller-owned controller.
|
|
71
|
+
*/
|
|
41
72
|
readonly signal?: AbortSignal
|
|
73
|
+
/**
|
|
74
|
+
* How long `close()` waits for provider cleanup after fencing locally.
|
|
75
|
+
* Defaults to five seconds. `0` preserves an unbounded provider-close wait.
|
|
76
|
+
*/
|
|
77
|
+
readonly closeTimeoutMs?: number
|
|
42
78
|
readonly log?: Logger
|
|
43
79
|
/** Overrides the generated id, so a host can correlate its own. */
|
|
44
80
|
readonly runId?: RunId
|
|
@@ -50,36 +86,133 @@ export interface BidiRun {
|
|
|
50
86
|
events(): AsyncIterable<BidiRunEvent>
|
|
51
87
|
/** Push input from the human. */
|
|
52
88
|
send(input: Parameters<BidiSession['send']>[0]): Promise<void>
|
|
89
|
+
/**
|
|
90
|
+
* Fence the local run immediately, abort tool contexts and close the
|
|
91
|
+
* provider once. It does not wait for tool code that ignores cancellation;
|
|
92
|
+
* provider cleanup is observed for `BidiRunParams.closeTimeoutMs`.
|
|
93
|
+
*/
|
|
53
94
|
close(): Promise<void>
|
|
54
95
|
}
|
|
55
96
|
|
|
56
97
|
export async function startBidiRun(params: BidiRunParams): Promise<BidiRun> {
|
|
98
|
+
params.signal?.throwIfAborted()
|
|
99
|
+
const closeTimeoutMs = params.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS
|
|
100
|
+
if (
|
|
101
|
+
!Number.isInteger(closeTimeoutMs) ||
|
|
102
|
+
closeTimeoutMs < 0 ||
|
|
103
|
+
closeTimeoutMs > MAX_TIMER_DELAY_MS
|
|
104
|
+
) {
|
|
105
|
+
throw new RangeError(
|
|
106
|
+
`BidiRunParams.closeTimeoutMs must be an integer from 0 through ${MAX_TIMER_DELAY_MS}`,
|
|
107
|
+
)
|
|
108
|
+
}
|
|
57
109
|
const runId = params.runId ?? generateRunId()
|
|
58
110
|
const log = resolveLogger(params.log).child({
|
|
59
111
|
[SCOPE_ATTRIBUTE]: 'runtime/bidi/session',
|
|
60
112
|
[NAMZU.RUN_ID]: runId,
|
|
61
113
|
})
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
114
|
+
const lifetime = new AbortController()
|
|
115
|
+
const queue: BidiRunEvent[] = []
|
|
116
|
+
let wake: (() => void) | undefined
|
|
117
|
+
let closed = false
|
|
118
|
+
let session: BidiSession | undefined
|
|
119
|
+
let transportCloseRequested = false
|
|
120
|
+
let transportClosePromise: Promise<void> | undefined
|
|
121
|
+
|
|
122
|
+
const requestTransportClose = (): Promise<void> => {
|
|
123
|
+
transportCloseRequested = true
|
|
124
|
+
if (!session) return Promise.resolve()
|
|
125
|
+
if (!transportClosePromise) {
|
|
126
|
+
const ownedSession = session
|
|
127
|
+
transportClosePromise = Promise.resolve().then(async () => await ownedSession.close())
|
|
128
|
+
}
|
|
129
|
+
return transportClosePromise
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const beginClose = (reason: unknown, closeTransport: boolean): void => {
|
|
133
|
+
if (!closed) {
|
|
134
|
+
closed = true
|
|
135
|
+
lifetime.abort(reason)
|
|
136
|
+
wake?.()
|
|
137
|
+
}
|
|
138
|
+
if (closeTransport) {
|
|
139
|
+
void requestTransportClose().catch((error: unknown) => {
|
|
140
|
+
log.warn('Duplex provider session close failed', {
|
|
141
|
+
'exception.message': toErrorMessage(error),
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const onCallerAbort = (): void => beginClose(params.signal?.reason, true)
|
|
148
|
+
params.signal?.addEventListener('abort', onCallerAbort, { once: true })
|
|
149
|
+
lifetime.signal.addEventListener(
|
|
150
|
+
'abort',
|
|
151
|
+
() => params.signal?.removeEventListener('abort', onCallerAbort),
|
|
152
|
+
{ once: true },
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
const connecting = Promise.resolve()
|
|
156
|
+
.then(
|
|
157
|
+
async () =>
|
|
158
|
+
await params.provider.connect({
|
|
159
|
+
...params.connect,
|
|
160
|
+
signal: lifetime.signal,
|
|
161
|
+
}),
|
|
162
|
+
)
|
|
163
|
+
.then((connected) => {
|
|
164
|
+
session = connected
|
|
165
|
+
if (transportCloseRequested) {
|
|
166
|
+
void requestTransportClose().catch((error: unknown) => {
|
|
167
|
+
log.warn('Late duplex provider session close failed', {
|
|
168
|
+
'exception.message': toErrorMessage(error),
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
return connected
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
let removeConnectAbort: (() => void) | undefined
|
|
176
|
+
const connectionAbort = new Promise<never>((_, reject) => {
|
|
177
|
+
const rejectFromLifetime = () => reject(lifetime.signal.reason)
|
|
178
|
+
removeConnectAbort = () => lifetime.signal.removeEventListener('abort', rejectFromLifetime)
|
|
179
|
+
if (lifetime.signal.aborted) rejectFromLifetime()
|
|
180
|
+
else lifetime.signal.addEventListener('abort', rejectFromLifetime, { once: true })
|
|
65
181
|
})
|
|
66
182
|
|
|
183
|
+
let activeSession: BidiSession
|
|
184
|
+
try {
|
|
185
|
+
activeSession = await Promise.race([connecting, connectionAbort])
|
|
186
|
+
lifetime.signal.throwIfAborted()
|
|
187
|
+
} catch (error) {
|
|
188
|
+
removeConnectAbort?.()
|
|
189
|
+
params.signal?.removeEventListener('abort', onCallerAbort)
|
|
190
|
+
if (lifetime.signal.aborted) {
|
|
191
|
+
void connecting.catch(() => undefined)
|
|
192
|
+
throw lifetime.signal.reason
|
|
193
|
+
}
|
|
194
|
+
throw error
|
|
195
|
+
}
|
|
196
|
+
removeConnectAbort?.()
|
|
197
|
+
|
|
67
198
|
// One generation of work. Bumped by every interruption, so a tool that
|
|
68
199
|
// started under an older generation knows its answer is stale without
|
|
69
200
|
// needing a handle on the call that cancelled it.
|
|
70
201
|
let generation = 0
|
|
71
|
-
const
|
|
202
|
+
const executionIds = new Set<string>()
|
|
72
203
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
const emit = (event: BidiRunEvent) => {
|
|
204
|
+
const emit = (event: BidiRunEvent): boolean => {
|
|
205
|
+
if (closed) return false
|
|
76
206
|
queue.push(event)
|
|
77
207
|
wake?.()
|
|
208
|
+
return true
|
|
78
209
|
}
|
|
79
210
|
|
|
80
211
|
const executeCall = async (call: { id: string; name: string; arguments: string }) => {
|
|
81
212
|
const startedUnder = generation
|
|
82
|
-
emit({ type: 'tool_started', runId, toolUseId: call.id, toolName: call.name })
|
|
213
|
+
if (!emit({ type: 'tool_started', runId, toolUseId: call.id, toolName: call.name })) {
|
|
214
|
+
return
|
|
215
|
+
}
|
|
83
216
|
|
|
84
217
|
let output: string
|
|
85
218
|
let isError = false
|
|
@@ -93,7 +226,7 @@ export async function startBidiRun(params: BidiRunParams): Promise<BidiRun> {
|
|
|
93
226
|
const context: ToolContext = {
|
|
94
227
|
runId,
|
|
95
228
|
workingDirectory: params.workingDirectory,
|
|
96
|
-
abortSignal:
|
|
229
|
+
abortSignal: lifetime.signal,
|
|
97
230
|
env: params.env ?? {},
|
|
98
231
|
log: (level, message) => log[level](message),
|
|
99
232
|
toolUseId: call.id,
|
|
@@ -106,6 +239,7 @@ export async function startBidiRun(params: BidiRunParams): Promise<BidiRun> {
|
|
|
106
239
|
isError = true
|
|
107
240
|
}
|
|
108
241
|
|
|
242
|
+
if (closed) return
|
|
109
243
|
if (startedUnder !== generation) {
|
|
110
244
|
// The human spoke over the model while this ran. Delivering the
|
|
111
245
|
// answer now would put it in a conversation that has moved on.
|
|
@@ -113,6 +247,12 @@ export async function startBidiRun(params: BidiRunParams): Promise<BidiRun> {
|
|
|
113
247
|
return
|
|
114
248
|
}
|
|
115
249
|
|
|
250
|
+
// Entering the provider send is the publication commit point. A later
|
|
251
|
+
// conversational interruption cannot recall a write already handed to
|
|
252
|
+
// the provider, but closing the run still closes the whole session and
|
|
253
|
+
// fences the local terminal event.
|
|
254
|
+
await activeSession.sendToolResult(call.id, output, isError)
|
|
255
|
+
if (closed) return
|
|
116
256
|
emit({
|
|
117
257
|
type: 'tool_completed',
|
|
118
258
|
runId,
|
|
@@ -121,13 +261,12 @@ export async function startBidiRun(params: BidiRunParams): Promise<BidiRun> {
|
|
|
121
261
|
output,
|
|
122
262
|
isError,
|
|
123
263
|
})
|
|
124
|
-
await session.sendToolResult(call.id, output, isError)
|
|
125
264
|
}
|
|
126
265
|
|
|
127
|
-
let closed = false
|
|
128
266
|
const pump = (async () => {
|
|
129
267
|
try {
|
|
130
|
-
for await (const event of
|
|
268
|
+
for await (const event of activeSession.events()) {
|
|
269
|
+
if (closed) break
|
|
131
270
|
switch (event.type) {
|
|
132
271
|
case 'text':
|
|
133
272
|
emit({ type: 'text', runId, text: event.text })
|
|
@@ -136,13 +275,20 @@ export async function startBidiRun(params: BidiRunParams): Promise<BidiRun> {
|
|
|
136
275
|
emit({ type: 'audio', runId, data: event.data, mediaType: event.mediaType })
|
|
137
276
|
break
|
|
138
277
|
case 'tool_call': {
|
|
278
|
+
if (executionIds.has(event.id)) {
|
|
279
|
+
const error = new Error(
|
|
280
|
+
`Duplex provider repeated tool-call id "${event.id}". Re-executing it could repeat a side effect, so the session was closed.`,
|
|
281
|
+
)
|
|
282
|
+
emit({ type: 'error', runId, message: error.message })
|
|
283
|
+
beginClose(error, true)
|
|
284
|
+
break
|
|
285
|
+
}
|
|
286
|
+
executionIds.add(event.id)
|
|
139
287
|
// Started, not awaited: awaiting here would stall the very
|
|
140
288
|
// stream an interruption arrives on.
|
|
141
|
-
|
|
289
|
+
void executeCall(event).catch((err: unknown) => {
|
|
142
290
|
emit({ type: 'error', runId, message: toErrorMessage(err) })
|
|
143
291
|
})
|
|
144
|
-
inflight.add(running)
|
|
145
|
-
void running.finally(() => inflight.delete(running))
|
|
146
292
|
break
|
|
147
293
|
}
|
|
148
294
|
case 'turn_complete':
|
|
@@ -161,7 +307,7 @@ export async function startBidiRun(params: BidiRunParams): Promise<BidiRun> {
|
|
|
161
307
|
runId,
|
|
162
308
|
...(event.reason !== undefined ? { reason: event.reason } : {}),
|
|
163
309
|
})
|
|
164
|
-
closed
|
|
310
|
+
beginClose(new Error(event.reason ?? 'the duplex provider session closed'), false)
|
|
165
311
|
break
|
|
166
312
|
default: {
|
|
167
313
|
const _exhaustive: never = event
|
|
@@ -171,13 +317,15 @@ export async function startBidiRun(params: BidiRunParams): Promise<BidiRun> {
|
|
|
171
317
|
if (closed) break
|
|
172
318
|
}
|
|
173
319
|
} catch (err) {
|
|
174
|
-
|
|
320
|
+
if (!closed) {
|
|
321
|
+
emit({ type: 'error', runId, message: toErrorMessage(err) })
|
|
322
|
+
beginClose(err, true)
|
|
323
|
+
}
|
|
175
324
|
} finally {
|
|
176
|
-
closed
|
|
177
|
-
// Let a consumer parked on the queue notice the end.
|
|
178
|
-
wake?.()
|
|
325
|
+
if (!closed) beginClose(new Error('the duplex provider event stream ended'), true)
|
|
179
326
|
}
|
|
180
327
|
})()
|
|
328
|
+
void pump.catch(() => undefined)
|
|
181
329
|
|
|
182
330
|
async function* events(): AsyncIterable<BidiRunEvent> {
|
|
183
331
|
while (true) {
|
|
@@ -196,15 +344,16 @@ export async function startBidiRun(params: BidiRunParams): Promise<BidiRun> {
|
|
|
196
344
|
return {
|
|
197
345
|
runId,
|
|
198
346
|
events,
|
|
199
|
-
send: (input) =>
|
|
347
|
+
send: async (input) => {
|
|
348
|
+
lifetime.signal.throwIfAborted()
|
|
349
|
+
// As with tool results, entering the provider send is the atomic
|
|
350
|
+
// publication boundary. A caller must not retry merely because the
|
|
351
|
+
// lifetime changed after the provider accepted the input.
|
|
352
|
+
await activeSession.send(input)
|
|
353
|
+
},
|
|
200
354
|
close: async () => {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
wake?.()
|
|
204
|
-
// Tools still running are awaited, so a close cannot leave one
|
|
205
|
-
// writing into a session nobody is reading.
|
|
206
|
-
await Promise.allSettled([...inflight])
|
|
207
|
-
await pump.catch(() => undefined)
|
|
355
|
+
beginClose(new Error('the duplex run was closed by its host'), true)
|
|
356
|
+
await waitForProviderClose(requestTransportClose(), closeTimeoutMs)
|
|
208
357
|
},
|
|
209
358
|
}
|
|
210
359
|
}
|