@volter/world-core 2.0.37 → 3.0.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.
Files changed (205) hide show
  1. package/README.md +4 -5
  2. package/app-route.cjs +12 -6
  3. package/app-route.d.cts +1 -1
  4. package/dist/app-route.cjs +12 -6
  5. package/dist/app-route.d.cts +1 -1
  6. package/dist/generated/pack-facts.json +1410 -3069
  7. package/dist/inject.cjs +64 -9
  8. package/dist/pack-facts.cjs +44 -0
  9. package/dist/src/actions.d.ts +3 -3
  10. package/dist/src/actions.js +22 -16
  11. package/dist/src/ancestry.d.ts +14 -2
  12. package/dist/src/ancestry.js +92 -2
  13. package/dist/src/anthropic-wire.d.ts +39 -0
  14. package/dist/src/anthropic-wire.js +136 -0
  15. package/dist/src/bytes.d.ts +7 -0
  16. package/dist/src/bytes.js +35 -0
  17. package/dist/src/changeset.d.ts +1 -1
  18. package/dist/src/changeset.js +0 -0
  19. package/dist/src/clickhouse/index.d.ts +3 -0
  20. package/dist/src/clickhouse/index.js +6 -0
  21. package/dist/src/clickhouse/sql.d.ts +233 -0
  22. package/dist/src/clickhouse/sql.js +4329 -0
  23. package/dist/src/clickhouse/types.d.ts +18 -0
  24. package/dist/src/clickhouse/types.js +47 -0
  25. package/dist/src/clickhouse/values.d.ts +146 -0
  26. package/dist/src/clickhouse/values.js +858 -0
  27. package/dist/src/client-bundle.js +2 -3
  28. package/dist/src/cors.d.ts +15 -0
  29. package/dist/src/cors.js +31 -0
  30. package/dist/src/derived-core.d.ts +487 -24
  31. package/dist/src/derived-core.js +788 -144
  32. package/dist/src/derived-real.d.ts +13 -0
  33. package/dist/src/derived-real.js +518 -0
  34. package/dist/src/derived.d.ts +35 -1
  35. package/dist/src/derived.js +61 -9
  36. package/dist/src/emit.js +1 -2
  37. package/dist/src/events.d.ts +206 -0
  38. package/dist/src/events.js +341 -0
  39. package/dist/src/executor.d.ts +3 -0
  40. package/dist/src/executor.js +19 -2
  41. package/dist/src/file-response.d.ts +6 -0
  42. package/dist/src/file-response.js +30 -0
  43. package/dist/src/fork.js +3 -2
  44. package/dist/src/git/history.d.ts +7 -0
  45. package/dist/src/git/history.js +24 -0
  46. package/dist/src/git/index.d.ts +1 -0
  47. package/dist/src/git/index.js +1 -0
  48. package/dist/src/git/lfs.d.ts +28 -0
  49. package/dist/src/git/lfs.js +66 -0
  50. package/dist/src/git/objects.js +3 -8
  51. package/dist/src/git/smart-http.d.ts +3 -1
  52. package/dist/src/git/smart-http.js +67 -6
  53. package/dist/src/graphql-wire.d.ts +29 -0
  54. package/dist/src/graphql-wire.js +101 -0
  55. package/dist/src/grpc-wire.d.ts +67 -0
  56. package/dist/src/grpc-wire.js +170 -0
  57. package/dist/src/h2.d.ts +40 -0
  58. package/dist/src/h2.js +656 -0
  59. package/dist/src/head.d.ts +32 -3
  60. package/dist/src/head.js +161 -40
  61. package/dist/src/history.d.ts +1 -1
  62. package/dist/src/history.js +6 -6
  63. package/dist/src/hpack.json +1 -0
  64. package/dist/src/index.d.ts +64 -75
  65. package/dist/src/index.js +58 -101
  66. package/dist/src/log.js +28 -19
  67. package/dist/src/machines.d.ts +50 -0
  68. package/dist/src/machines.js +151 -0
  69. package/dist/src/managed-database.d.ts +86 -0
  70. package/dist/src/managed-database.js +283 -0
  71. package/dist/src/multipart.d.ts +11 -0
  72. package/dist/src/multipart.js +51 -0
  73. package/dist/src/observe.d.ts +15 -5
  74. package/dist/src/observe.js +23 -9
  75. package/dist/src/openai-wire.d.ts +108 -0
  76. package/dist/src/openai-wire.js +337 -0
  77. package/dist/src/pack-assets.d.ts +3 -4
  78. package/dist/src/pack-assets.js +15 -10
  79. package/dist/src/pack-fetch.d.ts +77 -0
  80. package/dist/src/pack-fetch.js +449 -0
  81. package/dist/src/pack-paths.d.ts +12 -0
  82. package/dist/src/pack-paths.js +86 -0
  83. package/dist/src/packRegistry.d.ts +69 -162
  84. package/dist/src/packRegistry.js +55 -20
  85. package/dist/src/people.d.ts +13 -0
  86. package/dist/src/people.js +18 -0
  87. package/dist/src/placeholder-image.d.ts +5 -0
  88. package/dist/src/placeholder-image.js +114 -0
  89. package/dist/src/protobuf.d.ts +28 -0
  90. package/dist/src/protobuf.js +332 -0
  91. package/dist/src/redis/engine.js +1 -1
  92. package/dist/src/request-scope.d.ts +1 -1
  93. package/dist/src/request-scope.js +6 -4
  94. package/dist/src/resource-blob.d.ts +5 -0
  95. package/dist/src/resource-blob.js +11 -0
  96. package/dist/src/runtime.d.ts +85 -0
  97. package/dist/src/runtime.js +104 -0
  98. package/dist/src/s3/wire.d.ts +60 -0
  99. package/dist/src/s3/wire.js +157 -0
  100. package/dist/src/scenario.d.ts +3 -0
  101. package/dist/src/scenario.js +2 -0
  102. package/dist/src/schema-sample.d.ts +1 -0
  103. package/dist/src/schema-sample.js +21 -0
  104. package/dist/src/sealed-box.d.ts +14 -0
  105. package/dist/src/sealed-box.js +225 -0
  106. package/dist/src/serve-http.d.ts +14 -0
  107. package/dist/src/serve-http.js +27 -3
  108. package/dist/src/serve.d.ts +6 -0
  109. package/dist/src/serve.js +69 -14
  110. package/dist/src/signing.d.ts +135 -0
  111. package/dist/src/signing.js +222 -0
  112. package/dist/src/sigv4.d.ts +48 -0
  113. package/dist/src/sigv4.js +167 -0
  114. package/dist/src/smtp.d.ts +16 -0
  115. package/dist/src/smtp.js +72 -0
  116. package/dist/src/sockets.d.ts +51 -0
  117. package/dist/src/sockets.js +90 -0
  118. package/dist/src/state-system.d.ts +1 -0
  119. package/dist/src/state-system.js +1 -1
  120. package/dist/src/storage.d.ts +1 -1
  121. package/dist/src/storage.js +3 -3
  122. package/dist/src/trace-context.js +1 -1
  123. package/dist/src/twin-fetch.d.ts +0 -7
  124. package/dist/src/twin-fetch.js +0 -14
  125. package/dist/src/vendor-call.d.ts +6 -0
  126. package/dist/src/vendor-call.js +41 -0
  127. package/dist/src/world-store.js +1 -1
  128. package/dist/vendor-hosts.cjs +36 -125
  129. package/dist/vendor-hosts.d.cts +8 -0
  130. package/generated/pack-facts.json +1410 -3069
  131. package/inject.cjs +64 -9
  132. package/pack-facts.cjs +44 -0
  133. package/package.json +17 -3
  134. package/src/actions.ts +23 -16
  135. package/src/ancestry.ts +74 -2
  136. package/src/anthropic-wire.ts +137 -0
  137. package/src/bytes.ts +42 -0
  138. package/src/changeset.ts +5 -5
  139. package/src/clickhouse/index.ts +6 -0
  140. package/src/clickhouse/sql.ts +3059 -0
  141. package/src/clickhouse/types.ts +44 -0
  142. package/src/clickhouse/values.ts +697 -0
  143. package/src/client-bundle.ts +2 -3
  144. package/src/cors.ts +34 -0
  145. package/src/derived-core.ts +1013 -146
  146. package/src/derived-real.ts +434 -0
  147. package/src/derived.ts +73 -3
  148. package/src/emit.ts +1 -2
  149. package/src/events.ts +449 -0
  150. package/src/executor.ts +24 -2
  151. package/src/file-response.ts +27 -0
  152. package/src/fork.ts +3 -2
  153. package/src/git/history.ts +19 -0
  154. package/src/git/index.ts +1 -0
  155. package/src/git/lfs.ts +67 -0
  156. package/src/git/objects.ts +3 -5
  157. package/src/git/smart-http.ts +56 -6
  158. package/src/graphql-wire.ts +106 -0
  159. package/src/grpc-wire.ts +159 -0
  160. package/src/h2.ts +627 -0
  161. package/src/head.ts +132 -41
  162. package/src/history.ts +6 -6
  163. package/src/hpack.json +1 -0
  164. package/src/index.ts +82 -329
  165. package/src/log.ts +27 -18
  166. package/src/machines.ts +151 -0
  167. package/src/managed-database.ts +299 -0
  168. package/src/multipart.ts +51 -0
  169. package/src/observe.ts +31 -15
  170. package/src/openai-wire.ts +371 -0
  171. package/src/pack-assets.ts +15 -11
  172. package/src/pack-fetch.ts +458 -0
  173. package/src/pack-paths.ts +72 -0
  174. package/src/packRegistry.ts +79 -167
  175. package/src/people.ts +31 -0
  176. package/src/placeholder-image.ts +88 -0
  177. package/src/protobuf.ts +251 -0
  178. package/src/redis/engine.ts +1 -1
  179. package/src/request-scope.ts +8 -4
  180. package/src/resource-blob.ts +13 -0
  181. package/src/runtime.ts +344 -0
  182. package/src/s3/wire.ts +172 -0
  183. package/src/scenario.ts +4 -0
  184. package/src/schema-sample.ts +24 -0
  185. package/src/sealed-box.ts +182 -0
  186. package/src/serve-http.ts +31 -3
  187. package/src/serve.ts +58 -14
  188. package/src/signing.ts +231 -0
  189. package/src/sigv4.ts +158 -0
  190. package/src/smtp.ts +76 -0
  191. package/src/sockets.ts +140 -0
  192. package/src/state-system.ts +2 -2
  193. package/src/storage.ts +3 -3
  194. package/src/trace-context.ts +1 -1
  195. package/src/twin-fetch.ts +0 -20
  196. package/src/vendor-call.ts +41 -0
  197. package/src/world-store.ts +1 -1
  198. package/vendor-hosts.cjs +36 -125
  199. package/vendor-hosts.d.cts +8 -0
  200. package/dist/src/mirror-shell.d.ts +0 -2
  201. package/dist/src/mirror-shell.js +0 -13
  202. package/dist/src/v1-removed.d.ts +0 -159
  203. package/dist/src/v1-removed.js +0 -124
  204. package/src/mirror-shell.ts +0 -15
  205. package/src/v1-removed.ts +0 -172
@@ -0,0 +1,337 @@
1
+ import { sampleFromSchema } from "./schema-sample.js";
2
+ const obj = (v) => (v && typeof v === 'object' && !Array.isArray(v) ? v : {});
3
+ const arr = (v) => (Array.isArray(v) ? v : []);
4
+ /** Tokens, estimated at about four characters a token: a twin's count, not a tokenizer's. */
5
+ export const estimateTokens = (text) => Math.max(1, Math.ceil(text.length / 4));
6
+ // ── chat completions: requests ─────────────────────────────────────────────────────────────────
7
+ /** A message's content as text: a string, or its text parts joined. */
8
+ export const chatText = (content) => (typeof content === 'string' ? content : arr(content).map((p) => (typeof p.text === 'string' ? p.text : '')).join(''));
9
+ /** The last user message's text. */
10
+ export function chatLastUserText(messages) {
11
+ for (let i = messages.length - 1; i >= 0; i--)
12
+ if (messages[i].role === 'user')
13
+ return chatText(messages[i].content);
14
+ return '';
15
+ }
16
+ /** The tool results the last message carries (a `tool` message), by its name or call id. */
17
+ export const chatToolResults = (messages) => (messages.at(-1)?.role === 'tool' ? [String(messages.at(-1).name ?? messages.at(-1).tool_call_id ?? '')] : []);
18
+ /** The labeled stub for a chat request: with tools offered (`tool_choice` not `none`) and the last message not a tool's
19
+ * result, it calls the tool the choice names, else the first, with arguments its schema admits; with a JSON response
20
+ * format, it answers a value the schema admits; otherwise it echoes the last user message. `label` names the twin. */
21
+ export function chatStubTurn(body, label) {
22
+ const model = String(body.model);
23
+ const messages = arr(body.messages);
24
+ const tools = arr(body.tools).filter((t) => obj(t.function).name !== undefined);
25
+ const choice = body.tool_choice ?? 'auto';
26
+ const named = typeof choice === 'object' ? String(obj(obj(choice).function).name ?? '') : '';
27
+ if (tools.length && choice !== 'none' && (chatToolResults(messages).length === 0 || choice === 'required' || named)) {
28
+ const f = obj(((named ? tools.find((t) => obj(t.function).name === named) : undefined) ?? tools[0]).function);
29
+ return { toolCalls: [{ name: String(f.name), arguments: sampleFromSchema(f.parameters, String(f.name)) }] };
30
+ }
31
+ const format = obj(body.response_format);
32
+ if (format.type === 'json_schema')
33
+ return { text: JSON.stringify(sampleFromSchema(obj(format.json_schema).schema)) };
34
+ if (format.type === 'json_object')
35
+ return { text: JSON.stringify({ twin_stub: `deterministic stub from the ${label} (${model}): no model runs` }) };
36
+ const said = chatLastUserText(messages).trim();
37
+ return { text: `[twin-stub:${model}] This is a deterministic stub from the ${label} (no model runs). Your last message: ${said.length > 200 ? `${said.slice(0, 200)}…` : said || '(empty)'}` };
38
+ }
39
+ function chatParts(s) {
40
+ let text = s.turn.text ?? null;
41
+ let finish = s.turn.finishReason ?? (s.turn.toolCalls?.length ? 'tool_calls' : 'stop');
42
+ if (text !== null && s.maxTokens !== undefined && estimateTokens(text) > s.maxTokens) {
43
+ text = text.slice(0, s.maxTokens * 4);
44
+ finish = 'length';
45
+ }
46
+ const calls = (s.turn.toolCalls ?? []).map((c, i) => ({ id: s.callId(i), type: 'function', function: { name: c.name, arguments: JSON.stringify(c.arguments ?? {}) } }));
47
+ const reasoning = s.turn.reasoning ?? null;
48
+ const prompt = estimateTokens(s.messages.map((m) => chatText(m.content)).join('\n'));
49
+ const completion = estimateTokens([text ?? '', ...calls.map((c) => c.function.arguments)].join(''));
50
+ const reasoningTokens = reasoning ? estimateTokens(reasoning) : 0;
51
+ const usage = {
52
+ prompt_tokens: prompt, completion_tokens: completion + reasoningTokens, total_tokens: prompt + completion + reasoningTokens,
53
+ prompt_tokens_details: { cached_tokens: 0 }, completion_tokens_details: { reasoning_tokens: reasoningTokens }, ...(s.usageExtra ?? {}),
54
+ };
55
+ return { text, finish, calls, usage, reasoning };
56
+ }
57
+ /** A chat completion's body (`object: chat.completion`), one choice. */
58
+ export function chatCompletion(s) {
59
+ const p = chatParts(s);
60
+ const field = s.reasoningField ?? 'reasoning';
61
+ const message = { role: 'assistant', content: p.text, refusal: null, ...(p.reasoning ? { [field]: p.reasoning } : {}), ...(p.calls.length ? { tool_calls: p.calls } : {}) };
62
+ return {
63
+ id: s.id, ...(s.extra ?? {}), model: s.model, object: 'chat.completion', created: s.created,
64
+ choices: [{ index: 0, message, logprobs: null, finish_reason: p.finish, ...(s.nativeFinish ? { native_finish_reason: p.finish } : {}) }], usage: p.usage,
65
+ };
66
+ }
67
+ /** A chat completion streamed: its chunks (`object: chat.completion.chunk`) as Server-Sent Events, the text in two
68
+ * deltas, the last chunk carrying the finish reason and the usage, then `data: [DONE]`. `comment` is a keep-alive a
69
+ * vendor sends first (OpenRouter's `: OPENROUTER PROCESSING`). */
70
+ export function chatCompletionSSE(s) {
71
+ const p = chatParts(s);
72
+ const field = s.reasoningField ?? 'reasoning';
73
+ const chunk = (delta, last) => `data: ${JSON.stringify({
74
+ id: s.id, ...((last ? s.extra : s.interimExtra ?? s.extra) ?? {}), model: s.model, object: 'chat.completion.chunk', created: s.created,
75
+ choices: [{ index: 0, delta, logprobs: null, finish_reason: last ? p.finish : null, ...(s.nativeFinish ? { native_finish_reason: last ? p.finish : null } : {}) }],
76
+ ...(last ? { usage: p.usage } : {}),
77
+ })}\n\n`;
78
+ const half = p.text ? Math.ceil(p.text.length / 2) : 0;
79
+ return [
80
+ ...(s.comment ? [`: ${s.comment}\n\n`] : []),
81
+ ...(p.reasoning ? [chunk({ role: 'assistant', content: '', [field]: p.reasoning }, false)] : []),
82
+ ...(p.text ? [chunk({ role: 'assistant', content: p.text.slice(0, half) }, false), ...(p.text.length > half ? [chunk({ content: p.text.slice(half) }, false)] : [])] : []),
83
+ ...(p.calls.length ? [chunk({ role: 'assistant', content: null, tool_calls: p.calls.map((c, i) => ({ index: i, ...c })) }, false)] : []),
84
+ chunk({}, true),
85
+ 'data: [DONE]\n\n',
86
+ ].join('');
87
+ }
88
+ // ── the AI SDK's language-model protocol (Vercel's AI Gateway) ─────────────────────────────────────
89
+ // `@ai-sdk/gateway` posts a model call's options as `@ai-sdk/provider`'s LanguageModelV4 defines them (the model in the
90
+ // `ai-language-model-id` header) and reads back its generate result, or its stream parts as Server-Sent Events
91
+ // (https://unpkg.com/@ai-sdk/provider@4.0.14/dist/index.d.ts, `LanguageModelV4GenerateResult`, `LanguageModelV4StreamPart`).
92
+ /** A V4 call's options as the chat completions request they mean: its prompt as messages, its tools, tool choice,
93
+ * response format and output limit; so the chat stub and the wire's scenario read it. */
94
+ export function aiSdkChatBody(call, model) {
95
+ const text = (content) => (typeof content === 'string' ? content : arr(content).filter((p) => p.type === 'text' || p.type === 'reasoning').map((p) => String(p.text ?? '')).join(''));
96
+ const messages = [];
97
+ for (const m of arr(call.prompt)) {
98
+ if (m.role === 'tool')
99
+ for (const r of arr(m.content).filter((p) => p.type === 'tool-result'))
100
+ messages.push({ role: 'tool', tool_call_id: r.toolCallId, name: r.toolName, content: JSON.stringify(r.output ?? null) });
101
+ else if (m.role === 'assistant') {
102
+ const calls = arr(m.content).filter((p) => p.type === 'tool-call').map((c) => ({ id: c.toolCallId, type: 'function', function: { name: c.toolName, arguments: typeof c.input === 'string' ? c.input : JSON.stringify(c.input ?? {}) } }));
103
+ messages.push({ role: 'assistant', content: text(m.content), ...(calls.length ? { tool_calls: calls } : {}) });
104
+ }
105
+ else
106
+ messages.push({ role: String(m.role ?? 'user'), content: text(m.content) });
107
+ }
108
+ const tools = arr(call.tools).filter((x) => x.type === 'function').map((x) => ({ type: 'function', function: { name: x.name, description: x.description, parameters: x.inputSchema } }));
109
+ const choice = obj(call.toolChoice);
110
+ const format = obj(call.responseFormat);
111
+ return {
112
+ model, messages,
113
+ ...(tools.length ? { tools } : {}),
114
+ ...(choice.type === 'tool' ? { tool_choice: { type: 'function', function: { name: choice.toolName } } } : typeof choice.type === 'string' ? { tool_choice: choice.type } : {}),
115
+ ...(format.type === 'json' ? { response_format: format.schema ? { type: 'json_schema', json_schema: { name: format.name ?? 'response', schema: format.schema } } : { type: 'json_object' } } : {}),
116
+ ...(typeof call.maxOutputTokens === 'number' ? { max_tokens: call.maxOutputTokens } : {}),
117
+ };
118
+ }
119
+ const UNIFIED = { stop: 'stop', length: 'length', tool_calls: 'tool-calls', content_filter: 'content-filter' };
120
+ function lmParts(s) {
121
+ const p = chatParts(s);
122
+ const u = p.usage;
123
+ return {
124
+ content: [
125
+ ...(p.reasoning ? [{ type: 'reasoning', text: p.reasoning }] : []),
126
+ ...(p.text !== null ? [{ type: 'text', text: p.text }] : []),
127
+ ...p.calls.map((c) => ({ type: 'tool-call', toolCallId: c.id, toolName: c.function.name, input: c.function.arguments })),
128
+ ],
129
+ finishReason: { unified: UNIFIED[p.finish] ?? 'other', raw: p.finish },
130
+ usage: {
131
+ inputTokens: { total: u.prompt_tokens, noCache: u.prompt_tokens, cacheRead: 0, cacheWrite: 0 },
132
+ outputTokens: { total: u.completion_tokens, text: u.completion_tokens - u.completion_tokens_details.reasoning_tokens, reasoning: u.completion_tokens_details.reasoning_tokens },
133
+ },
134
+ };
135
+ }
136
+ /** A V4 generate result: the turn's content (reasoning, text, tool calls with their input as JSON text), its finish
137
+ * reason (unified, and the raw one) and its usage; `extra` is what the server adds (the gateway's provider metadata). */
138
+ export function languageModelResult(s) {
139
+ const r = lmParts(s);
140
+ return { ...r, response: { id: s.id, modelId: s.model, timestamp: new Date(s.created * 1000).toISOString() }, warnings: [], ...(s.extra ?? {}) };
141
+ }
142
+ /** A V4 stream: its parts as Server-Sent Events (stream-start, response-metadata, the reasoning, the text in two deltas,
143
+ * each tool call's input then the call, and the finish), with no `[DONE]`: the SDK reads every event as a part. */
144
+ export function languageModelSSE(s) {
145
+ const r = lmParts(s);
146
+ const out = [{ type: 'stream-start', warnings: [] }, { type: 'response-metadata', id: s.id, modelId: s.model, timestamp: new Date(s.created * 1000).toISOString() }];
147
+ for (const [i, c] of r.content.entries()) {
148
+ if (c.type === 'reasoning')
149
+ out.push({ type: 'reasoning-start', id: `reasoning-${i}` }, { type: 'reasoning-delta', id: `reasoning-${i}`, delta: c.text }, { type: 'reasoning-end', id: `reasoning-${i}` });
150
+ else if (c.type === 'text') {
151
+ const text = String(c.text);
152
+ const half = Math.ceil(text.length / 2);
153
+ out.push({ type: 'text-start', id: `text-${i}` }, { type: 'text-delta', id: `text-${i}`, delta: text.slice(0, half) }, ...(text.length > half ? [{ type: 'text-delta', id: `text-${i}`, delta: text.slice(half) }] : []), { type: 'text-end', id: `text-${i}` });
154
+ }
155
+ else
156
+ out.push({ type: 'tool-input-start', id: c.toolCallId, toolName: c.toolName }, { type: 'tool-input-delta', id: c.toolCallId, delta: c.input }, { type: 'tool-input-end', id: c.toolCallId }, c);
157
+ }
158
+ out.push({ type: 'finish', finishReason: r.finishReason, usage: r.usage, ...(s.extra ?? {}) });
159
+ return out.map((part) => `data: ${JSON.stringify(part)}\n\n`).join('');
160
+ }
161
+ // ── Responses: requests ────────────────────────────────────────────────────────────────────────
162
+ /** A Responses request's input as items: a string is one user message. */
163
+ export const responsesItems = (input) => (typeof input === 'string' ? [{ type: 'message', role: 'user', content: input }] : arr(input));
164
+ const itemText = (content) => (typeof content === 'string' ? content : arr(content).map((p) => (typeof p.text === 'string' ? p.text : '')).join(''));
165
+ /** The last user message's text in a Responses input. */
166
+ export function responsesLastUserText(input) {
167
+ const items = responsesItems(input);
168
+ for (let i = items.length - 1; i >= 0; i--)
169
+ if ((items[i].role ?? (items[i].type === 'message' ? 'user' : '')) === 'user')
170
+ return itemText(items[i].content);
171
+ return '';
172
+ }
173
+ /** The function-call outputs the input ends with. */
174
+ export const responsesToolResults = (input) => responsesItems(input).filter((i) => i.type === 'function_call_output').map((i) => String(i.call_id ?? ''));
175
+ /** The labeled stub for a Responses request: a function tool is called (unless the input already carries its output or
176
+ * `tool_choice` is `none`), a JSON schema format answers a value it admits, otherwise the last user text is echoed. */
177
+ export function responsesStubTurn(body, label) {
178
+ const model = String(body.model);
179
+ const tools = arr(body.tools).filter((t) => t.type === 'function' && typeof t.name === 'string');
180
+ const choice = body.tool_choice ?? 'auto';
181
+ const named = typeof choice === 'object' ? String(obj(choice).name ?? '') : '';
182
+ if (tools.length && choice !== 'none' && (responsesToolResults(body.input).length === 0 || choice === 'required' || named)) {
183
+ const t = (named ? tools.find((x) => x.name === named) : undefined) ?? tools[0];
184
+ return { toolCalls: [{ name: String(t.name), arguments: sampleFromSchema(t.parameters, String(t.name)) }] };
185
+ }
186
+ const format = obj(obj(body.text).format);
187
+ if (format.type === 'json_schema')
188
+ return { text: JSON.stringify(sampleFromSchema(format.schema)) };
189
+ if (format.type === 'json_object')
190
+ return { text: JSON.stringify({ twin_stub: `deterministic stub from the ${label} (${model}): no model runs` }) };
191
+ const said = responsesLastUserText(body.input).trim();
192
+ return { text: `[twin-stub:${model}] This is a deterministic stub from the ${label} (no model runs). Your last message: ${said.length > 200 ? `${said.slice(0, 200)}…` : said || '(empty)'}` };
193
+ }
194
+ /** A Responses object (`object: response`, `status: completed`): its output items (the reasoning when there is some,
195
+ * the message with its output text, or function calls) and its usage. */
196
+ export function responsesAnswer(s) {
197
+ const b = s.body;
198
+ let text = s.turn.text ?? null;
199
+ const max = typeof b.max_output_tokens === 'number' ? b.max_output_tokens : undefined;
200
+ let incomplete = null;
201
+ if (text !== null && max !== undefined && estimateTokens(text) > max) {
202
+ text = text.slice(0, max * 4);
203
+ incomplete = { reason: 'max_output_tokens' };
204
+ }
205
+ const output = [
206
+ ...(s.turn.reasoning ? [{ type: 'reasoning', id: s.itemId('rs', 0), summary: [{ type: 'summary_text', text: s.turn.reasoning }], status: 'completed' }] : []),
207
+ ...(text !== null ? [{ type: 'message', id: s.itemId('msg', 0), status: incomplete ? 'incomplete' : 'completed', role: 'assistant', content: [{ type: 'output_text', text, annotations: [], logprobs: [] }] }] : []),
208
+ ...(s.turn.toolCalls ?? []).map((c, i) => ({ type: 'function_call', id: s.itemId('fc', i), call_id: s.itemId('call', i), name: c.name, arguments: JSON.stringify(c.arguments ?? {}), status: 'completed' })),
209
+ ];
210
+ const input = estimateTokens([String(b.instructions ?? ''), ...responsesItems(b.input).map((i) => itemText(i.content ?? i.output))].join('\n'));
211
+ const out = estimateTokens([text ?? '', ...(s.turn.toolCalls ?? []).map((c) => JSON.stringify(c.arguments ?? {}))].join(''));
212
+ const reasoningTokens = s.turn.reasoning ? estimateTokens(s.turn.reasoning) : 0;
213
+ return {
214
+ id: s.id, object: 'response', created_at: s.createdAt, status: incomplete ? 'incomplete' : 'completed', ...(s.extra ?? {}),
215
+ error: null, incomplete_details: incomplete, instructions: b.instructions ?? null, max_output_tokens: max ?? null, model: s.model, output,
216
+ parallel_tool_calls: b.parallel_tool_calls ?? true, previous_response_id: b.previous_response_id ?? null,
217
+ reasoning: { effort: obj(b.reasoning).effort ?? null, summary: obj(b.reasoning).summary ?? null }, store: b.store ?? true,
218
+ temperature: b.temperature ?? 1, text: b.text ?? { format: { type: 'text' } }, tool_choice: b.tool_choice ?? 'auto', tools: b.tools ?? [], top_p: b.top_p ?? 1,
219
+ usage: { input_tokens: input, input_tokens_details: { cached_tokens: 0 }, output_tokens: out + reasoningTokens, output_tokens_details: { reasoning_tokens: reasoningTokens }, total_tokens: input + out + reasoningTokens },
220
+ metadata: b.metadata ?? {},
221
+ };
222
+ }
223
+ /** A Responses object streamed: the events the wire sends (`response.created`, `response.in_progress`, each output
224
+ * item's added, its text deltas and done, `response.completed`), each `event:` and `data:` with its sequence number. */
225
+ export function responsesSSE(s) {
226
+ const done = responsesAnswer(s);
227
+ const pending = { ...done, status: 'in_progress', output: [], usage: null };
228
+ const events = [{ type: 'response.created', response: pending }, { type: 'response.in_progress', response: pending }];
229
+ for (const [i, item] of done.output.entries()) {
230
+ if (item.type === 'message') {
231
+ const text = String((item.content[0] ?? {}).text ?? '');
232
+ events.push({ type: 'response.output_item.added', output_index: i, item: { ...item, status: 'in_progress', content: [] } });
233
+ events.push({ type: 'response.content_part.added', item_id: item.id, output_index: i, content_index: 0, part: { type: 'output_text', text: '', annotations: [] } });
234
+ const half = Math.ceil(text.length / 2);
235
+ for (const delta of [text.slice(0, half), text.slice(half)].filter(Boolean))
236
+ events.push({ type: 'response.output_text.delta', item_id: item.id, output_index: i, content_index: 0, delta, logprobs: [] });
237
+ events.push({ type: 'response.output_text.done', item_id: item.id, output_index: i, content_index: 0, text, logprobs: [] });
238
+ events.push({ type: 'response.content_part.done', item_id: item.id, output_index: i, content_index: 0, part: item.content[0] });
239
+ }
240
+ else if (item.type === 'function_call') {
241
+ events.push({ type: 'response.output_item.added', output_index: i, item: { ...item, arguments: '', status: 'in_progress' } });
242
+ events.push({ type: 'response.function_call_arguments.delta', item_id: item.id, output_index: i, delta: item.arguments });
243
+ events.push({ type: 'response.function_call_arguments.done', item_id: item.id, output_index: i, arguments: item.arguments });
244
+ }
245
+ else {
246
+ events.push({ type: 'response.output_item.added', output_index: i, item });
247
+ }
248
+ events.push({ type: 'response.output_item.done', output_index: i, item });
249
+ }
250
+ events.push({ type: done.status === 'incomplete' ? 'response.incomplete' : 'response.completed', response: done });
251
+ return events.map((e, n) => `event: ${String(e.type)}\ndata: ${JSON.stringify({ ...e, sequence_number: n })}\n\n`).join('');
252
+ }
253
+ /** Whether a request forbids every tool call: OpenAI's `tool_choice: 'none'`, Anthropic's `{ type: 'none' }`. */
254
+ export const forbidsTools = (choice) => choice === 'none' || obj(choice).type === 'none';
255
+ /** The turn a scenario's decision scripts (`respond`: text, toolCalls, reasoning, finishReason), or undefined. */
256
+ export function scenarioTurn(decision) {
257
+ if (!decision || decision.kind !== 'handler')
258
+ return undefined;
259
+ const r = obj(decision.respond);
260
+ return {
261
+ ...(typeof r.text === 'string' ? { text: r.text } : {}),
262
+ ...(r.toolCalls !== undefined ? { toolCalls: (Array.isArray(r.toolCalls) ? r.toolCalls : [r.toolCalls]) } : {}),
263
+ ...(typeof r.reasoning === 'string' ? { reasoning: r.reasoning } : {}),
264
+ ...(typeof r.finishReason === 'string' ? { finishReason: r.finishReason } : {}),
265
+ };
266
+ }
267
+ const nonEmpty = (v) => typeof v === 'string' && v.length > 0;
268
+ const RESPOND_KEYS = new Set(['text', 'toolCalls', 'reasoning', 'finishReason']);
269
+ /** A request as the scenario reads it: its model, its text, its last user text, the tools it offers and the tool
270
+ * results it ends with, from a chat completion's messages or a Responses input. */
271
+ export function wireRequest(body) {
272
+ const messages = arr(body.messages);
273
+ const tools = arr(body.tools).map((t) => String(obj(t.function).name ?? t.name ?? '')).filter(Boolean);
274
+ const forbidden = forbidsTools(body.tool_choice) ? { toolsForbidden: true } : {};
275
+ if (messages.length)
276
+ return { model: String(body.model ?? ''), text: messages.map((m) => chatText(m.content)).join('\n'), lastUser: chatLastUserText(messages), tools, results: chatToolResults(messages), ...forbidden };
277
+ const items = responsesItems(body.input);
278
+ return { model: String(body.model ?? ''), text: [String(body.instructions ?? ''), ...items.map((i) => itemText(i.content))].join('\n'), lastUser: responsesLastUserText(body.input), tools, results: responsesToolResults(body.input), ...forbidden };
279
+ }
280
+ /** The scenario of a vendor on this wire: its operations, and its error body for a scripted fault. `readers` reads an
281
+ * operation whose request is another wire's (a gateway's Anthropic Messages surface: anthropicWire's
282
+ * `messagesWireRequest`), so one scenario scripts every surface's turns alike. */
283
+ export function scenario(vendor, operations, faultBody, readers = {}) {
284
+ const adapter = {
285
+ vendor,
286
+ renderFault: (f) => ({ body: faultBody(f.status, f.message) }),
287
+ features: (r) => ({ model: r.model, lastUserText: r.lastUser.slice(0, 300), tools: r.tools, lastMessageIsToolResult: r.results.length > 0, toolResultFor: r.results }),
288
+ matchers: {
289
+ modelEquals: (r, c) => nonEmpty(c) && r.model === c,
290
+ userTextIncludes: (r, c) => nonEmpty(c) && r.lastUser.toLowerCase().includes(c.toLowerCase()),
291
+ anyTextIncludes: (r, c) => nonEmpty(c) && r.text.toLowerCase().includes(c.toLowerCase()),
292
+ lastMessageIsToolResult: (r, c) => typeof c === 'boolean' && (r.results.length > 0) === c,
293
+ toolResultFor: (r, c) => nonEmpty(c) && r.results.includes(c),
294
+ hasTool: (r, c) => nonEmpty(c) && r.tools.includes(c),
295
+ },
296
+ text: (r) => r.text,
297
+ // source: https://platform.openai.com/docs/api-reference/chat/create "none means the model will not call any tool and instead generates a message"
298
+ admits: (r, respond) => !(r.toolsForbidden && obj(respond).toolCalls !== undefined),
299
+ validateOn: (on) => {
300
+ for (const k of ['modelEquals', 'userTextIncludes', 'anyTextIncludes', 'toolResultFor', 'hasTool'])
301
+ if (on[k] !== undefined && !nonEmpty(on[k]))
302
+ return `on.${k} is a non-empty string`;
303
+ if (on.lastMessageIsToolResult !== undefined && typeof on.lastMessageIsToolResult !== 'boolean')
304
+ return 'on.lastMessageIsToolResult is a boolean';
305
+ return null;
306
+ },
307
+ validateRespond: (respond) => {
308
+ if (typeof respond !== 'object' || respond === null || Array.isArray(respond))
309
+ return 'respond is an object { text?, toolCalls?, reasoning?, finishReason? }';
310
+ const r = respond;
311
+ for (const k of Object.keys(r))
312
+ if (!RESPOND_KEYS.has(k))
313
+ return `respond: unknown key "${k}" (valid: ${[...RESPOND_KEYS].join(', ')})`;
314
+ if (r.text !== undefined && typeof r.text !== 'string')
315
+ return 'respond.text is a string';
316
+ if (r.reasoning !== undefined && typeof r.reasoning !== 'string')
317
+ return 'respond.reasoning is a string';
318
+ for (const c of r.toolCalls === undefined ? [] : Array.isArray(r.toolCalls) ? r.toolCalls : [r.toolCalls]) {
319
+ const u = c;
320
+ if (!u || typeof u !== 'object' || Array.isArray(u) || !nonEmpty(u.name))
321
+ return 'respond.toolCalls[].name is a non-empty string';
322
+ }
323
+ if (r.text === undefined && r.toolCalls === undefined)
324
+ return 'respond needs text or toolCalls';
325
+ return null;
326
+ },
327
+ };
328
+ // a V4 call (the AI SDK's protocol) is read as the chat request it means, its model in its header
329
+ const request = (ctx) => {
330
+ const body = (ctx.body ?? {});
331
+ const read = Object.hasOwn(readers, ctx.call.operation.id) ? readers[ctx.call.operation.id] : undefined;
332
+ if (read)
333
+ return read(body);
334
+ return wireRequest(Array.isArray(body.prompt) ? aiSdkChatBody(body, ctx.call.request.headers.get('ai-language-model-id') ?? '') : body);
335
+ };
336
+ return { adapter, operations, request };
337
+ }
@@ -7,15 +7,14 @@ export interface PackAssetStore {
7
7
  export declare function assetContentType(relPath: string): string;
8
8
  /** A relative path confined to a pack's tree: no absolute, no `..`, no empty segment. */
9
9
  export declare function confinedAssetPath(relPath: string): string | null;
10
- /** The Bun shell's store: the pack's own directory under the catalog (`packages/twin/<vendor>`).
11
- * `twinDir` ends with a slash. */
10
+ /** The host's store: a pack-directory resolver, or a catalog root ending in a slash. */
12
11
  export declare class LocalPackAssets implements PackAssetStore {
13
12
  private readonly twinDir;
14
- constructor(twinDir: string);
13
+ constructor(twinDir: string | ((vendor: string) => string | undefined | Promise<string | undefined>));
15
14
  fetch(vendor: string, relPath: string): Promise<Response | null>;
16
15
  }
17
16
  /** The workerd shell's store: the static-assets binding, where the deploy step places each
18
- * pack's declared assets under `/{vendor}/pack/<relPath>` beside the mirror shells. */
17
+ * pack's declared assets under `/{vendor}/pack/<relPath>`. */
19
18
  export declare class BindingPackAssets implements PackAssetStore {
20
19
  private readonly assets;
21
20
  constructor(assets: {
@@ -1,15 +1,14 @@
1
1
  // THE PACK-ASSET SEAM (runtime contract R20). A pack may ship bytes it serves byte-for-byte —
2
- // clerk's vendored clerk-js dist (136 files, 14.5 MB), a mirror shell — that are neither
2
+ // clerk's vendored clerk-js dist (136 files, 14.5 MB) — that are neither
3
3
  // committed text (size) nor world-state blobs (R11's seam is keyed under a world's state root
4
4
  // and filled by requests). They are PACK assets: read-only, versioned with the package, the
5
5
  // same on every world. This seam is how a pack reaches them without touching a host: the
6
6
  // pack declares them on its descriptor (`assets`), reads them through `getActivePackAssets()`,
7
7
  // and the SHELL binds the store — the Bun shell reads the pack's own tree, workerd the
8
- // static-assets binding the mirror shells already deploy through. A pack that reads its tree
8
+ // static-assets binding. A pack that reads its tree
9
9
  // with Bun.file or import.meta is host-bound (R12b); one that reads through here is not.
10
- // No node builtins at module scope: `@volter/world-core`'s index re-exports this module and every mirror
11
- // client bundle (browser target) pulls the index in — a static `node:fs`/`node:url` import here
12
- // broke every mirror bundle the day the seam landed. The local store reads through Bun's file
10
+ // No node builtins at module scope: `@volter/world-core`'s index re-exports this module and a browser
11
+ // bundle pulls the index in, so a static `node:fs`/`node:url` import here would break it. The local store reads through Bun's file
13
12
  // API at call time; the worker store never touches a filesystem.
14
13
  import { existsSync, readFileSync, statSync } from 'node:fs';
15
14
  const CONTENT_TYPES = {
@@ -30,8 +29,7 @@ export function confinedAssetPath(relPath) {
30
29
  return null;
31
30
  return segs.join('/');
32
31
  }
33
- /** The Bun shell's store: the pack's own directory under the catalog (`packages/twin/<vendor>`).
34
- * `twinDir` ends with a slash. */
32
+ /** The host's store: a pack-directory resolver, or a catalog root ending in a slash. */
35
33
  export class LocalPackAssets {
36
34
  twinDir;
37
35
  constructor(twinDir) {
@@ -41,14 +39,17 @@ export class LocalPackAssets {
41
39
  const safe = confinedAssetPath(relPath);
42
40
  if (safe === null || !/^[a-z][a-z0-9-]*$/.test(vendor))
43
41
  return null;
44
- const file = `${this.twinDir}${vendor}/${safe}`; // confined: no `..`, no absolute, no empty segment (above)
42
+ const dir = typeof this.twinDir === 'string' ? `${this.twinDir}${vendor}` : await this.twinDir(vendor);
43
+ if (dir === undefined)
44
+ return null;
45
+ const file = `${dir}/${safe}`; // confined: no `..`, no absolute, no empty segment (above)
45
46
  if (!existsSync(file) || !statSync(file).isFile())
46
47
  return null;
47
48
  return new Response(readFileSync(file), { status: 200, headers: { 'content-type': assetContentType(safe) } });
48
49
  }
49
50
  }
50
51
  /** The workerd shell's store: the static-assets binding, where the deploy step places each
51
- * pack's declared assets under `/{vendor}/pack/<relPath>` beside the mirror shells. */
52
+ * pack's declared assets under `/{vendor}/pack/<relPath>`. */
52
53
  export class BindingPackAssets {
53
54
  assets;
54
55
  constructor(assets) {
@@ -68,7 +69,11 @@ let active;
68
69
  /** The bound store — the Bun shell's local tree unless a shell bound another. */
69
70
  export function getActivePackAssets() {
70
71
  if (active === undefined)
71
- active = new LocalPackAssets(new URL('../../twin/', import.meta.url).pathname);
72
+ active = new LocalPackAssets(async (vendor) => {
73
+ const { vendorPackageDir } = await import("./pack-paths.js");
74
+ const { fileURLToPath } = await import('node:url');
75
+ return vendorPackageDir(process.cwd(), vendor) ?? vendorPackageDir(fileURLToPath(new URL('.', import.meta.url)), vendor);
76
+ });
72
77
  return active;
73
78
  }
74
79
  export function setActivePackAssets(store) {
@@ -0,0 +1,77 @@
1
+ import { type DerivedManifest, type Handler, type HandlerContext, type VendorManifest } from './derived-core.js';
2
+ import { type DerivedFetch, type DerivedOwner, type DerivedSurface } from './derived.js';
3
+ import { type PackScenarioAdapter } from './scenario.js';
4
+ import { type SocketEngine } from './sockets.js';
5
+ import { type GraphqlPart } from './graphql-wire.js';
6
+ /** What a pack declares and writes, and nothing it assembles itself. */
7
+ export type PackParts = {
8
+ manifest: DerivedManifest;
9
+ surface: DerivedSurface;
10
+ /** `semantics/index.ts`: the handlers, by operationId. */
11
+ handlers?: Record<string, Handler>;
12
+ /** `semantics/doors.ts`: a door's answer, by the id the manifest's `doors` gives it. */
13
+ doors?: Record<string, Handler>;
14
+ /** Each `screens/<id>.tsx`'s answer, by the id the manifest's `screens` gives it. */
15
+ screens?: Record<string, Handler>;
16
+ /** `semantics/around.ts`: what the vendor does around every request to its API, one the surface names or not (a key
17
+ * checked, a plan's limits, a quota counted after a success), over a context whose operation is the request's (or
18
+ * `unmatched`); `next` answers the request itself, or the one it is given (the vendor's own rewrite of it: a query
19
+ * token moved to its header, a caller resolved into a header only the vendor's own front sets). */
20
+ around?: (ctx: HandlerContext, next: (request?: Request) => Promise<Response>) => Promise<Response>;
21
+ /** `semantics/clock.ts`: the vendor's own moves the World clock has made due, caught up before anything is answered.
22
+ * They are the vendor's, not the caller's: they land under a read-only request too. */
23
+ clock?: (ctx: HandlerContext) => Promise<void>;
24
+ /** `semantics/scenario.ts`: how the World's scenario decides a model vendor's turn — the operations it decides, the
25
+ * request each is as the scenario reads it, and the vendor's own matchers and fault body (the adapter). */
26
+ scenario?: PackScenario;
27
+ /** `semantics/gap.ts`: the vendor's answer for what it does not serve, where its manifest's `gap` cannot say it (Clerk's
28
+ * Frontend API: Go's plain-text 404 for a path it does not have, `signed_out` for an operation asked without a
29
+ * client), over a context whose operation is the one matched, or `unmatched`. */
30
+ gap?: (ctx: HandlerContext) => Response | Promise<Response>;
31
+ /** `semantics/tenant.ts`: the tenant the caller acts in, which the core scopes the manifest's `tenant` by. */
32
+ tenant?: (ctx: HandlerContext) => string | undefined | Promise<string | undefined>;
33
+ /** The vendor's lanes, by the name the manifest's `lanes` routes give them: each its own pack fetch and manifest. */
34
+ lanes?: Record<string, LanePart>;
35
+ /** `semantics/graphql.ts` with the vendor's schema (`generated/graphql-sdl.gen.json`): the GraphQL wire over the same
36
+ * state, served at the manifest's `graphql.paths` (graphql-wire.ts). */
37
+ graphql?: GraphqlPart<HandlerContext> & {
38
+ sdl: string;
39
+ };
40
+ /** `semantics/sockets.ts`: each socket's engine, by the id the manifest's `sockets` gives it (sockets.ts). */
41
+ sockets?: Record<string, SocketEngine<HandlerContext>>;
42
+ };
43
+ /** A pack's scenario (`semantics/scenario.ts` exports `scenario`): the adapter the kernel's engine reads the World's
44
+ * scenario document with, the operations it decides a turn of, and the request an operation is to it (undefined when
45
+ * the request is not one it decides: the handler answers the vendor's refusal). */
46
+ export type PackScenario<Req = any> = {
47
+ adapter: PackScenarioAdapter<Req>;
48
+ operations: ReadonlyArray<string>;
49
+ request: (ctx: HandlerContext) => Req | undefined;
50
+ };
51
+ /** A lane as its vendor's fetch is given it: its own pack fetch, and its manifest (the doors it declares). */
52
+ export type LanePart = {
53
+ fetch: ((request: Request) => Promise<Response>) & {
54
+ serves?: (method: string, path: string) => boolean;
55
+ };
56
+ manifest: {
57
+ doors?: ReadonlyArray<{
58
+ method: string;
59
+ path: string;
60
+ }>;
61
+ };
62
+ };
63
+ /** Where a pack serves: its World's root, whether it was started read-only, the World instant when a caller pins it, the
64
+ * World's managed Postgres the runtime binds a pack declaring `managedDatabase` to (a handler's `ctx.engine`), and the
65
+ * World's scenario file for a model vendor's turns (`scenarioPath`, the runtime's `--scenario`). */
66
+ export type PackFetchOptions = {
67
+ root?: string;
68
+ readOnly?: boolean;
69
+ clock?: () => string;
70
+ database?: string;
71
+ scenarioPath?: string;
72
+ };
73
+ /** A pack's HTTP surface, as the kernel serves it from the pack's parts. */
74
+ export declare function createPackFetch(parts: PackParts, options?: PackFetchOptions): DerivedFetch;
75
+ export declare function createVendorFetch(manifest: VendorManifest, lanes: Record<string, LanePart>): ((request: Request) => Promise<Response>) & {
76
+ owners: () => Record<string, DerivedOwner>;
77
+ };