@namzu/sdk 31.1.0 → 33.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/CHANGELOG.md +188 -0
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +4 -0
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +4 -0
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/agents/runAgent.d.ts +4 -0
- package/dist/agents/runAgent.d.ts.map +1 -1
- package/dist/agents/runAgent.js +4 -0
- package/dist/agents/runAgent.js.map +1 -1
- package/dist/authorization/gate.d.ts +1 -1
- package/dist/authorization/gate.js +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/directory/derive-supervisor.d.ts.map +1 -1
- package/dist/directory/derive-supervisor.js +5 -0
- package/dist/directory/derive-supervisor.js.map +1 -1
- package/dist/directory/derive.d.ts.map +1 -1
- package/dist/directory/derive.js +5 -0
- package/dist/directory/derive.js.map +1 -1
- package/dist/directory/load.d.ts.map +1 -1
- package/dist/directory/load.js +1 -0
- package/dist/directory/load.js.map +1 -1
- package/dist/directory/types.d.ts +2 -0
- package/dist/directory/types.d.ts.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/code-runtime/types.d.ts +11 -1
- package/dist/execution/code-runtime/types.d.ts.map +1 -1
- package/dist/execution/code-runtime/types.js.map +1 -1
- package/dist/execution/code-runtime/worker.d.ts.map +1 -1
- package/dist/execution/code-runtime/worker.js +67 -9
- package/dist/execution/code-runtime/worker.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/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +1 -0
- package/dist/manager/agent/lifecycle.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/errors.d.ts +1 -0
- package/dist/provider/errors.d.ts.map +1 -1
- package/dist/provider/errors.js +39 -1
- package/dist/provider/errors.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 +7 -5
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +9 -4
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +2 -1
- package/dist/public-types.d.ts.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/reporter.d.ts.map +1 -1
- package/dist/run/reporter.js +6 -1
- package/dist/run/reporter.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 +824 -174
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +5 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +47 -4
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +1 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +34 -14
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.js +2 -2
- package/dist/runtime/query/iteration/phases/advisory.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/iteration/provider-rejected-image.d.ts +13 -0
- package/dist/runtime/query/iteration/provider-rejected-image.d.ts.map +1 -0
- package/dist/runtime/query/iteration/provider-rejected-image.js +91 -0
- package/dist/runtime/query/iteration/provider-rejected-image.js.map +1 -0
- package/dist/runtime/query/iteration/stream-turn.d.ts +4 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +7 -3
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/request-rich-content.d.ts +13 -0
- package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
- package/dist/runtime/query/request-rich-content.js +173 -17
- 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 +1 -0
- 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/store/attachment/index.d.ts +24 -2
- package/dist/store/attachment/index.d.ts.map +1 -1
- package/dist/store/attachment/index.js +52 -5
- package/dist/store/attachment/index.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +39 -2
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/tools/builtins/lsp.d.ts +1 -1
- package/dist/tools/builtins/run-code.d.ts.map +1 -1
- package/dist/tools/builtins/run-code.js +24 -16
- 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/base.d.ts +4 -0
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/factory.d.ts +1 -0
- package/dist/types/agent/factory.d.ts.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/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 +31 -1
- package/dist/types/message/index.d.ts.map +1 -1
- package/dist/types/message/index.js +43 -0
- 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/error.d.ts +4 -1
- package/dist/types/provider/error.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 +10 -2
- 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 +129 -12
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.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/agents/ReactiveAgent.ts +4 -0
- package/src/agents/SupervisorAgent.ts +4 -0
- package/src/agents/runAgent.ts +8 -0
- package/src/authorization/gate.ts +1 -1
- 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/directory/derive-supervisor.ts +5 -0
- package/src/directory/derive.ts +5 -0
- package/src/directory/load.ts +1 -0
- package/src/directory/types.ts +2 -0
- package/src/execution/base.ts +124 -7
- package/src/execution/code-runtime/types.ts +15 -1
- package/src/execution/code-runtime/worker.ts +72 -9
- 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/manager/agent/lifecycle.ts +1 -0
- package/src/plugin/lifecycle.ts +9 -3
- package/src/process/kill-tree.ts +11 -13
- package/src/provider/errors.ts +40 -1
- 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 +23 -2
- package/src/public-types.ts +11 -0
- package/src/registry/tool/execute.ts +230 -64
- package/src/run/command-gate.ts +12 -0
- package/src/run/reporter.ts +7 -1
- 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 +987 -172
- package/src/runtime/query/index.ts +59 -6
- package/src/runtime/query/iteration/index.ts +69 -29
- package/src/runtime/query/iteration/phases/advisory.ts +2 -2
- package/src/runtime/query/iteration/phases/tool-review.ts +87 -23
- package/src/runtime/query/iteration/provider-rejected-image.ts +106 -0
- package/src/runtime/query/iteration/stream-turn.ts +12 -2
- package/src/runtime/query/request-rich-content.ts +213 -15
- package/src/runtime/query/result.ts +1 -0
- 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/store/attachment/index.ts +100 -15
- package/src/tools/builtins/computer-use.ts +45 -2
- package/src/tools/builtins/run-code.ts +24 -16
- package/src/tools/builtins/skill.ts +325 -7
- package/src/tools/coordinator/agent.ts +108 -33
- package/src/types/agent/base.ts +4 -0
- package/src/types/agent/factory.ts +1 -0
- 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/execution/index.ts +46 -1
- package/src/types/hitl/index.ts +11 -0
- package/src/types/message/index.ts +78 -1
- package/src/types/plugin/index.ts +15 -0
- package/src/types/provider/error.ts +4 -1
- package/src/types/provider/interface.ts +18 -0
- package/src/types/run/events.ts +18 -4
- package/src/types/sandbox/index.ts +15 -10
- package/src/types/tool/index.ts +159 -15
- package/src/types/workspace/ref.ts +5 -0
- package/src/utils/abort.ts +18 -0
package/src/provider/errors.ts
CHANGED
|
@@ -57,6 +57,7 @@ const PROVIDER_ERROR_KINDS: readonly ProviderErrorKind[] = [
|
|
|
57
57
|
export class ProviderRequestError extends Error {
|
|
58
58
|
public readonly kind: ProviderErrorKind
|
|
59
59
|
public readonly providerId: string
|
|
60
|
+
public readonly providerCode?: string
|
|
60
61
|
public readonly status?: number
|
|
61
62
|
public readonly retryAfterMs?: number
|
|
62
63
|
/**
|
|
@@ -81,6 +82,8 @@ export class ProviderRequestError extends Error {
|
|
|
81
82
|
this.name = 'ProviderRequestError'
|
|
82
83
|
this.kind = init.kind
|
|
83
84
|
this.providerId = init.providerId
|
|
85
|
+
const exactProviderCode = safeProviderCode(init.providerCode)
|
|
86
|
+
if (exactProviderCode !== undefined) this.providerCode = exactProviderCode
|
|
84
87
|
if (init.status !== undefined) this.status = init.status
|
|
85
88
|
if (init.retryAfterMs !== undefined) this.retryAfterMs = init.retryAfterMs
|
|
86
89
|
if (init.detail !== undefined) this.detail = init.detail
|
|
@@ -90,6 +93,32 @@ export class ProviderRequestError extends Error {
|
|
|
90
93
|
/** Longest detail worth carrying. A provider's complaint is a sentence. */
|
|
91
94
|
const DETAIL_MAX = 400
|
|
92
95
|
|
|
96
|
+
/** Provider codes are identifiers, not another channel for an arbitrary response body. */
|
|
97
|
+
const PROVIDER_CODE = /^[A-Za-z][A-Za-z0-9._-]{0,79}$/
|
|
98
|
+
|
|
99
|
+
function safeProviderCode(value: unknown): string | undefined {
|
|
100
|
+
if (typeof value !== 'string' || !PROVIDER_CODE.test(value)) return undefined
|
|
101
|
+
return redactSecrets(value) === value ? value : undefined
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function providerCode(value: unknown): string | undefined {
|
|
105
|
+
let decoded = value
|
|
106
|
+
if (typeof decoded === 'string') {
|
|
107
|
+
try {
|
|
108
|
+
decoded = JSON.parse(decoded)
|
|
109
|
+
} catch {
|
|
110
|
+
return undefined
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (typeof decoded !== 'object' || decoded === null) return undefined
|
|
114
|
+
const record = decoded as Record<string, unknown>
|
|
115
|
+
const nested =
|
|
116
|
+
typeof record.error === 'object' && record.error !== null
|
|
117
|
+
? (record.error as Record<string, unknown>).code
|
|
118
|
+
: undefined
|
|
119
|
+
return safeProviderCode(record.code ?? nested)
|
|
120
|
+
}
|
|
121
|
+
|
|
93
122
|
/**
|
|
94
123
|
* Credential shapes to scrub before a provider's words are kept.
|
|
95
124
|
*
|
|
@@ -161,11 +190,15 @@ function pickMessage(value: unknown): string | undefined {
|
|
|
161
190
|
|
|
162
191
|
/** Is this a classified provider failure, whichever SDK copy threw it? */
|
|
163
192
|
export function isProviderRequestError(err: unknown): err is ProviderRequestError {
|
|
193
|
+
const exactProviderCode = (err as { providerCode?: unknown } | null)?.providerCode
|
|
164
194
|
return (
|
|
165
195
|
err instanceof Error &&
|
|
166
196
|
err.name === 'ProviderRequestError' &&
|
|
167
197
|
typeof (err as { providerId?: unknown }).providerId === 'string' &&
|
|
168
|
-
PROVIDER_ERROR_KINDS.includes(
|
|
198
|
+
PROVIDER_ERROR_KINDS.includes(
|
|
199
|
+
(err as { kind?: ProviderErrorKind }).kind as ProviderErrorKind,
|
|
200
|
+
) &&
|
|
201
|
+
(exactProviderCode === undefined || safeProviderCode(exactProviderCode) === exactProviderCode)
|
|
169
202
|
)
|
|
170
203
|
}
|
|
171
204
|
|
|
@@ -393,6 +426,7 @@ export function providerVendorError(input: {
|
|
|
393
426
|
}): ProviderRequestError {
|
|
394
427
|
const { error } = input
|
|
395
428
|
const status = vendorErrorStatus(error)
|
|
429
|
+
const exactProviderCode = providerCode(error)
|
|
396
430
|
const name = error instanceof Error ? error.name : ''
|
|
397
431
|
const message = error instanceof Error ? error.message : ''
|
|
398
432
|
|
|
@@ -411,6 +445,8 @@ export function providerVendorError(input: {
|
|
|
411
445
|
kind = 'server'
|
|
412
446
|
} else if (status !== undefined) {
|
|
413
447
|
kind = classifyProviderHttpStatus(status, message)
|
|
448
|
+
} else if (exactProviderCode === 'invalid_image') {
|
|
449
|
+
kind = 'bad_request'
|
|
414
450
|
} else if (bodySaysContextOverflow(message)) {
|
|
415
451
|
kind = 'context_overflow'
|
|
416
452
|
} else {
|
|
@@ -428,6 +464,7 @@ export function providerVendorError(input: {
|
|
|
428
464
|
return new ProviderRequestError({
|
|
429
465
|
kind,
|
|
430
466
|
providerId: input.providerId,
|
|
467
|
+
...(exactProviderCode !== undefined ? { providerCode: exactProviderCode } : {}),
|
|
431
468
|
...(status !== undefined ? { status } : {}),
|
|
432
469
|
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
433
470
|
...(detail !== undefined ? { detail } : {}),
|
|
@@ -450,9 +487,11 @@ export function providerHttpError(input: {
|
|
|
450
487
|
const kind = classifyProviderHttpStatus(input.status, input.body)
|
|
451
488
|
const retryAfterMs = parseRetryAfterMs(input.retryAfter, input.now ?? Date.now())
|
|
452
489
|
const detail = vendorDetail(input.body)
|
|
490
|
+
const exactProviderCode = providerCode(input.body)
|
|
453
491
|
return new ProviderRequestError({
|
|
454
492
|
kind,
|
|
455
493
|
providerId: input.providerId,
|
|
494
|
+
...(exactProviderCode !== undefined ? { providerCode: exactProviderCode } : {}),
|
|
456
495
|
status: input.status,
|
|
457
496
|
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
458
497
|
...(detail !== undefined ? { detail } : {}),
|
package/src/provider/fallback.ts
CHANGED
|
@@ -230,6 +230,40 @@ function memberReasoningEffortLevels(
|
|
|
230
230
|
return member.provider.effortLevelsFor?.(model, thinking)
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
/** Read one member's model-owned default using its routed model id. */
|
|
234
|
+
function memberReasoningEffortDefault(
|
|
235
|
+
member: ProviderChainMember,
|
|
236
|
+
requestModel: string,
|
|
237
|
+
thinking?: ThinkingConfig,
|
|
238
|
+
): ReasoningEffort | undefined {
|
|
239
|
+
return member.provider.reasoningEffortDefaultFor?.(member.model ?? requestModel, thinking)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* A fallback request has one unambiguous default only when every route agrees.
|
|
244
|
+
*
|
|
245
|
+
* Omitting effort lets whichever member serves the request choose its own
|
|
246
|
+
* default. Publishing the head's answer as the chain's answer can therefore
|
|
247
|
+
* make the same shortcut move in opposite directions after fallback. The
|
|
248
|
+
* agreed value must also survive the chain-wide exact menu.
|
|
249
|
+
*/
|
|
250
|
+
function commonReasoningEffortDefault(
|
|
251
|
+
members: readonly ProviderChainMember[],
|
|
252
|
+
requestModel: string,
|
|
253
|
+
thinking?: ThinkingConfig,
|
|
254
|
+
): ReasoningEffort | undefined {
|
|
255
|
+
const common = commonReasoningEffortLevels(members, requestModel, thinking)
|
|
256
|
+
if (common === undefined) return undefined
|
|
257
|
+
let agreed: ReasoningEffort | undefined
|
|
258
|
+
for (const member of members) {
|
|
259
|
+
const value = memberReasoningEffortDefault(member, requestModel, thinking)
|
|
260
|
+
if (value === undefined) return undefined
|
|
261
|
+
if (agreed !== undefined && value !== agreed) return undefined
|
|
262
|
+
agreed = value
|
|
263
|
+
}
|
|
264
|
+
return agreed !== undefined && common.includes(agreed) ? agreed : undefined
|
|
265
|
+
}
|
|
266
|
+
|
|
233
267
|
/**
|
|
234
268
|
* The levels one request may carry safely through every member it can reach.
|
|
235
269
|
*
|
|
@@ -463,6 +497,11 @@ export function withProviderFallback(
|
|
|
463
497
|
// answer when any member cannot enumerate its selected model.
|
|
464
498
|
reasoningEffortLevelsFor: (model: string, thinking?: ThinkingConfig) =>
|
|
465
499
|
commonReasoningEffortLevels(members, model, thinking),
|
|
500
|
+
// Present on the chain wrapper for the same reason the menu method is:
|
|
501
|
+
// `undefined` is the honest answer when a member cannot answer, defaults
|
|
502
|
+
// disagree, or the value is absent from the common exact menu.
|
|
503
|
+
reasoningEffortDefaultFor: (model: string, thinking?: ThinkingConfig) =>
|
|
504
|
+
commonReasoningEffortDefault(members, model, thinking),
|
|
466
505
|
// Compatibility projection only. Existing consumers of the deprecated
|
|
467
506
|
// member keep the head-only answer they had; new consumers use the
|
|
468
507
|
// canonical chain-aware member above.
|
|
@@ -220,6 +220,14 @@ export function withStreamIdleTimeout(
|
|
|
220
220
|
) => provider.reasoningEffortLevelsFor?.(model, thinking),
|
|
221
221
|
}
|
|
222
222
|
: {}),
|
|
223
|
+
...(provider.reasoningEffortDefaultFor
|
|
224
|
+
? {
|
|
225
|
+
reasoningEffortDefaultFor: (
|
|
226
|
+
model: string,
|
|
227
|
+
thinking?: Parameters<NonNullable<LLMProvider['reasoningEffortDefaultFor']>>[1],
|
|
228
|
+
) => provider.reasoningEffortDefaultFor?.(model, thinking),
|
|
229
|
+
}
|
|
230
|
+
: {}),
|
|
223
231
|
...(provider.effortLevelsFor
|
|
224
232
|
? {
|
|
225
233
|
effortLevelsFor: (
|
package/src/provider/retry.ts
CHANGED
|
@@ -275,6 +275,14 @@ export function withProviderRetry(
|
|
|
275
275
|
) => provider.reasoningEffortLevelsFor?.(model, thinking),
|
|
276
276
|
}
|
|
277
277
|
: {}),
|
|
278
|
+
...(provider.reasoningEffortDefaultFor
|
|
279
|
+
? {
|
|
280
|
+
reasoningEffortDefaultFor: (
|
|
281
|
+
model: string,
|
|
282
|
+
thinking?: Parameters<NonNullable<LLMProvider['reasoningEffortDefaultFor']>>[1],
|
|
283
|
+
) => provider.reasoningEffortDefaultFor?.(model, thinking),
|
|
284
|
+
}
|
|
285
|
+
: {}),
|
|
278
286
|
// Forwarded for the same reason `healthCheck` is, and both were
|
|
279
287
|
// missing until something consumed them. A member this wrapper drops
|
|
280
288
|
// does not fail — it reads as "this driver cannot answer", which is a
|
package/src/public-runtime.ts
CHANGED
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
|
|
13
13
|
export { VERSION } from './version.js'
|
|
14
14
|
|
|
15
|
+
// The opt-in model-authored-code backend. `RunCodeToolOptions.runtime` has
|
|
16
|
+
// always accepted this contract; exporting the implementation and its refusal
|
|
17
|
+
// class makes that signature nameable from the package root.
|
|
18
|
+
export { HostCallDeniedError } from './execution/code-runtime/types.js'
|
|
19
|
+
export { WorkerCodeRuntime } from './execution/code-runtime/worker.js'
|
|
20
|
+
|
|
15
21
|
export {
|
|
16
22
|
CompactionConfigSchema,
|
|
17
23
|
PluginRuntimeConfigSchema,
|
|
@@ -287,7 +293,11 @@ export {
|
|
|
287
293
|
formatSteeringNote,
|
|
288
294
|
} from './runtime/query/steering.js'
|
|
289
295
|
export type { SteeringChannel } from './runtime/query/steering.js'
|
|
290
|
-
export {
|
|
296
|
+
export {
|
|
297
|
+
BidiSessionCloseTimeoutError,
|
|
298
|
+
createMockBidiProvider,
|
|
299
|
+
startBidiRun,
|
|
300
|
+
} from './runtime/bidi/index.js'
|
|
291
301
|
export { PromptCache } from './runtime/query/prompt-cache.js'
|
|
292
302
|
export {
|
|
293
303
|
CheckpointManager,
|
|
@@ -666,6 +676,7 @@ export {
|
|
|
666
676
|
export {
|
|
667
677
|
BaseConnector,
|
|
668
678
|
BaseExecutionContext,
|
|
679
|
+
CommandCancellationUnsupportedError,
|
|
669
680
|
ConnectorManager,
|
|
670
681
|
ConnectorRegistry,
|
|
671
682
|
EnvironmentConnectorManager,
|
|
@@ -689,6 +700,7 @@ export {
|
|
|
689
700
|
mcpToolResultToToolResult,
|
|
690
701
|
mcpToolToToolDefinition,
|
|
691
702
|
RemoteExecutionContext,
|
|
703
|
+
RemoteExecutionBusyError,
|
|
692
704
|
ScopedConnectorRegistry,
|
|
693
705
|
// The only transport in the tree that can RUN an `MCPServer`. It reached
|
|
694
706
|
// `connector/mcp/index.ts` and stopped there, so the server was public
|
|
@@ -995,6 +1007,7 @@ export { assertMemoryStatus } from './types/memory/index.js'
|
|
|
995
1007
|
export {
|
|
996
1008
|
createAssistantMessage,
|
|
997
1009
|
createProjectInstructionMessage,
|
|
1010
|
+
createRuntimeContextMessage,
|
|
998
1011
|
createSystemMessage,
|
|
999
1012
|
createToolMessage,
|
|
1000
1013
|
hasNonTextBlocks,
|
|
@@ -1002,7 +1015,10 @@ export {
|
|
|
1002
1015
|
toolResultToText,
|
|
1003
1016
|
createUserMessage,
|
|
1004
1017
|
isProjectInstructionMessageSource,
|
|
1018
|
+
isRuntimeContextMessageSource,
|
|
1019
|
+
isModelContentOmission,
|
|
1005
1020
|
MAX_PROJECT_INSTRUCTION_SOURCE_FILES,
|
|
1021
|
+
RUNTIME_CONTEXT_MESSAGE_KINDS,
|
|
1006
1022
|
} from './types/message/index.js'
|
|
1007
1023
|
export { isTerminalPlanStatus } from './types/plan/index.js'
|
|
1008
1024
|
export {
|
|
@@ -1198,8 +1214,10 @@ export {
|
|
|
1198
1214
|
// Inline base64 lands in the transcript, in every checkpoint, and on the
|
|
1199
1215
|
// wire once per turn; a reference does not.
|
|
1200
1216
|
export {
|
|
1217
|
+
DEFAULT_ATTACHMENT_RESOLVE_TIMEOUT_MS,
|
|
1201
1218
|
AttachmentMediaTypeMismatchError,
|
|
1202
1219
|
AttachmentNotFoundError,
|
|
1220
|
+
AttachmentResolutionTimeoutError,
|
|
1203
1221
|
NoAttachmentStoreError,
|
|
1204
1222
|
isStoredAttachment,
|
|
1205
1223
|
resolveAttachment,
|
|
@@ -1254,7 +1272,10 @@ export type {
|
|
|
1254
1272
|
CompactionVerificationOptions,
|
|
1255
1273
|
UsageSink,
|
|
1256
1274
|
} from './compaction/verifier.js'
|
|
1257
|
-
export type {
|
|
1275
|
+
export type {
|
|
1276
|
+
PluginDiscoveryOptions,
|
|
1277
|
+
PluginEnablementCapabilities,
|
|
1278
|
+
} from './plugin/loader.js'
|
|
1258
1279
|
export type { ProbeContextInput } from './probe/context.js'
|
|
1259
1280
|
export type {
|
|
1260
1281
|
GoalCommandScope,
|
package/src/public-types.ts
CHANGED
|
@@ -19,6 +19,16 @@ export type * from './types/common/index.js'
|
|
|
19
19
|
export type { CoalesceOptions } from './streaming/coalesce.js'
|
|
20
20
|
export type * from './types/bidi/index.js'
|
|
21
21
|
export type * from './types/tool/index.js'
|
|
22
|
+
export type {
|
|
23
|
+
CodeRunOutcome,
|
|
24
|
+
CodeRunResult,
|
|
25
|
+
CodeRuntime,
|
|
26
|
+
HostCallContext,
|
|
27
|
+
HostCallHandler,
|
|
28
|
+
HostCallRequest,
|
|
29
|
+
HostCallResult,
|
|
30
|
+
RunCodeOptions,
|
|
31
|
+
} from './execution/code-runtime/types.js'
|
|
22
32
|
// The directory convention: what a loaded `agent/` directory is, and what the
|
|
23
33
|
// loader reports about the files it could not use.
|
|
24
34
|
export type * from './directory/types.js'
|
|
@@ -336,6 +346,7 @@ export type {
|
|
|
336
346
|
|
|
337
347
|
export type {
|
|
338
348
|
AttachmentOperationOptions,
|
|
349
|
+
AttachmentResolutionOptions,
|
|
339
350
|
AttachmentStore,
|
|
340
351
|
StoredAttachment,
|
|
341
352
|
StoredBytes,
|
|
@@ -7,10 +7,12 @@ import { isTrustedReadOnly } from '../../tools/trusted-read-only.js'
|
|
|
7
7
|
import type { ToolResultGuardrailSpec } from '../../types/guardrail/index.js'
|
|
8
8
|
import type {
|
|
9
9
|
LLMToolSchema,
|
|
10
|
+
PreparedToolExecution,
|
|
10
11
|
ToolAvailability,
|
|
11
12
|
ToolContext,
|
|
12
13
|
ToolDefinition,
|
|
13
14
|
ToolExecutionResult,
|
|
15
|
+
ToolPreparationResult,
|
|
14
16
|
ToolRegistryConfig,
|
|
15
17
|
ToolTierConfig,
|
|
16
18
|
} from '../../types/tool/index.js'
|
|
@@ -87,6 +89,82 @@ export function assertToolName(name: string): void {
|
|
|
87
89
|
)
|
|
88
90
|
}
|
|
89
91
|
|
|
92
|
+
function clonePreparedInput(value: unknown, freeze: boolean, path = '$'): unknown {
|
|
93
|
+
const active = new WeakSet<object>()
|
|
94
|
+
const copies = new WeakMap<object, object>()
|
|
95
|
+
|
|
96
|
+
const clone = (candidate: unknown, at: string): unknown => {
|
|
97
|
+
if (candidate === null || typeof candidate === 'string' || typeof candidate === 'boolean') {
|
|
98
|
+
return candidate
|
|
99
|
+
}
|
|
100
|
+
if (typeof candidate === 'number') {
|
|
101
|
+
if (!Number.isFinite(candidate) || Object.is(candidate, -0)) {
|
|
102
|
+
throw new TypeError(`${at} must be a finite JSON number`)
|
|
103
|
+
}
|
|
104
|
+
return candidate
|
|
105
|
+
}
|
|
106
|
+
if (typeof candidate !== 'object') {
|
|
107
|
+
throw new TypeError(`${at} must be a JSON value, not ${typeof candidate}`)
|
|
108
|
+
}
|
|
109
|
+
if (active.has(candidate)) throw new TypeError(`${at} contains a cycle`)
|
|
110
|
+
const existing = copies.get(candidate)
|
|
111
|
+
if (existing) return existing
|
|
112
|
+
|
|
113
|
+
active.add(candidate)
|
|
114
|
+
try {
|
|
115
|
+
if (Array.isArray(candidate)) {
|
|
116
|
+
const extra = Reflect.ownKeys(candidate).filter(
|
|
117
|
+
(key) => key !== 'length' && (typeof key !== 'string' || !/^(0|[1-9]\d*)$/.test(key)),
|
|
118
|
+
)
|
|
119
|
+
if (extra.length > 0) throw new TypeError(`${at} has non-JSON array properties`)
|
|
120
|
+
const result: unknown[] = new Array(candidate.length)
|
|
121
|
+
copies.set(candidate, result)
|
|
122
|
+
for (let index = 0; index < candidate.length; index++) {
|
|
123
|
+
const descriptor = Object.getOwnPropertyDescriptor(candidate, String(index))
|
|
124
|
+
if (!descriptor) throw new TypeError(`${at}[${index}] is a sparse array hole`)
|
|
125
|
+
if (!descriptor.enumerable || !('value' in descriptor)) {
|
|
126
|
+
throw new TypeError(`${at}[${index}] must be an enumerable data property`)
|
|
127
|
+
}
|
|
128
|
+
result[index] = clone(descriptor.value, `${at}[${index}]`)
|
|
129
|
+
}
|
|
130
|
+
if (freeze) Object.freeze(result)
|
|
131
|
+
return result
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const prototype = Object.getPrototypeOf(candidate)
|
|
135
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
136
|
+
throw new TypeError(`${at} must be a plain JSON object`)
|
|
137
|
+
}
|
|
138
|
+
// JSON does not preserve prototypes. Canonicalize both admitted plain
|
|
139
|
+
// shapes to an ordinary object so a disk checkpoint round-trip compares
|
|
140
|
+
// equal to a fresh preparation of the same semantic value. Properties
|
|
141
|
+
// are still defined explicitly, so a literal "__proto__" key remains
|
|
142
|
+
// data rather than changing this object's prototype.
|
|
143
|
+
const result: Record<string, unknown> = {}
|
|
144
|
+
copies.set(candidate, result)
|
|
145
|
+
for (const key of Reflect.ownKeys(candidate)) {
|
|
146
|
+
if (typeof key !== 'string') throw new TypeError(`${at} has a symbol property`)
|
|
147
|
+
const descriptor = Object.getOwnPropertyDescriptor(candidate, key)
|
|
148
|
+
if (!descriptor?.enumerable || !('value' in descriptor)) {
|
|
149
|
+
throw new TypeError(`${at}.${key} must be an enumerable data property`)
|
|
150
|
+
}
|
|
151
|
+
Object.defineProperty(result, key, {
|
|
152
|
+
value: clone(descriptor.value, `${at}.${key}`),
|
|
153
|
+
enumerable: true,
|
|
154
|
+
writable: !freeze,
|
|
155
|
+
configurable: !freeze,
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
if (freeze) Object.freeze(result)
|
|
159
|
+
return result
|
|
160
|
+
} finally {
|
|
161
|
+
active.delete(candidate)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return clone(value, path)
|
|
166
|
+
}
|
|
167
|
+
|
|
90
168
|
/**
|
|
91
169
|
* Two sources contributed the same tool name and neither may take it.
|
|
92
170
|
*
|
|
@@ -136,9 +214,17 @@ export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
|
|
|
136
214
|
private availability: Map<string, ToolAvailability> = new Map()
|
|
137
215
|
private tierConfig?: ToolTierConfig
|
|
138
216
|
private resultGuardrails?: readonly ToolResultGuardrailSpec[]
|
|
217
|
+
private readonly preparations = new WeakMap<
|
|
218
|
+
PreparedToolExecution,
|
|
219
|
+
{ readonly tool: ToolDefinition; readonly input: unknown }
|
|
220
|
+
>()
|
|
139
221
|
|
|
140
222
|
constructor(config?: ToolRegistryConfig) {
|
|
141
|
-
super({
|
|
223
|
+
super({
|
|
224
|
+
componentName: 'ToolRegistry',
|
|
225
|
+
idField: 'name',
|
|
226
|
+
logger: config?.logger,
|
|
227
|
+
})
|
|
142
228
|
this.tierConfig = config?.tierConfig
|
|
143
229
|
this.resultGuardrails = config?.resultGuardrails
|
|
144
230
|
}
|
|
@@ -401,10 +487,106 @@ Executable tool names, descriptions, and JSON input schemas are attached through
|
|
|
401
487
|
return this.getByAvailability(['active'], toolNames)
|
|
402
488
|
}
|
|
403
489
|
|
|
490
|
+
prepareExecution(toolName: string, rawInput: unknown): ToolPreparationResult {
|
|
491
|
+
const tool = this.getOrThrow(toolName)
|
|
492
|
+
const parseResult = tool.inputSchema.safeParse(rawInput)
|
|
493
|
+
if (!parseResult.success) {
|
|
494
|
+
return {
|
|
495
|
+
success: false,
|
|
496
|
+
result: this.validationFailure(tool, rawInput, parseResult.error),
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
let retainedInput: unknown
|
|
501
|
+
let reviewInput: unknown
|
|
502
|
+
try {
|
|
503
|
+
retainedInput = clonePreparedInput(parseResult.data, false)
|
|
504
|
+
reviewInput = clonePreparedInput(retainedInput, true)
|
|
505
|
+
} catch (err) {
|
|
506
|
+
const message = `Tool "${toolName}" produced an input that cannot be safely prepared for review and execution: ${toErrorMessage(err)}`
|
|
507
|
+
this.log.error('Prepared tool input could not be detached for review and execution', {
|
|
508
|
+
'namzu.tool.name': toolName,
|
|
509
|
+
'exception.message': toErrorMessage(err),
|
|
510
|
+
})
|
|
511
|
+
return {
|
|
512
|
+
success: false,
|
|
513
|
+
result: { success: false, output: '', error: message },
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const prepared = Object.freeze({ toolName, input: reviewInput })
|
|
518
|
+
this.preparations.set(prepared, { tool, input: retainedInput })
|
|
519
|
+
return { success: true, prepared }
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async executePrepared(
|
|
523
|
+
prepared: PreparedToolExecution,
|
|
524
|
+
context: ToolContext,
|
|
525
|
+
): Promise<ToolExecutionResult> {
|
|
526
|
+
const retained = this.preparations.get(prepared)
|
|
527
|
+
if (!retained) {
|
|
528
|
+
return {
|
|
529
|
+
success: false,
|
|
530
|
+
output: '',
|
|
531
|
+
error: `Tool "${prepared.toolName}" preparation is not owned by this registry or is no longer valid.`,
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (this.get(prepared.toolName) !== retained.tool) {
|
|
535
|
+
return {
|
|
536
|
+
success: false,
|
|
537
|
+
output: '',
|
|
538
|
+
error: `Tool "${prepared.toolName}" changed after its input was reviewed; prepare the call again.`,
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return this.executeRetained(prepared.toolName, retained.tool, retained.input, context)
|
|
542
|
+
}
|
|
543
|
+
|
|
404
544
|
async execute(
|
|
405
545
|
toolName: string,
|
|
406
546
|
rawInput: unknown,
|
|
407
547
|
context: ToolContext,
|
|
548
|
+
): Promise<ToolExecutionResult> {
|
|
549
|
+
let preparation: ToolPreparationResult
|
|
550
|
+
try {
|
|
551
|
+
preparation = this.prepareExecution(toolName, rawInput)
|
|
552
|
+
} catch (err) {
|
|
553
|
+
return this.rejectPreparationWithClosedSpan(toolName, context, err)
|
|
554
|
+
}
|
|
555
|
+
if (!preparation.success) return preparation.result
|
|
556
|
+
return this.executePrepared(preparation.prepared, context)
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
private rejectPreparationWithClosedSpan(
|
|
560
|
+
toolName: string,
|
|
561
|
+
context: ToolContext,
|
|
562
|
+
err: unknown,
|
|
563
|
+
): Promise<never> {
|
|
564
|
+
const tracer = getTracer()
|
|
565
|
+
const parentCtx = context.parentSpan
|
|
566
|
+
? trace.setSpan(otelContext.active(), context.parentSpan)
|
|
567
|
+
: otelContext.active()
|
|
568
|
+
return tracer.startActiveSpan(toolSpanName(toolName), {}, parentCtx, async (span) => {
|
|
569
|
+
try {
|
|
570
|
+
span.setAttributes({
|
|
571
|
+
[GENAI.TOOL_NAME]: toolName,
|
|
572
|
+
[GENAI.TOOL_TYPE]: 'function',
|
|
573
|
+
...(context.toolUseId !== undefined ? { [GENAI.TOOL_CALL_ID]: context.toolUseId } : {}),
|
|
574
|
+
[NAMZU.TOOL_SUCCESS]: false,
|
|
575
|
+
[NAMZU.TOOL_ERROR]: toErrorMessage(err),
|
|
576
|
+
})
|
|
577
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: toErrorMessage(err) })
|
|
578
|
+
throw err
|
|
579
|
+
} finally {
|
|
580
|
+
span.end()
|
|
581
|
+
}
|
|
582
|
+
})
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
private async executeRetained(
|
|
586
|
+
toolName: string,
|
|
587
|
+
tool: ToolDefinition,
|
|
588
|
+
finalInput: unknown,
|
|
589
|
+
context: ToolContext,
|
|
408
590
|
): Promise<ToolExecutionResult> {
|
|
409
591
|
const tracer = getTracer()
|
|
410
592
|
|
|
@@ -437,8 +619,6 @@ Executable tool names, descriptions, and JSON input schemas are attached through
|
|
|
437
619
|
...(context.toolUseId !== undefined ? { [GENAI.TOOL_CALL_ID]: context.toolUseId } : {}),
|
|
438
620
|
})
|
|
439
621
|
|
|
440
|
-
const tool = this.getOrThrow(toolName)
|
|
441
|
-
|
|
442
622
|
const availability = this.getAvailability(toolName)
|
|
443
623
|
if (availability !== 'active') {
|
|
444
624
|
const msg = `Tool "${toolName}" is ${availability} and cannot be executed`
|
|
@@ -492,7 +672,7 @@ Executable tool names, descriptions, and JSON input schemas are attached through
|
|
|
492
672
|
|
|
493
673
|
const mode = context.permissionContext?.mode ?? 'auto'
|
|
494
674
|
if (mode === 'plan') {
|
|
495
|
-
const isReadOnly = isTrustedReadOnly(tool,
|
|
675
|
+
const isReadOnly = isTrustedReadOnly(tool, finalInput)
|
|
496
676
|
if (!isReadOnly) {
|
|
497
677
|
const msg = `plan mode: non-read-only tool "${toolName}" blocked`
|
|
498
678
|
span.setAttributes({
|
|
@@ -510,63 +690,6 @@ Executable tool names, descriptions, and JSON input schemas are attached through
|
|
|
510
690
|
}
|
|
511
691
|
}
|
|
512
692
|
|
|
513
|
-
const parseResult = tool.inputSchema.safeParse(rawInput)
|
|
514
|
-
if (!parseResult.success) {
|
|
515
|
-
const errorMessage = parseResult.error.issues
|
|
516
|
-
.map((i) => `${i.path.join('.')}: ${i.message}`)
|
|
517
|
-
.join('; ')
|
|
518
|
-
|
|
519
|
-
// Distinguish "model sent an empty/no-arg call" from
|
|
520
|
-
// "model sent partial args" — the first is most often a
|
|
521
|
-
// streaming hiccup or a definition-test ping (a provider
|
|
522
|
-
// occasionally pings tool surfaces with `{}` while the
|
|
523
|
-
// schema is still loading), the second is a genuine
|
|
524
|
-
// programming mistake by the model. The model self-
|
|
525
|
-
// corrects MUCH more reliably when the error tells it
|
|
526
|
-
// (a) which fields are required, (b) their types, and
|
|
527
|
-
// (c) a minimal example call. Without these hints the
|
|
528
|
-
// downstream UI just shows a red "Failed" row and the
|
|
529
|
-
// model rarely retries with the right args.
|
|
530
|
-
const isEmptyInput =
|
|
531
|
-
rawInput === null ||
|
|
532
|
-
rawInput === undefined ||
|
|
533
|
-
(typeof rawInput === 'object' &&
|
|
534
|
-
!Array.isArray(rawInput) &&
|
|
535
|
-
Object.keys(rawInput as Record<string, unknown>).length === 0)
|
|
536
|
-
|
|
537
|
-
const requiredHint = describeRequiredInput(tool.inputSchema)
|
|
538
|
-
// A conditional schema's required shape cannot be reconstructed
|
|
539
|
-
// from JSON Schema's top-level `required`, so the author gets to
|
|
540
|
-
// say what a valid retry looks like.
|
|
541
|
-
const recoveryHint = tool.validationErrorHint?.trim()
|
|
542
|
-
? ` ${tool.validationErrorHint.trim()}`
|
|
543
|
-
: ''
|
|
544
|
-
|
|
545
|
-
const enrichedMessage = isEmptyInput
|
|
546
|
-
? `Tool "${toolName}" was called with no arguments. ${requiredHint}${recoveryHint} Retry the call with the required parameters populated.`
|
|
547
|
-
: `Validation failed for "${toolName}": ${errorMessage}. ${requiredHint}${recoveryHint}`
|
|
548
|
-
|
|
549
|
-
this.log.error('Tool input validation failed', {
|
|
550
|
-
'namzu.tool.name': toolName,
|
|
551
|
-
'namzu.registry.errors': errorMessage,
|
|
552
|
-
'namzu.registry.empty': isEmptyInput,
|
|
553
|
-
})
|
|
554
|
-
|
|
555
|
-
span.setAttributes({
|
|
556
|
-
[NAMZU.TOOL_SUCCESS]: false,
|
|
557
|
-
[NAMZU.TOOL_ERROR]: `Validation: ${errorMessage}`,
|
|
558
|
-
})
|
|
559
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage })
|
|
560
|
-
|
|
561
|
-
return {
|
|
562
|
-
success: false,
|
|
563
|
-
output: '',
|
|
564
|
-
error: enrichedMessage,
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
const finalInput = parseResult.data
|
|
569
|
-
|
|
570
693
|
try {
|
|
571
694
|
this.log.debug('Executing tool', { 'namzu.tool.name': toolName })
|
|
572
695
|
const startedAt = Date.now()
|
|
@@ -604,7 +727,10 @@ Executable tool names, descriptions, and JSON input schemas are attached through
|
|
|
604
727
|
)
|
|
605
728
|
if (!result.success && result.error) {
|
|
606
729
|
span.setAttribute(NAMZU.TOOL_ERROR, result.error)
|
|
607
|
-
span.setStatus({
|
|
730
|
+
span.setStatus({
|
|
731
|
+
code: SpanStatusCode.ERROR,
|
|
732
|
+
message: result.error,
|
|
733
|
+
})
|
|
608
734
|
} else {
|
|
609
735
|
span.setStatus({ code: SpanStatusCode.OK })
|
|
610
736
|
}
|
|
@@ -622,7 +748,10 @@ Executable tool names, descriptions, and JSON input schemas are attached through
|
|
|
622
748
|
[NAMZU.TOOL_SUCCESS]: false,
|
|
623
749
|
[NAMZU.TOOL_ERROR]: err.message,
|
|
624
750
|
})
|
|
625
|
-
span.setStatus({
|
|
751
|
+
span.setStatus({
|
|
752
|
+
code: SpanStatusCode.ERROR,
|
|
753
|
+
message: err.message,
|
|
754
|
+
})
|
|
626
755
|
throw err
|
|
627
756
|
}
|
|
628
757
|
const errorMessage = toErrorMessage(err)
|
|
@@ -635,7 +764,10 @@ Executable tool names, descriptions, and JSON input schemas are attached through
|
|
|
635
764
|
[NAMZU.TOOL_SUCCESS]: false,
|
|
636
765
|
[NAMZU.TOOL_ERROR]: errorMessage,
|
|
637
766
|
})
|
|
638
|
-
span.setStatus({
|
|
767
|
+
span.setStatus({
|
|
768
|
+
code: SpanStatusCode.ERROR,
|
|
769
|
+
message: errorMessage,
|
|
770
|
+
})
|
|
639
771
|
span.recordException(err instanceof Error ? err : new Error(errorMessage))
|
|
640
772
|
|
|
641
773
|
return {
|
|
@@ -655,6 +787,40 @@ Executable tool names, descriptions, and JSON input schemas are attached through
|
|
|
655
787
|
})
|
|
656
788
|
}
|
|
657
789
|
|
|
790
|
+
private validationFailure(
|
|
791
|
+
tool: ToolDefinition,
|
|
792
|
+
rawInput: unknown,
|
|
793
|
+
error: {
|
|
794
|
+
readonly issues: readonly {
|
|
795
|
+
readonly path: readonly PropertyKey[]
|
|
796
|
+
readonly message: string
|
|
797
|
+
}[]
|
|
798
|
+
},
|
|
799
|
+
): ToolExecutionResult {
|
|
800
|
+
const errorMessage = error.issues
|
|
801
|
+
.map((issue) => `${issue.path.join('.')}: ${issue.message}`)
|
|
802
|
+
.join('; ')
|
|
803
|
+
const isEmptyInput =
|
|
804
|
+
rawInput === null ||
|
|
805
|
+
rawInput === undefined ||
|
|
806
|
+
(typeof rawInput === 'object' &&
|
|
807
|
+
!Array.isArray(rawInput) &&
|
|
808
|
+
Object.keys(rawInput as Record<string, unknown>).length === 0)
|
|
809
|
+
const requiredHint = describeRequiredInput(tool.inputSchema)
|
|
810
|
+
const recoveryHint = tool.validationErrorHint?.trim()
|
|
811
|
+
? ` ${tool.validationErrorHint.trim()}`
|
|
812
|
+
: ''
|
|
813
|
+
const enrichedMessage = isEmptyInput
|
|
814
|
+
? `Tool "${tool.name}" was called with no arguments. ${requiredHint}${recoveryHint} Retry the call with the required parameters populated.`
|
|
815
|
+
: `Validation failed for "${tool.name}": ${errorMessage}. ${requiredHint}${recoveryHint}`
|
|
816
|
+
this.log.error('Tool input validation failed', {
|
|
817
|
+
'namzu.tool.name': tool.name,
|
|
818
|
+
'namzu.registry.errors': errorMessage,
|
|
819
|
+
'namzu.registry.empty': isEmptyInput,
|
|
820
|
+
})
|
|
821
|
+
return { success: false, output: '', error: enrichedMessage }
|
|
822
|
+
}
|
|
823
|
+
|
|
658
824
|
private getByAvailability(states: ToolAvailability[], filter?: string[]): ToolDefinition[] {
|
|
659
825
|
const candidates = filter ? filter.map((n) => this.getOrThrow(n)) : this.getAll()
|
|
660
826
|
return candidates.filter((t) => states.includes(this.getAvailability(t.name)))
|