@tanstack/ai 0.42.0 → 0.43.1
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.d.ts +3 -1
- package/dist/esm/middlewares/otel.js +599 -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 +23 -5
- 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
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// Dependency-free SHA-256 (FIPS 180-4). Sync and isomorphic (Node + browser)
|
|
2
|
+
// so interrupt hashing needs no crypto library. Users can replace the whole
|
|
3
|
+
// algorithm through the `interrupts.hash` option; this is only the default.
|
|
4
|
+
// ponytail: bundled ~60-line hash, swap via interrupts.hash if you need more.
|
|
5
|
+
const SHA256_K = new Uint32Array([
|
|
6
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
|
7
|
+
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
|
8
|
+
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
|
9
|
+
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
10
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
|
11
|
+
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
|
12
|
+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
|
13
|
+
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
14
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
|
15
|
+
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
|
16
|
+
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
function rotr(x: number, n: number): number {
|
|
20
|
+
return (x >>> n) | (x << (32 - n))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function sha256Hex(input: string): string {
|
|
24
|
+
const msg = new TextEncoder().encode(input)
|
|
25
|
+
|
|
26
|
+
const bitLen = msg.length * 8
|
|
27
|
+
const withOne = msg.length + 1
|
|
28
|
+
const total = withOne + ((56 - (withOne % 64) + 64) % 64) + 8
|
|
29
|
+
const bytes = new Uint8Array(total)
|
|
30
|
+
bytes.set(msg)
|
|
31
|
+
bytes[msg.length] = 0x80
|
|
32
|
+
const view = new DataView(bytes.buffer)
|
|
33
|
+
view.setUint32(total - 8, Math.floor(bitLen / 0x100000000))
|
|
34
|
+
view.setUint32(total - 4, bitLen >>> 0)
|
|
35
|
+
|
|
36
|
+
let h0 = 0x6a09e667
|
|
37
|
+
let h1 = 0xbb67ae85
|
|
38
|
+
let h2 = 0x3c6ef372
|
|
39
|
+
let h3 = 0xa54ff53a
|
|
40
|
+
let h4 = 0x510e527f
|
|
41
|
+
let h5 = 0x9b05688c
|
|
42
|
+
let h6 = 0x1f83d9ab
|
|
43
|
+
let h7 = 0x5be0cd19
|
|
44
|
+
|
|
45
|
+
const w = new Uint32Array(64)
|
|
46
|
+
for (let offset = 0; offset < total; offset += 64) {
|
|
47
|
+
for (let i = 0; i < 16; i++) w[i] = view.getUint32(offset + i * 4)
|
|
48
|
+
for (let i = 16; i < 64; i++) {
|
|
49
|
+
const x15 = w[i - 15] ?? 0
|
|
50
|
+
const x2 = w[i - 2] ?? 0
|
|
51
|
+
const s0 = rotr(x15, 7) ^ rotr(x15, 18) ^ (x15 >>> 3)
|
|
52
|
+
const s1 = rotr(x2, 17) ^ rotr(x2, 19) ^ (x2 >>> 10)
|
|
53
|
+
w[i] = ((w[i - 16] ?? 0) + s0 + (w[i - 7] ?? 0) + s1) >>> 0
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let a = h0
|
|
57
|
+
let b = h1
|
|
58
|
+
let c = h2
|
|
59
|
+
let d = h3
|
|
60
|
+
let e = h4
|
|
61
|
+
let f = h5
|
|
62
|
+
let g = h6
|
|
63
|
+
let hh = h7
|
|
64
|
+
for (let i = 0; i < 64; i++) {
|
|
65
|
+
const bigS1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)
|
|
66
|
+
const ch = (e & f) ^ (~e & g)
|
|
67
|
+
const t1 = (hh + bigS1 + ch + (SHA256_K[i] ?? 0) + (w[i] ?? 0)) >>> 0
|
|
68
|
+
const bigS0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)
|
|
69
|
+
const maj = (a & b) ^ (a & c) ^ (b & c)
|
|
70
|
+
const t2 = (bigS0 + maj) >>> 0
|
|
71
|
+
hh = g
|
|
72
|
+
g = f
|
|
73
|
+
f = e
|
|
74
|
+
e = (d + t1) >>> 0
|
|
75
|
+
d = c
|
|
76
|
+
c = b
|
|
77
|
+
b = a
|
|
78
|
+
a = (t1 + t2) >>> 0
|
|
79
|
+
}
|
|
80
|
+
h0 = (h0 + a) >>> 0
|
|
81
|
+
h1 = (h1 + b) >>> 0
|
|
82
|
+
h2 = (h2 + c) >>> 0
|
|
83
|
+
h3 = (h3 + d) >>> 0
|
|
84
|
+
h4 = (h4 + e) >>> 0
|
|
85
|
+
h5 = (h5 + f) >>> 0
|
|
86
|
+
h6 = (h6 + g) >>> 0
|
|
87
|
+
h7 = (h7 + hh) >>> 0
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const hex = (n: number): string => (n >>> 0).toString(16).padStart(8, '0')
|
|
91
|
+
return (
|
|
92
|
+
hex(h0) +
|
|
93
|
+
hex(h1) +
|
|
94
|
+
hex(h2) +
|
|
95
|
+
hex(h3) +
|
|
96
|
+
hex(h4) +
|
|
97
|
+
hex(h5) +
|
|
98
|
+
hex(h6) +
|
|
99
|
+
hex(h7)
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* A hash function for interrupt bindings and resolution fingerprints. Receives
|
|
105
|
+
* canonical JSON text and returns an opaque string. Must be deterministic; the
|
|
106
|
+
* server compares hashes it computed against the ones in a binding, so the same
|
|
107
|
+
* function has to run wherever a given binding is produced and checked.
|
|
108
|
+
*/
|
|
109
|
+
export type InterruptHash = (canonicalJson: string) => string
|
|
110
|
+
|
|
111
|
+
/** The built-in default: SHA-256, prefixed so the algorithm is self-describing. */
|
|
112
|
+
export function defaultInterruptHash(canonicalJson: string): string {
|
|
113
|
+
return `sha256:${sha256Hex(canonicalJson)}`
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function canonical(value: unknown, active: WeakSet<object>): string {
|
|
117
|
+
if (value === null) return 'null'
|
|
118
|
+
if (typeof value === 'string' || typeof value === 'boolean') {
|
|
119
|
+
return JSON.stringify(value)
|
|
120
|
+
}
|
|
121
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
122
|
+
return JSON.stringify(value)
|
|
123
|
+
}
|
|
124
|
+
if (typeof value !== 'object') {
|
|
125
|
+
throw new TypeError('Interrupt values must be JSON-compatible.')
|
|
126
|
+
}
|
|
127
|
+
if (active.has(value)) {
|
|
128
|
+
throw new TypeError('Interrupt values must not cycle.')
|
|
129
|
+
}
|
|
130
|
+
if (
|
|
131
|
+
!Array.isArray(value) &&
|
|
132
|
+
Object.getPrototypeOf(value) !== Object.prototype &&
|
|
133
|
+
Object.getPrototypeOf(value) !== null
|
|
134
|
+
) {
|
|
135
|
+
throw new TypeError('Interrupt values must use plain JSON objects.')
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
active.add(value)
|
|
139
|
+
let encoded: string
|
|
140
|
+
if (Array.isArray(value)) {
|
|
141
|
+
const items: Array<string> = []
|
|
142
|
+
for (let index = 0; index < value.length; index++) {
|
|
143
|
+
items.push(canonical(value[index], active))
|
|
144
|
+
}
|
|
145
|
+
encoded = `[${items.join(',')}]`
|
|
146
|
+
} else {
|
|
147
|
+
const record = value as Record<string, unknown>
|
|
148
|
+
encoded = `{${Object.keys(record)
|
|
149
|
+
.sort()
|
|
150
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(record[key], active)}`)
|
|
151
|
+
.join(',')}}`
|
|
152
|
+
}
|
|
153
|
+
active.delete(value)
|
|
154
|
+
return encoded
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function canonicalInterruptJson(value: unknown): string {
|
|
158
|
+
return canonical(value, new WeakSet<object>())
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function digestInterruptJson(
|
|
162
|
+
canonicalJson: string,
|
|
163
|
+
hash: InterruptHash = defaultInterruptHash,
|
|
164
|
+
): string {
|
|
165
|
+
if (typeof canonicalJson !== 'string') {
|
|
166
|
+
throw new TypeError('Interrupt digests require canonical JSON text.')
|
|
167
|
+
}
|
|
168
|
+
return hash(canonicalJson)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function freezeTree(value: unknown): void {
|
|
172
|
+
if (value === null || typeof value !== 'object' || Object.isFrozen(value)) {
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
Object.values(value).forEach(freezeTree)
|
|
176
|
+
Object.freeze(value)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function cloneAndDeepFreezeJson<T>(value: T): T {
|
|
180
|
+
const clone: T = JSON.parse(canonicalInterruptJson(value))
|
|
181
|
+
freezeTree(clone)
|
|
182
|
+
return clone
|
|
183
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canonicalInterruptJson,
|
|
3
|
+
cloneAndDeepFreezeJson,
|
|
4
|
+
digestInterruptJson,
|
|
5
|
+
} from './interrupt-serialization'
|
|
6
|
+
import type { RunAgentResumeItem } from './types'
|
|
7
|
+
|
|
8
|
+
export interface InterruptCorrelation {
|
|
9
|
+
threadId: string
|
|
10
|
+
interruptedRunId: string
|
|
11
|
+
generation: number
|
|
12
|
+
submissionId?: string
|
|
13
|
+
continuationRunId?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type ItemInterruptErrorCode =
|
|
17
|
+
| 'invalid-payload'
|
|
18
|
+
| 'invalid-edited-args'
|
|
19
|
+
| 'invalid-tool-output'
|
|
20
|
+
| 'invalid-response-schema'
|
|
21
|
+
| 'unknown-interrupt'
|
|
22
|
+
| 'expired'
|
|
23
|
+
| 'stale'
|
|
24
|
+
| 'conflict'
|
|
25
|
+
| 'legacy-unsupported'
|
|
26
|
+
|
|
27
|
+
export type BatchInterruptErrorCode =
|
|
28
|
+
| 'incomplete-batch'
|
|
29
|
+
| 'item-validation-failed'
|
|
30
|
+
| 'unsupported-bulk-operation'
|
|
31
|
+
| 'async-resolver'
|
|
32
|
+
| 'inactive-transaction'
|
|
33
|
+
| 'mixed-provenance'
|
|
34
|
+
| 'transport'
|
|
35
|
+
| 'server'
|
|
36
|
+
| 'protocol'
|
|
37
|
+
| 'invalid-response-schema'
|
|
38
|
+
| 'expired'
|
|
39
|
+
| 'stale'
|
|
40
|
+
| 'conflict'
|
|
41
|
+
| 'legacy-submit-failed'
|
|
42
|
+
|
|
43
|
+
export interface ItemInterruptError extends InterruptCorrelation {
|
|
44
|
+
scope: 'item'
|
|
45
|
+
interruptId: string
|
|
46
|
+
code: ItemInterruptErrorCode
|
|
47
|
+
message: string
|
|
48
|
+
path?: ReadonlyArray<string | number>
|
|
49
|
+
source: 'client' | 'server'
|
|
50
|
+
retryable: boolean
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface BatchInterruptError extends InterruptCorrelation {
|
|
54
|
+
scope: 'batch'
|
|
55
|
+
code: BatchInterruptErrorCode
|
|
56
|
+
message: string
|
|
57
|
+
source: 'client' | 'server' | 'transport'
|
|
58
|
+
retryable: boolean
|
|
59
|
+
interruptIds: ReadonlyArray<string>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type InterruptSubmissionError = ItemInterruptError | BatchInterruptError
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Wire version of {@link InterruptBinding}.
|
|
66
|
+
*
|
|
67
|
+
* The binding is the only part of an AG-UI `Interrupt` that this package
|
|
68
|
+
* claims — it rides in `metadata` under
|
|
69
|
+
* {@link INTERRUPT_BINDING_METADATA_KEY} and tells the resume path how to
|
|
70
|
+
* correlate an answer back to a paused run. Producers stamp `v`; readers
|
|
71
|
+
* reject any version they don't understand rather than duck-typing the fields.
|
|
72
|
+
*
|
|
73
|
+
* That matters because an AG-UI `Interrupt` is a shared envelope. Another
|
|
74
|
+
* producer — a workflow engine projecting a durable approval, a third-party
|
|
75
|
+
* agent — can legitimately put its own binding in the same envelope. Versioning
|
|
76
|
+
* makes "not mine" a clean rejection instead of a partial match that resumes
|
|
77
|
+
* against the wrong owner.
|
|
78
|
+
*/
|
|
79
|
+
export const INTERRUPT_BINDING_VERSION = 1 as const
|
|
80
|
+
|
|
81
|
+
interface InterruptBindingBase {
|
|
82
|
+
/** @see INTERRUPT_BINDING_VERSION */
|
|
83
|
+
v: typeof INTERRUPT_BINDING_VERSION
|
|
84
|
+
interruptId: string
|
|
85
|
+
interruptedRunId: string
|
|
86
|
+
generation: number
|
|
87
|
+
responseSchemaHash: string
|
|
88
|
+
expiresAt?: string
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type InterruptBinding =
|
|
92
|
+
| (InterruptBindingBase & {
|
|
93
|
+
kind: 'tool-approval'
|
|
94
|
+
toolName: string
|
|
95
|
+
toolCallId: string
|
|
96
|
+
originalArgs: unknown
|
|
97
|
+
inputSchemaHash: string
|
|
98
|
+
approvalSchemaHash: string
|
|
99
|
+
})
|
|
100
|
+
| (InterruptBindingBase & {
|
|
101
|
+
kind: 'client-tool-execution'
|
|
102
|
+
toolName: string
|
|
103
|
+
toolCallId: string
|
|
104
|
+
outputSchemaHash: string
|
|
105
|
+
})
|
|
106
|
+
| (InterruptBindingBase & {
|
|
107
|
+
kind: 'generic'
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
export type UnopenedInterruptBinding = InterruptBinding extends infer TBinding
|
|
111
|
+
? TBinding extends InterruptBinding
|
|
112
|
+
? Omit<TBinding, 'interruptedRunId' | 'generation'>
|
|
113
|
+
: never
|
|
114
|
+
: never
|
|
115
|
+
|
|
116
|
+
export type ToolApprovalResolution =
|
|
117
|
+
| boolean
|
|
118
|
+
| {
|
|
119
|
+
approved: true
|
|
120
|
+
editedArgs?: unknown
|
|
121
|
+
payload?: unknown
|
|
122
|
+
}
|
|
123
|
+
| {
|
|
124
|
+
approved: false
|
|
125
|
+
payload?: unknown
|
|
126
|
+
editedArgs?: never
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function canonicalizeInterruptResolutions(
|
|
130
|
+
resolutions: ReadonlyArray<RunAgentResumeItem>,
|
|
131
|
+
): {
|
|
132
|
+
resolutions: ReadonlyArray<RunAgentResumeItem>
|
|
133
|
+
canonicalResolutions: string
|
|
134
|
+
fingerprint: string
|
|
135
|
+
} {
|
|
136
|
+
const sorted = [...resolutions].sort((left, right) =>
|
|
137
|
+
left.interruptId.localeCompare(right.interruptId),
|
|
138
|
+
)
|
|
139
|
+
const frozen = cloneAndDeepFreezeJson(sorted)
|
|
140
|
+
const canonicalResolutions = canonicalInterruptJson(frozen)
|
|
141
|
+
return Object.freeze({
|
|
142
|
+
resolutions: frozen,
|
|
143
|
+
canonicalResolutions,
|
|
144
|
+
fingerprint: digestInterruptJson(canonicalResolutions),
|
|
145
|
+
})
|
|
146
|
+
}
|
package/src/locks.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distributed-mutex primitive — coordination, not state persistence.
|
|
3
|
+
*
|
|
4
|
+
* Its own subpath (`@tanstack/ai/locks`) so it stays out of the main barrel and
|
|
5
|
+
* consumers opt in explicitly. Provide a store with `withLocks`; downstream
|
|
6
|
+
* middleware (e.g. `@tanstack/ai-sandbox`'s `ensure`) reads it via `getLocks` /
|
|
7
|
+
* `LocksCapability`. Import from here, not from `@tanstack/ai-persistence`.
|
|
8
|
+
*/
|
|
9
|
+
export {
|
|
10
|
+
LocksCapability,
|
|
11
|
+
getLocks,
|
|
12
|
+
provideLocks,
|
|
13
|
+
InMemoryLockStore,
|
|
14
|
+
withLocks,
|
|
15
|
+
defineLock,
|
|
16
|
+
} from './activities/chat/middleware/index'
|
|
17
|
+
export type { LockStore } from './activities/chat/middleware/index'
|
package/src/logger/types.ts
CHANGED
|
@@ -29,7 +29,7 @@ export interface Logger {
|
|
|
29
29
|
*/
|
|
30
30
|
export interface DebugCategories {
|
|
31
31
|
/**
|
|
32
|
-
* Raw chunks/frames received from a provider SDK (OpenAI, Anthropic, Gemini, Ollama, Grok, Groq, OpenRouter, fal, ElevenLabs). Emitted inside every streaming adapter's chunk loop.
|
|
32
|
+
* Raw chunks/frames received from a provider SDK (OpenAI, Anthropic, Gemini, Ollama, Grok, Groq, OpenRouter, fal, ElevenLabs, BytePlus). Emitted inside every streaming adapter's chunk loop.
|
|
33
33
|
*/
|
|
34
34
|
provider?: boolean
|
|
35
35
|
/**
|
package/src/middlewares/otel.ts
CHANGED
|
@@ -33,7 +33,9 @@ import type {
|
|
|
33
33
|
* Scope (role) of an OTel span emitted by this middleware.
|
|
34
34
|
*
|
|
35
35
|
* - `chat` — the root span for a single `chat()` call
|
|
36
|
-
* - `iteration` — one per agent-loop
|
|
36
|
+
* - `iteration` — one per provider model call (agent-loop `beforeModel`
|
|
37
|
+
* turn, or the separate `structuredOutput` finalization when
|
|
38
|
+
* `outputSchema` skips the agent loop — see #1054)
|
|
37
39
|
* - `tool` — one per tool execution inside an iteration
|
|
38
40
|
* - `generation` — the single span for a media activity call
|
|
39
41
|
* (`generateImage`, `generateVideo`, `generateSpeech`, …)
|
|
@@ -83,6 +85,7 @@ const OPERATION_NAME: Record<GenerationActivity, string> = {
|
|
|
83
85
|
audio: 'audio_generation',
|
|
84
86
|
tts: 'text_to_speech',
|
|
85
87
|
transcription: 'transcription',
|
|
88
|
+
summarize: 'summarize',
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
export interface OtelMiddlewareOptions {
|
|
@@ -400,7 +403,16 @@ export function otelMiddleware(
|
|
|
400
403
|
},
|
|
401
404
|
|
|
402
405
|
onConfig(ctx, config) {
|
|
403
|
-
|
|
406
|
+
// Open an iteration span for every provider model call:
|
|
407
|
+
// - `beforeModel`: agent-loop chatStream turns
|
|
408
|
+
// - `structuredOutput`: separate structured-output finalization
|
|
409
|
+
// (no-tools + outputSchema skips the agent loop, so without this
|
|
410
|
+
// phase there is no generation span and captureContent is a silent
|
|
411
|
+
// no-op — see #1054).
|
|
412
|
+
// Native-combined mode never fires `structuredOutput`, so a run that
|
|
413
|
+
// already opened spans via `beforeModel` is not double-counted.
|
|
414
|
+
if (ctx.phase !== 'beforeModel' && ctx.phase !== 'structuredOutput')
|
|
415
|
+
return
|
|
404
416
|
safeCall('otel.onConfig', () => {
|
|
405
417
|
const state = stateByCtx.get(ctx)
|
|
406
418
|
if (!state) return
|
|
@@ -410,20 +422,26 @@ export function otelMiddleware(
|
|
|
410
422
|
// on it. Close it here, just before opening the next iteration.
|
|
411
423
|
closeIterationSpan(state, ctx)
|
|
412
424
|
|
|
425
|
+
// Number spans by the order of model calls this middleware has seen,
|
|
426
|
+
// not by `ctx.iteration`. After an agent-loop turn, structured-output
|
|
427
|
+
// finalization reuses the engine's last iteration index; using our
|
|
428
|
+
// own counter keeps finalization as a distinct leaf (#N+1).
|
|
429
|
+
const iteration = state.iterationCount
|
|
430
|
+
|
|
413
431
|
const info: OtelSpanInfo<'iteration'> = {
|
|
414
432
|
kind: 'iteration',
|
|
415
433
|
ctx,
|
|
416
|
-
iteration
|
|
434
|
+
iteration,
|
|
417
435
|
}
|
|
418
436
|
const name =
|
|
419
437
|
safeCall('otel.spanNameFormatter', () => spanNameFormatter?.(info)) ??
|
|
420
|
-
`chat ${ctx.model} #${
|
|
438
|
+
`chat ${ctx.model} #${iteration}`
|
|
421
439
|
|
|
422
440
|
const baseAttrs: Record<string, AttributeValue> = {
|
|
423
441
|
'gen_ai.system': ctx.provider,
|
|
424
442
|
'gen_ai.operation.name': 'chat',
|
|
425
443
|
'gen_ai.request.model': ctx.model,
|
|
426
|
-
'tanstack.ai.iteration':
|
|
444
|
+
'tanstack.ai.iteration': iteration,
|
|
427
445
|
}
|
|
428
446
|
// Sampling options now live in provider-native `modelOptions`, and
|
|
429
447
|
// providers spell them differently (e.g. `max_output_tokens`,
|
package/src/realtime/index.ts
CHANGED
|
@@ -19,15 +19,11 @@ export type * from './types'
|
|
|
19
19
|
* import { realtimeToken } from '@tanstack/ai'
|
|
20
20
|
* import { openaiRealtimeToken } from '@tanstack/ai-openai'
|
|
21
21
|
*
|
|
22
|
-
* //
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* model: 'gpt-realtime',
|
|
28
|
-
* }),
|
|
29
|
-
* })
|
|
30
|
-
* })
|
|
22
|
+
* // On the server (e.g. inside a server route or framework server
|
|
23
|
+
* // function), mint an ephemeral token for the client:
|
|
24
|
+
* const token = await realtimeToken({
|
|
25
|
+
* adapter: openaiRealtimeToken({ model: 'gpt-realtime' }),
|
|
26
|
+
* })
|
|
31
27
|
* ```
|
|
32
28
|
*/
|
|
33
29
|
export async function realtimeToken(
|
package/src/scope.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared identity/isolation scope for the TanStack AI subsystems that persist
|
|
3
|
+
* or recall per-conversation data — `@tanstack/ai-persistence` (keyed CRUD over
|
|
4
|
+
* threads, runs, interrupts) and `@tanstack/ai-memory` (ranked recall/save).
|
|
5
|
+
*
|
|
6
|
+
* Both subsystems answer the same underlying question — "whose data is this?" —
|
|
7
|
+
* so they share ONE identity vocabulary defined here rather than each inventing
|
|
8
|
+
* its own. `threadId` is the single conversation key across the codebase (it is
|
|
9
|
+
* `ChatMiddlewareContext.threadId`, and `conversationId` is deprecated in favor
|
|
10
|
+
* of it); a subsystem must never introduce a second name (`sessionId`,
|
|
11
|
+
* `conversationId`, …) for the same concept.
|
|
12
|
+
*
|
|
13
|
+
* ## Security
|
|
14
|
+
*
|
|
15
|
+
* A `Scope` is an isolation boundary. Derive every field server-side from
|
|
16
|
+
* trusted, validated session state — **never** from client input. `threadId`
|
|
17
|
+
* in particular resolves from a client-supplied value on the request, so a
|
|
18
|
+
* subsystem that reads/writes user-owned data (memory, per-user metadata) must
|
|
19
|
+
* pair it with a server-trusted `userId`/`tenantId` and must not treat a bare
|
|
20
|
+
* client `threadId` as sufficient isolation: thread ids are guessable, so on
|
|
21
|
+
* their own they let one caller read another's data.
|
|
22
|
+
*/
|
|
23
|
+
export interface Scope {
|
|
24
|
+
/**
|
|
25
|
+
* The conversation this data belongs to. Required — the minimal isolation
|
|
26
|
+
* key both subsystems already center on. Same concept as
|
|
27
|
+
* `ChatMiddlewareContext.threadId`.
|
|
28
|
+
*/
|
|
29
|
+
threadId: string
|
|
30
|
+
/**
|
|
31
|
+
* Durable end-user identity, for cross-thread recall and per-user isolation.
|
|
32
|
+
* Optional, but required in practice for any multi-user deployment — a
|
|
33
|
+
* `threadId` alone is not an authorization boundary (see Security above).
|
|
34
|
+
*/
|
|
35
|
+
userId?: string
|
|
36
|
+
/**
|
|
37
|
+
* Tenant/organization boundary for multi-tenant deployments. When present,
|
|
38
|
+
* every read and write must be confined to it.
|
|
39
|
+
*/
|
|
40
|
+
tenantId?: string
|
|
41
|
+
/**
|
|
42
|
+
* Logical partition within a tenant/user (e.g. separating distinct memory
|
|
43
|
+
* banks or persistence namespaces). Reserved — no subsystem keys on it yet;
|
|
44
|
+
* adapters that don't understand it must ignore it rather than error.
|
|
45
|
+
*/
|
|
46
|
+
namespace?: string
|
|
47
|
+
}
|