@mate-academy/llm-gateway 7.7.0 → 8.0.0-canary.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 (93) hide show
  1. package/README.md +210 -0
  2. package/dist/LLMService.typedefs.d.ts +44 -0
  3. package/dist/LLMService.typedefs.js +13 -1
  4. package/dist/LLMService.typedefs.js.map +1 -1
  5. package/dist/advanced.d.ts +11 -0
  6. package/dist/advanced.js +32 -0
  7. package/dist/advanced.js.map +1 -0
  8. package/dist/client/LLMAgent.d.ts +63 -0
  9. package/dist/client/LLMAgent.js +32 -0
  10. package/dist/client/LLMAgent.js.map +1 -0
  11. package/dist/client/agentRun.typedefs.d.ts +170 -0
  12. package/dist/client/agentRun.typedefs.js +24 -0
  13. package/dist/client/agentRun.typedefs.js.map +1 -0
  14. package/dist/client/agentRunner.d.ts +119 -0
  15. package/dist/client/agentRunner.js +379 -0
  16. package/dist/client/agentRunner.js.map +1 -0
  17. package/dist/client/codegen/extractVariables.d.ts +7 -0
  18. package/dist/client/codegen/extractVariables.js +21 -0
  19. package/dist/client/codegen/extractVariables.js.map +1 -0
  20. package/dist/client/codegen/fetchPromptRecords.d.ts +14 -0
  21. package/dist/client/codegen/fetchPromptRecords.js +75 -0
  22. package/dist/client/codegen/fetchPromptRecords.js.map +1 -0
  23. package/dist/client/codegen/generateSnapshot.d.ts +19 -0
  24. package/dist/client/codegen/generateSnapshot.js +28 -0
  25. package/dist/client/codegen/generateSnapshot.js.map +1 -0
  26. package/dist/client/codegen/index.d.ts +6 -0
  27. package/dist/client/codegen/index.js +23 -0
  28. package/dist/client/codegen/index.js.map +1 -0
  29. package/dist/client/codegen/promptCatalog.typedefs.d.ts +51 -0
  30. package/dist/client/codegen/promptCatalog.typedefs.js +3 -0
  31. package/dist/client/codegen/promptCatalog.typedefs.js.map +1 -0
  32. package/dist/client/codegen/promptName.d.ts +8 -0
  33. package/dist/client/codegen/promptName.js +21 -0
  34. package/dist/client/codegen/promptName.js.map +1 -0
  35. package/dist/client/codegen/renderSnapshot.d.ts +24 -0
  36. package/dist/client/codegen/renderSnapshot.js +135 -0
  37. package/dist/client/codegen/renderSnapshot.js.map +1 -0
  38. package/dist/client/createLLMClient.d.ts +31 -0
  39. package/dist/client/createLLMClient.js +309 -0
  40. package/dist/client/createLLMClient.js.map +1 -0
  41. package/dist/client/createLLMClient.typedefs.d.ts +81 -0
  42. package/dist/client/createLLMClient.typedefs.js +11 -0
  43. package/dist/client/createLLMClient.typedefs.js.map +1 -0
  44. package/dist/client/defineLLMPrompts.d.ts +30 -0
  45. package/dist/client/defineLLMPrompts.js +13 -0
  46. package/dist/client/defineLLMPrompts.js.map +1 -0
  47. package/dist/client/errors.d.ts +57 -0
  48. package/dist/client/errors.js +70 -0
  49. package/dist/client/errors.js.map +1 -0
  50. package/dist/client/index.d.ts +12 -0
  51. package/dist/client/index.js +29 -0
  52. package/dist/client/index.js.map +1 -0
  53. package/dist/client/llmConfig.schema.d.ts +53 -0
  54. package/dist/client/llmConfig.schema.js +49 -0
  55. package/dist/client/llmConfig.schema.js.map +1 -0
  56. package/dist/client/plainMessages.d.ts +12 -0
  57. package/dist/client/plainMessages.js +19 -0
  58. package/dist/client/plainMessages.js.map +1 -0
  59. package/dist/client/promptClientPort.typedefs.d.ts +60 -0
  60. package/dist/client/promptClientPort.typedefs.js +3 -0
  61. package/dist/client/promptClientPort.typedefs.js.map +1 -0
  62. package/dist/client/promptRegistry.runtime.d.ts +72 -0
  63. package/dist/client/promptRegistry.runtime.js +173 -0
  64. package/dist/client/promptRegistry.runtime.js.map +1 -0
  65. package/dist/client/promptSnapshot.typedefs.d.ts +37 -0
  66. package/dist/client/promptSnapshot.typedefs.js +3 -0
  67. package/dist/client/promptSnapshot.typedefs.js.map +1 -0
  68. package/dist/client/traceIO.d.ts +13 -0
  69. package/dist/client/traceIO.js +44 -0
  70. package/dist/client/traceIO.js.map +1 -0
  71. package/dist/client/validationGate.d.ts +28 -0
  72. package/dist/client/validationGate.js +76 -0
  73. package/dist/client/validationGate.js.map +1 -0
  74. package/dist/codegen.d.ts +6 -0
  75. package/dist/codegen.js +23 -0
  76. package/dist/codegen.js.map +1 -0
  77. package/dist/index.d.ts +1 -0
  78. package/dist/index.js +1 -0
  79. package/dist/index.js.map +1 -1
  80. package/dist/providers/GoogleGenerativeAI/services/GoogleGenerativeAIAssistance.service.d.ts +7 -0
  81. package/dist/providers/GoogleGenerativeAI/services/GoogleGenerativeAIAssistance.service.js +74 -7
  82. package/dist/providers/GoogleGenerativeAI/services/GoogleGenerativeAIAssistance.service.js.map +1 -1
  83. package/dist/providers/LLMAPI/services/LLMAPIAssistance.service.d.ts +7 -0
  84. package/dist/providers/LLMAPI/services/LLMAPIAssistance.service.js +79 -12
  85. package/dist/providers/LLMAPI/services/LLMAPIAssistance.service.js.map +1 -1
  86. package/dist/providers/OpenAI/services/OpenAIAssistance.service.js +72 -15
  87. package/dist/providers/OpenAI/services/OpenAIAssistance.service.js.map +1 -1
  88. package/dist/services/LLMAssistanceService.abstract.d.ts +9 -1
  89. package/dist/services/LLMAssistanceService.abstract.js +13 -0
  90. package/dist/services/LLMAssistanceService.abstract.js.map +1 -1
  91. package/dist/utilities/tools/LLMTool.d.ts +4 -0
  92. package/dist/utilities/tools/LLMTool.js.map +1 -1
  93. package/package.json +35 -2
package/README.md CHANGED
@@ -141,6 +141,216 @@ To assert emitted observations in tests, register a test double implementing
141
141
  `LLMGatewayTracer` via `initLLMGateway({ tracer })` and assert what it captured
142
142
  (see `@mate-academy/llm-tracer`'s README for asserting real Langfuse spans).
143
143
 
144
+ ### v2 Client (`createLLMClient`)
145
+
146
+ The v2 client is the prompt-name-first call surface. A call site names the
147
+ operation (the Langfuse prompt name); everything else — prompt text, model,
148
+ provider, params, credentials, reporter wiring, tracing, structured output —
149
+ resolves from it inside the package. Build it once at the composition root and
150
+ inject it via DI; feature code never sees configuration or credentials.
151
+
152
+ Live prompt fetching is behind the `LLMGatewayPromptClient` port, not a
153
+ Langfuse SDK client: the gateway carries no `@langfuse/*` dependency of its
154
+ own. `@mate-academy/prompt-client`'s `LLMPromptClient` satisfies this port
155
+ structurally — pass its `promptClient` straight through. Omitting
156
+ `promptClient` runs the client on the build-time snapshot alone (the same
157
+ no-op-by-omission story as the tracer port).
158
+
159
+ ```typescript
160
+ import {
161
+ createLLMClient,
162
+ defineLLMPrompts,
163
+ LLMSchema,
164
+ } from '@mate-academy/llm-gateway';
165
+ import { LLMPrompt, langfusePromptSnapshot } from './langfusePrompts.generated';
166
+
167
+ const llmPromptRegistry = defineLLMPrompts({
168
+ [LLMPrompt.CityPredictionPredictCityName]: {
169
+ schema: LLMSchema.object({ cityName: LLMSchema.string().nullable() }),
170
+ },
171
+ });
172
+
173
+ const llm = createLLMClient({
174
+ registry: llmPromptRegistry,
175
+ snapshot: langfusePromptSnapshot,
176
+ credentials: async ({ provider, promptName, product }) => providerOptions,
177
+ reporting: { reporter },
178
+ logger,
179
+ context: { product, appEnvironment },
180
+ mode: 'production',
181
+ promptClient, // an `@mate-academy/prompt-client` bundle's `promptClient`, or omit for snapshot-only
182
+ });
183
+
184
+ const { cityName } = await llm.generate(
185
+ LLMPrompt.CityPredictionPredictCityName,
186
+ { variables: { locationName, countryName }, context: { userId } },
187
+ );
188
+ ```
189
+
190
+ - **Typed end to end.** The client is generic over `typeof registry`. Variables
191
+ are typed from the generated snapshot (strict on required names, tolerant of
192
+ extras so a Langfuse edit can never break a build); the return type is the
193
+ bound schema's inferred type, or `string` when no schema is bound.
194
+ - **Single validation gate on every fetch.** Vars subset, `config` zod-parse,
195
+ provider/model in the gateway map, param ceilings, and the resolved model's
196
+ capabilities vs the registry `requires`. Any failure serves the last-known-good
197
+ snapshot and emits the `LangfuseFallbackServed` metric; `LLMConfigError` throws
198
+ only when the live config and the fallback are both unusable.
199
+ - **Errors throw with a taxonomy** (`LLMGatewayError` base + `LLMProviderError`,
200
+ `LLMSchemaValidationError`, `LLMAbortedError`, `LLMConfigError`); validated
201
+ `data` is the return value, never an `'error' in response` union.
202
+ - **Override gating.** `mode: 'production'` rejects per-call `overrides` with
203
+ `LLMConfigError`; only `mode: 'experiment'` (harness/playground/tests) honors
204
+ them.
205
+
206
+ #### Agent runs (`runAgent`)
207
+
208
+ `llm.runAgent` runs a tool-calling agent whose instructions are a registry
209
+ prompt: the Langfuse prompt text is the agent's system instructions and its
210
+ `config` routes the model, so an agent is versioned and re-routed exactly like
211
+ any other operation. The provider assistance loop executes the model⇄tool
212
+ rounds; subagents are exposed to the model as tools (one level deep — a
213
+ subagent cannot declare its own subagents).
214
+
215
+ ```typescript
216
+ const turn = await llm.runAgent(LLMPrompt.ContentEditorRootAgent, {
217
+ variables: { courseName },
218
+ input: userMessage,
219
+ history: persistedMessages, // resume from stored session state
220
+ tools: [createTopicTool, updateTheoryTool, askUserTool],
221
+ subagents: [{
222
+ prompt: LLMPrompt.ContentEditorResearchSubagent,
223
+ name: 'researcher',
224
+ description: 'Researches sources for course content',
225
+ variables: { courseName },
226
+ tools: [searchTool],
227
+ }],
228
+ context: { userId },
229
+ onEvent: (event) => publishAndPersist(event), // WS updates + run history
230
+ });
231
+
232
+ if (turn.stopReason === LLMToolLoopStopReasons.TerminalTool) {
233
+ await askTheUser(turn.terminalTool.output); // agent handed control back
234
+ } else {
235
+ await applyStructure(turn.output); // the model's answer
236
+ }
237
+ ```
238
+
239
+ - **Structured progress events.** Every step emits an `LLMAgentEvent`
240
+ (`agent_started/message/completed/failed`, `tool_call_started/completed/failed`,
241
+ `subagent_started/completed/failed`) through `onEvent`, for live subscription
242
+ updates and durable run persistence. Events carry correlation ids from one
243
+ sequence per root run — `runId` on every event, `invocationId` on tool and
244
+ subagent events, `subagentRunId` linking a delegation to the nested run's
245
+ events — so parallel tool calls and repeated delegations reconstruct into an
246
+ unambiguous run tree. Listeners may be async; a throw or rejection is logged
247
+ and never affects the run.
248
+ - **Intermediate narration.** When the model returns visible assistant text
249
+ alongside tool calls in a round that will continue, that text is emitted as
250
+ `agent_message` (attributed to the emitting run, so a subagent's narration
251
+ carries the subagent's identity) before the round's tools run. Reasoning /
252
+ thinking content and the final answer are never sent this way — the final
253
+ answer is `agent_completed.output`.
254
+ - **Terminal tools end the turn.** A tool declaring `terminal: true` (an
255
+ `ask_user` tool, say) hands control back to the application. The round it
256
+ appears in still runs in full — every call of that round, including parallel
257
+ ones, executes and emits its `tool_call_*` events — but the results are not
258
+ fed back and no further model round starts. The run then returns
259
+ `stopReason: 'terminal_tool'` with `terminalTool` carrying the tool's name
260
+ and output; if several terminal calls land in one round, the first in the
261
+ round's order is the outcome (all still execute). This is ordinary control
262
+ flow — no exception, no abort — and `maxToolIterations` is untouched. A
263
+ terminal tool that throws still ends the turn, carrying its failure message
264
+ as the outcome. Delegation tools are never terminal, so a subagent that stops
265
+ on its own terminal tool returns that output as its delegation result and the
266
+ parent's loop continues.
267
+ - **Subagent names are tool names.** A subagent's `name` must match
268
+ `[a-zA-Z0-9_-]+` (it is exposed to the model as a tool); an invalid name
269
+ fails the run upfront with `LLMConfigError` instead of being silently
270
+ rewritten.
271
+
272
+ The plain-object form above is complete on its own. `llm.defineAgent` is
273
+ optional sugar for reusable, composable definitions: it returns an immutable
274
+ `LLMAgent` instance (typed against the registry) that `runAgent` accepts in
275
+ place of a prompt key, and that other agents accept as a subagent. Unlike
276
+ plain-object subagents, `LLMAgent` subagents may declare their own
277
+ `subagents` — instances are immutable, so a delegation cycle cannot be
278
+ constructed. Agent-level `variables` are a base merged under the per-run
279
+ `variables`; a subagent used as a delegation tool must carry `name` and
280
+ `description`.
281
+
282
+ ```typescript
283
+ const researcher = llm.defineAgent({
284
+ prompt: LLMPrompt.ContentEditorResearchSubagent,
285
+ name: 'researcher',
286
+ description: 'Researches sources for course content',
287
+ variables: { courseName },
288
+ tools: [searchTool],
289
+ });
290
+
291
+ const rootAgent = llm.defineAgent({
292
+ prompt: LLMPrompt.ContentEditorRootAgent,
293
+ tools: [createTopicTool, updateTheoryTool],
294
+ subagents: [researcher],
295
+ });
296
+
297
+ const turn = await llm.runAgent(rootAgent, {
298
+ variables: { courseName },
299
+ input: userMessage,
300
+ context: { userId },
301
+ onEvent: (event) => publishAndPersist(event),
302
+ });
303
+ ```
304
+ - **Typed final output.** A run returns a result discriminated by `stopReason`.
305
+ For an answered turn (`completed`, or `max_iterations`) the prompt's binding
306
+ drives `output` exactly like `generate`: the bound schema's inferred type, or
307
+ the final assistant text when no schema is bound. A `terminal_tool` turn has
308
+ no model answer, so the bound schema is deliberately not applied — `output`
309
+ is absent and `terminalTool` is the outcome instead. Both carry `text`, the
310
+ visible assistant text of the final round.
311
+ - **Tool-capability gate.** When a run has tools or subagents, the validation
312
+ gate additionally requires the resolved model to declare the `tools`
313
+ capability, so a Langfuse re-route to a tool-less model serves the fallback
314
+ instead of failing mid-run.
315
+ - **Langfuse for free.** Provider services already record generation and tool
316
+ observations under the active trace; wrap the run with the tracer's
317
+ `withTrace` at the call site to group the whole agent session.
318
+ - Overrides, credentials, reporter context, and the error taxonomy behave
319
+ exactly as in `generate`.
320
+
321
+ #### Prompt snapshot codegen
322
+
323
+ `langfusePrompts.generated.ts` is produced by `npm run langfuse:generate` (root),
324
+ which fetches every labeled prompt and emits the `LLMPrompt` enum, per-prompt
325
+ variable unions, typed `compile()` helpers, and the snapshot used as the outage
326
+ fallback. It is gitignored exactly like GraphQL generated files: regenerated
327
+ locally on demand, in CI before image builds (with a cached-artifact fallback so a
328
+ Langfuse outage never fails a build), and refreshed non-blocking at API pod boot.
329
+
330
+ `generateSnapshot` (exported from `@mate-academy/llm-gateway/codegen`) takes an
331
+ injected `LLMPromptCatalog` instead of constructing a Langfuse SDK client
332
+ itself — the caller owns the catalog's credentials and its Langfuse project.
333
+ `@mate-academy/prompt-client`'s `LLMPromptClient` satisfies this port too, so
334
+ the same instance a runtime composition root builds can be reused for codegen:
335
+
336
+ ```typescript
337
+ import { generateSnapshot } from '@mate-academy/llm-gateway/codegen';
338
+
339
+ await generateSnapshot({
340
+ catalog: promptClient, // an `@mate-academy/prompt-client` bundle's `promptClient`
341
+ label: 'production',
342
+ outputPath: './src/langfusePrompts.generated.ts',
343
+ onLog: (message) => console.log(message),
344
+ });
345
+ ```
346
+
347
+ #### Escape hatch
348
+
349
+ `@mate-academy/llm-gateway/advanced` re-exports `LLMServiceFactory`, the provider
350
+ services, and the model maps for the rare call site needing raw control. It
351
+ bypasses prompt management, the validation gate, and config-in-prompt routing —
352
+ prefer the v2 client.
353
+
144
354
  ### Logger Interface
145
355
 
146
356
  The package accepts an optional logger that implements the `LLMLoggerInterface` interface. Most logging libraries are compatible (`@mate-academy/logger`, winston, pino, etc.). If no logger is provided, no logging will occur.
@@ -312,6 +312,8 @@ export type LLMStructuredResult<T = any> = LLMRequestResult<{
312
312
  parseError?: string;
313
313
  toolIterationsUsed?: number;
314
314
  toolIterationsExhausted?: true;
315
+ stopReason?: LLMToolLoopStopReasons;
316
+ terminalTool?: LLMTerminalToolOutcome;
315
317
  usage?: LLMModelUsage;
316
318
  cost?: LLMCostsResult;
317
319
  }>;
@@ -422,6 +424,16 @@ export type LLMAssistanceOptions<Provider extends LLMProviders, Reporter extends
422
424
  storageId?: string;
423
425
  tools?: LLMToolDefinition[];
424
426
  maxToolIterations?: number;
427
+ /**
428
+ * Invoked with the model's visible assistant text from a tool-calling round
429
+ * that will continue the loop (narration emitted alongside tool calls),
430
+ * before that round's tools execute. Never carries the final round's answer
431
+ * or reasoning/thinking content; the text may be empty when the round
432
+ * produced only tool calls, so the consumer skips empty/whitespace-only text.
433
+ * Observability-only: the callback must not throw — the tool loop does not
434
+ * guard the call.
435
+ */
436
+ onAssistantNarration?: (text: string) => void;
425
437
  };
426
438
  /**
427
439
  * Result type for assistance requests.
@@ -430,6 +442,8 @@ export type LLMAssistanceResult = LLMRequestResult<{
430
442
  text: string;
431
443
  toolIterationsUsed?: number;
432
444
  toolIterationsExhausted?: true;
445
+ stopReason?: LLMToolLoopStopReasons;
446
+ terminalTool?: LLMTerminalToolOutcome;
433
447
  }>;
434
448
  /**
435
449
  * Options for a one-shot prompt in a newly created chat.
@@ -479,6 +493,36 @@ export interface LLMToolDefinition<Schema extends LLMSchemaInterface = LLMSchema
479
493
  description: string;
480
494
  parameters: Schema;
481
495
  execute: (args: InferSchema<Schema>) => Promise<LLMToolResult> | LLMToolResult;
496
+ /**
497
+ * Ends the turn once this tool runs. The round executes in full (every call
498
+ * of that round, including parallel ones), but its results are not fed back
499
+ * and no further model round starts — the loop stops with
500
+ * `LLMToolLoopStopReasons.TerminalTool` and this tool's output as the turn
501
+ * outcome. Use for tools that hand control back to the application, such as
502
+ * an `ask_user` tool that needs a human reply before the agent can continue.
503
+ */
504
+ terminal?: boolean;
505
+ }
506
+ /**
507
+ * Why a provider's model⇄tool loop stopped. `Completed` is the ordinary end
508
+ * (a model round returned no tool calls), `MaxIterations` means the loop hit
509
+ * `maxToolIterations` with tool calls still pending, and `TerminalTool` means
510
+ * a tool declaring `terminal` ran and ended the turn.
511
+ */
512
+ export declare enum LLMToolLoopStopReasons {
513
+ Completed = "completed",
514
+ MaxIterations = "max_iterations",
515
+ TerminalTool = "terminal_tool"
516
+ }
517
+ /**
518
+ * The terminal tool call that ended a turn: the tool's name and the output it
519
+ * returned, which the application handles instead of a model answer. When more
520
+ * than one terminal call lands in the same round, the first in the round's
521
+ * order is reported (all of them still execute).
522
+ */
523
+ export interface LLMTerminalToolOutcome {
524
+ name: string;
525
+ output: LLMToolResult;
482
526
  }
483
527
  /**
484
528
  * Function type for counting tokens in messages for a specific provider's model.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LLMUploadFileMimeTypes = exports.LLMMessageContentType = exports.LLMRoles = exports.LLMPurposes = exports.LLMProviders = void 0;
3
+ exports.LLMToolLoopStopReasons = exports.LLMUploadFileMimeTypes = exports.LLMMessageContentType = exports.LLMRoles = exports.LLMPurposes = exports.LLMProviders = void 0;
4
4
  /**
5
5
  * Enum of supported LLM providers.
6
6
  */
@@ -57,4 +57,16 @@ var LLMUploadFileMimeTypes;
57
57
  LLMUploadFileMimeTypes["AUDIO_WEBM"] = "audio/webm";
58
58
  LLMUploadFileMimeTypes["AUDIO_OGG"] = "audio/ogg";
59
59
  })(LLMUploadFileMimeTypes || (exports.LLMUploadFileMimeTypes = LLMUploadFileMimeTypes = {}));
60
+ /**
61
+ * Why a provider's model⇄tool loop stopped. `Completed` is the ordinary end
62
+ * (a model round returned no tool calls), `MaxIterations` means the loop hit
63
+ * `maxToolIterations` with tool calls still pending, and `TerminalTool` means
64
+ * a tool declaring `terminal` ran and ended the turn.
65
+ */
66
+ var LLMToolLoopStopReasons;
67
+ (function (LLMToolLoopStopReasons) {
68
+ LLMToolLoopStopReasons["Completed"] = "completed";
69
+ LLMToolLoopStopReasons["MaxIterations"] = "max_iterations";
70
+ LLMToolLoopStopReasons["TerminalTool"] = "terminal_tool";
71
+ })(LLMToolLoopStopReasons || (exports.LLMToolLoopStopReasons = LLMToolLoopStopReasons = {}));
60
72
  //# sourceMappingURL=LLMService.typedefs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LLMService.typedefs.js","sourceRoot":"","sources":["../src/LLMService.typedefs.ts"],"names":[],"mappings":";;;AAkCA;;GAEG;AACH,IAAY,YAIX;AAJD,WAAY,YAAY;IACtB,iCAAiB,CAAA;IACjB,yDAAyC,CAAA;IACzC,iCAAiB,CAAA;AACnB,CAAC,EAJW,YAAY,4BAAZ,YAAY,QAIvB;AAoBD;;GAEG;AACH,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,wCAAyB,CAAA;IACzB,wCAAyB,CAAA;IACzB,8CAA+B,CAAA;IAC/B,8CAA+B,CAAA;AACjC,CAAC,EALW,WAAW,2BAAX,WAAW,QAKtB;AAiLD;;GAEG;AACH,IAAY,QAGX;AAHD,WAAY,QAAQ;IAClB,yBAAa,CAAA;IACb,mCAAuB,CAAA;AACzB,CAAC,EAHW,QAAQ,wBAAR,QAAQ,QAGnB;AAED;;GAEG;AACH,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,sCAAa,CAAA;IACb,gDAAuB,CAAA;IACvB,kDAAyB,CAAA;AAC3B,CAAC,EAJW,qBAAqB,qCAArB,qBAAqB,QAIhC;AA8KD;;GAEG;AACH,IAAY,sBAeX;AAfD,WAAY,sBAAsB;IAChC,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,iDAAuB,CAAA;IACvB,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,yDAA+B,CAAA;IAC/B,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,oDAA0B,CAAA;IAC1B,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,iDAAuB,CAAA;AACzB,CAAC,EAfW,sBAAsB,sCAAtB,sBAAsB,QAejC"}
1
+ {"version":3,"file":"LLMService.typedefs.js","sourceRoot":"","sources":["../src/LLMService.typedefs.ts"],"names":[],"mappings":";;;AAkCA;;GAEG;AACH,IAAY,YAIX;AAJD,WAAY,YAAY;IACtB,iCAAiB,CAAA;IACjB,yDAAyC,CAAA;IACzC,iCAAiB,CAAA;AACnB,CAAC,EAJW,YAAY,4BAAZ,YAAY,QAIvB;AAoBD;;GAEG;AACH,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,wCAAyB,CAAA;IACzB,wCAAyB,CAAA;IACzB,8CAA+B,CAAA;IAC/B,8CAA+B,CAAA;AACjC,CAAC,EALW,WAAW,2BAAX,WAAW,QAKtB;AAiLD;;GAEG;AACH,IAAY,QAGX;AAHD,WAAY,QAAQ;IAClB,yBAAa,CAAA;IACb,mCAAuB,CAAA;AACzB,CAAC,EAHW,QAAQ,wBAAR,QAAQ,QAGnB;AAED;;GAEG;AACH,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,sCAAa,CAAA;IACb,gDAAuB,CAAA;IACvB,kDAAyB,CAAA;AAC3B,CAAC,EAJW,qBAAqB,qCAArB,qBAAqB,QAIhC;AAgLD;;GAEG;AACH,IAAY,sBAeX;AAfD,WAAY,sBAAsB;IAChC,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,iDAAuB,CAAA;IACvB,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,yDAA+B,CAAA;IAC/B,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,oDAA0B,CAAA;IAC1B,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,iDAAuB,CAAA;IACvB,mDAAyB,CAAA;IACzB,iDAAuB,CAAA;AACzB,CAAC,EAfW,sBAAsB,sCAAtB,sBAAsB,QAejC;AAwND;;;;;GAKG;AACH,IAAY,sBAIX;AAJD,WAAY,sBAAsB;IAChC,iDAAuB,CAAA;IACvB,0DAAgC,CAAA;IAChC,wDAA8B,CAAA;AAChC,CAAC,EAJW,sBAAsB,sCAAtB,sBAAsB,QAIjC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Escape hatch entry point. Re-exports the internal engine — `LLMServiceFactory`,
3
+ * the provider services, and the model maps — for the rare call site that needs
4
+ * raw control the v2 client does not expose. Discouraged: prefer `createLLMClient`
5
+ * + the typed registry. This surface bypasses prompt management, the validation
6
+ * gate, and config-in-prompt routing.
7
+ */
8
+ export { LLMServiceFactory } from './LLMService.factory';
9
+ export { LLM_SERVICE_FACTORIES, LLM_SERVICE_MODELS, } from './LLMService.constants';
10
+ export * from './providers';
11
+ export * from './services';
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.LLM_SERVICE_MODELS = exports.LLM_SERVICE_FACTORIES = exports.LLMServiceFactory = void 0;
18
+ /**
19
+ * Escape hatch entry point. Re-exports the internal engine — `LLMServiceFactory`,
20
+ * the provider services, and the model maps — for the rare call site that needs
21
+ * raw control the v2 client does not expose. Discouraged: prefer `createLLMClient`
22
+ * + the typed registry. This surface bypasses prompt management, the validation
23
+ * gate, and config-in-prompt routing.
24
+ */
25
+ var LLMService_factory_1 = require("./LLMService.factory");
26
+ Object.defineProperty(exports, "LLMServiceFactory", { enumerable: true, get: function () { return LLMService_factory_1.LLMServiceFactory; } });
27
+ var LLMService_constants_1 = require("./LLMService.constants");
28
+ Object.defineProperty(exports, "LLM_SERVICE_FACTORIES", { enumerable: true, get: function () { return LLMService_constants_1.LLM_SERVICE_FACTORIES; } });
29
+ Object.defineProperty(exports, "LLM_SERVICE_MODELS", { enumerable: true, get: function () { return LLMService_constants_1.LLM_SERVICE_MODELS; } });
30
+ __exportStar(require("./providers"), exports);
31
+ __exportStar(require("./services"), exports);
32
+ //# sourceMappingURL=advanced.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advanced.js","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA;;;;;;GAMG;AACH,2DAAyD;AAAhD,uHAAA,iBAAiB,OAAA;AAC1B,+DAGgC;AAF9B,6HAAA,qBAAqB,OAAA;AACrB,0HAAA,kBAAkB,OAAA;AAEpB,8CAA4B;AAC5B,6CAA2B"}
@@ -0,0 +1,63 @@
1
+ import { type LLMToolDefinition } from '../LLMService.typedefs';
2
+ import { type LLMPromptRegistry } from '../client/defineLLMPrompts';
3
+ import { type LLMVariableValue } from '../client/promptSnapshot.typedefs';
4
+ import { type LLMPromptVariables } from '../client/createLLMClient.typedefs';
5
+ /**
6
+ * A bounded specialist the root agent may delegate to, as a plain object.
7
+ * `prompt` names the registry entry whose Langfuse prompt is the subagent's
8
+ * instructions (and whose config routes its model); `name`/`description` are
9
+ * what the root model sees when deciding to delegate. A plain-object subagent
10
+ * cannot declare its own subagents — use `LLMAgent` instances (via
11
+ * `llm.defineAgent`) when deeper composition is needed.
12
+ */
13
+ export type LLMAgentSubagentDefinition<Registry extends LLMPromptRegistry, VariableMap extends Record<keyof Registry, string>> = {
14
+ [Key in keyof Registry]: {
15
+ prompt: Key;
16
+ name: string;
17
+ description: string;
18
+ variables: LLMPromptVariables<VariableMap[Key]>;
19
+ tools?: LLMToolDefinition[];
20
+ maxToolIterations?: number;
21
+ };
22
+ }[keyof Registry];
23
+ /**
24
+ * Anything accepted in a `subagents` list: a plain definition object or an
25
+ * `LLMAgent` instance — both describe the same delegation tool.
26
+ */
27
+ export type LLMAgentSubagent<Registry extends LLMPromptRegistry, VariableMap extends Record<keyof Registry, string>> = LLMAgentSubagentDefinition<Registry, VariableMap> | LLMAgent<Registry, VariableMap>;
28
+ /**
29
+ * The declarative description of one agent. `prompt` names the registry entry
30
+ * whose Langfuse prompt is the agent's instructions (and whose config routes
31
+ * its model). `name`/`description` are required when the agent is used as a
32
+ * subagent — the name becomes the delegation tool the parent model calls.
33
+ * `variables` given here are a base merged under the per-run variables (for a
34
+ * subagent they are the only source).
35
+ */
36
+ export interface LLMAgentDefinition<Registry extends LLMPromptRegistry, VariableMap extends Record<keyof Registry, string>, Key extends keyof Registry> {
37
+ prompt: Key;
38
+ name?: string;
39
+ description?: string;
40
+ variables?: LLMPromptVariables<VariableMap[Key]>;
41
+ tools?: LLMToolDefinition[];
42
+ subagents?: LLMAgentSubagent<Registry, VariableMap>[];
43
+ maxToolIterations?: number;
44
+ }
45
+ /**
46
+ * An immutable agent definition bound to the prompt registry. Optional sugar
47
+ * over the plain-object `runAgent` options: build instances with
48
+ * `llm.defineAgent(...)` — the client factory carries the registry generics,
49
+ * so `prompt`, `variables`, and the `runAgent` return type stay fully typed.
50
+ * Agents compose: a subagent may itself be an `LLMAgent` with its own
51
+ * subagents; because instances are immutable, a delegation cycle cannot be
52
+ * constructed and nesting depth is always finite.
53
+ */
54
+ export declare class LLMAgent<Registry extends LLMPromptRegistry = LLMPromptRegistry, VariableMap extends Record<keyof Registry, string> = Record<keyof Registry, string>, Key extends keyof Registry = keyof Registry> {
55
+ readonly prompt: Key;
56
+ readonly name: string | undefined;
57
+ readonly description: string | undefined;
58
+ readonly variables: Record<string, LLMVariableValue> | undefined;
59
+ readonly tools: LLMToolDefinition[] | undefined;
60
+ readonly subagents: LLMAgentSubagent<Registry, VariableMap>[] | undefined;
61
+ readonly maxToolIterations: number | undefined;
62
+ constructor(definition: LLMAgentDefinition<Registry, VariableMap, Key>);
63
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LLMAgent = void 0;
4
+ /**
5
+ * An immutable agent definition bound to the prompt registry. Optional sugar
6
+ * over the plain-object `runAgent` options: build instances with
7
+ * `llm.defineAgent(...)` — the client factory carries the registry generics,
8
+ * so `prompt`, `variables`, and the `runAgent` return type stay fully typed.
9
+ * Agents compose: a subagent may itself be an `LLMAgent` with its own
10
+ * subagents; because instances are immutable, a delegation cycle cannot be
11
+ * constructed and nesting depth is always finite.
12
+ */
13
+ class LLMAgent {
14
+ prompt;
15
+ name;
16
+ description;
17
+ variables;
18
+ tools;
19
+ subagents;
20
+ maxToolIterations;
21
+ constructor(definition) {
22
+ this.prompt = definition.prompt;
23
+ this.name = definition.name;
24
+ this.description = definition.description;
25
+ this.variables = definition.variables;
26
+ this.tools = definition.tools;
27
+ this.subagents = definition.subagents;
28
+ this.maxToolIterations = definition.maxToolIterations;
29
+ }
30
+ }
31
+ exports.LLMAgent = LLMAgent;
32
+ //# sourceMappingURL=LLMAgent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LLMAgent.js","sourceRoot":"","sources":["../../src/client/LLMAgent.ts"],"names":[],"mappings":";;;AA8DA;;;;;;;;GAQG;AACH,MAAa,QAAQ;IAMV,MAAM,CAAM;IAEZ,IAAI,CAAqB;IAEzB,WAAW,CAAqB;IAEhC,SAAS,CAA+C;IAExD,KAAK,CAAkC;IAEvC,SAAS,CAAwD;IAEjE,iBAAiB,CAAqB;IAE/C,YAAY,UAA0D;QACpE,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC;QAC1C,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;QACtC,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;QACtC,IAAI,CAAC,iBAAiB,GAAG,UAAU,CAAC,iBAAiB,CAAC;IACxD,CAAC;CACF;AA7BD,4BA6BC"}
@@ -0,0 +1,170 @@
1
+ import { type LLMToolDefinition, type LLMToolResult, type LLMTerminalToolOutcome, type LLMToolLoopStopReasons } from '../LLMService.typedefs';
2
+ import { type LLMPromptRegistry } from '../client/defineLLMPrompts';
3
+ import { type LLMVariableValue } from '../client/promptSnapshot.typedefs';
4
+ import { type LLMCallOverrides, type LLMClientCallContext, type LLMPlainMessage } from '../client/createLLMClient.typedefs';
5
+ import { type LLMAgentSubagent } from '../client/LLMAgent';
6
+ /**
7
+ * Structured progress events an agent run emits while it works. They exist for
8
+ * two consumers with different needs: live UI updates (publish each event over
9
+ * a subscription/WS channel) and durable run history (persist each event as it
10
+ * arrives). Events are observability output, not control flow — a listener
11
+ * failure never affects the run.
12
+ */
13
+ export declare enum LLMAgentEventTypes {
14
+ AgentStarted = "agent_started",
15
+ AgentMessage = "agent_message",
16
+ AgentCompleted = "agent_completed",
17
+ AgentFailed = "agent_failed",
18
+ ToolCallStarted = "tool_call_started",
19
+ ToolCallCompleted = "tool_call_completed",
20
+ ToolCallFailed = "tool_call_failed",
21
+ SubagentStarted = "subagent_started",
22
+ SubagentCompleted = "subagent_completed",
23
+ SubagentFailed = "subagent_failed"
24
+ }
25
+ /**
26
+ * `agent` names the run that emitted the event: the prompt name for the root
27
+ * run, the subagent's `name` for a delegated run. `runId` identifies that run
28
+ * uniquely within the root run's event stream (ids come from one sequence
29
+ * spanning the whole tree), so a flat listener can rebuild the run tree even
30
+ * when the same subagent runs twice or tools execute in parallel.
31
+ */
32
+ interface LLMAgentEventBase {
33
+ agent: string;
34
+ runId: number;
35
+ }
36
+ /** Correlates the started/completed/failed events of one tool invocation. */
37
+ interface LLMAgentInvocationEventBase extends LLMAgentEventBase {
38
+ invocationId: number;
39
+ }
40
+ /**
41
+ * `subagentRunId` is the `runId` carried by the delegated run's own events,
42
+ * linking a Subagent* event to the nested Agent* events it produced.
43
+ */
44
+ interface LLMAgentSubagentEventBase extends LLMAgentInvocationEventBase {
45
+ subagent: string;
46
+ subagentRunId: number;
47
+ }
48
+ export interface LLMAgentStartedEvent extends LLMAgentEventBase {
49
+ type: LLMAgentEventTypes.AgentStarted;
50
+ input: string;
51
+ }
52
+ /**
53
+ * Visible assistant text the model produced in a tool-calling round that will
54
+ * continue the loop — narration emitted alongside tool calls, before those
55
+ * tools run. The final round's answer is never sent here (it is
56
+ * `LLMAgentCompletedEvent.output`); reasoning/thinking content and
57
+ * empty/whitespace-only text are never sent either. `agent`/`runId` identify
58
+ * the emitting run, so a subagent's narration is attributed to the subagent.
59
+ */
60
+ export interface LLMAgentMessageEvent extends LLMAgentEventBase {
61
+ type: LLMAgentEventTypes.AgentMessage;
62
+ text: string;
63
+ }
64
+ export interface LLMAgentCompletedEvent extends LLMAgentEventBase {
65
+ type: LLMAgentEventTypes.AgentCompleted;
66
+ output: string;
67
+ durationMs: number;
68
+ }
69
+ export interface LLMAgentFailedEvent extends LLMAgentEventBase {
70
+ type: LLMAgentEventTypes.AgentFailed;
71
+ error: string;
72
+ durationMs: number;
73
+ }
74
+ export interface LLMAgentToolCallStartedEvent extends LLMAgentInvocationEventBase {
75
+ type: LLMAgentEventTypes.ToolCallStarted;
76
+ tool: string;
77
+ input: unknown;
78
+ }
79
+ export interface LLMAgentToolCallCompletedEvent extends LLMAgentInvocationEventBase {
80
+ type: LLMAgentEventTypes.ToolCallCompleted;
81
+ tool: string;
82
+ output: LLMToolResult;
83
+ durationMs: number;
84
+ }
85
+ export interface LLMAgentToolCallFailedEvent extends LLMAgentInvocationEventBase {
86
+ type: LLMAgentEventTypes.ToolCallFailed;
87
+ tool: string;
88
+ error: string;
89
+ durationMs: number;
90
+ }
91
+ export interface LLMAgentSubagentStartedEvent extends LLMAgentSubagentEventBase {
92
+ type: LLMAgentEventTypes.SubagentStarted;
93
+ input: string;
94
+ }
95
+ export interface LLMAgentSubagentCompletedEvent extends LLMAgentSubagentEventBase {
96
+ type: LLMAgentEventTypes.SubagentCompleted;
97
+ output: string;
98
+ durationMs: number;
99
+ }
100
+ export interface LLMAgentSubagentFailedEvent extends LLMAgentSubagentEventBase {
101
+ type: LLMAgentEventTypes.SubagentFailed;
102
+ error: string;
103
+ durationMs: number;
104
+ }
105
+ export type LLMAgentEvent = LLMAgentStartedEvent | LLMAgentMessageEvent | LLMAgentCompletedEvent | LLMAgentFailedEvent | LLMAgentToolCallStartedEvent | LLMAgentToolCallCompletedEvent | LLMAgentToolCallFailedEvent | LLMAgentSubagentStartedEvent | LLMAgentSubagentCompletedEvent | LLMAgentSubagentFailedEvent;
106
+ /**
107
+ * May be async: a returned promise's rejection is caught and logged, so a
108
+ * failing listener (WS publish, DB persist) never affects the agent run.
109
+ */
110
+ export type LLMAgentEventListener = (event: LLMAgentEvent) => void | Promise<void>;
111
+ /**
112
+ * A turn that produced a model answer: either the model finished on its own
113
+ * (`Completed`) or the loop hit `maxToolIterations` (`MaxIterations`). `output`
114
+ * is the bound schema's type, or the final assistant text when no schema is
115
+ * bound — exactly what `generate` returns.
116
+ */
117
+ export interface LLMAgentAnsweredRunResult<Output> {
118
+ stopReason: Exclude<LLMToolLoopStopReasons, LLMToolLoopStopReasons.TerminalTool>;
119
+ output: Output;
120
+ /** Visible assistant text of the final round. */
121
+ text: string;
122
+ terminalTool?: undefined;
123
+ }
124
+ /**
125
+ * A turn ended by a tool declaring `terminal` (for example an `ask_user` tool).
126
+ * The model produced no final answer — the round ran in full, its results were
127
+ * not fed back, and no further model round started — so the turn's outcome is
128
+ * `terminalTool`, which the application handles before resuming the agent.
129
+ */
130
+ export interface LLMAgentTerminalToolRunResult {
131
+ stopReason: LLMToolLoopStopReasons.TerminalTool;
132
+ terminalTool: LLMTerminalToolOutcome;
133
+ /** Visible assistant text of the terminating round; often empty. */
134
+ text: string;
135
+ output?: undefined;
136
+ }
137
+ /**
138
+ * What one agent run produced. Discriminate on `stopReason` (or on the presence
139
+ * of `terminalTool`) to tell an answered turn from one handed back to the
140
+ * application by a terminal tool.
141
+ */
142
+ export type LLMAgentRunResult<Output> = LLMAgentAnsweredRunResult<Output> | LLMAgentTerminalToolRunResult;
143
+ /**
144
+ * Per-run inputs shared by both `runAgent` forms. When running an `LLMAgent`
145
+ * instance these are the only options — the agent already carries its tools,
146
+ * subagents, and iteration bound.
147
+ */
148
+ export interface LLMAgentRunOptions<Variables extends Record<string, LLMVariableValue>> {
149
+ /** Variables compiled into the agent's instructions prompt. */
150
+ variables: Variables;
151
+ /** The user request the agent works on this run. */
152
+ input: string;
153
+ /** Prior conversation restored from persisted session state. */
154
+ history?: LLMPlainMessage[];
155
+ context?: LLMClientCallContext;
156
+ abortSignal?: AbortSignal;
157
+ overrides?: LLMCallOverrides;
158
+ onEvent?: LLMAgentEventListener;
159
+ }
160
+ /**
161
+ * Options for the prompt-key form of `runAgent`, where the agent shape is
162
+ * declared inline instead of via an `LLMAgent` instance.
163
+ */
164
+ export interface LLMAgentInlineRunOptions<Variables extends Record<string, LLMVariableValue>, Registry extends LLMPromptRegistry, VariableMap extends Record<keyof Registry, string>> extends LLMAgentRunOptions<Variables> {
165
+ /** Executable tools available to the agent. */
166
+ tools?: LLMToolDefinition[];
167
+ subagents?: LLMAgentSubagent<Registry, VariableMap>[];
168
+ maxToolIterations?: number;
169
+ }
170
+ export {};
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LLMAgentEventTypes = void 0;
4
+ /**
5
+ * Structured progress events an agent run emits while it works. They exist for
6
+ * two consumers with different needs: live UI updates (publish each event over
7
+ * a subscription/WS channel) and durable run history (persist each event as it
8
+ * arrives). Events are observability output, not control flow — a listener
9
+ * failure never affects the run.
10
+ */
11
+ var LLMAgentEventTypes;
12
+ (function (LLMAgentEventTypes) {
13
+ LLMAgentEventTypes["AgentStarted"] = "agent_started";
14
+ LLMAgentEventTypes["AgentMessage"] = "agent_message";
15
+ LLMAgentEventTypes["AgentCompleted"] = "agent_completed";
16
+ LLMAgentEventTypes["AgentFailed"] = "agent_failed";
17
+ LLMAgentEventTypes["ToolCallStarted"] = "tool_call_started";
18
+ LLMAgentEventTypes["ToolCallCompleted"] = "tool_call_completed";
19
+ LLMAgentEventTypes["ToolCallFailed"] = "tool_call_failed";
20
+ LLMAgentEventTypes["SubagentStarted"] = "subagent_started";
21
+ LLMAgentEventTypes["SubagentCompleted"] = "subagent_completed";
22
+ LLMAgentEventTypes["SubagentFailed"] = "subagent_failed";
23
+ })(LLMAgentEventTypes || (exports.LLMAgentEventTypes = LLMAgentEventTypes = {}));
24
+ //# sourceMappingURL=agentRun.typedefs.js.map