@tanstack/ai 0.42.0 → 0.43.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/README.md +15 -1
- package/dist/esm/activities/chat/adapter.js +23 -16
- package/dist/esm/activities/chat/adapter.js.map +1 -1
- package/dist/esm/activities/chat/agent-loop-strategies.d.ts +5 -36
- package/dist/esm/activities/chat/agent-loop-strategies.js +75 -21
- package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -1
- package/dist/esm/activities/chat/cancel.d.ts +40 -0
- package/dist/esm/activities/chat/cancel.js +54 -0
- package/dist/esm/activities/chat/cancel.js.map +1 -0
- package/dist/esm/activities/chat/index.d.ts +28 -21
- package/dist/esm/activities/chat/index.js +2100 -1813
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/mcp/manager.d.ts +2 -2
- package/dist/esm/activities/chat/mcp/manager.js +90 -77
- package/dist/esm/activities/chat/mcp/manager.js.map +1 -1
- package/dist/esm/activities/chat/mcp/types.d.ts +2 -2
- package/dist/esm/activities/chat/messages.js +397 -346
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/middleware/builder.js +17 -15
- package/dist/esm/activities/chat/middleware/builder.js.map +1 -1
- package/dist/esm/activities/chat/middleware/capabilities.js +78 -43
- package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -1
- package/dist/esm/activities/chat/middleware/compose.d.ts +94 -1
- package/dist/esm/activities/chat/middleware/compose.js +623 -531
- package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
- package/dist/esm/activities/chat/middleware/define.js +12 -5
- package/dist/esm/activities/chat/middleware/define.js.map +1 -1
- package/dist/esm/activities/chat/middleware/index.d.ts +5 -1
- package/dist/esm/activities/chat/middleware/locks.d.ts +50 -0
- package/dist/esm/activities/chat/middleware/locks.js +71 -0
- package/dist/esm/activities/chat/middleware/locks.js.map +1 -0
- package/dist/esm/activities/chat/middleware/pending-turn.d.ts +15 -0
- package/dist/esm/activities/chat/middleware/pending-turn.js +35 -0
- package/dist/esm/activities/chat/middleware/pending-turn.js.map +1 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.d.ts +23 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.js +42 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.js.map +1 -0
- package/dist/esm/activities/chat/middleware/run-store.d.ts +283 -0
- package/dist/esm/activities/chat/middleware/run-store.js +176 -0
- package/dist/esm/activities/chat/middleware/run-store.js.map +1 -0
- package/dist/esm/activities/chat/middleware/sandbox-runtime.js +14 -8
- package/dist/esm/activities/chat/middleware/sandbox-runtime.js.map +1 -1
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +79 -70
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +59 -2
- package/dist/esm/activities/chat/middleware/validate.js +23 -28
- package/dist/esm/activities/chat/middleware/validate.js.map +1 -1
- package/dist/esm/activities/chat/stream/json-parser.js +39 -25
- package/dist/esm/activities/chat/stream/json-parser.js.map +1 -1
- package/dist/esm/activities/chat/stream/message-updaters.js +275 -234
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +24 -4
- package/dist/esm/activities/chat/stream/processor.js +1341 -1542
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/stream/strategies.js +69 -53
- package/dist/esm/activities/chat/stream/strategies.js.map +1 -1
- package/dist/esm/activities/chat/tools/approval-schema.d.ts +19 -0
- package/dist/esm/activities/chat/tools/approval-schema.js +117 -0
- package/dist/esm/activities/chat/tools/approval-schema.js.map +1 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js +164 -191
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
- package/dist/esm/activities/chat/tools/lazy-tools.js +24 -12
- package/dist/esm/activities/chat/tools/lazy-tools.js.map +1 -1
- package/dist/esm/activities/chat/tools/schema-converter.js +293 -146
- package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +18 -2
- package/dist/esm/activities/chat/tools/tool-calls.js +522 -531
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +75 -16
- package/dist/esm/activities/chat/tools/tool-definition.js +95 -23
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
- package/dist/esm/activities/error-payload.js +85 -47
- package/dist/esm/activities/error-payload.js.map +1 -1
- package/dist/esm/activities/generateAudio/adapter.js +22 -15
- package/dist/esm/activities/generateAudio/adapter.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.d.ts +4 -0
- package/dist/esm/activities/generateAudio/index.js +141 -105
- package/dist/esm/activities/generateAudio/index.js.map +1 -1
- package/dist/esm/activities/generateImage/adapter.js +22 -15
- package/dist/esm/activities/generateImage/adapter.js.map +1 -1
- package/dist/esm/activities/generateImage/index.d.ts +4 -0
- package/dist/esm/activities/generateImage/index.js +155 -111
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/adapter.js +22 -15
- package/dist/esm/activities/generateSpeech/adapter.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.d.ts +4 -0
- package/dist/esm/activities/generateSpeech/index.js +159 -110
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/adapter.js +22 -15
- package/dist/esm/activities/generateTranscription/adapter.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.d.ts +4 -0
- package/dist/esm/activities/generateTranscription/index.js +159 -100
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/adapter.js +36 -29
- package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +143 -19
- package/dist/esm/activities/generateVideo/index.js +456 -279
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/snap.js +60 -48
- package/dist/esm/activities/generateVideo/snap.js.map +1 -1
- package/dist/esm/activities/index.js +8 -34
- package/dist/esm/activities/middleware/index.d.ts +1 -1
- package/dist/esm/activities/middleware/run.d.ts +10 -0
- package/dist/esm/activities/middleware/run.js +53 -29
- package/dist/esm/activities/middleware/run.js.map +1 -1
- package/dist/esm/activities/middleware/types.d.ts +44 -6
- package/dist/esm/activities/stream-generation-result.d.ts +4 -1
- package/dist/esm/activities/stream-generation-result.js +79 -44
- package/dist/esm/activities/stream-generation-result.js.map +1 -1
- package/dist/esm/activities/summarize/adapter.js +22 -15
- package/dist/esm/activities/summarize/adapter.js.map +1 -1
- package/dist/esm/activities/summarize/chat-stream-summarize.js +252 -202
- package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
- package/dist/esm/activities/summarize/index.d.ts +27 -0
- package/dist/esm/activities/summarize/index.js +268 -102
- package/dist/esm/activities/summarize/index.js.map +1 -1
- package/dist/esm/adapter-internals.d.ts +2 -1
- package/dist/esm/adapter-internals.js +4 -11
- package/dist/esm/client.d.ts +25 -3
- package/dist/esm/client.js +131 -64
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/custom-events.d.ts +76 -0
- package/dist/esm/custom-events.js +37 -0
- package/dist/esm/custom-events.js.map +1 -0
- package/dist/esm/delivery-detach.d.ts +50 -0
- package/dist/esm/delivery-detach.js +71 -0
- package/dist/esm/delivery-detach.js.map +1 -0
- package/dist/esm/delivery-disconnect.d.ts +62 -0
- package/dist/esm/delivery-disconnect.js +81 -0
- package/dist/esm/delivery-disconnect.js.map +1 -0
- package/dist/esm/extend-adapter.js +19 -17
- package/dist/esm/extend-adapter.js.map +1 -1
- package/dist/esm/index.d.ts +24 -6
- package/dist/esm/index.js +30 -98
- package/dist/esm/interrupt-resume.d.ts +71 -0
- package/dist/esm/interrupt-resume.js +438 -0
- package/dist/esm/interrupt-resume.js.map +1 -0
- package/dist/esm/interrupt-serialization.d.ts +12 -0
- package/dist/esm/interrupt-serialization.js +178 -0
- package/dist/esm/interrupt-serialization.js.map +1 -0
- package/dist/esm/interrupts.d.ts +84 -0
- package/dist/esm/interrupts.js +31 -0
- package/dist/esm/interrupts.js.map +1 -0
- package/dist/esm/locks.d.ts +10 -0
- package/dist/esm/locks.js +2 -0
- package/dist/esm/logger/console-logger.js +101 -78
- package/dist/esm/logger/console-logger.js.map +1 -1
- package/dist/esm/logger/internal-logger.js +104 -89
- package/dist/esm/logger/internal-logger.js.map +1 -1
- package/dist/esm/logger/resolve.js +54 -49
- package/dist/esm/logger/resolve.js.map +1 -1
- package/dist/esm/logger/types.d.ts +1 -1
- package/dist/esm/middlewares/content-guard.js +142 -148
- package/dist/esm/middlewares/content-guard.js.map +1 -1
- package/dist/esm/middlewares/index.js +2 -6
- package/dist/esm/middlewares/otel.js +598 -732
- package/dist/esm/middlewares/otel.js.map +1 -1
- package/dist/esm/middlewares/usage-attributes.js +47 -40
- package/dist/esm/middlewares/usage-attributes.js.map +1 -1
- package/dist/esm/realtime/event-emitter.js +24 -25
- package/dist/esm/realtime/event-emitter.js.map +1 -1
- package/dist/esm/realtime/index.d.ts +5 -9
- package/dist/esm/realtime/index.js +29 -6
- package/dist/esm/realtime/index.js.map +1 -1
- package/dist/esm/scope.d.ts +47 -0
- package/dist/esm/stream-durability.d.ts +171 -0
- package/dist/esm/stream-durability.js +295 -0
- package/dist/esm/stream-durability.js.map +1 -0
- package/dist/esm/stream-to-response.d.ts +178 -13
- package/dist/esm/stream-to-response.js +663 -115
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/strip-to-spec-middleware.js +30 -16
- package/dist/esm/strip-to-spec-middleware.js.map +1 -1
- package/dist/esm/system-prompts.js +27 -21
- package/dist/esm/system-prompts.js.map +1 -1
- package/dist/esm/tool-registry.js +72 -45
- package/dist/esm/tool-registry.js.map +1 -1
- package/dist/esm/tools/provider-tool.js +14 -5
- package/dist/esm/tools/provider-tool.js.map +1 -1
- package/dist/esm/types.d.ts +321 -42
- package/dist/esm/types.js +2 -0
- package/dist/esm/utilities/ag-ui-wire.js +79 -93
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/chat-params.d.ts +26 -4
- package/dist/esm/utilities/chat-params.js +218 -92
- package/dist/esm/utilities/chat-params.js.map +1 -1
- package/dist/esm/utilities/errors.js +28 -18
- package/dist/esm/utilities/errors.js.map +1 -1
- package/dist/esm/utilities/media-prompt.js +46 -41
- package/dist/esm/utilities/media-prompt.js.map +1 -1
- package/dist/esm/utilities/numbers.js +13 -10
- package/dist/esm/utilities/numbers.js.map +1 -1
- package/dist/esm/utilities/provider-executed.js +20 -11
- package/dist/esm/utilities/provider-executed.js.map +1 -1
- package/dist/esm/utilities/sampling-keys.js +31 -19
- package/dist/esm/utilities/sampling-keys.js.map +1 -1
- package/dist/esm/utilities/tool-result.js +42 -30
- package/dist/esm/utilities/tool-result.js.map +1 -1
- package/dist/esm/utilities/usage.js +27 -9
- package/dist/esm/utilities/usage.js.map +1 -1
- package/dist/esm/utils.js +26 -18
- package/dist/esm/utils.js.map +1 -1
- package/package.json +10 -6
- package/skills/ai-core/SKILL.md +69 -18
- package/skills/ai-core/adapter-configuration/SKILL.md +44 -21
- package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +1 -3
- package/skills/ai-core/adapter-configuration/references/byteplus-adapter.md +148 -0
- package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -6
- package/skills/ai-core/adapter-configuration/references/groq-adapter.md +2 -6
- package/skills/ai-core/adapter-configuration/references/openai-adapter.md +1 -3
- package/skills/ai-core/ag-ui-protocol/SKILL.md +1 -1
- package/skills/ai-core/chat-experience/SKILL.md +98 -11
- package/skills/ai-core/client-persistence/SKILL.md +277 -0
- package/skills/ai-core/custom-backend-integration/SKILL.md +1 -1
- package/skills/ai-core/debug-logging/SKILL.md +1 -1
- package/skills/ai-core/locks/SKILL.md +143 -0
- package/skills/ai-core/media-generation/SKILL.md +144 -12
- package/skills/ai-core/middleware/SKILL.md +258 -33
- package/skills/ai-core/structured-outputs/SKILL.md +1 -1
- package/skills/ai-core/tool-calling/SKILL.md +54 -61
- package/src/activities/chat/agent-loop-strategies.ts +5 -39
- package/src/activities/chat/cancel.ts +81 -0
- package/src/activities/chat/index.ts +1091 -200
- package/src/activities/chat/mcp/manager.ts +4 -4
- package/src/activities/chat/mcp/types.ts +2 -2
- package/src/activities/chat/messages.ts +5 -3
- package/src/activities/chat/middleware/builder.ts +1 -1
- package/src/activities/chat/middleware/compose.ts +186 -9
- package/src/activities/chat/middleware/index.ts +26 -0
- package/src/activities/chat/middleware/locks.ts +102 -0
- package/src/activities/chat/middleware/pending-turn.ts +47 -0
- package/src/activities/chat/middleware/run-disconnect.ts +62 -0
- package/src/activities/chat/middleware/run-store.ts +412 -0
- package/src/activities/chat/middleware/types.ts +62 -1
- package/src/activities/chat/stream/processor.ts +189 -5
- package/src/activities/chat/tools/approval-schema.ts +205 -0
- package/src/activities/chat/tools/tool-calls.ts +106 -13
- package/src/activities/chat/tools/tool-definition.ts +210 -39
- package/src/activities/generateAudio/index.ts +20 -3
- package/src/activities/generateImage/index.ts +20 -3
- package/src/activities/generateSpeech/index.ts +25 -3
- package/src/activities/generateTranscription/index.ts +26 -3
- package/src/activities/generateVideo/index.ts +345 -82
- package/src/activities/middleware/index.ts +2 -0
- package/src/activities/middleware/run.ts +31 -0
- package/src/activities/middleware/types.ts +49 -5
- package/src/activities/stream-generation-result.ts +30 -2
- package/src/activities/summarize/chat-stream-summarize.ts +5 -0
- package/src/activities/summarize/index.ts +200 -10
- package/src/adapter-internals.ts +10 -1
- package/src/client.ts +244 -0
- package/src/custom-events.ts +107 -0
- package/src/delivery-detach.ts +72 -0
- package/src/delivery-disconnect.ts +84 -0
- package/src/index.ts +138 -1
- package/src/interrupt-resume.ts +824 -0
- package/src/interrupt-serialization.ts +183 -0
- package/src/interrupts.ts +146 -0
- package/src/locks.ts +17 -0
- package/src/logger/types.ts +1 -1
- package/src/middlewares/otel.ts +1 -0
- package/src/realtime/index.ts +5 -9
- package/src/scope.ts +47 -0
- package/src/stream-durability.ts +598 -0
- package/src/stream-to-response.ts +1051 -95
- package/src/strip-to-spec-middleware.ts +3 -3
- package/src/types.ts +405 -45
- package/src/utilities/chat-params.ts +245 -55
- package/dist/esm/activities/index.js.map +0 -1
- package/dist/esm/adapter-internals.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/middlewares/index.js.map +0 -1
|
@@ -1,167 +1,314 @@
|
|
|
1
|
+
//#region src/activities/chat/tools/schema-converter.ts
|
|
2
|
+
/**
|
|
3
|
+
* Build a JSONSchema object from any plain key/value source. The `JSONSchema`
|
|
4
|
+
* interface's `[key: string]: any` index signature makes every property
|
|
5
|
+
* assignable through bracket access without a type cast — copying keys here
|
|
6
|
+
* lets us narrow either `Record<string, unknown>` (returned by
|
|
7
|
+
* `~standard.jsonSchema.input()`) or a `JSONSchema` (from the SchemaInput
|
|
8
|
+
* pass-through arm) into the typed view used by the rest of this module.
|
|
9
|
+
*
|
|
10
|
+
* Accepts `object` so callers don't need a cast when narrowing from union
|
|
11
|
+
* types like `SchemaInput`.
|
|
12
|
+
*/
|
|
1
13
|
function toJsonSchema(obj) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
16
|
+
if (key === "$schema") continue;
|
|
17
|
+
result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
8
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Whether a value can carry a `~standard` property. Most schema libraries
|
|
23
|
+
* (Zod, Valibot) return plain objects, but ArkType's `type()` returns a
|
|
24
|
+
* *callable function* with `~standard` attached — so `typeof` must accept
|
|
25
|
+
* both `'object'` and `'function'` or ArkType schemas are missed entirely
|
|
26
|
+
* (issue #276).
|
|
27
|
+
*/
|
|
9
28
|
function isPropertyCarrier(schema) {
|
|
10
|
-
|
|
29
|
+
return (typeof schema === "object" || typeof schema === "function") && schema !== null;
|
|
11
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if a value is a Standard JSON Schema compliant schema.
|
|
33
|
+
* Standard JSON Schema compliant libraries (Zod v4+, ArkType, Valibot with toStandardJsonSchema, etc.)
|
|
34
|
+
* implement the '~standard' property with jsonSchema converter methods.
|
|
35
|
+
*/
|
|
12
36
|
function isStandardJSONSchema(schema) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
return typeof standard.jsonSchema.input === "function";
|
|
37
|
+
if (!isPropertyCarrier(schema) || !("~standard" in schema)) return false;
|
|
38
|
+
const standard = schema["~standard"];
|
|
39
|
+
if (typeof standard !== "object" || standard === null || !("version" in standard) || standard.version !== 1 || !("jsonSchema" in standard) || typeof standard.jsonSchema !== "object" || standard.jsonSchema === null || !("input" in standard.jsonSchema)) return false;
|
|
40
|
+
return typeof standard.jsonSchema.input === "function";
|
|
19
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a value is a Standard Schema compliant schema (for validation).
|
|
44
|
+
* Standard Schema compliant libraries implement the '~standard' property with a validate function.
|
|
45
|
+
*/
|
|
20
46
|
function isStandardSchema(schema) {
|
|
21
|
-
|
|
47
|
+
return isPropertyCarrier(schema) && "~standard" in schema && typeof schema["~standard"] === "object" && schema["~standard"] !== null && "version" in schema["~standard"] && schema["~standard"].version === 1 && "validate" in schema["~standard"] && typeof schema["~standard"].validate === "function";
|
|
22
48
|
}
|
|
49
|
+
/** Drop an empty map to `undefined` so leaf/no-op subtrees don't litter it. */
|
|
23
50
|
function pruneMap(map) {
|
|
24
|
-
|
|
51
|
+
return Object.keys(map).length > 0 ? map : void 0;
|
|
25
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Transform a JSON schema to be compatible with OpenAI's structured output requirements.
|
|
55
|
+
* OpenAI requires:
|
|
56
|
+
* - All properties must be in the `required` array
|
|
57
|
+
* - Optional fields should have null added to their type union
|
|
58
|
+
* - additionalProperties must be false for objects
|
|
59
|
+
*
|
|
60
|
+
* Alongside the transformed schema it returns a {@link NullWideningMap} marking
|
|
61
|
+
* exactly the positions where `null` was added, so `undoNullWidening` can strip
|
|
62
|
+
* those synthesized nulls (and only those) from the provider's response.
|
|
63
|
+
*
|
|
64
|
+
* @param schema - JSON schema to transform
|
|
65
|
+
* @param originalRequired - Original required array (to know which fields were optional)
|
|
66
|
+
* @returns Transformed schema + the null-widening map for the round trip
|
|
67
|
+
*/
|
|
26
68
|
function makeStructuredOutputCompatible(schema, originalRequired = []) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
69
|
+
const result = { ...schema };
|
|
70
|
+
const map = {};
|
|
71
|
+
if (result.type === "object" && result.properties) {
|
|
72
|
+
const properties = { ...result.properties };
|
|
73
|
+
const allPropertyNames = Object.keys(properties);
|
|
74
|
+
const propertyMaps = {};
|
|
75
|
+
for (const propName of allPropertyNames) {
|
|
76
|
+
const prop = properties[propName];
|
|
77
|
+
if (!prop) continue;
|
|
78
|
+
const wasOptional = !originalRequired.includes(propName);
|
|
79
|
+
let widenedHere = false;
|
|
80
|
+
let childMap;
|
|
81
|
+
if (prop.type === "object" && prop.properties) {
|
|
82
|
+
const nested = makeStructuredOutputCompatible(prop, prop.required || []);
|
|
83
|
+
properties[propName] = wasOptional ? {
|
|
84
|
+
...nested.schema,
|
|
85
|
+
type: ["object", "null"]
|
|
86
|
+
} : nested.schema;
|
|
87
|
+
widenedHere = wasOptional;
|
|
88
|
+
childMap = nested.nullWidening;
|
|
89
|
+
} else if (prop.type === "array" && prop.items) {
|
|
90
|
+
const items = Array.isArray(prop.items) ? prop.items[0] : prop.items;
|
|
91
|
+
const nestedItems = items ? makeStructuredOutputCompatible(items, items.required || []) : void 0;
|
|
92
|
+
properties[propName] = {
|
|
93
|
+
...prop,
|
|
94
|
+
items: nestedItems ? nestedItems.schema : prop.items,
|
|
95
|
+
...wasOptional ? { type: ["array", "null"] } : {}
|
|
96
|
+
};
|
|
97
|
+
widenedHere = wasOptional;
|
|
98
|
+
childMap = nestedItems?.nullWidening ? { items: nestedItems.nullWidening } : void 0;
|
|
99
|
+
} else if (wasOptional) {
|
|
100
|
+
if (prop.type && !Array.isArray(prop.type)) {
|
|
101
|
+
properties[propName] = {
|
|
102
|
+
...prop,
|
|
103
|
+
type: [prop.type, "null"]
|
|
104
|
+
};
|
|
105
|
+
widenedHere = true;
|
|
106
|
+
} else if (Array.isArray(prop.type) && !prop.type.includes("null")) {
|
|
107
|
+
properties[propName] = {
|
|
108
|
+
...prop,
|
|
109
|
+
type: [...prop.type, "null"]
|
|
110
|
+
};
|
|
111
|
+
widenedHere = true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (widenedHere || childMap) propertyMaps[propName] = {
|
|
115
|
+
...childMap ?? {},
|
|
116
|
+
...widenedHere ? { widened: true } : {}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
result.properties = properties;
|
|
120
|
+
result.required = allPropertyNames;
|
|
121
|
+
result.additionalProperties = false;
|
|
122
|
+
if (Object.keys(propertyMaps).length > 0) map.properties = propertyMaps;
|
|
123
|
+
}
|
|
124
|
+
if (result.type === "array" && result.items) {
|
|
125
|
+
const items = Array.isArray(result.items) ? result.items[0] : result.items;
|
|
126
|
+
if (items) {
|
|
127
|
+
const nestedItems = makeStructuredOutputCompatible(items, items.required || []);
|
|
128
|
+
result.items = nestedItems.schema;
|
|
129
|
+
if (nestedItems.nullWidening) map.items = nestedItems.nullWidening;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
schema: result,
|
|
134
|
+
nullWidening: pruneMap(map)
|
|
135
|
+
};
|
|
87
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Normalize any supported schema input to a typed, UN-widened `JSONSchema` —
|
|
139
|
+
* the shared first half of conversion, before any structured-output widening.
|
|
140
|
+
*
|
|
141
|
+
* - Standard JSON Schemas are rebuilt structurally (dropping `$schema`, which
|
|
142
|
+
* LLM providers ignore) and given the explicit `type`/`properties`/`required`
|
|
143
|
+
* defaults object shapes need downstream.
|
|
144
|
+
* - Plain `JSONSchema` inputs are rebuilt into the typed view; non-object inputs
|
|
145
|
+
* are surfaced untouched (they can't be widened).
|
|
146
|
+
* - Standard Schema validators lacking a `~standard.jsonSchema` converter throw
|
|
147
|
+
* with actionable guidance, rather than shipping `{ '~standard': … }` to the
|
|
148
|
+
* provider and producing an opaque downstream error.
|
|
149
|
+
*/
|
|
88
150
|
function toTypedJsonSchema(schema) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
result.required = [];
|
|
100
|
-
}
|
|
101
|
-
return result;
|
|
102
|
-
}
|
|
103
|
-
if (isStandardSchema(schema)) {
|
|
104
|
-
throw new Error(
|
|
105
|
-
"Schema is a Standard Schema validator but does not expose a JSON Schema converter on `~standard.jsonSchema`. Use Zod v4.2+, ArkType v2.1.28+, or wrap a Valibot schema with `toStandardJsonSchema()` from `@valibot/to-json-schema` before passing it as `outputSchema`."
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
if (typeof schema !== "object") return schema;
|
|
109
|
-
return toJsonSchema(schema);
|
|
151
|
+
if (isStandardJSONSchema(schema)) {
|
|
152
|
+
const result = toJsonSchema(schema["~standard"].jsonSchema.input({ target: "draft-07" }));
|
|
153
|
+
if ("properties" in result && !result.type) result.type = "object";
|
|
154
|
+
if (result.type === "object" && !("properties" in result)) result.properties = {};
|
|
155
|
+
if (result.type === "object" && !("required" in result)) result.required = [];
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
if (isStandardSchema(schema)) throw new Error("Schema is a Standard Schema validator but does not expose a JSON Schema converter on `~standard.jsonSchema`. Use Zod v4.2+, ArkType v2.1.28+, or wrap a Valibot schema with `toStandardJsonSchema()` from `@valibot/to-json-schema` before passing it as `outputSchema`.");
|
|
159
|
+
if (typeof schema !== "object") return schema;
|
|
160
|
+
return toJsonSchema(schema);
|
|
110
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Converts a Standard JSON Schema compliant schema or plain JSONSchema to JSON Schema format
|
|
164
|
+
* compatible with LLM providers.
|
|
165
|
+
*
|
|
166
|
+
* Supports any schema library that implements the Standard JSON Schema spec (v1):
|
|
167
|
+
* - Zod v4+ (natively supports StandardJSONSchemaV1)
|
|
168
|
+
* - ArkType (natively supports StandardJSONSchemaV1)
|
|
169
|
+
* - Valibot (via `toStandardJsonSchema()` from `@valibot/to-json-schema`)
|
|
170
|
+
*
|
|
171
|
+
* If the input is already a plain JSONSchema object, it is returned as-is.
|
|
172
|
+
*
|
|
173
|
+
* @param schema - Standard JSON Schema compliant schema or plain JSONSchema object to convert
|
|
174
|
+
* @param options - Conversion options
|
|
175
|
+
* @returns JSON Schema object that can be sent to LLM providers
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* // Using Zod v4+ (natively supports Standard JSON Schema)
|
|
180
|
+
* import * as z from 'zod';
|
|
181
|
+
*
|
|
182
|
+
* const zodSchema = z.object({
|
|
183
|
+
* location: z.string().describe('City name'),
|
|
184
|
+
* unit: z.enum(['celsius', 'fahrenheit']).optional()
|
|
185
|
+
* });
|
|
186
|
+
*
|
|
187
|
+
* const jsonSchema = convertSchemaToJsonSchema(zodSchema);
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* // Using ArkType (natively supports Standard JSON Schema)
|
|
191
|
+
* import { type } from 'arktype';
|
|
192
|
+
*
|
|
193
|
+
* const arkSchema = type({
|
|
194
|
+
* location: 'string',
|
|
195
|
+
* unit: "'celsius' | 'fahrenheit'"
|
|
196
|
+
* });
|
|
197
|
+
*
|
|
198
|
+
* const jsonSchema = convertSchemaToJsonSchema(arkSchema);
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* // Using Valibot (via toStandardJsonSchema)
|
|
202
|
+
* import * as v from 'valibot';
|
|
203
|
+
* import { toStandardJsonSchema } from '@valibot/to-json-schema';
|
|
204
|
+
*
|
|
205
|
+
* const valibotSchema = toStandardJsonSchema(v.object({
|
|
206
|
+
* location: v.string(),
|
|
207
|
+
* unit: v.optional(v.picklist(['celsius', 'fahrenheit']))
|
|
208
|
+
* }));
|
|
209
|
+
*
|
|
210
|
+
* const jsonSchema = convertSchemaToJsonSchema(valibotSchema);
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* // Using JSONSchema directly (passes through unchanged)
|
|
214
|
+
* const rawSchema = {
|
|
215
|
+
* type: 'object',
|
|
216
|
+
* properties: { location: { type: 'string' } },
|
|
217
|
+
* required: ['location']
|
|
218
|
+
* };
|
|
219
|
+
* const result = convertSchemaToJsonSchema(rawSchema);
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
111
222
|
function convertSchemaToJsonSchema(schema, options = {}) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (!forStructuredOutput) return base;
|
|
120
|
-
return makeStructuredOutputCompatible(base, base.required || []).schema;
|
|
223
|
+
if (!schema) return void 0;
|
|
224
|
+
const { forStructuredOutput = false } = options;
|
|
225
|
+
if (!forStructuredOutput && !isStandardJSONSchema(schema) && !isStandardSchema(schema)) return schema;
|
|
226
|
+
const base = toTypedJsonSchema(schema);
|
|
227
|
+
if (!base || typeof base !== "object") return base;
|
|
228
|
+
if (!forStructuredOutput) return base;
|
|
229
|
+
return makeStructuredOutputCompatible(base, base.required || []).schema;
|
|
121
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Convert a schema for structured output AND capture the {@link NullWideningMap}
|
|
233
|
+
* recording every `null` the strict-mode widening synthesized. The map lets the
|
|
234
|
+
* caller undo that widening on the provider's response (via `undoNullWidening`)
|
|
235
|
+
* before validating against the original schema — optional fields read back as
|
|
236
|
+
* absent while genuine `.nullable()` nulls survive. The map is `undefined` when
|
|
237
|
+
* the schema isn't a widenable object or when no field needed widening.
|
|
238
|
+
*/
|
|
122
239
|
function convertSchemaForStructuredOutput(schema) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
240
|
+
if (!schema) return {
|
|
241
|
+
jsonSchema: void 0,
|
|
242
|
+
nullWideningMap: void 0
|
|
243
|
+
};
|
|
244
|
+
const base = toTypedJsonSchema(schema);
|
|
245
|
+
if (!base || typeof base !== "object") return {
|
|
246
|
+
jsonSchema: base,
|
|
247
|
+
nullWideningMap: void 0
|
|
248
|
+
};
|
|
249
|
+
const { schema: jsonSchema, nullWidening } = makeStructuredOutputCompatible(base, base.required || []);
|
|
250
|
+
return {
|
|
251
|
+
jsonSchema,
|
|
252
|
+
nullWideningMap: nullWidening
|
|
253
|
+
};
|
|
133
254
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
255
|
+
/**
|
|
256
|
+
* Validates data against a Standard Schema compliant schema.
|
|
257
|
+
*
|
|
258
|
+
* @param schema - Standard Schema compliant schema
|
|
259
|
+
* @param data - Data to validate
|
|
260
|
+
* @returns Validation result with success status, data or issues
|
|
261
|
+
*/
|
|
262
|
+
async function validateWithStandardSchema(schema, data) {
|
|
263
|
+
if (!isStandardSchema(schema)) return {
|
|
264
|
+
success: true,
|
|
265
|
+
data
|
|
266
|
+
};
|
|
267
|
+
const result = await schema["~standard"].validate(data);
|
|
268
|
+
if (!result.issues) return {
|
|
269
|
+
success: true,
|
|
270
|
+
data: result.value
|
|
271
|
+
};
|
|
272
|
+
return {
|
|
273
|
+
success: false,
|
|
274
|
+
issues: result.issues.map((issue) => ({
|
|
275
|
+
message: issue.message || "Validation failed",
|
|
276
|
+
path: issue.path?.map(String)
|
|
277
|
+
}))
|
|
278
|
+
};
|
|
143
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* Error thrown when Standard Schema validation fails. Carries the original
|
|
282
|
+
* `issues` array so consumers (middleware `onError`, callers catching from
|
|
283
|
+
* `chat({ outputSchema })`) can programmatically inspect each failure.
|
|
284
|
+
*/
|
|
285
|
+
var StandardSchemaValidationError = class extends Error {
|
|
286
|
+
name = "StandardSchemaValidationError";
|
|
287
|
+
issues;
|
|
288
|
+
constructor(issues) {
|
|
289
|
+
super(`Validation failed: ${issues.map((i) => i.message || "Validation failed").join(", ")}`);
|
|
290
|
+
this.issues = issues;
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* Synchronously validates data against a Standard Schema compliant schema.
|
|
295
|
+
* Note: Some Standard Schema implementations may only support async validation.
|
|
296
|
+
* In those cases, this function will throw.
|
|
297
|
+
*
|
|
298
|
+
* @param schema - Standard Schema compliant schema
|
|
299
|
+
* @param data - Data to validate
|
|
300
|
+
* @returns Parsed/validated data
|
|
301
|
+
* @throws StandardSchemaValidationError if validation fails; Error if the
|
|
302
|
+
* schema only supports async validation.
|
|
303
|
+
*/
|
|
144
304
|
function parseWithStandardSchema(schema, data) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
throw new Error(
|
|
151
|
-
"Schema validation returned a Promise. Use validateWithStandardSchema for async validation."
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
if (!result.issues) {
|
|
155
|
-
return result.value;
|
|
156
|
-
}
|
|
157
|
-
throw new StandardSchemaValidationError(result.issues);
|
|
305
|
+
if (!isStandardSchema(schema)) return data;
|
|
306
|
+
const result = schema["~standard"].validate(data);
|
|
307
|
+
if (result instanceof Promise) throw new Error("Schema validation returned a Promise. Use validateWithStandardSchema for async validation.");
|
|
308
|
+
if (!result.issues) return result.value;
|
|
309
|
+
throw new StandardSchemaValidationError(result.issues);
|
|
158
310
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
isStandardJSONSchema,
|
|
164
|
-
isStandardSchema,
|
|
165
|
-
parseWithStandardSchema
|
|
166
|
-
};
|
|
167
|
-
//# sourceMappingURL=schema-converter.js.map
|
|
311
|
+
//#endregion
|
|
312
|
+
export { StandardSchemaValidationError, convertSchemaForStructuredOutput, convertSchemaToJsonSchema, isStandardJSONSchema, isStandardSchema, parseWithStandardSchema, validateWithStandardSchema };
|
|
313
|
+
|
|
314
|
+
//# sourceMappingURL=schema-converter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-converter.js","sources":["../../../../../src/activities/chat/tools/schema-converter.ts"],"sourcesContent":["import type {\n StandardJSONSchemaV1,\n StandardSchemaV1,\n} from '@standard-schema/spec'\nimport type { NullWideningMap } from '@tanstack/ai-utils'\nimport type { JSONSchema, SchemaInput } from '../../../types'\n\n/**\n * Build a JSONSchema object from any plain key/value source. The `JSONSchema`\n * interface's `[key: string]: any` index signature makes every property\n * assignable through bracket access without a type cast — copying keys here\n * lets us narrow either `Record<string, unknown>` (returned by\n * `~standard.jsonSchema.input()`) or a `JSONSchema` (from the SchemaInput\n * pass-through arm) into the typed view used by the rest of this module.\n *\n * Accepts `object` so callers don't need a cast when narrowing from union\n * types like `SchemaInput`.\n */\nfunction toJsonSchema(obj: object): JSONSchema {\n const result: JSONSchema = {}\n for (const [key, value] of Object.entries(obj)) {\n if (key === '$schema') continue // not needed by LLM providers\n result[key] = value\n }\n return result\n}\n\n/**\n * Whether a value can carry a `~standard` property. Most schema libraries\n * (Zod, Valibot) return plain objects, but ArkType's `type()` returns a\n * *callable function* with `~standard` attached — so `typeof` must accept\n * both `'object'` and `'function'` or ArkType schemas are missed entirely\n * (issue #276).\n */\nfunction isPropertyCarrier(schema: unknown): schema is Record<string, unknown> {\n return (\n (typeof schema === 'object' || typeof schema === 'function') &&\n schema !== null\n )\n}\n\n/**\n * Check if a value is a Standard JSON Schema compliant schema.\n * Standard JSON Schema compliant libraries (Zod v4+, ArkType, Valibot with toStandardJsonSchema, etc.)\n * implement the '~standard' property with jsonSchema converter methods.\n */\nexport function isStandardJSONSchema(\n schema: unknown,\n): schema is StandardJSONSchemaV1 {\n if (!isPropertyCarrier(schema) || !('~standard' in schema)) return false\n\n const standard = schema['~standard']\n if (\n typeof standard !== 'object' ||\n standard === null ||\n !('version' in standard) ||\n standard.version !== 1 ||\n !('jsonSchema' in standard) ||\n typeof standard.jsonSchema !== 'object' ||\n standard.jsonSchema === null ||\n !('input' in standard.jsonSchema)\n ) {\n return false\n }\n\n return typeof standard.jsonSchema.input === 'function'\n}\n\n/**\n * Check if a value is a Standard Schema compliant schema (for validation).\n * Standard Schema compliant libraries implement the '~standard' property with a validate function.\n */\nexport function isStandardSchema(schema: unknown): schema is StandardSchemaV1 {\n return (\n isPropertyCarrier(schema) &&\n '~standard' in schema &&\n typeof schema['~standard'] === 'object' &&\n schema['~standard'] !== null &&\n 'version' in schema['~standard'] &&\n schema['~standard'].version === 1 &&\n 'validate' in schema['~standard'] &&\n typeof schema['~standard'].validate === 'function'\n )\n}\n\n/**\n * Result of {@link makeStructuredOutputCompatible}: the strict-ready schema plus\n * a {@link NullWideningMap} recording every position where a `null` was\n * synthesized, so the response can be un-widened before validation without\n * re-deriving (or guessing) which nulls were synthetic.\n */\ninterface StructuredOutputConversion {\n schema: JSONSchema\n nullWidening: NullWideningMap | undefined\n}\n\n/** Drop an empty map to `undefined` so leaf/no-op subtrees don't litter it. */\nfunction pruneMap(map: NullWideningMap): NullWideningMap | undefined {\n return Object.keys(map).length > 0 ? map : undefined\n}\n\n/**\n * Transform a JSON schema to be compatible with OpenAI's structured output requirements.\n * OpenAI requires:\n * - All properties must be in the `required` array\n * - Optional fields should have null added to their type union\n * - additionalProperties must be false for objects\n *\n * Alongside the transformed schema it returns a {@link NullWideningMap} marking\n * exactly the positions where `null` was added, so `undoNullWidening` can strip\n * those synthesized nulls (and only those) from the provider's response.\n *\n * @param schema - JSON schema to transform\n * @param originalRequired - Original required array (to know which fields were optional)\n * @returns Transformed schema + the null-widening map for the round trip\n */\nfunction makeStructuredOutputCompatible(\n schema: JSONSchema,\n originalRequired: Array<string> = [],\n): StructuredOutputConversion {\n const result: JSONSchema = { ...schema }\n const map: NullWideningMap = {}\n\n // Handle object types\n if (result.type === 'object' && result.properties) {\n const properties: Record<string, JSONSchema> = { ...result.properties }\n const allPropertyNames = Object.keys(properties)\n const propertyMaps: Record<string, NullWideningMap> = {}\n\n // Transform each property\n for (const propName of allPropertyNames) {\n const prop = properties[propName]\n if (!prop) continue\n const wasOptional = !originalRequired.includes(propName)\n // `null` synthesized AT this property (the field itself can come back null).\n let widenedHere = false\n // Map describing widened positions INSIDE this property.\n let childMap: NullWideningMap | undefined\n\n // Recursively transform nested objects/arrays\n if (prop.type === 'object' && prop.properties) {\n const nested = makeStructuredOutputCompatible(prop, prop.required || [])\n properties[propName] = wasOptional\n ? { ...nested.schema, type: ['object', 'null'] }\n : nested.schema\n widenedHere = wasOptional\n childMap = nested.nullWidening\n } else if (prop.type === 'array' && prop.items) {\n const items = Array.isArray(prop.items) ? prop.items[0] : prop.items\n const nestedItems = items\n ? makeStructuredOutputCompatible(items, items.required || [])\n : undefined\n properties[propName] = {\n ...prop,\n items: nestedItems ? nestedItems.schema : prop.items,\n ...(wasOptional ? { type: ['array', 'null'] } : {}),\n }\n widenedHere = wasOptional\n childMap = nestedItems?.nullWidening\n ? { items: nestedItems.nullWidening }\n : undefined\n } else if (wasOptional) {\n // Make optional fields nullable by adding null to the type. Mark\n // `widenedHere` only where we actually add `null`; a field already\n // typed nullable (`.nullish()`) is left as-is and keeps its null.\n if (prop.type && !Array.isArray(prop.type)) {\n properties[propName] = { ...prop, type: [prop.type, 'null'] }\n widenedHere = true\n } else if (Array.isArray(prop.type) && !prop.type.includes('null')) {\n properties[propName] = { ...prop, type: [...prop.type, 'null'] }\n widenedHere = true\n }\n }\n\n if (widenedHere || childMap) {\n propertyMaps[propName] = {\n ...(childMap ?? {}),\n ...(widenedHere ? { widened: true } : {}),\n }\n }\n }\n\n result.properties = properties\n // ALL properties must be required for OpenAI structured output\n result.required = allPropertyNames\n // additionalProperties must be false\n result.additionalProperties = false\n if (Object.keys(propertyMaps).length > 0) map.properties = propertyMaps\n }\n\n // Handle array types with object items\n if (result.type === 'array' && result.items) {\n const items = Array.isArray(result.items) ? result.items[0] : result.items\n if (items) {\n const nestedItems = makeStructuredOutputCompatible(\n items,\n items.required || [],\n )\n result.items = nestedItems.schema\n if (nestedItems.nullWidening) map.items = nestedItems.nullWidening\n }\n }\n\n return { schema: result, nullWidening: pruneMap(map) }\n}\n\n/**\n * Options for schema conversion\n */\nexport interface ConvertSchemaOptions {\n /**\n * When true, transforms the schema to be compatible with OpenAI's structured output requirements:\n * - All properties are added to the `required` array\n * - Optional fields get null added to their type union\n * - additionalProperties is set to false for all objects\n *\n * @default false\n */\n forStructuredOutput?: boolean\n}\n\n/**\n * Normalize any supported schema input to a typed, UN-widened `JSONSchema` —\n * the shared first half of conversion, before any structured-output widening.\n *\n * - Standard JSON Schemas are rebuilt structurally (dropping `$schema`, which\n * LLM providers ignore) and given the explicit `type`/`properties`/`required`\n * defaults object shapes need downstream.\n * - Plain `JSONSchema` inputs are rebuilt into the typed view; non-object inputs\n * are surfaced untouched (they can't be widened).\n * - Standard Schema validators lacking a `~standard.jsonSchema` converter throw\n * with actionable guidance, rather than shipping `{ '~standard': … }` to the\n * provider and producing an opaque downstream error.\n */\nfunction toTypedJsonSchema(schema: SchemaInput): JSONSchema | undefined {\n if (isStandardJSONSchema(schema)) {\n const jsonSchema = schema['~standard'].jsonSchema.input({\n target: 'draft-07',\n })\n const result: JSONSchema = toJsonSchema(jsonSchema)\n if ('properties' in result && !result.type) result.type = 'object'\n if (result.type === 'object' && !('properties' in result)) {\n result.properties = {}\n }\n if (result.type === 'object' && !('required' in result)) {\n result.required = []\n }\n return result\n }\n\n if (isStandardSchema(schema)) {\n throw new Error(\n 'Schema is a Standard Schema validator but does not expose a JSON Schema ' +\n 'converter on `~standard.jsonSchema`. Use Zod v4.2+, ArkType v2.1.28+, ' +\n 'or wrap a Valibot schema with `toStandardJsonSchema()` from ' +\n '`@valibot/to-json-schema` before passing it as `outputSchema`.',\n )\n }\n\n if (typeof schema !== 'object') return schema\n return toJsonSchema(schema)\n}\n\n/**\n * Converts a Standard JSON Schema compliant schema or plain JSONSchema to JSON Schema format\n * compatible with LLM providers.\n *\n * Supports any schema library that implements the Standard JSON Schema spec (v1):\n * - Zod v4+ (natively supports StandardJSONSchemaV1)\n * - ArkType (natively supports StandardJSONSchemaV1)\n * - Valibot (via `toStandardJsonSchema()` from `@valibot/to-json-schema`)\n *\n * If the input is already a plain JSONSchema object, it is returned as-is.\n *\n * @param schema - Standard JSON Schema compliant schema or plain JSONSchema object to convert\n * @param options - Conversion options\n * @returns JSON Schema object that can be sent to LLM providers\n *\n * @example\n * ```typescript\n * // Using Zod v4+ (natively supports Standard JSON Schema)\n * import * as z from 'zod';\n *\n * const zodSchema = z.object({\n * location: z.string().describe('City name'),\n * unit: z.enum(['celsius', 'fahrenheit']).optional()\n * });\n *\n * const jsonSchema = convertSchemaToJsonSchema(zodSchema);\n *\n * @example\n * // Using ArkType (natively supports Standard JSON Schema)\n * import { type } from 'arktype';\n *\n * const arkSchema = type({\n * location: 'string',\n * unit: \"'celsius' | 'fahrenheit'\"\n * });\n *\n * const jsonSchema = convertSchemaToJsonSchema(arkSchema);\n *\n * @example\n * // Using Valibot (via toStandardJsonSchema)\n * import * as v from 'valibot';\n * import { toStandardJsonSchema } from '@valibot/to-json-schema';\n *\n * const valibotSchema = toStandardJsonSchema(v.object({\n * location: v.string(),\n * unit: v.optional(v.picklist(['celsius', 'fahrenheit']))\n * }));\n *\n * const jsonSchema = convertSchemaToJsonSchema(valibotSchema);\n *\n * @example\n * // Using JSONSchema directly (passes through unchanged)\n * const rawSchema = {\n * type: 'object',\n * properties: { location: { type: 'string' } },\n * required: ['location']\n * };\n * const result = convertSchemaToJsonSchema(rawSchema);\n * ```\n */\nexport function convertSchemaToJsonSchema(\n schema: SchemaInput | undefined,\n options: ConvertSchemaOptions = {},\n): JSONSchema | undefined {\n if (!schema) return undefined\n\n const { forStructuredOutput = false } = options\n\n // Plain-JSONSchema passthrough: with no widening requested, return the schema\n // by reference so callers comparing via `===` keep identity. Only the widening\n // path needs the rebuilt, normalized view from `toTypedJsonSchema`.\n if (\n !forStructuredOutput &&\n !isStandardJSONSchema(schema) &&\n !isStandardSchema(schema)\n ) {\n return schema\n }\n\n const base = toTypedJsonSchema(schema)\n // Non-object inputs can't be widened; surface them untouched.\n if (!base || typeof base !== 'object') return base\n if (!forStructuredOutput) return base\n return makeStructuredOutputCompatible(base, base.required || []).schema\n}\n\n/**\n * Convert a schema for structured output AND capture the {@link NullWideningMap}\n * recording every `null` the strict-mode widening synthesized. The map lets the\n * caller undo that widening on the provider's response (via `undoNullWidening`)\n * before validating against the original schema — optional fields read back as\n * absent while genuine `.nullable()` nulls survive. The map is `undefined` when\n * the schema isn't a widenable object or when no field needed widening.\n */\nexport function convertSchemaForStructuredOutput(\n schema: SchemaInput | undefined,\n): {\n jsonSchema: JSONSchema | undefined\n nullWideningMap: NullWideningMap | undefined\n} {\n if (!schema) return { jsonSchema: undefined, nullWideningMap: undefined }\n const base = toTypedJsonSchema(schema)\n if (!base || typeof base !== 'object') {\n return { jsonSchema: base, nullWideningMap: undefined }\n }\n const { schema: jsonSchema, nullWidening } = makeStructuredOutputCompatible(\n base,\n base.required || [],\n )\n return { jsonSchema, nullWideningMap: nullWidening }\n}\n\n/**\n * Validates data against a Standard Schema compliant schema.\n *\n * @param schema - Standard Schema compliant schema\n * @param data - Data to validate\n * @returns Validation result with success status, data or issues\n */\nexport async function validateWithStandardSchema<T>(\n schema: unknown,\n data: unknown,\n): Promise<\n | { success: true; data: T }\n | {\n success: false\n issues: Array<{ message: string; path?: Array<string> | undefined }>\n }\n> {\n if (!isStandardSchema(schema)) {\n // If it's not a Standard Schema, just return the data as-is\n return { success: true, data: data as T }\n }\n\n const result = await schema['~standard'].validate(data)\n\n if (!result.issues) {\n return { success: true, data: result.value as T }\n }\n\n return {\n success: false,\n issues: result.issues.map((issue) => ({\n message: issue.message || 'Validation failed',\n path: issue.path?.map(String),\n })),\n }\n}\n\n/**\n * Error thrown when Standard Schema validation fails. Carries the original\n * `issues` array so consumers (middleware `onError`, callers catching from\n * `chat({ outputSchema })`) can programmatically inspect each failure.\n */\nexport class StandardSchemaValidationError extends Error {\n override readonly name = 'StandardSchemaValidationError'\n readonly issues: ReadonlyArray<StandardSchemaV1.Issue>\n\n constructor(issues: ReadonlyArray<StandardSchemaV1.Issue>) {\n super(\n `Validation failed: ${issues\n .map((i) => i.message || 'Validation failed')\n .join(', ')}`,\n )\n this.issues = issues\n }\n}\n\n/**\n * Synchronously validates data against a Standard Schema compliant schema.\n * Note: Some Standard Schema implementations may only support async validation.\n * In those cases, this function will throw.\n *\n * @param schema - Standard Schema compliant schema\n * @param data - Data to validate\n * @returns Parsed/validated data\n * @throws StandardSchemaValidationError if validation fails; Error if the\n * schema only supports async validation.\n */\nexport function parseWithStandardSchema<T>(schema: unknown, data: unknown): T {\n if (!isStandardSchema(schema)) {\n // If it's not a Standard Schema, just return the data as-is\n return data as T\n }\n\n const result = schema['~standard'].validate(data)\n\n // Handle async result (Promise)\n if (result instanceof Promise) {\n throw new Error(\n 'Schema validation returned a Promise. Use validateWithStandardSchema for async validation.',\n )\n }\n // Standard Schema validation returns { value } for success or { issues } for failure\n if (!result.issues) {\n return result.value as T\n }\n\n throw new StandardSchemaValidationError(result.issues)\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema-converter.js","names":[],"sources":["../../../../../src/activities/chat/tools/schema-converter.ts"],"sourcesContent":["import type {\n StandardJSONSchemaV1,\n StandardSchemaV1,\n} from '@standard-schema/spec'\nimport type { NullWideningMap } from '@tanstack/ai-utils'\nimport type { JSONSchema, SchemaInput } from '../../../types'\n\n/**\n * Build a JSONSchema object from any plain key/value source. The `JSONSchema`\n * interface's `[key: string]: any` index signature makes every property\n * assignable through bracket access without a type cast — copying keys here\n * lets us narrow either `Record<string, unknown>` (returned by\n * `~standard.jsonSchema.input()`) or a `JSONSchema` (from the SchemaInput\n * pass-through arm) into the typed view used by the rest of this module.\n *\n * Accepts `object` so callers don't need a cast when narrowing from union\n * types like `SchemaInput`.\n */\nfunction toJsonSchema(obj: object): JSONSchema {\n const result: JSONSchema = {}\n for (const [key, value] of Object.entries(obj)) {\n if (key === '$schema') continue // not needed by LLM providers\n result[key] = value\n }\n return result\n}\n\n/**\n * Whether a value can carry a `~standard` property. Most schema libraries\n * (Zod, Valibot) return plain objects, but ArkType's `type()` returns a\n * *callable function* with `~standard` attached — so `typeof` must accept\n * both `'object'` and `'function'` or ArkType schemas are missed entirely\n * (issue #276).\n */\nfunction isPropertyCarrier(schema: unknown): schema is Record<string, unknown> {\n return (\n (typeof schema === 'object' || typeof schema === 'function') &&\n schema !== null\n )\n}\n\n/**\n * Check if a value is a Standard JSON Schema compliant schema.\n * Standard JSON Schema compliant libraries (Zod v4+, ArkType, Valibot with toStandardJsonSchema, etc.)\n * implement the '~standard' property with jsonSchema converter methods.\n */\nexport function isStandardJSONSchema(\n schema: unknown,\n): schema is StandardJSONSchemaV1 {\n if (!isPropertyCarrier(schema) || !('~standard' in schema)) return false\n\n const standard = schema['~standard']\n if (\n typeof standard !== 'object' ||\n standard === null ||\n !('version' in standard) ||\n standard.version !== 1 ||\n !('jsonSchema' in standard) ||\n typeof standard.jsonSchema !== 'object' ||\n standard.jsonSchema === null ||\n !('input' in standard.jsonSchema)\n ) {\n return false\n }\n\n return typeof standard.jsonSchema.input === 'function'\n}\n\n/**\n * Check if a value is a Standard Schema compliant schema (for validation).\n * Standard Schema compliant libraries implement the '~standard' property with a validate function.\n */\nexport function isStandardSchema(schema: unknown): schema is StandardSchemaV1 {\n return (\n isPropertyCarrier(schema) &&\n '~standard' in schema &&\n typeof schema['~standard'] === 'object' &&\n schema['~standard'] !== null &&\n 'version' in schema['~standard'] &&\n schema['~standard'].version === 1 &&\n 'validate' in schema['~standard'] &&\n typeof schema['~standard'].validate === 'function'\n )\n}\n\n/**\n * Result of {@link makeStructuredOutputCompatible}: the strict-ready schema plus\n * a {@link NullWideningMap} recording every position where a `null` was\n * synthesized, so the response can be un-widened before validation without\n * re-deriving (or guessing) which nulls were synthetic.\n */\ninterface StructuredOutputConversion {\n schema: JSONSchema\n nullWidening: NullWideningMap | undefined\n}\n\n/** Drop an empty map to `undefined` so leaf/no-op subtrees don't litter it. */\nfunction pruneMap(map: NullWideningMap): NullWideningMap | undefined {\n return Object.keys(map).length > 0 ? map : undefined\n}\n\n/**\n * Transform a JSON schema to be compatible with OpenAI's structured output requirements.\n * OpenAI requires:\n * - All properties must be in the `required` array\n * - Optional fields should have null added to their type union\n * - additionalProperties must be false for objects\n *\n * Alongside the transformed schema it returns a {@link NullWideningMap} marking\n * exactly the positions where `null` was added, so `undoNullWidening` can strip\n * those synthesized nulls (and only those) from the provider's response.\n *\n * @param schema - JSON schema to transform\n * @param originalRequired - Original required array (to know which fields were optional)\n * @returns Transformed schema + the null-widening map for the round trip\n */\nfunction makeStructuredOutputCompatible(\n schema: JSONSchema,\n originalRequired: Array<string> = [],\n): StructuredOutputConversion {\n const result: JSONSchema = { ...schema }\n const map: NullWideningMap = {}\n\n // Handle object types\n if (result.type === 'object' && result.properties) {\n const properties: Record<string, JSONSchema> = { ...result.properties }\n const allPropertyNames = Object.keys(properties)\n const propertyMaps: Record<string, NullWideningMap> = {}\n\n // Transform each property\n for (const propName of allPropertyNames) {\n const prop = properties[propName]\n if (!prop) continue\n const wasOptional = !originalRequired.includes(propName)\n // `null` synthesized AT this property (the field itself can come back null).\n let widenedHere = false\n // Map describing widened positions INSIDE this property.\n let childMap: NullWideningMap | undefined\n\n // Recursively transform nested objects/arrays\n if (prop.type === 'object' && prop.properties) {\n const nested = makeStructuredOutputCompatible(prop, prop.required || [])\n properties[propName] = wasOptional\n ? { ...nested.schema, type: ['object', 'null'] }\n : nested.schema\n widenedHere = wasOptional\n childMap = nested.nullWidening\n } else if (prop.type === 'array' && prop.items) {\n const items = Array.isArray(prop.items) ? prop.items[0] : prop.items\n const nestedItems = items\n ? makeStructuredOutputCompatible(items, items.required || [])\n : undefined\n properties[propName] = {\n ...prop,\n items: nestedItems ? nestedItems.schema : prop.items,\n ...(wasOptional ? { type: ['array', 'null'] } : {}),\n }\n widenedHere = wasOptional\n childMap = nestedItems?.nullWidening\n ? { items: nestedItems.nullWidening }\n : undefined\n } else if (wasOptional) {\n // Make optional fields nullable by adding null to the type. Mark\n // `widenedHere` only where we actually add `null`; a field already\n // typed nullable (`.nullish()`) is left as-is and keeps its null.\n if (prop.type && !Array.isArray(prop.type)) {\n properties[propName] = { ...prop, type: [prop.type, 'null'] }\n widenedHere = true\n } else if (Array.isArray(prop.type) && !prop.type.includes('null')) {\n properties[propName] = { ...prop, type: [...prop.type, 'null'] }\n widenedHere = true\n }\n }\n\n if (widenedHere || childMap) {\n propertyMaps[propName] = {\n ...(childMap ?? {}),\n ...(widenedHere ? { widened: true } : {}),\n }\n }\n }\n\n result.properties = properties\n // ALL properties must be required for OpenAI structured output\n result.required = allPropertyNames\n // additionalProperties must be false\n result.additionalProperties = false\n if (Object.keys(propertyMaps).length > 0) map.properties = propertyMaps\n }\n\n // Handle array types with object items\n if (result.type === 'array' && result.items) {\n const items = Array.isArray(result.items) ? result.items[0] : result.items\n if (items) {\n const nestedItems = makeStructuredOutputCompatible(\n items,\n items.required || [],\n )\n result.items = nestedItems.schema\n if (nestedItems.nullWidening) map.items = nestedItems.nullWidening\n }\n }\n\n return { schema: result, nullWidening: pruneMap(map) }\n}\n\n/**\n * Options for schema conversion\n */\nexport interface ConvertSchemaOptions {\n /**\n * When true, transforms the schema to be compatible with OpenAI's structured output requirements:\n * - All properties are added to the `required` array\n * - Optional fields get null added to their type union\n * - additionalProperties is set to false for all objects\n *\n * @default false\n */\n forStructuredOutput?: boolean\n}\n\n/**\n * Normalize any supported schema input to a typed, UN-widened `JSONSchema` —\n * the shared first half of conversion, before any structured-output widening.\n *\n * - Standard JSON Schemas are rebuilt structurally (dropping `$schema`, which\n * LLM providers ignore) and given the explicit `type`/`properties`/`required`\n * defaults object shapes need downstream.\n * - Plain `JSONSchema` inputs are rebuilt into the typed view; non-object inputs\n * are surfaced untouched (they can't be widened).\n * - Standard Schema validators lacking a `~standard.jsonSchema` converter throw\n * with actionable guidance, rather than shipping `{ '~standard': … }` to the\n * provider and producing an opaque downstream error.\n */\nfunction toTypedJsonSchema(schema: SchemaInput): JSONSchema | undefined {\n if (isStandardJSONSchema(schema)) {\n const jsonSchema = schema['~standard'].jsonSchema.input({\n target: 'draft-07',\n })\n const result: JSONSchema = toJsonSchema(jsonSchema)\n if ('properties' in result && !result.type) result.type = 'object'\n if (result.type === 'object' && !('properties' in result)) {\n result.properties = {}\n }\n if (result.type === 'object' && !('required' in result)) {\n result.required = []\n }\n return result\n }\n\n if (isStandardSchema(schema)) {\n throw new Error(\n 'Schema is a Standard Schema validator but does not expose a JSON Schema ' +\n 'converter on `~standard.jsonSchema`. Use Zod v4.2+, ArkType v2.1.28+, ' +\n 'or wrap a Valibot schema with `toStandardJsonSchema()` from ' +\n '`@valibot/to-json-schema` before passing it as `outputSchema`.',\n )\n }\n\n if (typeof schema !== 'object') return schema\n return toJsonSchema(schema)\n}\n\n/**\n * Converts a Standard JSON Schema compliant schema or plain JSONSchema to JSON Schema format\n * compatible with LLM providers.\n *\n * Supports any schema library that implements the Standard JSON Schema spec (v1):\n * - Zod v4+ (natively supports StandardJSONSchemaV1)\n * - ArkType (natively supports StandardJSONSchemaV1)\n * - Valibot (via `toStandardJsonSchema()` from `@valibot/to-json-schema`)\n *\n * If the input is already a plain JSONSchema object, it is returned as-is.\n *\n * @param schema - Standard JSON Schema compliant schema or plain JSONSchema object to convert\n * @param options - Conversion options\n * @returns JSON Schema object that can be sent to LLM providers\n *\n * @example\n * ```typescript\n * // Using Zod v4+ (natively supports Standard JSON Schema)\n * import * as z from 'zod';\n *\n * const zodSchema = z.object({\n * location: z.string().describe('City name'),\n * unit: z.enum(['celsius', 'fahrenheit']).optional()\n * });\n *\n * const jsonSchema = convertSchemaToJsonSchema(zodSchema);\n *\n * @example\n * // Using ArkType (natively supports Standard JSON Schema)\n * import { type } from 'arktype';\n *\n * const arkSchema = type({\n * location: 'string',\n * unit: \"'celsius' | 'fahrenheit'\"\n * });\n *\n * const jsonSchema = convertSchemaToJsonSchema(arkSchema);\n *\n * @example\n * // Using Valibot (via toStandardJsonSchema)\n * import * as v from 'valibot';\n * import { toStandardJsonSchema } from '@valibot/to-json-schema';\n *\n * const valibotSchema = toStandardJsonSchema(v.object({\n * location: v.string(),\n * unit: v.optional(v.picklist(['celsius', 'fahrenheit']))\n * }));\n *\n * const jsonSchema = convertSchemaToJsonSchema(valibotSchema);\n *\n * @example\n * // Using JSONSchema directly (passes through unchanged)\n * const rawSchema = {\n * type: 'object',\n * properties: { location: { type: 'string' } },\n * required: ['location']\n * };\n * const result = convertSchemaToJsonSchema(rawSchema);\n * ```\n */\nexport function convertSchemaToJsonSchema(\n schema: SchemaInput | undefined,\n options: ConvertSchemaOptions = {},\n): JSONSchema | undefined {\n if (!schema) return undefined\n\n const { forStructuredOutput = false } = options\n\n // Plain-JSONSchema passthrough: with no widening requested, return the schema\n // by reference so callers comparing via `===` keep identity. Only the widening\n // path needs the rebuilt, normalized view from `toTypedJsonSchema`.\n if (\n !forStructuredOutput &&\n !isStandardJSONSchema(schema) &&\n !isStandardSchema(schema)\n ) {\n return schema\n }\n\n const base = toTypedJsonSchema(schema)\n // Non-object inputs can't be widened; surface them untouched.\n if (!base || typeof base !== 'object') return base\n if (!forStructuredOutput) return base\n return makeStructuredOutputCompatible(base, base.required || []).schema\n}\n\n/**\n * Convert a schema for structured output AND capture the {@link NullWideningMap}\n * recording every `null` the strict-mode widening synthesized. The map lets the\n * caller undo that widening on the provider's response (via `undoNullWidening`)\n * before validating against the original schema — optional fields read back as\n * absent while genuine `.nullable()` nulls survive. The map is `undefined` when\n * the schema isn't a widenable object or when no field needed widening.\n */\nexport function convertSchemaForStructuredOutput(\n schema: SchemaInput | undefined,\n): {\n jsonSchema: JSONSchema | undefined\n nullWideningMap: NullWideningMap | undefined\n} {\n if (!schema) return { jsonSchema: undefined, nullWideningMap: undefined }\n const base = toTypedJsonSchema(schema)\n if (!base || typeof base !== 'object') {\n return { jsonSchema: base, nullWideningMap: undefined }\n }\n const { schema: jsonSchema, nullWidening } = makeStructuredOutputCompatible(\n base,\n base.required || [],\n )\n return { jsonSchema, nullWideningMap: nullWidening }\n}\n\n/**\n * Validates data against a Standard Schema compliant schema.\n *\n * @param schema - Standard Schema compliant schema\n * @param data - Data to validate\n * @returns Validation result with success status, data or issues\n */\nexport async function validateWithStandardSchema<T>(\n schema: unknown,\n data: unknown,\n): Promise<\n | { success: true; data: T }\n | {\n success: false\n issues: Array<{ message: string; path?: Array<string> | undefined }>\n }\n> {\n if (!isStandardSchema(schema)) {\n // If it's not a Standard Schema, just return the data as-is\n return { success: true, data: data as T }\n }\n\n const result = await schema['~standard'].validate(data)\n\n if (!result.issues) {\n return { success: true, data: result.value as T }\n }\n\n return {\n success: false,\n issues: result.issues.map((issue) => ({\n message: issue.message || 'Validation failed',\n path: issue.path?.map(String),\n })),\n }\n}\n\n/**\n * Error thrown when Standard Schema validation fails. Carries the original\n * `issues` array so consumers (middleware `onError`, callers catching from\n * `chat({ outputSchema })`) can programmatically inspect each failure.\n */\nexport class StandardSchemaValidationError extends Error {\n override readonly name = 'StandardSchemaValidationError'\n readonly issues: ReadonlyArray<StandardSchemaV1.Issue>\n\n constructor(issues: ReadonlyArray<StandardSchemaV1.Issue>) {\n super(\n `Validation failed: ${issues\n .map((i) => i.message || 'Validation failed')\n .join(', ')}`,\n )\n this.issues = issues\n }\n}\n\n/**\n * Synchronously validates data against a Standard Schema compliant schema.\n * Note: Some Standard Schema implementations may only support async validation.\n * In those cases, this function will throw.\n *\n * @param schema - Standard Schema compliant schema\n * @param data - Data to validate\n * @returns Parsed/validated data\n * @throws StandardSchemaValidationError if validation fails; Error if the\n * schema only supports async validation.\n */\nexport function parseWithStandardSchema<T>(schema: unknown, data: unknown): T {\n if (!isStandardSchema(schema)) {\n // If it's not a Standard Schema, just return the data as-is\n return data as T\n }\n\n const result = schema['~standard'].validate(data)\n\n // Handle async result (Promise)\n if (result instanceof Promise) {\n throw new Error(\n 'Schema validation returned a Promise. Use validateWithStandardSchema for async validation.',\n )\n }\n // Standard Schema validation returns { value } for success or { issues } for failure\n if (!result.issues) {\n return result.value as T\n }\n\n throw new StandardSchemaValidationError(result.issues)\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ToolApprovalResolution } from '../../../interrupts.js';
|
|
1
2
|
import { AnyTool, CustomEvent, ModelMessage, RunFinishedEvent, Tool, ToolCall, ToolCallArgsEvent, ToolCallEndEvent, ToolCallStartEvent, ToolExecutionContext } from '../../../types.js';
|
|
2
3
|
import { AfterToolCallInfo, BeforeToolCallDecision } from '../middleware/types.js';
|
|
3
4
|
import { ContextFromTool, DefinedContext, MergeContext, UnionToIntersection } from '../runtime-context-types.js';
|
|
@@ -101,6 +102,17 @@ export interface ToolResult {
|
|
|
101
102
|
state?: 'output-available' | 'output-error';
|
|
102
103
|
/** Duration of tool execution in milliseconds (only for server-executed tools) */
|
|
103
104
|
duration?: number;
|
|
105
|
+
/**
|
|
106
|
+
* Parsed tool input (after JSON parse + optional Standard Schema validation).
|
|
107
|
+
* Surfaced on engine-emitted `TOOL_CALL_END` events for TypedStreamChunk consumers.
|
|
108
|
+
*/
|
|
109
|
+
input?: unknown;
|
|
110
|
+
/**
|
|
111
|
+
* Parsed tool output before wire serialization. Surfaced on engine-emitted
|
|
112
|
+
* `TOOL_CALL_END` events so consumers can read typed `output` without
|
|
113
|
+
* re-parsing `result`. Undefined on error paths and when execution is skipped.
|
|
114
|
+
*/
|
|
115
|
+
output?: unknown;
|
|
104
116
|
}
|
|
105
117
|
export interface ApprovalRequest {
|
|
106
118
|
toolCallId: string;
|
|
@@ -113,6 +125,10 @@ export interface ClientToolRequest {
|
|
|
113
125
|
toolName: string;
|
|
114
126
|
input: any;
|
|
115
127
|
}
|
|
128
|
+
export interface ToolResumeExecutionState {
|
|
129
|
+
deniedToolResults?: ReadonlyMap<string, unknown>;
|
|
130
|
+
cancelledToolCallIds?: ReadonlySet<string>;
|
|
131
|
+
}
|
|
116
132
|
interface ExecuteToolCallsResult {
|
|
117
133
|
/** Tool results ready to send to LLM */
|
|
118
134
|
results: Array<ToolResult>;
|
|
@@ -137,9 +153,9 @@ export declare function executeServerTool<TContext = unknown>(toolCall: ToolCall
|
|
|
137
153
|
*
|
|
138
154
|
* @param toolCalls - Tool calls from the LLM
|
|
139
155
|
* @param tools - Available tools with their configurations
|
|
140
|
-
* @param approvals - Map
|
|
156
|
+
* @param approvals - Map keyed by toolCallId (or `approval_${toolCallId}`) → ToolApprovalResolution
|
|
141
157
|
* @param clientResults - Map of client-side execution results (toolCallId -> result)
|
|
142
158
|
* @param createCustomEventChunk - Factory to create CustomEvent chunks (optional)
|
|
143
159
|
*/
|
|
144
|
-
export declare function executeToolCalls<TContext = unknown>(toolCalls: Array<ToolCall>, tools: ReadonlyArray<AnyTool>, approvals?: Map<string,
|
|
160
|
+
export declare function executeToolCalls<TContext = unknown>(toolCalls: Array<ToolCall>, tools: ReadonlyArray<AnyTool>, approvals?: Map<string, ToolApprovalResolution>, clientResults?: Map<string, any>, createCustomEventChunk?: (eventName: string, value: Record<string, any>) => CustomEvent, middlewareHooks?: ToolExecutionMiddlewareHooks, userContext?: TContext, abortSignal?: AbortSignal, resumeState?: ToolResumeExecutionState): AsyncGenerator<CustomEvent, ExecuteToolCallsResult, void>;
|
|
145
161
|
export {};
|