theorum 0.1.14 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/README.md +178 -89
  2. package/esm/mod.d.ts +21 -11
  3. package/esm/mod.js +15 -8
  4. package/esm/src/cli/commands/bench.js +6 -3
  5. package/esm/src/cli/commands/fuzz-canary.d.ts +13 -0
  6. package/esm/src/cli/commands/fuzz-canary.js +195 -0
  7. package/esm/src/cli/commands/fuzz-guardrails.d.ts +3 -5
  8. package/esm/src/cli/commands/fuzz-guardrails.js +4 -581
  9. package/esm/src/cli/commands/profile.js +25 -14
  10. package/esm/src/cli/commands/run.d.ts +3 -0
  11. package/esm/src/cli/commands/run.js +22 -30
  12. package/esm/src/cli/commands/test.d.ts +10 -1
  13. package/esm/src/cli/commands/test.js +31 -31
  14. package/esm/src/cli/event-log.d.ts +19 -0
  15. package/esm/src/cli/event-log.js +147 -0
  16. package/esm/src/cli/index.js +45 -11
  17. package/esm/src/cli/matrix/synthesizer.d.ts +7 -9
  18. package/esm/src/cli/matrix/synthesizer.js +32 -106
  19. package/esm/src/guardrails/canary-gate.d.ts +20 -0
  20. package/esm/src/guardrails/canary-gate.js +31 -0
  21. package/esm/src/guardrails/canary.d.ts +26 -0
  22. package/esm/src/guardrails/canary.js +139 -0
  23. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +16 -0
  24. package/esm/src/guardrails/corpus/canary-egress-attacks.js +151 -0
  25. package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +11 -0
  26. package/esm/src/guardrails/corpus/fuzz-inbound.js +216 -0
  27. package/esm/src/guardrails/corpus/inbound-payloads.d.ts +10 -0
  28. package/esm/src/guardrails/corpus/inbound-payloads.js +124 -0
  29. package/esm/src/guardrails/corpus/live-attacks.d.ts +20 -0
  30. package/esm/src/guardrails/corpus/live-attacks.js +232 -0
  31. package/esm/src/guardrails/corpus/mod.d.ts +13 -0
  32. package/esm/src/guardrails/corpus/mod.js +11 -0
  33. package/esm/src/guardrails/corpus/secrets.d.ts +16 -0
  34. package/esm/src/guardrails/corpus/secrets.js +16 -0
  35. package/esm/src/guardrails/corpus/strings.d.ts +27 -0
  36. package/esm/src/guardrails/corpus/strings.js +33 -0
  37. package/esm/src/guardrails/corpus/types.d.ts +37 -0
  38. package/esm/src/guardrails/corpus/types.js +6 -0
  39. package/esm/src/guardrails/egress.d.ts +9 -0
  40. package/esm/src/guardrails/egress.js +36 -0
  41. package/esm/src/guardrails/error.js +6 -4
  42. package/esm/src/guardrails/injection.js +28 -5
  43. package/esm/src/guardrails/live-outbound-gate.d.ts +39 -0
  44. package/esm/src/guardrails/live-outbound-gate.js +180 -0
  45. package/esm/src/guardrails/mod.d.ts +13 -4
  46. package/esm/src/guardrails/mod.js +10 -4
  47. package/esm/src/guardrails/quota.js +1 -1
  48. package/esm/src/guardrails/sanitize.d.ts +11 -15
  49. package/esm/src/guardrails/sanitize.js +40 -49
  50. package/esm/src/guardrails/sensitive.js +2 -1
  51. package/esm/src/guardrails/testing.d.ts +10 -0
  52. package/esm/src/guardrails/testing.js +9 -0
  53. package/esm/src/host/client-turn.d.ts +19 -0
  54. package/esm/src/host/client-turn.js +32 -0
  55. package/esm/src/host/mod.d.ts +5 -3
  56. package/esm/src/host/mod.js +4 -3
  57. package/esm/src/interface/blocks.d.ts +20 -0
  58. package/esm/src/interface/blocks.js +180 -0
  59. package/esm/src/interface/from-profile.d.ts +14 -0
  60. package/esm/src/interface/from-profile.js +104 -0
  61. package/esm/src/interface/inputs.d.ts +8 -0
  62. package/esm/src/interface/inputs.js +127 -0
  63. package/esm/src/interface/mod.d.ts +10 -0
  64. package/esm/src/interface/mod.js +9 -0
  65. package/esm/src/interface/types.d.ts +153 -0
  66. package/esm/src/interface/types.js +13 -0
  67. package/esm/src/kernel/engine/delta.d.ts +24 -2
  68. package/esm/src/kernel/engine/delta.js +519 -29
  69. package/esm/src/kernel/engine/live-inbound.d.ts +9 -0
  70. package/esm/src/kernel/engine/live-inbound.js +17 -0
  71. package/esm/src/kernel/engine/repair.js +1 -1
  72. package/esm/src/kernel/engine/runner/gates.d.ts +1 -1
  73. package/esm/src/kernel/engine/runner/gates.js +7 -7
  74. package/esm/src/kernel/engine/runner/mod.js +13 -13
  75. package/esm/src/kernel/engine/runner/state.d.ts +7 -0
  76. package/esm/src/kernel/engine/runner/steps.d.ts +1 -1
  77. package/esm/src/kernel/engine/runner/steps.js +171 -37
  78. package/esm/src/kernel/engine/runner/stream.d.ts +1 -2
  79. package/esm/src/kernel/engine/runner/stream.js +66 -29
  80. package/esm/src/kernel/engine/session/mod.d.ts +23 -0
  81. package/esm/src/kernel/engine/session/mod.js +205 -0
  82. package/esm/src/kernel/mod.d.ts +9 -10
  83. package/esm/src/kernel/mod.js +6 -8
  84. package/esm/src/kernel/registry/attachments.d.ts +4 -2
  85. package/esm/src/kernel/registry/attachments.js +6 -3
  86. package/esm/src/kernel/registry/catalog.d.ts +3 -16
  87. package/esm/src/kernel/registry/catalog.js +5 -81
  88. package/esm/src/kernel/registry/ingress.d.ts +9 -4
  89. package/esm/src/kernel/registry/ingress.js +73 -63
  90. package/esm/src/kernel/registry/profiles.d.ts +35 -12
  91. package/esm/src/kernel/registry/profiles.js +159 -66
  92. package/esm/src/kernel/registry/provider-request.js +11 -7
  93. package/esm/src/kernel/registry/resolve.d.ts +5 -6
  94. package/esm/src/kernel/registry/resolve.js +100 -70
  95. package/esm/src/kernel/registry/vault.d.ts +12 -7
  96. package/esm/src/kernel/registry/vault.js +30 -8
  97. package/esm/src/kernel/schema.d.ts +145 -0
  98. package/esm/src/kernel/schema.js +462 -0
  99. package/esm/src/kernel/stop.d.ts +15 -10
  100. package/esm/src/kernel/stop.js +5 -5
  101. package/esm/src/kernel/tools/execute.d.ts +45 -0
  102. package/esm/src/kernel/tools/execute.js +363 -0
  103. package/esm/src/kernel/tools/harness.d.ts +8 -0
  104. package/esm/src/kernel/tools/harness.js +44 -0
  105. package/esm/src/kernel/tools/invoke.d.ts +10 -0
  106. package/esm/src/kernel/tools/invoke.js +83 -0
  107. package/esm/src/kernel/tools/mod.d.ts +11 -0
  108. package/esm/src/kernel/tools/mod.js +10 -0
  109. package/esm/src/kernel/tools/project.d.ts +12 -0
  110. package/esm/src/kernel/tools/project.js +34 -0
  111. package/esm/src/kernel/tools/registry.d.ts +23 -0
  112. package/esm/src/kernel/tools/registry.js +71 -0
  113. package/esm/src/kernel/tools/resolve.d.ts +29 -0
  114. package/esm/src/kernel/tools/resolve.js +262 -0
  115. package/esm/src/kernel/tools/schema.d.ts +13 -0
  116. package/esm/src/kernel/tools/schema.js +159 -0
  117. package/esm/src/kernel/tools/types.d.ts +216 -0
  118. package/esm/src/kernel/tools/types.js +9 -0
  119. package/esm/src/kernel/types.d.ts +338 -193
  120. package/esm/src/observability/trace-attach.d.ts +6 -4
  121. package/esm/src/observability/trace-attach.js +39 -25
  122. package/esm/src/observability/trace-record.d.ts +11 -9
  123. package/esm/src/observability/trace-record.js +36 -23
  124. package/esm/src/observability/trace-usage.d.ts +10 -3
  125. package/esm/src/observability/trace-usage.js +70 -17
  126. package/esm/src/observability/trace.d.ts +9 -1
  127. package/esm/src/observability/trace.js +11 -3
  128. package/esm/src/presets/google/speech-voices.d.ts +11 -0
  129. package/esm/src/presets/google/speech-voices.js +41 -0
  130. package/esm/src/presets/google.d.ts +36 -24
  131. package/esm/src/presets/google.js +50 -63
  132. package/esm/src/presets/mod.d.ts +2 -2
  133. package/esm/src/presets/mod.js +1 -1
  134. package/esm/src/providers/create-provider.d.ts +14 -14
  135. package/esm/src/providers/create-provider.js +55 -23
  136. package/esm/src/providers/google/interactions/framing.d.ts +15 -0
  137. package/esm/src/providers/google/interactions/framing.js +208 -0
  138. package/esm/src/providers/google/interactions/mod.d.ts +7 -0
  139. package/esm/src/providers/google/interactions/mod.js +7 -0
  140. package/esm/src/providers/google/interactions/stream.d.ts +83 -0
  141. package/esm/src/providers/google/interactions/stream.js +588 -0
  142. package/esm/src/providers/google/keys.d.ts +26 -0
  143. package/esm/src/providers/{keys.js → google/keys.js} +19 -31
  144. package/esm/src/providers/google/live/framing.d.ts +46 -0
  145. package/esm/src/providers/google/live/framing.js +515 -0
  146. package/esm/src/providers/google/live/openapi-schema.d.ts +6 -0
  147. package/esm/src/providers/google/live/openapi-schema.js +45 -0
  148. package/esm/src/providers/google/live/session.d.ts +25 -0
  149. package/esm/src/providers/google/live/session.js +134 -0
  150. package/esm/src/providers/google/live/stream.d.ts +36 -0
  151. package/esm/src/providers/google/live/stream.js +201 -0
  152. package/esm/src/providers/google/urls.d.ts +6 -0
  153. package/esm/src/providers/google/urls.js +6 -0
  154. package/esm/src/providers/local/local.d.ts +30 -0
  155. package/esm/src/providers/{local.js → local/local.js} +66 -126
  156. package/esm/src/providers/local/mod.d.ts +9 -0
  157. package/esm/src/providers/local/mod.js +9 -0
  158. package/esm/src/providers/mod.d.ts +6 -3
  159. package/esm/src/providers/mod.js +3 -1
  160. package/esm/src/providers/openrouter/chat.d.ts +87 -0
  161. package/esm/src/providers/{openrouter.js → openrouter/chat.js} +70 -229
  162. package/esm/src/providers/openrouter/image.d.ts +34 -0
  163. package/esm/src/providers/openrouter/image.js +286 -0
  164. package/esm/src/providers/openrouter/openai/chat-payload.d.ts +24 -0
  165. package/esm/src/providers/openrouter/openai/chat-payload.js +60 -0
  166. package/esm/src/providers/openrouter/openai/compat.d.ts +47 -0
  167. package/esm/src/providers/openrouter/openai/compat.js +194 -0
  168. package/esm/src/providers/openrouter/openai/image-payload.d.ts +18 -0
  169. package/esm/src/providers/openrouter/openai/image-payload.js +84 -0
  170. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +22 -0
  171. package/esm/src/providers/openrouter/openai/sdk-messages.js +95 -0
  172. package/esm/src/providers/openrouter/resolve-api-key.d.ts +9 -0
  173. package/esm/src/providers/openrouter/resolve-api-key.js +24 -0
  174. package/esm/src/providers/openrouter/speech.d.ts +23 -0
  175. package/esm/src/providers/{speech.js → openrouter/speech.js} +32 -55
  176. package/esm/src/providers/probe.d.ts +1 -0
  177. package/esm/src/providers/probe.js +22 -0
  178. package/esm/src/providers/shared/pcm.d.ts +12 -0
  179. package/esm/src/providers/{pcm.js → shared/pcm.js} +16 -3
  180. package/esm/src/providers/shared/sse.d.ts +18 -0
  181. package/esm/src/providers/shared/sse.js +87 -0
  182. package/esm/src/providers/shared/tool-args.d.ts +17 -0
  183. package/esm/src/providers/shared/tool-args.js +45 -0
  184. package/esm/src/providers/shared/upstream-tap.d.ts +5 -0
  185. package/esm/src/providers/{google-tap.js → shared/upstream-tap.js} +4 -7
  186. package/esm/src/providers/shared/upstream-tape.d.ts +6 -0
  187. package/esm/src/providers/{gemini-tape.js → shared/upstream-tape.js} +12 -22
  188. package/esm/src/providers/types.d.ts +27 -0
  189. package/esm/src/providers/types.js +1 -0
  190. package/package.json +11 -7
  191. package/docs/cli.md +0 -97
  192. package/docs/guardrails.md +0 -178
  193. package/docs/host.md +0 -97
  194. package/docs/kernel.md +0 -404
  195. package/docs/observability.md +0 -105
  196. package/docs/openrouter.md +0 -125
  197. package/docs/presets-google.md +0 -91
  198. package/docs/presets.md +0 -88
  199. package/docs/providers.md +0 -201
  200. package/docs/streaming.md +0 -96
  201. package/esm/src/kernel/engine/boundary.d.ts +0 -10
  202. package/esm/src/kernel/engine/boundary.js +0 -55
  203. package/esm/src/kernel/engine/runner/tools.d.ts +0 -13
  204. package/esm/src/kernel/engine/runner/tools.js +0 -198
  205. package/esm/src/kernel/registry/tools.d.ts +0 -12
  206. package/esm/src/kernel/registry/tools.js +0 -36
  207. package/esm/src/providers/expose-for-tests.d.ts +0 -1
  208. package/esm/src/providers/expose-for-tests.js +0 -25
  209. package/esm/src/providers/gemini-tape.d.ts +0 -2
  210. package/esm/src/providers/google-tap.d.ts +0 -3
  211. package/esm/src/providers/interactions.d.ts +0 -5
  212. package/esm/src/providers/interactions.js +0 -169
  213. package/esm/src/providers/keys.d.ts +0 -19
  214. package/esm/src/providers/local.d.ts +0 -29
  215. package/esm/src/providers/openrouter-mod.d.ts +0 -13
  216. package/esm/src/providers/openrouter-mod.js +0 -12
  217. package/esm/src/providers/openrouter-payload.d.ts +0 -39
  218. package/esm/src/providers/openrouter-payload.js +0 -195
  219. package/esm/src/providers/openrouter.d.ts +0 -15
  220. package/esm/src/providers/pcm.d.ts +0 -7
  221. package/esm/src/providers/provider.d.ts +0 -15
  222. package/esm/src/providers/provider.js +0 -176
  223. package/esm/src/providers/speech.d.ts +0 -23
  224. package/esm/src/providers/sse.d.ts +0 -7
  225. package/esm/src/providers/sse.js +0 -55
  226. package/esm/src/streaming/mod.d.ts +0 -9
  227. package/esm/src/streaming/mod.js +0 -8
  228. /package/esm/src/{streaming → host}/readStreamingJsonStringField.d.ts +0 -0
  229. /package/esm/src/{streaming → host}/readStreamingJsonStringField.js +0 -0
@@ -1,16 +1,18 @@
1
- import type { ResolvedGeneration, TurnRequest } from '../kernel/types.js';
1
+ import type { Protocol } from '../kernel/schema.js';
2
+ import type { ResolvedGeneration, TurnEvent, TurnRequest } from '../kernel/types.js';
2
3
  import type { TraceRecord } from './trace-record.js';
3
4
  declare function attachResolved(record: TraceRecord, args: {
4
5
  safe: TurnRequest;
5
6
  model?: string;
6
- bucket?: string;
7
+ keySlot?: string;
7
8
  generation?: ResolvedGeneration;
8
9
  }): void;
9
10
  declare function attachTape(record: TraceRecord, args: {
10
- gemini?: unknown;
11
+ upstream?: unknown;
11
12
  canary?: string;
12
13
  system?: string;
13
14
  generation?: ResolvedGeneration;
15
+ protocol?: Protocol;
14
16
  }): Promise<void>;
15
- declare function attachUsage(record: TraceRecord, gemini: unknown, done: Record<string, unknown> | undefined): void;
17
+ declare function attachUsage(record: TraceRecord, upstream: unknown, done: Record<string, unknown> | undefined, events?: TurnEvent[]): void;
16
18
  export { attachResolved, attachTape, attachUsage };
@@ -1,9 +1,8 @@
1
1
  import { providerCompleteRequest } from '../kernel/registry/provider-request.js';
2
- import { tapeGemini } from '../providers/gemini-tape.js';
3
- import { toInteractionsBody } from '../providers/interactions.js';
4
- import { httpStatus } from './trace-usage.js';
2
+ import { tapeUpstream } from '../providers/shared/upstream-tape.js';
3
+ import { httpStatus, openAiFinishReason, tokensFromEvents } from './trace-usage.js';
5
4
  function attachResolved(record, args) {
6
- const { safe, model, bucket, generation } = args;
5
+ const { safe, model, keySlot, generation } = args;
7
6
  if (safe.projectId) {
8
7
  record.projectId = safe.projectId;
9
8
  }
@@ -13,9 +12,6 @@ function attachResolved(record, args) {
13
12
  if (safe.thinking !== undefined) {
14
13
  record.thinking = safe.thinking;
15
14
  }
16
- if (safe.tools) {
17
- record.tools = safe.tools;
18
- }
19
15
  if (safe.metadata) {
20
16
  record.metadata = safe.metadata;
21
17
  }
@@ -25,43 +21,61 @@ function attachResolved(record, args) {
25
21
  apiId: generation?.apiId ?? model,
26
22
  };
27
23
  }
28
- if (bucket) {
29
- record.bucket = bucket;
24
+ if (keySlot) {
25
+ record.keySlot = keySlot;
30
26
  }
31
27
  if (generation) {
32
- record.generation = {
28
+ const traceGeneration = {
33
29
  thinking: generation.thinking,
34
30
  summaries: generation.summaries,
35
31
  temperature: generation.temperature,
36
32
  maxOutputTokens: generation.maxOutputTokens,
37
33
  builtins: generation.builtins,
38
- custom: generation.custom,
34
+ visibleTools: generation.tools.visible,
39
35
  structured: generation.structured,
40
36
  image: generation.image,
41
37
  };
38
+ record.generation = traceGeneration;
42
39
  }
43
40
  }
44
41
  async function attachTape(record, args) {
45
- const { gemini, canary, system, generation } = args;
46
- if (gemini !== undefined) {
47
- record.gemini = await tapeGemini(gemini, canary ?? '');
42
+ const { upstream, canary, system, generation, protocol } = args;
43
+ if (upstream !== undefined) {
44
+ record.upstreamLog = await tapeUpstream(upstream, canary ?? '');
48
45
  }
49
- if (generation && system !== undefined) {
50
- record.wire = await tapeGemini(toInteractionsBody(providerCompleteRequest(generation, system)), canary ?? '');
46
+ if (generation && system !== undefined && protocol === 'geminiInteractions') {
47
+ const { toInteractionsBody } = await import('../providers/google/interactions/framing.js');
48
+ record.wire = await tapeUpstream(toInteractionsBody(providerCompleteRequest(generation, system)), canary ?? '');
51
49
  }
52
50
  }
53
- function attachUsage(record, gemini, done) {
51
+ function attachUsageTokens(record, done, events) {
54
52
  if (done?.usage !== undefined) {
55
53
  record.usage = done.usage;
54
+ return;
56
55
  }
57
- const upStatus = httpStatus(gemini);
58
- if (upStatus !== undefined || done) {
59
- record.upstream = {
60
- status: upStatus,
61
- id: done?.id,
62
- finish: done?.status,
63
- serviceTier: done?.service_tier ?? done?.serviceTier,
64
- };
56
+ if (!events) {
57
+ return;
58
+ }
59
+ const tokens = tokensFromEvents(events);
60
+ if (tokens) {
61
+ record.usage = tokens;
65
62
  }
66
63
  }
64
+ function attachUpstreamSummary(record, upstream, done) {
65
+ const upStatus = httpStatus(upstream);
66
+ const finishReason = openAiFinishReason(upstream);
67
+ if (upStatus === undefined && !done && finishReason === undefined) {
68
+ return;
69
+ }
70
+ record.upstream = {
71
+ status: upStatus,
72
+ id: done?.id,
73
+ finish: done?.status ?? finishReason,
74
+ serviceTier: done?.service_tier ?? done?.serviceTier,
75
+ };
76
+ }
77
+ function attachUsage(record, upstream, done, events) {
78
+ attachUsageTokens(record, done, events);
79
+ attachUpstreamSummary(record, upstream, done);
80
+ }
67
81
  export { attachResolved, attachTape, attachUsage };
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @module
8
8
  */
9
+ import type { Protocol } from '../kernel/schema.js';
9
10
  import type { ResolvedGeneration, TurnEvent, TurnRequest } from '../kernel/types.js';
10
11
  /** Hash-only image reference stored in trace records. */
11
12
  export interface TraceImage {
@@ -47,20 +48,19 @@ interface TraceRecord {
47
48
  projectId?: string;
48
49
  select?: string;
49
50
  thinking?: boolean;
50
- tools?: TurnRequest['tools'];
51
51
  metadata?: Record<string, unknown>;
52
52
  model?: {
53
53
  id: string;
54
54
  apiId: string;
55
55
  };
56
- bucket?: string;
56
+ keySlot?: string;
57
57
  generation?: {
58
58
  thinking: string;
59
- summaries: string;
60
- temperature: number;
61
- maxOutputTokens: number;
59
+ summaries?: string;
60
+ temperature?: number;
61
+ maxOutputTokens?: number;
62
62
  builtins: string[];
63
- custom: string[];
63
+ visibleTools: string[];
64
64
  structured: string | null;
65
65
  image: unknown;
66
66
  };
@@ -75,7 +75,8 @@ interface TraceRecord {
75
75
  };
76
76
  wire?: unknown;
77
77
  events: TraceEvent[];
78
- gemini?: unknown;
78
+ /** Raw upstream tap rows (HTTP, SSE, provider events). */
79
+ upstreamLog?: unknown;
79
80
  usage?: unknown;
80
81
  upstream?: {
81
82
  status?: unknown;
@@ -102,12 +103,13 @@ declare function buildRecord(args: {
102
103
  events: TurnEvent[];
103
104
  started: number;
104
105
  model?: string;
105
- bucket?: string;
106
+ keySlot?: string;
106
107
  thrown?: unknown;
107
- gemini?: unknown;
108
+ upstreamLog?: unknown;
108
109
  canary?: string;
109
110
  system?: string;
110
111
  generation?: ResolvedGeneration;
112
+ protocol?: Protocol;
111
113
  sanitizedReq?: TurnRequest;
112
114
  }): Promise<TraceRecord>;
113
115
  export type { TraceRecord };
@@ -6,12 +6,12 @@
6
6
  *
7
7
  * @module
8
8
  */
9
+ import { OMIT_CANARY } from '../guardrails/canary.js';
9
10
  import { isAbortError, publicError } from '../guardrails/error.js';
10
- import { redactSensitiveOnly, sanitizeText, sanitizeTurnRequest } from '../guardrails/sanitize.js';
11
- import { OMIT_CANARY } from '../kernel/engine/boundary.js';
11
+ import { redactSensitiveOnly, sanitizeText, sanitizeTurnRequestForTrace, } from '../guardrails/sanitize.js';
12
12
  import { sha256 } from '../kernel/engine/hash.js';
13
13
  import { attachResolved, attachTape, attachUsage } from './trace-attach.js';
14
- import { completedInteraction } from './trace-usage.js';
14
+ import { completedInteraction, stopKindFromEvents } from './trace-usage.js';
15
15
  const TRACE_VERSION = 2;
16
16
  const TITLE_MAX = 80;
17
17
  function hashBlobs(blobs) {
@@ -38,13 +38,22 @@ async function snapshotEvent(event) {
38
38
  row.structured = event.structured;
39
39
  }
40
40
  if (event.tool) {
41
- const { name, arguments: args, result } = event.tool;
41
+ const { name, arguments: args, output, phase, failure } = event.tool;
42
42
  row.tool = { name, arguments: args };
43
- if (result) {
43
+ if (output !== undefined && phase === 'complete') {
44
+ const data = typeof output === 'object' && output !== null
45
+ ? output
46
+ : { value: output };
44
47
  row.tool.result = {
45
- status: result.status,
46
- ...(result.finding ? { finding: result.finding } : {}),
47
- ...(result.data ? { data: result.data } : {}),
48
+ status: 'ok',
49
+ ...(typeof data.finding === 'string' ? { finding: data.finding } : {}),
50
+ data,
51
+ };
52
+ }
53
+ else if (phase === 'error' && failure) {
54
+ row.tool.result = {
55
+ status: 'error',
56
+ finding: failure.message,
48
57
  };
49
58
  }
50
59
  }
@@ -63,12 +72,7 @@ async function snapshotEvent(event) {
63
72
  return row;
64
73
  }
65
74
  function requestForTrace(req) {
66
- try {
67
- return sanitizeTurnRequest(req);
68
- }
69
- catch {
70
- return { profile: req.profile, input: {} };
71
- }
75
+ return sanitizeTurnRequestForTrace(req);
72
76
  }
73
77
  function internalError(err) {
74
78
  if (typeof err === 'string') {
@@ -102,22 +106,28 @@ function attachFailure(record, thrown, lastErr, canary) {
102
106
  }
103
107
  }
104
108
  async function buildRecord(args) {
105
- const { req, events, started, model, bucket, thrown, gemini, canary, system, generation } = args;
106
- const safe = args.sanitizedReq ?? requestForTrace(req);
109
+ const { req, events, started, model, keySlot, thrown, upstreamLog, canary, system, generation } = args;
110
+ const protocol = args.protocol;
111
+ const traced = args.sanitizedReq ? { request: args.sanitizedReq } : requestForTrace(req);
112
+ const safe = traced.request;
107
113
  const input = safe.input ?? {};
108
114
  const snapped = await Promise.all(events.map((event) => snapshotEvent(event)));
109
115
  const lastErr = [...snapped].reverse().find((row) => row.type === 'error');
110
- const done = completedInteraction(gemini);
111
- const status = done?.status;
112
116
  const aborted = isAbortError(thrown);
113
- const ok = !(thrown || lastErr) && status !== 'cancelled' && !aborted;
117
+ const stopKind = stopKindFromEvents(events);
118
+ const done = completedInteraction(upstreamLog);
119
+ const interactionStatus = done?.status;
120
+ const cancelled = aborted ||
121
+ stopKind === 'cancelled' ||
122
+ (protocol === 'geminiInteractions' && interactionStatus === 'cancelled');
123
+ const ok = !(thrown || lastErr) && !cancelled;
114
124
  const record = {
115
125
  v: TRACE_VERSION,
116
126
  id: crypto.randomUUID(),
117
127
  ts: started,
118
128
  ms: Date.now() - started,
119
129
  streamed: true,
120
- cancelled: status === 'cancelled' || aborted,
130
+ cancelled,
121
131
  previousInteractionId: safe.previousInteractionId ?? null,
122
132
  store: safe.store ?? null,
123
133
  profile: safe.profile,
@@ -135,10 +145,13 @@ async function buildRecord(args) {
135
145
  if (title) {
136
146
  record.title = title;
137
147
  }
138
- await attachTape(record, { gemini, canary, system, generation });
139
- attachUsage(record, gemini, done);
140
- attachResolved(record, { safe, model, bucket, generation });
148
+ await attachTape(record, { upstream: upstreamLog, canary, system, generation, protocol });
149
+ attachUsage(record, upstreamLog, done, events);
150
+ attachResolved(record, { safe, model, keySlot, generation });
141
151
  attachFailure(record, thrown, lastErr, canary);
152
+ if (traced.sanitizeError && !record.errorInternal) {
153
+ record.errorInternal = sanitizeText(`request sanitize for trace failed: ${traced.sanitizeError}`);
154
+ }
142
155
  return record;
143
156
  }
144
157
  export { buildRecord };
@@ -1,3 +1,10 @@
1
- declare function completedInteraction(gemini: unknown): Record<string, unknown> | undefined;
2
- declare function httpStatus(gemini: unknown): unknown;
3
- export { completedInteraction, httpStatus };
1
+ import type { TurnEvent, TurnTokens } from '../kernel/types.js';
2
+ declare function completedInteraction(upstream: unknown): Record<string, unknown> | undefined;
3
+ /** Extract the terminal stop kind from the TurnEvent stream (protocol-agnostic). */
4
+ declare function stopKindFromEvents(events: TurnEvent[]): string | undefined;
5
+ /** Extract the last tokens snapshot from the TurnEvent stream. */
6
+ declare function tokensFromEvents(events: TurnEvent[]): TurnTokens | undefined;
7
+ /** Extract finish_reason from OpenAI-compat upstream tap rows. */
8
+ declare function openAiFinishReason(upstream: unknown): string | undefined;
9
+ declare function httpStatus(upstream: unknown): unknown;
10
+ export { completedInteraction, httpStatus, openAiFinishReason, stopKindFromEvents, tokensFromEvents, };
@@ -2,31 +2,84 @@ import { asRecord } from '../kernel/engine/record.js';
2
2
  function eventName(row) {
3
3
  return String(row.event_type ?? row.eventType ?? '');
4
4
  }
5
- function completedInteraction(gemini) {
6
- if (!Array.isArray(gemini)) {
7
- return undefined;
5
+ function upstreamRows(upstream) {
6
+ if (!Array.isArray(upstream)) {
7
+ return [];
8
8
  }
9
- for (let i = gemini.length - 1; i >= 0; i -= 1) {
10
- const row = asRecord(gemini[i]);
11
- if (row) {
12
- const name = eventName(row);
13
- if (name === 'interaction.completed' || name === 'interaction.complete') {
14
- return asRecord(row.interaction) ?? row;
15
- }
9
+ return upstream
10
+ .map((item) => asRecord(item))
11
+ .filter((row) => row != null);
12
+ }
13
+ function lastUpstreamRow(upstream, pred) {
14
+ const rows = upstreamRows(upstream);
15
+ for (let i = rows.length - 1; i >= 0; i -= 1) {
16
+ if (pred(rows[i])) {
17
+ return rows[i];
18
+ }
19
+ }
20
+ return undefined;
21
+ }
22
+ function firstUpstreamRow(upstream, pred) {
23
+ for (const row of upstreamRows(upstream)) {
24
+ if (pred(row)) {
25
+ return row;
16
26
  }
17
27
  }
18
28
  return undefined;
19
29
  }
20
- function httpStatus(gemini) {
21
- if (!Array.isArray(gemini)) {
30
+ function completedInteraction(upstream) {
31
+ const row = lastUpstreamRow(upstream, (r) => {
32
+ const name = eventName(r);
33
+ return name === 'interaction.completed' || name === 'interaction.complete';
34
+ });
35
+ return row ? (asRecord(row.interaction) ?? row) : undefined;
36
+ }
37
+ /** Extract the terminal stop kind from the TurnEvent stream (protocol-agnostic). */
38
+ function stopKindFromEvents(events) {
39
+ for (let i = events.length - 1; i >= 0; i -= 1) {
40
+ const ev = events[i];
41
+ if (ev?.type === 'done' && ev.stop) {
42
+ return ev.stop.kind;
43
+ }
44
+ }
45
+ return undefined;
46
+ }
47
+ /** Extract the last tokens snapshot from the TurnEvent stream. */
48
+ function tokensFromEvents(events) {
49
+ for (let i = events.length - 1; i >= 0; i -= 1) {
50
+ const ev = events[i];
51
+ if (ev?.type === 'tokens' && ev.tokens) {
52
+ return ev.tokens;
53
+ }
54
+ }
55
+ return undefined;
56
+ }
57
+ /** Extract finish_reason from OpenAI-compat upstream tap rows. */
58
+ function openAiFinishReason(upstream) {
59
+ const row = lastUpstreamRow(upstream, (r) => {
60
+ const choices = r.choices;
61
+ if (!Array.isArray(choices)) {
62
+ return false;
63
+ }
64
+ return choices.some((choice) => asRecord(choice)?.finish_reason != null);
65
+ });
66
+ if (!row) {
67
+ return undefined;
68
+ }
69
+ const choices = row.choices;
70
+ if (!Array.isArray(choices)) {
22
71
  return undefined;
23
72
  }
24
- for (const item of gemini) {
25
- const row = asRecord(item);
26
- if (row && eventName(row) === 'http_response') {
27
- return row.status;
73
+ for (const choice of choices) {
74
+ const c = asRecord(choice);
75
+ if (c?.finish_reason != null) {
76
+ return String(c.finish_reason);
28
77
  }
29
78
  }
30
79
  return undefined;
31
80
  }
32
- export { completedInteraction, httpStatus };
81
+ function httpStatus(upstream) {
82
+ const row = firstUpstreamRow(upstream, (r) => eventName(r) === 'http_response');
83
+ return row?.status;
84
+ }
85
+ export { completedInteraction, httpStatus, openAiFinishReason, stopKindFromEvents, tokensFromEvents, };
@@ -2,8 +2,16 @@ import type { TraceRecord } from './trace-record.js';
2
2
  /** Minimal async destination for completed turn trace records. */
3
3
  interface TraceSink {
4
4
  write: (record: TraceRecord) => Promise<void>;
5
+ /**
6
+ * Optional host hook when `writeTrace` catches record-build or write failures.
7
+ * Must not throw; tracing never fails the turn.
8
+ */
9
+ onError?: (err: unknown) => void;
5
10
  }
6
- /** Write a trace record without allowing trace failures to fail the turn. */
11
+ /**
12
+ * Write a trace record without allowing trace failures to fail the turn.
13
+ * Build/write errors are forwarded to `sink.onError` when provided.
14
+ */
7
15
  declare function writeTrace(sink: TraceSink, record: Promise<TraceRecord>): Promise<void>;
8
16
  /** Trace sink that drops records. */
9
17
  declare function noopSink(): TraceSink;
@@ -19,13 +19,21 @@ const MIB = KIB * KIB;
19
19
  const ROTATE_MIB = 32;
20
20
  const ROTATE_BYTES = ROTATE_MIB * MIB;
21
21
  const FILE_DAY = /^turns-(\d{4}-\d{2}-\d{2})(?:-\d+)?\.jsonl$/;
22
- /** Write a trace record without allowing trace failures to fail the turn. */
22
+ /**
23
+ * Write a trace record without allowing trace failures to fail the turn.
24
+ * Build/write errors are forwarded to `sink.onError` when provided.
25
+ */
23
26
  async function writeTrace(sink, record) {
24
27
  try {
25
28
  await sink.write(await record);
26
29
  }
27
- catch {
28
- // Tracing must not fail the turn.
30
+ catch (err) {
31
+ try {
32
+ sink.onError?.(err);
33
+ }
34
+ catch {
35
+ // Host onError must not fail the turn.
36
+ }
29
37
  }
30
38
  }
31
39
  /** Trace sink that drops records. */
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Google Gemini TTS voice names for `speech.voice`.
3
+ *
4
+ * Standalone preset vocabulary — no kernel registry imports so docs UIs can
5
+ * import this file without pulling provider wiring.
6
+ *
7
+ * @module
8
+ */
9
+ /** Common Gemini TTS voice names. */
10
+ export declare const GOOGLE_SPEECH_VOICES: readonly ["Zephyr", "Puck", "Charon", "Kore", "Fenrir", "Leda", "Orus", "Aoede", "Callirrhoe", "Autonoe", "Enceladus", "Iapetus", "Umbriel", "Algieba", "Despina", "Erinome", "Algenib", "Rasalgethi", "Laomedeia", "Achernar", "Alnilam", "Schedar", "Gacrux", "Pulcherrima", "Achird", "Zubenelgenubi", "Vindemiatrix", "Sadachbia", "Sadaltager", "Sulafat"];
11
+ export type GoogleSpeechVoice = (typeof GOOGLE_SPEECH_VOICES)[number];
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Google Gemini TTS voice names for `speech.voice`.
3
+ *
4
+ * Standalone preset vocabulary — no kernel registry imports so docs UIs can
5
+ * import this file without pulling provider wiring.
6
+ *
7
+ * @module
8
+ */
9
+ /** Common Gemini TTS voice names. */
10
+ export const GOOGLE_SPEECH_VOICES = [
11
+ 'Zephyr',
12
+ 'Puck',
13
+ 'Charon',
14
+ 'Kore',
15
+ 'Fenrir',
16
+ 'Leda',
17
+ 'Orus',
18
+ 'Aoede',
19
+ 'Callirrhoe',
20
+ 'Autonoe',
21
+ 'Enceladus',
22
+ 'Iapetus',
23
+ 'Umbriel',
24
+ 'Algieba',
25
+ 'Despina',
26
+ 'Erinome',
27
+ 'Algenib',
28
+ 'Rasalgethi',
29
+ 'Laomedeia',
30
+ 'Achernar',
31
+ 'Alnilam',
32
+ 'Schedar',
33
+ 'Gacrux',
34
+ 'Pulcherrima',
35
+ 'Achird',
36
+ 'Zubenelgenubi',
37
+ 'Vindemiatrix',
38
+ 'Sadachbia',
39
+ 'Sadaltager',
40
+ 'Sulafat',
41
+ ];
@@ -1,50 +1,62 @@
1
1
  /**
2
2
  * Google / Gemini convenience preset.
3
3
  *
4
- * Kernel stays open (`string` pins). This pack owns Google vocabularies as
5
- * real unions so host profiles stay typed when they opt into the preset.
6
- *
7
- * Call `registerGooglePreset()` at host startup for tools; use the exported
8
- * types/constants when authoring image/speech-adjacent profile fields.
9
- *
10
4
  * @module
11
5
  */
12
6
  import "../../_dnt.polyfills.js";
13
- import type { ProfileImageSpec, ProfileSpeechSpec, ToolCatalogEntry } from '../kernel/types.js';
14
- /** Google Interactions / Gemini grounding builtins. */
15
- declare const GOOGLE_BUILTIN_TOOLS: Record<string, ToolCatalogEntry>;
7
+ import type { ProfileImageSpec, ProfileLiveSpec, ProfileSpeechSpec } from '../kernel/types.js';
8
+ import { GOOGLE_SPEECH_VOICES, type GoogleSpeechVoice } from './google/speech-voices.js';
16
9
  /** Common Gemini image input MIME allowlist. */
17
10
  declare const GOOGLE_IMAGE_INPUT_MIMES: readonly ["image/png", "image/jpeg", "image/webp", "image/heic", "image/heif"];
18
11
  /** Common voice/audio input MIME allowlist for Gemini multimodal. */
19
12
  declare const GOOGLE_VOICE_INPUT_MIMES: readonly ["audio/webm", "audio/wav", "audio/mpeg", "audio/mp4"];
20
- /** Common Gemini TTS voice names for `outputs.speech.voice`. */
21
- declare const GOOGLE_SPEECH_VOICES: readonly ["Zephyr", "Puck", "Charon", "Kore", "Fenrir", "Leda", "Orus", "Aoede", "Callirrhoe", "Autonoe", "Enceladus", "Iapetus", "Umbriel", "Algieba", "Despina", "Erinome", "Algenib", "Rasalgethi", "Laomedeia", "Achernar", "Alnilam", "Schedar", "Gacrux", "Pulcherrima", "Achird", "Zubenelgenubi", "Vindemiatrix", "Sadachbia", "Sadaltager", "Sulafat"];
22
- type GoogleSpeechVoice = (typeof GOOGLE_SPEECH_VOICES)[number];
23
- /**
24
- * `outputs.speech` pins narrowed to Google TTS vocabulary.
25
- * Assignable to kernel `ProfileSpeechSpec`.
26
- */
27
13
  type GoogleSpeechPins = Omit<ProfileSpeechSpec, 'voice'> & {
28
14
  voice?: GoogleSpeechVoice;
29
15
  };
30
- /** Aspect ratios commonly accepted by Gemini image models. */
16
+ type GoogleLivePins = Omit<ProfileLiveSpec, 'voice'> & {
17
+ voice?: GoogleSpeechVoice;
18
+ };
31
19
  declare const GOOGLE_IMAGE_ASPECT_RATIOS: readonly ["1:1", "3:2", "2:3", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"];
32
- /** Image sizes commonly accepted by Gemini Flash Lite image. */
33
20
  declare const GOOGLE_IMAGE_SIZES: readonly ["1K"];
34
21
  type GoogleImageInputMime = (typeof GOOGLE_IMAGE_INPUT_MIMES)[number];
35
22
  type GoogleVoiceInputMime = (typeof GOOGLE_VOICE_INPUT_MIMES)[number];
36
23
  type GoogleImageAspectRatio = (typeof GOOGLE_IMAGE_ASPECT_RATIOS)[number];
37
24
  type GoogleImageSize = (typeof GOOGLE_IMAGE_SIZES)[number];
38
- /**
39
- * `outputs.image` pins narrowed to Google image vocabulary.
40
- * Assignable to kernel `ProfileImageSpec`.
41
- */
42
25
  type GoogleImagePins = Omit<ProfileImageSpec, 'aspectRatio' | 'size' | 'mimeType'> & {
43
26
  aspectRatio?: GoogleImageAspectRatio;
44
27
  size?: GoogleImageSize;
45
28
  mimeType?: GoogleImageInputMime | 'image/jpeg';
46
29
  };
47
- /** Register Google provider builtins into the process-local tool catalog. */
30
+ declare const GOOGLE_BUILTIN_TOOLS: ({
31
+ type: "builtin";
32
+ name: string;
33
+ description: string;
34
+ category: string;
35
+ access: "read-only";
36
+ paths: string[];
37
+ loadTier: "T0";
38
+ permission: "auto";
39
+ forcePaidKey: boolean;
40
+ wire: {
41
+ interactions: string;
42
+ openRouter: string;
43
+ };
44
+ } | {
45
+ type: "builtin";
46
+ name: string;
47
+ description: string;
48
+ category: string;
49
+ access: "read-only";
50
+ paths: string[];
51
+ loadTier: "T0";
52
+ permission: "auto";
53
+ wire: {
54
+ interactions: string;
55
+ openRouter?: undefined;
56
+ };
57
+ forcePaidKey?: undefined;
58
+ })[];
59
+ /** Register Google provider builtins into the process-local tool registry. */
48
60
  declare function registerGooglePreset(): void;
49
- export type { GoogleImageAspectRatio, GoogleImageInputMime, GoogleImagePins, GoogleImageSize, GoogleSpeechPins, GoogleSpeechVoice, GoogleVoiceInputMime, };
61
+ export type { GoogleImageAspectRatio, GoogleImageInputMime, GoogleImagePins, GoogleImageSize, GoogleLivePins, GoogleSpeechPins, GoogleSpeechVoice, GoogleVoiceInputMime, };
50
62
  export { GOOGLE_BUILTIN_TOOLS, GOOGLE_IMAGE_ASPECT_RATIOS, GOOGLE_IMAGE_INPUT_MIMES, GOOGLE_IMAGE_SIZES, GOOGLE_SPEECH_VOICES, GOOGLE_VOICE_INPUT_MIMES, registerGooglePreset, };