pyric 0.1.0-alpha.19 → 0.1.0-alpha.21

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 (281) hide show
  1. package/README.md +64 -89
  2. package/dist/ai/blocked.d.ts +52 -0
  3. package/dist/ai/blocked.d.ts.map +1 -0
  4. package/dist/ai/blocked.js +83 -0
  5. package/dist/ai/blocked.js.map +1 -0
  6. package/dist/ai/broker/broker.d.ts +50 -0
  7. package/dist/ai/broker/broker.d.ts.map +1 -1
  8. package/dist/ai/broker/broker.js +157 -21
  9. package/dist/ai/broker/broker.js.map +1 -1
  10. package/dist/ai/broker/gemini-engine.d.ts +56 -0
  11. package/dist/ai/broker/gemini-engine.d.ts.map +1 -0
  12. package/dist/ai/broker/gemini-engine.js +235 -0
  13. package/dist/ai/broker/gemini-engine.js.map +1 -0
  14. package/dist/ai/broker/index.d.ts +2 -1
  15. package/dist/ai/broker/index.d.ts.map +1 -1
  16. package/dist/ai/broker/index.js +2 -1
  17. package/dist/ai/broker/index.js.map +1 -1
  18. package/dist/ai/broker/openai-engine.d.ts +10 -1
  19. package/dist/ai/broker/openai-engine.d.ts.map +1 -1
  20. package/dist/ai/broker/openai-engine.js +26 -4
  21. package/dist/ai/broker/openai-engine.js.map +1 -1
  22. package/dist/ai/broker/synthesizer.d.ts +14 -0
  23. package/dist/ai/broker/synthesizer.d.ts.map +1 -1
  24. package/dist/ai/broker/synthesizer.js +31 -0
  25. package/dist/ai/broker/synthesizer.js.map +1 -1
  26. package/dist/ai/broker/types.d.ts +29 -0
  27. package/dist/ai/broker/types.d.ts.map +1 -1
  28. package/dist/ai/instances.js +1 -1
  29. package/dist/ai/instances.js.map +1 -1
  30. package/dist/ai/internal.d.ts +5 -0
  31. package/dist/ai/internal.d.ts.map +1 -1
  32. package/dist/ai/internal.js +5 -0
  33. package/dist/ai/internal.js.map +1 -1
  34. package/dist/ai/response-helpers.d.ts.map +1 -1
  35. package/dist/ai/response-helpers.js +6 -24
  36. package/dist/ai/response-helpers.js.map +1 -1
  37. package/dist/analytics/index.d.ts +40 -0
  38. package/dist/analytics/index.d.ts.map +1 -0
  39. package/dist/analytics/index.js +25 -0
  40. package/dist/analytics/index.js.map +1 -0
  41. package/dist/app-check/index.d.ts +31 -0
  42. package/dist/app-check/index.d.ts.map +1 -0
  43. package/dist/app-check/index.js +20 -0
  44. package/dist/app-check/index.js.map +1 -0
  45. package/dist/auth/instances.js +1 -1
  46. package/dist/auth/instances.js.map +1 -1
  47. package/dist/database/controls.d.ts +1 -1
  48. package/dist/database/controls.js +1 -1
  49. package/dist/database/instances.js +1 -1
  50. package/dist/database/instances.js.map +1 -1
  51. package/dist/database/sandbox/backend.d.ts +1 -0
  52. package/dist/database/sandbox/backend.d.ts.map +1 -1
  53. package/dist/database/sandbox/backend.js +1 -0
  54. package/dist/database/sandbox/backend.js.map +1 -1
  55. package/dist/database/sandbox/rules-eval.d.ts +6 -2
  56. package/dist/database/sandbox/rules-eval.d.ts.map +1 -1
  57. package/dist/database/sandbox/rules-eval.js +15 -2
  58. package/dist/database/sandbox/rules-eval.js.map +1 -1
  59. package/dist/database/sandbox/write-plane.d.ts +1 -0
  60. package/dist/database/sandbox/write-plane.d.ts.map +1 -1
  61. package/dist/database/sandbox/write-plane.js +7 -2
  62. package/dist/database/sandbox/write-plane.js.map +1 -1
  63. package/dist/database/sandbox-controls.d.ts +12 -5
  64. package/dist/database/sandbox-controls.d.ts.map +1 -1
  65. package/dist/database/sandbox-controls.js +20 -9
  66. package/dist/database/sandbox-controls.js.map +1 -1
  67. package/dist/database/sandbox-namespace.d.ts +19 -1
  68. package/dist/database/sandbox-namespace.d.ts.map +1 -1
  69. package/dist/database/sandbox-namespace.js +24 -1
  70. package/dist/database/sandbox-namespace.js.map +1 -1
  71. package/dist/deferred/entry.d.ts +75 -0
  72. package/dist/deferred/entry.d.ts.map +1 -0
  73. package/dist/deferred/entry.js +143 -0
  74. package/dist/deferred/entry.js.map +1 -0
  75. package/dist/firestore/instances.js +1 -1
  76. package/dist/firestore/instances.js.map +1 -1
  77. package/dist/firestore/lite.d.ts +72 -0
  78. package/dist/firestore/lite.d.ts.map +1 -0
  79. package/dist/firestore/lite.js +22 -0
  80. package/dist/firestore/lite.js.map +1 -0
  81. package/dist/firestore/persistence.d.ts +2 -2
  82. package/dist/firestore/persistence.js +1 -1
  83. package/dist/firestore/sandbox-controls.d.ts +2 -0
  84. package/dist/firestore/sandbox-controls.d.ts.map +1 -1
  85. package/dist/firestore/sandbox-controls.js +8 -0
  86. package/dist/firestore/sandbox-controls.js.map +1 -1
  87. package/dist/functions/index.d.ts +29 -0
  88. package/dist/functions/index.d.ts.map +1 -0
  89. package/dist/functions/index.js +20 -0
  90. package/dist/functions/index.js.map +1 -0
  91. package/dist/messaging/client.d.ts +2 -1
  92. package/dist/messaging/client.d.ts.map +1 -1
  93. package/dist/messaging/client.js +2 -2
  94. package/dist/messaging/client.js.map +1 -1
  95. package/dist/messaging/instance.d.ts +2 -2
  96. package/dist/messaging/instance.d.ts.map +1 -1
  97. package/dist/messaging/instance.js +40 -6
  98. package/dist/messaging/instance.js.map +1 -1
  99. package/dist/messaging/sw.d.ts +2 -1
  100. package/dist/messaging/sw.d.ts.map +1 -1
  101. package/dist/messaging/sw.js +2 -2
  102. package/dist/messaging/sw.js.map +1 -1
  103. package/dist/performance/index.d.ts +22 -0
  104. package/dist/performance/index.d.ts.map +1 -0
  105. package/dist/performance/index.js +19 -0
  106. package/dist/performance/index.js.map +1 -0
  107. package/dist/remote-config/index.d.ts +40 -0
  108. package/dist/remote-config/index.d.ts.map +1 -0
  109. package/dist/remote-config/index.js +25 -0
  110. package/dist/remote-config/index.js.map +1 -0
  111. package/dist/rules/grammar/FirestoreValidator.d.ts.map +1 -1
  112. package/dist/rules/grammar/FirestoreValidator.js +43 -27
  113. package/dist/rules/grammar/FirestoreValidator.js.map +1 -1
  114. package/dist/rules/grammar/document-access-count.d.ts +24 -0
  115. package/dist/rules/grammar/document-access-count.d.ts.map +1 -0
  116. package/dist/rules/grammar/document-access-count.js +100 -0
  117. package/dist/rules/grammar/document-access-count.js.map +1 -0
  118. package/dist/rules/linter/ast-utils.d.ts +2 -6
  119. package/dist/rules/linter/ast-utils.d.ts.map +1 -1
  120. package/dist/rules/linter/ast-utils.js +2 -63
  121. package/dist/rules/linter/ast-utils.js.map +1 -1
  122. package/dist/rules/linter/hallucinations.d.ts +8 -0
  123. package/dist/rules/linter/hallucinations.d.ts.map +1 -1
  124. package/dist/rules/linter/hallucinations.js +121 -31
  125. package/dist/rules/linter/hallucinations.js.map +1 -1
  126. package/dist/rules/linter/linter.d.ts +10 -1
  127. package/dist/rules/linter/linter.d.ts.map +1 -1
  128. package/dist/rules/linter/linter.js +23 -9
  129. package/dist/rules/linter/linter.js.map +1 -1
  130. package/dist/rules/rtdb/grammar/RtdbExpr.ohm +5 -2
  131. package/dist/rules/rtdb/grammar/RtdbExpr.ohm.generated.d.ts +1 -1
  132. package/dist/rules/rtdb/grammar/RtdbExpr.ohm.generated.d.ts.map +1 -1
  133. package/dist/rules/rtdb/grammar/RtdbExpr.ohm.generated.js +5 -2
  134. package/dist/rules/rtdb/grammar/RtdbExpr.ohm.generated.js.map +1 -1
  135. package/dist/rules/rtdb/grammar/simulator.d.ts.map +1 -1
  136. package/dist/rules/rtdb/grammar/simulator.js +61 -15
  137. package/dist/rules/rtdb/grammar/simulator.js.map +1 -1
  138. package/dist/rules/rtdb/simulation/handler.d.ts.map +1 -1
  139. package/dist/rules/rtdb/simulation/handler.js +96 -35
  140. package/dist/rules/rtdb/simulation/handler.js.map +1 -1
  141. package/dist/rules/simulator/document-lookups.d.ts +4 -0
  142. package/dist/rules/simulator/document-lookups.d.ts.map +1 -1
  143. package/dist/rules/simulator/document-lookups.js +42 -3
  144. package/dist/rules/simulator/document-lookups.js.map +1 -1
  145. package/dist/rules/simulator/eval-error.d.ts +11 -0
  146. package/dist/rules/simulator/eval-error.d.ts.map +1 -1
  147. package/dist/rules/simulator/eval-error.js +14 -0
  148. package/dist/rules/simulator/eval-error.js.map +1 -1
  149. package/dist/rules/simulator/evaluation-builtins.d.ts.map +1 -1
  150. package/dist/rules/simulator/evaluation-builtins.js +33 -8
  151. package/dist/rules/simulator/evaluation-builtins.js.map +1 -1
  152. package/dist/rules/simulator/evaluation-context.d.ts +12 -0
  153. package/dist/rules/simulator/evaluation-context.d.ts.map +1 -1
  154. package/dist/rules/simulator/evaluator.d.ts +1 -1
  155. package/dist/rules/simulator/evaluator.d.ts.map +1 -1
  156. package/dist/rules/simulator/evaluator.js +16 -4
  157. package/dist/rules/simulator/evaluator.js.map +1 -1
  158. package/dist/rules/simulator/handler.d.ts.map +1 -1
  159. package/dist/rules/simulator/handler.js +52 -5
  160. package/dist/rules/simulator/handler.js.map +1 -1
  161. package/dist/rules/simulator/lookup-budget.d.ts +37 -0
  162. package/dist/rules/simulator/lookup-budget.d.ts.map +1 -0
  163. package/dist/rules/simulator/lookup-budget.js +96 -0
  164. package/dist/rules/simulator/lookup-budget.js.map +1 -0
  165. package/dist/rules/stdlib-modules.d.ts +7 -0
  166. package/dist/rules/stdlib-modules.d.ts.map +1 -1
  167. package/dist/rules/stdlib-modules.js +11 -11
  168. package/dist/rules/stdlib-modules.js.map +1 -1
  169. package/dist/sandbox/admin-firestore/get-firestore.d.ts +6 -0
  170. package/dist/sandbox/admin-firestore/get-firestore.d.ts.map +1 -1
  171. package/dist/sandbox/admin-firestore/get-firestore.js +22 -3
  172. package/dist/sandbox/admin-firestore/get-firestore.js.map +1 -1
  173. package/dist/sandbox/index.d.ts +1 -1
  174. package/dist/sandbox/index.d.ts.map +1 -1
  175. package/dist/sandbox/index.js +1 -1
  176. package/dist/sandbox/index.js.map +1 -1
  177. package/dist/sandbox/persistence/types.d.ts +1 -1
  178. package/dist/sandbox/remote.d.ts +2 -2
  179. package/dist/sandbox/sandbox-context.d.ts +8 -1
  180. package/dist/sandbox/sandbox-context.d.ts.map +1 -1
  181. package/dist/sandbox/sandbox-context.js +59 -8
  182. package/dist/sandbox/sandbox-context.js.map +1 -1
  183. package/dist/sandbox/types/auth-state.d.ts +1 -0
  184. package/dist/sandbox/types/auth-state.d.ts.map +1 -1
  185. package/dist/sandbox/types/events.d.ts +2 -1
  186. package/dist/sandbox/types/events.d.ts.map +1 -1
  187. package/dist/sandbox/types/operation.d.ts +1 -0
  188. package/dist/sandbox/types/operation.d.ts.map +1 -1
  189. package/dist/storage/enforce.d.ts +20 -1
  190. package/dist/storage/enforce.d.ts.map +1 -1
  191. package/dist/storage/enforce.js +47 -14
  192. package/dist/storage/enforce.js.map +1 -1
  193. package/dist/storage/index.d.ts +1 -1
  194. package/dist/storage/index.d.ts.map +1 -1
  195. package/dist/storage/list.js +1 -1
  196. package/dist/storage/list.js.map +1 -1
  197. package/dist/storage/persistence.d.ts.map +1 -1
  198. package/dist/storage/persistence.js +66 -14
  199. package/dist/storage/persistence.js.map +1 -1
  200. package/dist/storage/sandbox/rules-evaluation-error.d.ts +25 -0
  201. package/dist/storage/sandbox/rules-evaluation-error.d.ts.map +1 -1
  202. package/dist/storage/sandbox/rules-evaluation-error.js +29 -0
  203. package/dist/storage/sandbox/rules-evaluation-error.js.map +1 -1
  204. package/dist/storage/sandbox/rules-evaluator.d.ts +10 -5
  205. package/dist/storage/sandbox/rules-evaluator.d.ts.map +1 -1
  206. package/dist/storage/sandbox/rules-evaluator.js +105 -33
  207. package/dist/storage/sandbox/rules-evaluator.js.map +1 -1
  208. package/dist/storage/sandbox/rules-methods.d.ts.map +1 -1
  209. package/dist/storage/sandbox/rules-methods.js +17 -7
  210. package/dist/storage/sandbox/rules-methods.js.map +1 -1
  211. package/dist/storage/service.d.ts +23 -2
  212. package/dist/storage/service.d.ts.map +1 -1
  213. package/dist/storage/service.js +37 -26
  214. package/dist/storage/service.js.map +1 -1
  215. package/package.json +42 -2
  216. package/src/ai/blocked.ts +97 -0
  217. package/src/ai/broker/broker.ts +153 -22
  218. package/src/ai/broker/gemini-engine.ts +311 -0
  219. package/src/ai/broker/index.ts +2 -0
  220. package/src/ai/broker/openai-engine.ts +31 -3
  221. package/src/ai/broker/synthesizer.ts +34 -0
  222. package/src/ai/broker/types.ts +27 -1
  223. package/src/ai/instances.ts +1 -1
  224. package/src/ai/internal.ts +5 -0
  225. package/src/ai/response-helpers.ts +6 -25
  226. package/src/analytics/index.ts +53 -0
  227. package/src/app/dispatch.test.ts +3 -1
  228. package/src/app-check/index.ts +41 -0
  229. package/src/auth/instances.ts +1 -1
  230. package/src/database/controls.ts +1 -1
  231. package/src/database/instances.ts +1 -1
  232. package/src/database/sandbox/backend.ts +1 -0
  233. package/src/database/sandbox/rules-eval.ts +18 -2
  234. package/src/database/sandbox/write-plane.ts +8 -2
  235. package/src/database/sandbox-controls.ts +29 -9
  236. package/src/database/sandbox-namespace.ts +28 -1
  237. package/src/deferred/entry.ts +167 -0
  238. package/src/firestore/instances.ts +1 -1
  239. package/src/firestore/lite.ts +91 -0
  240. package/src/firestore/persistence.ts +2 -2
  241. package/src/firestore/sandbox-controls.ts +10 -0
  242. package/src/functions/index.ts +38 -0
  243. package/src/messaging/client.ts +3 -2
  244. package/src/messaging/instance.ts +44 -7
  245. package/src/messaging/sw.ts +3 -2
  246. package/src/performance/index.ts +31 -0
  247. package/src/remote-config/index.ts +53 -0
  248. package/src/rules/grammar/FirestoreValidator.ts +44 -28
  249. package/src/rules/grammar/document-access-count.ts +75 -0
  250. package/src/rules/linter/ast-utils.ts +2 -36
  251. package/src/rules/linter/hallucinations.ts +123 -25
  252. package/src/rules/linter/linter.ts +32 -10
  253. package/src/rules/rtdb/grammar/RtdbExpr.ohm +5 -2
  254. package/src/rules/rtdb/grammar/RtdbExpr.ohm.generated.ts +5 -2
  255. package/src/rules/rtdb/grammar/simulator.ts +41 -15
  256. package/src/rules/rtdb/simulation/handler.ts +149 -46
  257. package/src/rules/simulator/document-lookups.ts +46 -3
  258. package/src/rules/simulator/eval-error.ts +16 -0
  259. package/src/rules/simulator/evaluation-builtins.ts +35 -8
  260. package/src/rules/simulator/evaluation-context.ts +12 -0
  261. package/src/rules/simulator/evaluator.ts +14 -3
  262. package/src/rules/simulator/handler.ts +68 -4
  263. package/src/rules/simulator/lookup-budget.ts +101 -0
  264. package/src/rules/stdlib-modules.ts +19 -11
  265. package/src/sandbox/admin-firestore/get-firestore.ts +19 -3
  266. package/src/sandbox/index.ts +5 -1
  267. package/src/sandbox/persistence/types.ts +1 -1
  268. package/src/sandbox/remote.ts +2 -2
  269. package/src/sandbox/sandbox-context.ts +69 -9
  270. package/src/sandbox/types/auth-state.ts +1 -1
  271. package/src/sandbox/types/events.ts +2 -1
  272. package/src/sandbox/types/operation.ts +1 -1
  273. package/src/storage/enforce.ts +53 -14
  274. package/src/storage/index.ts +1 -1
  275. package/src/storage/list.ts +1 -1
  276. package/src/storage/persistence.ts +74 -16
  277. package/src/storage/sandbox/rules-evaluation-error.ts +32 -0
  278. package/src/storage/sandbox/rules-evaluator.ts +109 -32
  279. package/src/storage/sandbox/rules-methods.ts +21 -7
  280. package/src/storage/service.ts +93 -27
  281. package/README.md.orig +0 -53
@@ -18,6 +18,17 @@
18
18
  * - a model-turn functionCall part with no thoughtSignature
19
19
  * → `ai-error-fncall-missing-thought-signature`
20
20
  *
21
+ * It also announces the refusals production does NOT throw for: a safety /
22
+ * recitation / blocklist block arrives as a 200 with an empty candidate, so
23
+ * the broker lands a `response_blocked` event ({@link emitBlockIfBlocked})
24
+ * alongside the normal op event. Without it a filtered answer is
25
+ * indistinguishable from a model that simply had nothing to say.
26
+ *
27
+ * The same goes for a model SUBSTITUTION ({@link emitModelSubstitution}): an
28
+ * engine that redirects the requested model (an openai `modelMap` entry or
29
+ * catch-all `model`, a gemini experimental alias) answers normally, so
30
+ * nothing anywhere says the developer tested a model they never named.
31
+ *
21
32
  * Event emission is best-effort behind one small choke-point ({@link emit}):
22
33
  * a throw from the emit path (or any event consumer downstream) must never
23
34
  * poison the AI operation the caller just completed — handler errors are the
@@ -25,9 +36,11 @@
25
36
  * isolates listener throws; this guard covers the emit path itself).
26
37
  */
27
38
  import { emitSandboxEvent, makeServiceMutationEvent } from 'pyric/sandbox/internal';
39
+ import { describeResponseBlock } from '../blocked.js';
28
40
  import { AiBrokerError, Synthesizer, badRole, emptyContents, missingThoughtSignature } from './synthesizer.js';
29
41
  import { ScriptedEngine } from './scripted-engine.js';
30
42
  import { OpenAiEngine } from './openai-engine.js';
43
+ import { GeminiEngine } from './gemini-engine.js';
31
44
  /**
32
45
  * Roles production accepts, from the captured rejection text
33
46
  * (`ai-error-bad-role`): "Please use a valid role: SYSTEM, SYSTEM_1, USER,
@@ -68,6 +81,11 @@ export class AiBroker {
68
81
  this.engine = new ScriptedEngine(engine.script ?? [], new Synthesizer());
69
82
  this.engineKind = 'scripted';
70
83
  }
84
+ else if (engine.kind === 'gemini') {
85
+ this.engine = new GeminiEngine(engine);
86
+ this.engineKind = 'gemini';
87
+ this.engineBaseUrl = engine.baseUrl;
88
+ }
71
89
  else {
72
90
  this.engine = new OpenAiEngine(engine);
73
91
  this.engineKind = 'openai';
@@ -78,33 +96,126 @@ export class AiBroker {
78
96
  }
79
97
  /** One-line construction-time summary of what this broker resolved to. */
80
98
  describeEngine() {
81
- if (this.engineKind === 'openai') {
99
+ const isOpenAiEngine = this.engineKind === 'openai';
100
+ if (isOpenAiEngine) {
82
101
  return `[pyric/ai] engine resolved: openai (model=${this.engineModel ?? 'passthrough'}, upstream=${this.engineBaseUrl})`;
83
102
  }
84
- if (this.engineKind === 'custom') {
103
+ const isGeminiEngine = this.engineKind === 'gemini';
104
+ if (isGeminiEngine) {
105
+ return `[pyric/ai] engine resolved: gemini (upstream=${this.engineBaseUrl ?? 'https://generativelanguage.googleapis.com'})`;
106
+ }
107
+ const isCustomEngine = this.engineKind === 'custom';
108
+ if (isCustomEngine) {
85
109
  return '[pyric/ai] engine resolved: custom AnswerEngine';
86
110
  }
87
111
  return '[pyric/ai] engine resolved: scripted (zero-config unless a script is queued)';
88
112
  }
89
113
  /** Additive detail fields every emitted event carries so Studio can show the engine. */
90
114
  engineDetail() {
91
- return {
115
+ const detail = {
92
116
  engine: this.engineKind,
93
- ...(this.engineKind === 'openai'
94
- ? { model: this.engineModel, baseUrl: this.engineBaseUrl }
95
- : {}),
96
117
  };
118
+ const isOpenAiEngine = this.engineKind === 'openai';
119
+ if (isOpenAiEngine) {
120
+ detail.model = this.engineModel;
121
+ detail.baseUrl = this.engineBaseUrl;
122
+ }
123
+ const isGeminiEngine = this.engineKind === 'gemini';
124
+ if (isGeminiEngine) {
125
+ detail.baseUrl = this.engineBaseUrl ?? 'https://generativelanguage.googleapis.com';
126
+ }
127
+ return detail;
128
+ }
129
+ /**
130
+ * Announce a SAFETY / RECITATION / BLOCKLIST / … block on the event stream.
131
+ *
132
+ * A block is the broker's SILENT refusal: unlike `request_rejected` nothing
133
+ * throws (production answers 200 with an empty candidate), so an app that
134
+ * renders whatever `text()` gave it just shows nothing, and the developer
135
+ * gets no signal anywhere. Emitting at RESPONSE time (not from the response
136
+ * helpers, which only fire if someone reaches for content) means the event
137
+ * lands whether or not the caller ever asks for the text.
138
+ *
139
+ * Detection is `blocked.ts`'s, shared verbatim with the response helpers'
140
+ * throw path, so the stream and the thrown error can never disagree.
141
+ *
142
+ * Returns whether the envelope WAS blocked, so the stream wrapper can
143
+ * announce at most once across its chunks.
144
+ */
145
+ emitBlockIfBlocked(model, response) {
146
+ const block = describeResponseBlock(response);
147
+ if (block === null)
148
+ return false;
149
+ this.emit('response_blocked', model, { ...block });
150
+ return true;
151
+ }
152
+ /**
153
+ * Announce that the engine will answer as a DIFFERENT model than the one
154
+ * requested.
155
+ *
156
+ * A substitution is the quietest failure the broker has: nothing throws,
157
+ * content comes back, and the developer concludes they tested model X when
158
+ * model Y answered (an openai `modelMap` entry or catch-all `model`, a
159
+ * gemini experimental alias). Only engines that actually redirect implement
160
+ * {@link AnswerEngine.resolveEffectiveModel}; the rest are silent by
161
+ * construction.
162
+ *
163
+ * Fired at REQUEST time, before delegating: the swap is a property of the
164
+ * call about to go out, so it lands even when that call then fails.
165
+ * Comparison is bare-vs-bare, since `models/x` to `x` is the wire's prefix
166
+ * convention rather than a substitution, and an exact match emits nothing.
167
+ *
168
+ * `countTokens` is deliberately not announced: the openai engine never
169
+ * sends a model there at all (the count is synthesized locally), so an
170
+ * announcement would name an upstream call that never happens.
171
+ */
172
+ emitModelSubstitution(model) {
173
+ const resolve = this.engine.resolveEffectiveModel;
174
+ if (typeof resolve !== 'function')
175
+ return;
176
+ let effective;
177
+ try {
178
+ effective = resolve.call(this.engine, model);
179
+ }
180
+ catch {
181
+ // A misbehaving engine's self-report must never fail the op.
182
+ return;
183
+ }
184
+ const requestedBare = model.startsWith('models/') ? model.slice('models/'.length) : model;
185
+ if (effective.model === requestedBare)
186
+ return;
187
+ this.emit('model_substituted', model, {
188
+ requestedModel: model,
189
+ effectiveModel: effective.model,
190
+ reason: effective.reason,
191
+ });
192
+ }
193
+ emitRejectionIfBrokerError(model, err) {
194
+ const code = err instanceof AiBrokerError ? err.envelope.error.code : 500;
195
+ const status = err instanceof AiBrokerError ? err.envelope.error.status : 'INTERNAL';
196
+ const message = err instanceof AiBrokerError
197
+ ? err.envelope.error.message
198
+ : err instanceof Error ? err.message : String(err);
199
+ this.emit('request_rejected', model, { code, status, message });
97
200
  }
98
201
  async generateContent(req, model) {
99
202
  this.validate(req, model);
100
- const response = await this.engine.generateContent(req, model);
101
- this.emit('generate_content', model, {
102
- contentCount: req.contents.length,
103
- finishReason: response.candidates?.[0]?.finishReason,
104
- totalTokenCount: response.usageMetadata?.totalTokenCount,
105
- responseId: response.responseId,
106
- });
107
- return response;
203
+ this.emitModelSubstitution(model);
204
+ try {
205
+ const response = await this.engine.generateContent(req, model);
206
+ this.emit('generate_content', model, {
207
+ contentCount: req.contents.length,
208
+ finishReason: response.candidates?.[0]?.finishReason,
209
+ totalTokenCount: response.usageMetadata?.totalTokenCount,
210
+ responseId: response.responseId,
211
+ });
212
+ this.emitBlockIfBlocked(model, response);
213
+ return response;
214
+ }
215
+ catch (err) {
216
+ this.emitRejectionIfBrokerError(model, err);
217
+ throw err;
218
+ }
108
219
  }
109
220
  /**
110
221
  * Chunk objects with the captured framing SEMANTICS (finishReason last
@@ -114,25 +225,50 @@ export class AiBroker {
114
225
  */
115
226
  streamGenerateContent(req, model) {
116
227
  this.validate(req, model);
228
+ this.emitModelSubstitution(model);
117
229
  const inner = this.engine.streamGenerateContent(req, model);
118
230
  const emit = (chunkCount) => this.emit('stream_generate_content', model, {
119
231
  contentCount: req.contents.length,
120
232
  chunkCount,
121
233
  });
234
+ const emitRejection = (err) => this.emitRejectionIfBrokerError(model, err);
235
+ // A block surfaces on whichever chunk carries the finish reason (the last
236
+ // one, per the captured framing), so it is announced DURING iteration:
237
+ // an abandoned stream still reports why it produced nothing. At most one
238
+ // per stream: the aggregate has a single blocking reason, not one per chunk.
239
+ let announcedBlock = false;
240
+ const emitBlock = (chunk) => {
241
+ if (announcedBlock)
242
+ return;
243
+ announcedBlock = this.emitBlockIfBlocked(model, chunk);
244
+ };
122
245
  return (async function* wrapped() {
123
246
  let chunkCount = 0;
124
- for await (const chunk of inner) {
125
- chunkCount++;
126
- yield chunk;
247
+ try {
248
+ for await (const chunk of inner) {
249
+ chunkCount++;
250
+ emitBlock(chunk);
251
+ yield chunk;
252
+ }
253
+ emit(chunkCount);
254
+ }
255
+ catch (err) {
256
+ emitRejection(err);
257
+ throw err;
127
258
  }
128
- emit(chunkCount);
129
259
  })();
130
260
  }
131
261
  async countTokens(req, model) {
132
262
  this.validateContents(req, model);
133
- const response = await this.engine.countTokens(req, model);
134
- this.emit('count_tokens', model, { totalTokens: response.totalTokens });
135
- return response;
263
+ try {
264
+ const response = await this.engine.countTokens(req, model);
265
+ this.emit('count_tokens', model, { totalTokens: response.totalTokens });
266
+ return response;
267
+ }
268
+ catch (err) {
269
+ this.emitRejectionIfBrokerError(model, err);
270
+ throw err;
271
+ }
136
272
  }
137
273
  // ── Production-shaped validation ──────────────────────────────────────────
138
274
  validate(req, model) {
@@ -1 +1 @@
1
- {"version":3,"file":"broker.js","sourceRoot":"","sources":["../../../src/ai/broker/broker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"broker.js","sourceRoot":"","sources":["../../../src/ai/broker/broker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The Gemini AnswerEngine: Gemini wire in, Google AI Studio / Vertex AI REST API
3
+ * out, Gemini wire back.
4
+ *
5
+ * Unlike the browser-side `@firebase/ai` SDK (which calls Vertex AI directly
6
+ * from the browser and fails with HTTP 401 for sandboxed mock auth users),
7
+ * `GeminiEngine` runs on Pyric's backend server, authenticating via a local
8
+ * API key (`GEMINI_API_KEY` / `GOOGLE_GENAI_API_KEY` / `VITE_GEMINI_API_KEY`)
9
+ * or Google Cloud Application Default Credentials (`gcloud auth application-default login`)
10
+ * without exposing secrets to the browser.
11
+ */
12
+ import type { AnswerEngine, CountTokensRequest, CountTokensResponse, GenerateContentRequest, ModelResolution, WireChunk, WireResponse } from './types.js';
13
+ /** Where the gemini engine talks when no `baseUrl` overrides it. Published
14
+ * through `pyric/ai/internal` so the CLI's startup banner can name the same
15
+ * endpoint instead of keeping its own copy. */
16
+ export declare const GEMINI_DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com";
17
+ export interface GeminiEngineOptions {
18
+ /** Explicit API key. Absent ⇒ resolved from environment variables or ADC. */
19
+ apiKey?: string;
20
+ /** Explicit base URL override (default: https://generativelanguage.googleapis.com). */
21
+ baseUrl?: string;
22
+ /** Explicit fetch seam for testing or custom transport. */
23
+ fetch?: typeof fetch;
24
+ }
25
+ export declare class GeminiEngine implements AnswerEngine {
26
+ private readonly baseUrl;
27
+ private readonly fetchImpl;
28
+ private readonly explicitKey?;
29
+ constructor(options?: GeminiEngineOptions);
30
+ /**
31
+ * Resolves authentication credentials sequentially, checking static options,
32
+ * environment variables, and finally Google Cloud Application Default
33
+ * Credentials (`gcloud auth application-default print-access-token`).
34
+ */
35
+ private resolveAuthToken;
36
+ /**
37
+ * Which model this engine ACTUALLY calls upstream, and why it differs.
38
+ * Experimental and superseded flash aliases are redirected onto the served
39
+ * `gemini-flash-lite-latest`; everything else passes through. Reported so
40
+ * the broker can announce the redirect rather than let a developer believe
41
+ * `gemini-2.5-flash` answered when `gemini-flash-lite-latest` did
42
+ * ({@link AnswerEngine.resolveEffectiveModel}).
43
+ */
44
+ resolveEffectiveModel(model: string): ModelResolution;
45
+ private normalizeModel;
46
+ /**
47
+ * Formats upstream REST endpoint URLs and request headers for either Google
48
+ * AI Studio (`generativelanguage.googleapis.com`) or Vertex AI regional APIs.
49
+ */
50
+ private formatUpstreamRequest;
51
+ private fetchUpstream;
52
+ generateContent(req: GenerateContentRequest, model: string): Promise<WireResponse>;
53
+ streamGenerateContent(req: GenerateContentRequest, model: string): AsyncIterable<WireChunk>;
54
+ countTokens(req: CountTokensRequest, model: string): Promise<CountTokensResponse>;
55
+ }
56
+ //# sourceMappingURL=gemini-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-engine.d.ts","sourceRoot":"","sources":["../../../src/ai/broker/gemini-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,SAAS,EACT,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB;;gDAEgD;AAChD,eAAO,MAAM,uBAAuB,8CAA8C,CAAC;AAuBnF,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,qBAAa,YAAa,YAAW,YAAY;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsE;IAChG,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAS;gBAE1B,OAAO,CAAC,EAAE,mBAAmB;IAMzC;;;;OAIG;YACW,gBAAgB;IA8C9B;;;;;;;OAOG;IACH,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe;IAarD,OAAO,CAAC,cAAc;IAItB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;YA2Bf,aAAa;IA2CrB,eAAe,CAAC,GAAG,EAAE,sBAAsB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAQjF,qBAAqB,CAC1B,GAAG,EAAE,sBAAsB,EAC3B,KAAK,EAAE,MAAM,GACZ,aAAa,CAAC,SAAS,CAAC;IAyErB,WAAW,CAAC,GAAG,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAOxF"}
@@ -0,0 +1,235 @@
1
+ /**
2
+ * The Gemini AnswerEngine: Gemini wire in, Google AI Studio / Vertex AI REST API
3
+ * out, Gemini wire back.
4
+ *
5
+ * Unlike the browser-side `@firebase/ai` SDK (which calls Vertex AI directly
6
+ * from the browser and fails with HTTP 401 for sandboxed mock auth users),
7
+ * `GeminiEngine` runs on Pyric's backend server, authenticating via a local
8
+ * API key (`GEMINI_API_KEY` / `GOOGLE_GENAI_API_KEY` / `VITE_GEMINI_API_KEY`)
9
+ * or Google Cloud Application Default Credentials (`gcloud auth application-default login`)
10
+ * without exposing secrets to the browser.
11
+ */
12
+ import { AiBrokerError, errorEnvelope, redactUrl } from './synthesizer.js';
13
+ /** Where the gemini engine talks when no `baseUrl` overrides it. Published
14
+ * through `pyric/ai/internal` so the CLI's startup banner can name the same
15
+ * endpoint instead of keeping its own copy. */
16
+ export const GEMINI_DEFAULT_BASE_URL = 'https://generativelanguage.googleapis.com';
17
+ /**
18
+ * BROWSER-CLEAN: acquires `node:child_process` lazily via `process.getBuiltinModule`
19
+ * so no static node import exists for browser bundlers to resolve.
20
+ */
21
+ function getExecSync() {
22
+ const get = globalThis.process
23
+ ?.getBuiltinModule;
24
+ const hasGetBuiltinModule = typeof get === 'function';
25
+ if (!hasGetBuiltinModule) {
26
+ return null;
27
+ }
28
+ const cp = get.call(process, 'node:child_process');
29
+ const hasExecSync = cp !== undefined && typeof cp.execSync === 'function';
30
+ if (!hasExecSync) {
31
+ return null;
32
+ }
33
+ return cp.execSync;
34
+ }
35
+ export class GeminiEngine {
36
+ baseUrl;
37
+ fetchImpl;
38
+ explicitKey;
39
+ constructor(options) {
40
+ this.baseUrl = (options?.baseUrl ?? GEMINI_DEFAULT_BASE_URL).replace(/\/$/, '');
41
+ this.fetchImpl = options?.fetch ?? ((input, init) => fetch(input, init));
42
+ this.explicitKey = options?.apiKey;
43
+ }
44
+ /**
45
+ * Resolves authentication credentials sequentially, checking static options,
46
+ * environment variables, and finally Google Cloud Application Default
47
+ * Credentials (`gcloud auth application-default print-access-token`).
48
+ */
49
+ async resolveAuthToken() {
50
+ let key = this.explicitKey;
51
+ if (key === undefined) {
52
+ key = process.env.GEMINI_API_KEY;
53
+ }
54
+ if (key === undefined) {
55
+ key = process.env.GOOGLE_GENAI_API_KEY;
56
+ }
57
+ if (key === undefined) {
58
+ key = process.env.VITE_GEMINI_API_KEY;
59
+ }
60
+ if (key !== undefined) {
61
+ const trimmedKey = key.trim();
62
+ const hasStaticKey = trimmedKey !== '';
63
+ if (hasStaticKey) {
64
+ return { token: trimmedKey, isBearer: false };
65
+ }
66
+ }
67
+ try {
68
+ const execSyncFn = getExecSync();
69
+ const hasExecSyncFn = execSyncFn !== null;
70
+ if (hasExecSyncFn) {
71
+ const adcToken = execSyncFn('gcloud auth application-default print-access-token', {
72
+ encoding: 'utf8',
73
+ stdio: ['ignore', 'pipe', 'ignore'],
74
+ }).trim();
75
+ const hasAdcToken = adcToken !== '';
76
+ if (hasAdcToken) {
77
+ return { token: adcToken, isBearer: true };
78
+ }
79
+ }
80
+ }
81
+ catch {
82
+ // Best-effort attempt to recover ADC credentials when env keys are absent
83
+ }
84
+ throw new AiBrokerError(errorEnvelope(401, 'Pyric AI production passthrough mode requires GEMINI_API_KEY, GOOGLE_GENAI_API_KEY, or VITE_GEMINI_API_KEY in your server environment (or Application Default Credentials via `gcloud auth application-default login`).', 'UNAUTHENTICATED'));
85
+ }
86
+ /**
87
+ * Which model this engine ACTUALLY calls upstream, and why it differs.
88
+ * Experimental and superseded flash aliases are redirected onto the served
89
+ * `gemini-flash-lite-latest`; everything else passes through. Reported so
90
+ * the broker can announce the redirect rather than let a developer believe
91
+ * `gemini-2.5-flash` answered when `gemini-flash-lite-latest` did
92
+ * ({@link AnswerEngine.resolveEffectiveModel}).
93
+ */
94
+ resolveEffectiveModel(model) {
95
+ const stripped = model.replace(/^models\//, '');
96
+ const isExperimentalFlashLite = stripped === 'gemini-3.5-flash-lite' ||
97
+ stripped === 'gemini-2.5-flash' ||
98
+ stripped === 'gemini-2.5-flash-lite' ||
99
+ stripped === 'gemini-1.5-flash';
100
+ if (isExperimentalFlashLite) {
101
+ return { model: 'gemini-flash-lite-latest', reason: 'experimental alias' };
102
+ }
103
+ return { model: stripped, reason: 'passthrough' };
104
+ }
105
+ normalizeModel(model) {
106
+ return `models/${this.resolveEffectiveModel(model).model}`;
107
+ }
108
+ /**
109
+ * Formats upstream REST endpoint URLs and request headers for either Google
110
+ * AI Studio (`generativelanguage.googleapis.com`) or Vertex AI regional APIs.
111
+ */
112
+ formatUpstreamRequest(resource, action, auth) {
113
+ const isVertexUrl = this.baseUrl.includes('firebasevertexai.googleapis.com') ||
114
+ this.baseUrl.includes('aiplatform.googleapis.com');
115
+ const shouldUseBearerAuth = auth.isBearer || isVertexUrl;
116
+ const headers = {
117
+ 'Content-Type': 'application/json',
118
+ };
119
+ if (shouldUseBearerAuth) {
120
+ headers['Authorization'] = `Bearer ${auth.token}`;
121
+ return {
122
+ url: `${this.baseUrl}/v1beta/${resource}:${action}`,
123
+ headers,
124
+ };
125
+ }
126
+ return {
127
+ url: `${this.baseUrl}/v1beta/${resource}:${action}?key=${encodeURIComponent(auth.token)}`,
128
+ headers,
129
+ };
130
+ }
131
+ async fetchUpstream(url, headers, body) {
132
+ let response;
133
+ try {
134
+ response = await this.fetchImpl(url, {
135
+ method: 'POST',
136
+ headers,
137
+ body: JSON.stringify(body),
138
+ });
139
+ }
140
+ catch (err) {
141
+ // Redact both: `url` always carries the key when auth is a static key
142
+ // (not bearer/ADC); `message` is defensively redacted too in case the
143
+ // fetch implementation's own error text echoes the request URL.
144
+ const rawMessage = err instanceof Error ? err.message : String(err);
145
+ const safeUrl = redactUrl(url);
146
+ const safeMessage = redactUrl(rawMessage);
147
+ throw new AiBrokerError(errorEnvelope(502, `Failed to connect to Gemini API at ${safeUrl}: ${safeMessage}`, 'UNAVAILABLE'));
148
+ }
149
+ const isSuccess = response.ok;
150
+ if (!isSuccess) {
151
+ const errorText = await response.text().catch(() => '');
152
+ throw new AiBrokerError(errorEnvelope(response.status, `Gemini API returned status ${response.status}: ${redactUrl(errorText)}`, 'INTERNAL'));
153
+ }
154
+ return response;
155
+ }
156
+ async generateContent(req, model) {
157
+ const auth = await this.resolveAuthToken();
158
+ const resource = this.normalizeModel(model);
159
+ const { url, headers } = this.formatUpstreamRequest(resource, 'generateContent', auth);
160
+ const response = await this.fetchUpstream(url, headers, req);
161
+ return (await response.json());
162
+ }
163
+ async *streamGenerateContent(req, model) {
164
+ const auth = await this.resolveAuthToken();
165
+ const resource = this.normalizeModel(model);
166
+ const { url, headers } = this.formatUpstreamRequest(resource, 'streamGenerateContent?alt=sse', auth);
167
+ const response = await this.fetchUpstream(url, headers, req);
168
+ const hasBody = response.body !== null && response.body !== undefined;
169
+ if (!hasBody) {
170
+ throw new AiBrokerError(errorEnvelope(500, 'Gemini API returned an empty stream response.', 'INTERNAL'));
171
+ }
172
+ const reader = response.body.getReader();
173
+ const decoder = new TextDecoder();
174
+ let buffer = '';
175
+ try {
176
+ while (true) {
177
+ const { done, value } = await reader.read();
178
+ const isDone = done === true;
179
+ if (isDone) {
180
+ break;
181
+ }
182
+ buffer += decoder.decode(value, { stream: true });
183
+ const lines = buffer.split(/\r?\n/);
184
+ buffer = lines.pop() ?? '';
185
+ for (const line of lines) {
186
+ const isDataLine = line.startsWith('data: ');
187
+ if (!isDataLine) {
188
+ continue;
189
+ }
190
+ const dataStr = line.slice(6).trim();
191
+ const isEmptyOrDone = dataStr === '' || dataStr === '[DONE]';
192
+ if (isEmptyOrDone) {
193
+ continue;
194
+ }
195
+ try {
196
+ const chunk = JSON.parse(dataStr);
197
+ yield chunk;
198
+ }
199
+ catch {
200
+ // Ignore malformed SSE chunk in stream
201
+ }
202
+ }
203
+ }
204
+ const hasTrailingBuffer = buffer.trim().length > 0;
205
+ if (hasTrailingBuffer) {
206
+ const line = buffer.trim();
207
+ const isDataLine = line.startsWith('data: ');
208
+ if (isDataLine) {
209
+ const dataStr = line.slice(6).trim();
210
+ const isNotEmptyOrDone = dataStr !== '' && dataStr !== '[DONE]';
211
+ if (isNotEmptyOrDone) {
212
+ try {
213
+ const chunk = JSON.parse(dataStr);
214
+ yield chunk;
215
+ }
216
+ catch {
217
+ // Ignore malformed SSE chunk in stream
218
+ }
219
+ }
220
+ }
221
+ }
222
+ }
223
+ finally {
224
+ reader.releaseLock();
225
+ }
226
+ }
227
+ async countTokens(req, model) {
228
+ const auth = await this.resolveAuthToken();
229
+ const resource = this.normalizeModel(model);
230
+ const { url, headers } = this.formatUpstreamRequest(resource, 'countTokens', auth);
231
+ const response = await this.fetchUpstream(url, headers, req);
232
+ return (await response.json());
233
+ }
234
+ }
235
+ //# sourceMappingURL=gemini-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-engine.js","sourceRoot":"","sources":["../../../src/ai/broker/gemini-engine.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,8 @@
6
6
  */
7
7
  export { AiBroker, loadObservationEnvelope, type AiBrokerOptions } from './broker.js';
8
8
  export { ScriptedEngine, lastUserText, promptTextOf } from './scripted-engine.js';
9
+ export { GeminiEngine, GEMINI_DEFAULT_BASE_URL, type GeminiEngineOptions } from './gemini-engine.js';
9
10
  export { OpenAiEngine, ToolCallBuffer, SseParser, DONE_SENTINEL, geminiToOpenAIRequest, normalizeSchema, mapFinishReason, openAIToGeminiResponse, openAIChunkToParts, type OpenAiEngineOptions, type OpenAIRequest, type OpenAIResponse, type OpenAIStreamChunk, type OpenAIMessage, type OpenAIToolCall, } from './openai-engine.js';
10
- export { AiBrokerError, Synthesizer, errorEnvelope, unknownModel, badRole, emptyContents, missingThoughtSignature, resolveModelVersion, estimateTokens, mintThoughtSignature, mintFunctionCallId, type SynthesizeOptions, } from './synthesizer.js';
11
+ export { AiBrokerError, Synthesizer, errorEnvelope, unknownModel, badRole, emptyContents, missingThoughtSignature, resolveModelVersion, estimateTokens, mintThoughtSignature, mintFunctionCallId, redactUrl, type SynthesizeOptions, } from './synthesizer.js';
11
12
  export type { AnswerEngine, CountTokensRequest, CountTokensResponse, EngineConfig, GenerateContentRequest, RawEnvelope, ScriptEntry, ScriptMatcher, ScriptRespond, ScriptShorthand, WireCandidate, WireChunk, WireContent, WireErrorEnvelope, WirePart, WireResponse, WireUsageMetadata, } from './types.js';
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai/broker/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EACL,YAAY,EACZ,cAAc,EACd,SAAS,EACT,aAAa,EACb,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,aAAa,EACb,WAAW,EACX,aAAa,EACb,YAAY,EACZ,OAAO,EACP,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,EACb,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai/broker/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACrG,OAAO,EACL,YAAY,EACZ,cAAc,EACd,SAAS,EACT,aAAa,EACb,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,aAAa,EACb,WAAW,EACX,aAAa,EACb,YAAY,EACZ,OAAO,EACP,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,SAAS,EACT,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,EACb,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
@@ -6,6 +6,7 @@
6
6
  */
7
7
  export { AiBroker, loadObservationEnvelope } from './broker.js';
8
8
  export { ScriptedEngine, lastUserText, promptTextOf } from './scripted-engine.js';
9
+ export { GeminiEngine, GEMINI_DEFAULT_BASE_URL } from './gemini-engine.js';
9
10
  export { OpenAiEngine, ToolCallBuffer, SseParser, DONE_SENTINEL, geminiToOpenAIRequest, normalizeSchema, mapFinishReason, openAIToGeminiResponse, openAIChunkToParts, } from './openai-engine.js';
10
- export { AiBrokerError, Synthesizer, errorEnvelope, unknownModel, badRole, emptyContents, missingThoughtSignature, resolveModelVersion, estimateTokens, mintThoughtSignature, mintFunctionCallId, } from './synthesizer.js';
11
+ export { AiBrokerError, Synthesizer, errorEnvelope, unknownModel, badRole, emptyContents, missingThoughtSignature, resolveModelVersion, estimateTokens, mintThoughtSignature, mintFunctionCallId, redactUrl, } from './synthesizer.js';
11
12
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai/broker/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAwB,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EACL,YAAY,EACZ,cAAc,EACd,SAAS,EACT,aAAa,EACb,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,kBAAkB,GAOnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,aAAa,EACb,WAAW,EACX,aAAa,EACb,YAAY,EACZ,OAAO,EACP,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,GAEnB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai/broker/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAwB,MAAM,aAAa,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAA4B,MAAM,oBAAoB,CAAC;AACrG,OAAO,EACL,YAAY,EACZ,cAAc,EACd,SAAS,EACT,aAAa,EACb,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,kBAAkB,GAOnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,aAAa,EACb,WAAW,EACX,aAAa,EACb,YAAY,EACZ,OAAO,EACP,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,SAAS,GAEV,MAAM,kBAAkB,CAAC"}
@@ -24,7 +24,7 @@
24
24
  * throw exactly like production).
25
25
  */
26
26
  import { Synthesizer } from './synthesizer.js';
27
- import type { AnswerEngine, CountTokensRequest, CountTokensResponse, GenerateContentRequest, WireChunk, WirePart, WireResponse } from './types.js';
27
+ import type { AnswerEngine, CountTokensRequest, CountTokensResponse, GenerateContentRequest, ModelResolution, WireChunk, WirePart, WireResponse } from './types.js';
28
28
  export interface OpenAIToolCall {
29
29
  id: string;
30
30
  type: 'function';
@@ -174,6 +174,15 @@ export declare class OpenAiEngine implements AnswerEngine {
174
174
  * honors both fields — only the local openai engine does not.
175
175
  */
176
176
  private warnDroppedFieldsOnce;
177
+ /**
178
+ * Gemini model id to upstream model, WITH the reason: `modelMap[model]` ??
179
+ * `config.model` ?? passthrough. The reason is what makes the redirect
180
+ * legible in the dev terminal: "which of my three knobs sent this
181
+ * elsewhere?" is the whole question when the answer came from a model the
182
+ * developer never named. Bare (never `models/`-prefixed), per
183
+ * {@link AnswerEngine.resolveEffectiveModel}.
184
+ */
185
+ resolveEffectiveModel(model: string): ModelResolution;
177
186
  /** Gemini model id → upstream model: modelMap[model] ?? config.model ?? passthrough. */
178
187
  resolveUpstreamModel(model: string): string;
179
188
  generateContent(req: GenerateContentRequest, model: string): Promise<WireResponse>;