vern-llm 0.2.1 → 0.4.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.
package/dist/index.d.ts CHANGED
@@ -97,7 +97,7 @@ interface LLMClient {
97
97
  /** OpenAI reasoning-model param (o-series, gpt-5), ignored by providers that don't support it */
98
98
  reasoning_effort?: 'minimal' | 'low' | 'medium' | 'high';
99
99
  messages: Array<{
100
- role: 'system' | 'user';
100
+ role: 'system' | 'user' | 'assistant';
101
101
  content: string;
102
102
  }>;
103
103
  }, options: {
@@ -186,9 +186,23 @@ interface JsonSchemaSpec {
186
186
  strict?: boolean;
187
187
  description?: string;
188
188
  }
189
+ /** A single prior turn in a multi-turn conversation, passed via `history`. */
190
+ interface ConversationTurn {
191
+ role: 'user' | 'assistant';
192
+ content: string;
193
+ }
189
194
  interface CallParams<T = unknown> {
190
195
  systemPrompt: string;
191
196
  userContent: string;
197
+ /**
198
+ * Prior turns in the conversation, oldest first, NOT including the current
199
+ * `userContent` (that's appended automatically as the final user turn).
200
+ * Passed straight through to the provider so follow-up questions have
201
+ * access to earlier context. Must strictly alternate user/assistant and
202
+ * end on an assistant turn; validated up front and rejected with an
203
+ * LLMError('validation') before any request is made if malformed.
204
+ */
205
+ history?: ConversationTurn[];
192
206
  temperature?: number;
193
207
  jsonMode?: boolean;
194
208
  maxTokens?: number;
@@ -305,6 +319,15 @@ declare class VernLLM {
305
319
  * usage and a circuit breaker success before returning
306
320
  */
307
321
  private executeCall;
322
+ /**
323
+ * Anthropic and Gemini both require strict user/assistant alternation
324
+ * (and reject or silently mishandle two consecutive same-role turns), so
325
+ * this validates `history` up front rather than letting a malformed
326
+ * request surface as a confusing provider-side error. Thrown as a
327
+ * validation LLMError, which `shouldRetry` never retries, since retrying
328
+ * the same malformed input can't succeed
329
+ */
330
+ private validateHistory;
308
331
  /**
309
332
  * Applies per call defaults and shapes the params into the request
310
333
  * object expected by the underlying client, including the resolved
@@ -367,10 +390,9 @@ declare class VernLLM {
367
390
  * circuit breaker was configured on this instance
368
391
  */
369
392
  getCircuitState(): ("closed" | "open" | "half-open") | undefined;
370
- }
371
-
372
- //#endregion
393
+ } //#endregion
373
394
  //#region src/adapters/anthropic.d.ts
395
+
374
396
  //# sourceMappingURL=vernLLM.d.ts.map
375
397
  /** Minimal structural type for the Anthropic SDKs `messages.create` */
376
398
  interface AnthropicClient {
@@ -384,12 +406,23 @@ interface AnthropicClient {
384
406
  role: 'user' | 'assistant';
385
407
  content: string;
386
408
  }>;
409
+ tools?: Array<{
410
+ name: string;
411
+ description?: string;
412
+ input_schema: Record<string, unknown>;
413
+ }>;
414
+ tool_choice?: {
415
+ type: 'tool';
416
+ name: string;
417
+ };
387
418
  }, options: {
388
419
  signal: AbortSignal;
389
420
  }): Promise<{
390
421
  content: Array<{
391
422
  type: string;
392
423
  text?: string;
424
+ name?: string;
425
+ input?: unknown;
393
426
  }>;
394
427
  usage?: {
395
428
  input_tokens?: number;
@@ -400,10 +433,18 @@ interface AnthropicClient {
400
433
  }
401
434
  /**
402
435
  * Wraps an Anthropic SDK client so it satisfies the same `LLMClient`
403
- * interface VernLLM uses for OpenAI/Groq. Anthropics Messages API has no
404
- * `response_format: json_object` equivalent, so when the caller requests
405
- * JSON mode, this adapter appends an instruction to the system prompt
406
- * asking the model to respond with JSON only
436
+ * interface VernLLM uses for OpenAI/Groq.
437
+ *
438
+ * `response_format: json_schema` is mapped to Anthropics forced tool-use:
439
+ * a single tool is defined with `input_schema` set to the caller's schema,
440
+ * and `tool_choice` forces the model to call it, so the output is
441
+ * provider-constrained to match the schema rather than merely instructed
442
+ * to via prompt text (the same guarantee OpenAIs native `json_schema` mode
443
+ * gives, built on Anthropics tool-calling primitive instead).
444
+ *
445
+ * `response_format: json_object` (no schema to build a tool from) falls
446
+ * back to a system-prompt instruction, since theres nothing to constrain
447
+ * generation against.
407
448
  */
408
449
  declare function fromAnthropic(anthropicClient: AnthropicClient): LLMClient;
409
450
 
@@ -420,7 +461,7 @@ interface GeminiClient {
420
461
  generateContent(params: {
421
462
  model?: string;
422
463
  contents: Array<{
423
- role: 'user';
464
+ role: 'user' | 'model';
424
465
  parts: Array<{
425
466
  text: string;
426
467
  }>;
@@ -489,7 +530,7 @@ interface BedrockConverseClient {
489
530
  converse(params: {
490
531
  modelId: string;
491
532
  messages: Array<{
492
- role: 'user';
533
+ role: 'user' | 'assistant';
493
534
  content: Array<{
494
535
  text: string;
495
536
  }>;
@@ -501,6 +542,22 @@ interface BedrockConverseClient {
501
542
  temperature?: number;
502
543
  maxTokens?: number;
503
544
  };
545
+ toolConfig?: {
546
+ tools: Array<{
547
+ toolSpec: {
548
+ name: string;
549
+ description?: string;
550
+ inputSchema: {
551
+ json: Record<string, unknown>;
552
+ };
553
+ };
554
+ }>;
555
+ toolChoice?: {
556
+ tool: {
557
+ name: string;
558
+ };
559
+ };
560
+ };
504
561
  }, options: {
505
562
  signal: AbortSignal;
506
563
  }): Promise<{
@@ -508,6 +565,10 @@ interface BedrockConverseClient {
508
565
  message?: {
509
566
  content?: Array<{
510
567
  text?: string;
568
+ toolUse?: {
569
+ name?: string;
570
+ input?: unknown;
571
+ };
511
572
  }>;
512
573
  };
513
574
  };
@@ -526,11 +587,15 @@ interface BedrockConverseClient {
526
587
  * regardless of which underlying model `modelId` points at, as long as
527
588
  * that model supports Converse (most current-generation ones do)
528
589
  *
529
- * Theres no uniform native JSON Schema enforcement across families here
530
- * (some support it via forced tool-use, which varies per model), so
531
- * `jsonSchema`/`jsonMode` are emulated via a system-prompt instruction, same
532
- * approach as the Anthropic adapter. `reasoning_effort` has no Converse
533
- * equivalent and is dropped
590
+ * `response_format: json_schema` is mapped to Converses `toolConfig`: a
591
+ * single tool is defined from the schema and `toolChoice` forces the model
592
+ * to call it, constraining output at generation time rather than merely
593
+ * instructing for it via prompt text. Native tool support varies by model
594
+ * family (most current-generation ones support it via Converse; check your
595
+ * specific `modelId` if a call fails with an unsupported-parameter error).
596
+ * `response_format: json_object` (no schema to build a tool from) and
597
+ * `reasoning_effort` (no Converse equivalent) fall back to a system-prompt
598
+ * instruction and are dropped respectively.
534
599
  */
535
600
  declare function fromBedrock(bedrockClient: BedrockConverseClient): LLMClient;
536
601
 
@@ -614,5 +679,5 @@ declare const fromOllama: typeof fromOpenAICompatible;
614
679
  //#endregion
615
680
  //# sourceMappingURL=openaiCompatible.d.ts.map
616
681
 
617
- export { CacheAdapter, CachedCallParams, CallParams, CircuitBreaker, CircuitBreakerOptions, ConsoleLogger, FetchAdapterConfig, InMemoryCacheAdapter, JsonSchemaSpec, LLMClient, LLMError, LLMErrorType, Logger, OnUsage, RefundUsage, ReserveUsage, SchemaLike, TokenUsage, VernLLM, VernLLMOptions, fromAnthropic, fromBedrock, fromCerebras, fromDeepSeek, fromFetch, fromFireworks, fromGemini, fromGroq, fromMistral, fromOllama, fromOpenAICompatible, fromTogether, isLLMError };
682
+ export { CacheAdapter, CachedCallParams, CallParams, CircuitBreaker, CircuitBreakerOptions, ConsoleLogger, ConversationTurn, FetchAdapterConfig, InMemoryCacheAdapter, JsonSchemaSpec, LLMClient, LLMError, LLMErrorType, Logger, OnUsage, RefundUsage, ReserveUsage, SchemaLike, TokenUsage, VernLLM, VernLLMOptions, fromAnthropic, fromBedrock, fromCerebras, fromDeepSeek, fromFetch, fromFireworks, fromGemini, fromGroq, fromMistral, fromOllama, fromOpenAICompatible, fromTogether, isLLMError };
618
683
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/logger.ts","../src/circuitBreaker.ts","../src/types.ts","../src/vernLLM.ts","../src/adapters/anthropic.ts","../src/adapters/gemini.ts","../src/adapters/bedrock.ts","../src/adapters/fetch.ts","../src/adapters/openaiCompatible.ts"],"sourcesContent":null,"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/logger.ts","../src/circuitBreaker.ts","../src/types.ts","../src/vernLLM.ts","../src/adapters/anthropic.ts","../src/adapters/gemini.ts","../src/adapters/bedrock.ts","../src/adapters/fetch.ts","../src/adapters/openaiCompatible.ts"],"sourcesContent":null,"mappings":"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"}
package/dist/index.js CHANGED
@@ -111,9 +111,12 @@ function extractStatus(err) {
111
111
  * Runs an async function and cancels it if it takes longer than the given
112
112
  * timeout. Creates an internal abort controller that fires after the
113
113
  * timeout elapses, and combines it with any external signal the caller
114
- * passed in so either one can cancel the underlying call. The internal
115
- * timer is always cleared afterward, whether the function succeeds,
116
- * fails, or is aborted, so nothing is left running in the background
114
+ * passed in so either one can cancel the underlying call. If the internal
115
+ * timeout triggers and the underlying operation aborts, the error is
116
+ * converted into an LLMError with type "timeout". External cancellations
117
+ * continue to propagate as aborted errors. The internal timer is always
118
+ * cleared afterward, whether the function succeeds, fails, or is aborted,
119
+ * so nothing is left running in the background.
117
120
  */
118
121
  async function withTimeout(fn, timeoutMs, externalSignal) {
119
122
  const controller = new AbortController();
@@ -123,6 +126,9 @@ async function withTimeout(fn, timeoutMs, externalSignal) {
123
126
  const signal = externalSignal ? AbortSignal.any([externalSignal, controller.signal]) : controller.signal;
124
127
  try {
125
128
  return await fn(signal);
129
+ } catch (err) {
130
+ if (controller.signal.aborted && !externalSignal?.aborted && err instanceof DOMException && err.name === "AbortError") throw new LLMError("Request timed out", "timeout");
131
+ throw err;
126
132
  } finally {
127
133
  clearTimeout(timer);
128
134
  }
@@ -327,28 +333,53 @@ var VernLLM = class {
327
333
  return this.parseAndValidate(content, params.schema);
328
334
  }
329
335
  /**
336
+ * Anthropic and Gemini both require strict user/assistant alternation
337
+ * (and reject or silently mishandle two consecutive same-role turns), so
338
+ * this validates `history` up front rather than letting a malformed
339
+ * request surface as a confusing provider-side error. Thrown as a
340
+ * validation LLMError, which `shouldRetry` never retries, since retrying
341
+ * the same malformed input can't succeed
342
+ */
343
+ validateHistory(history) {
344
+ let previousRole;
345
+ for (const [index, turn] of history.entries()) {
346
+ if (turn.role !== "user" && turn.role !== "assistant") throw new LLMError(`Invalid history[${index}].role "${turn.role}": must be "user" or "assistant"`, "validation");
347
+ if (turn.role === previousRole) throw new LLMError(`history must alternate user/assistant turns: consecutive "${turn.role}" turns at history[${index - 1}] and history[${index}]`, "validation");
348
+ previousRole = turn.role;
349
+ }
350
+ if (previousRole === "user") throw new LLMError("The last entry in history is a \"user\" turn, which would collide with the current userContent turn. history must end with an \"assistant\" turn (or be empty).", "validation");
351
+ }
352
+ /**
330
353
  * Applies per call defaults and shapes the params into the request
331
354
  * object expected by the underlying client, including the resolved
332
355
  * response format. Also returns whether JSON parsing should be
333
356
  * applied to the response and which model was ultimately used
334
357
  */
335
358
  buildRequestPayload(params) {
336
- const { systemPrompt, userContent, temperature = .2, jsonMode = true, maxTokens = this.defaultMaxTokens, model = this.model, reasoningEffort, jsonSchema } = params;
359
+ const { systemPrompt, userContent, history = [], temperature = .2, jsonMode = true, maxTokens = this.defaultMaxTokens, model = this.model, reasoningEffort, jsonSchema } = params;
337
360
  const useJson = jsonMode || Boolean(jsonSchema);
338
361
  const responseFormat = this.buildResponseFormat(jsonSchema, useJson);
362
+ this.validateHistory(history);
339
363
  const request = {
340
364
  model,
341
365
  temperature,
342
366
  max_tokens: maxTokens,
343
367
  ...responseFormat ? { response_format: responseFormat } : {},
344
368
  ...reasoningEffort ? { reasoning_effort: reasoningEffort } : {},
345
- messages: [{
346
- role: "system",
347
- content: systemPrompt
348
- }, {
349
- role: "user",
350
- content: userContent
351
- }]
369
+ messages: [
370
+ {
371
+ role: "system",
372
+ content: systemPrompt
373
+ },
374
+ ...history.map((turn) => ({
375
+ role: turn.role,
376
+ content: turn.content
377
+ })),
378
+ {
379
+ role: "user",
380
+ content: userContent
381
+ }
382
+ ]
352
383
  };
353
384
  return {
354
385
  useJson,
@@ -485,19 +516,33 @@ var VernLLM = class {
485
516
  //#region src/adapters/anthropic.ts
486
517
  /**
487
518
  * Wraps an Anthropic SDK client so it satisfies the same `LLMClient`
488
- * interface VernLLM uses for OpenAI/Groq. Anthropics Messages API has no
489
- * `response_format: json_object` equivalent, so when the caller requests
490
- * JSON mode, this adapter appends an instruction to the system prompt
491
- * asking the model to respond with JSON only
519
+ * interface VernLLM uses for OpenAI/Groq.
520
+ *
521
+ * `response_format: json_schema` is mapped to Anthropics forced tool-use:
522
+ * a single tool is defined with `input_schema` set to the caller's schema,
523
+ * and `tool_choice` forces the model to call it, so the output is
524
+ * provider-constrained to match the schema rather than merely instructed
525
+ * to via prompt text (the same guarantee OpenAIs native `json_schema` mode
526
+ * gives, built on Anthropics tool-calling primitive instead).
527
+ *
528
+ * `response_format: json_object` (no schema to build a tool from) falls
529
+ * back to a system-prompt instruction, since theres nothing to constrain
530
+ * generation against.
492
531
  */
493
532
  function fromAnthropic(anthropicClient) {
494
533
  return { chat: { completions: { async create(params, options) {
495
534
  const systemMessage = params.messages.find((m) => m.role === "system");
496
- const userMessages = params.messages.filter((m) => m.role === "user");
535
+ const conversationMessages = params.messages.filter((m) => m.role === "user" || m.role === "assistant");
536
+ const toolName = params.response_format?.type === "json_schema" ? params.response_format.json_schema.name : void 0;
497
537
  let jsonInstruction;
498
- if (params.response_format?.type === "json_schema") {
499
- const { name, schema } = params.response_format.json_schema;
500
- jsonInstruction = `Respond with valid JSON only, no prose or markdown fences. The JSON must conform to this schema (name: "${name}"):\n${JSON.stringify(schema)}`;
538
+ let tools;
539
+ if (params.response_format?.type === "json_schema" && toolName) {
540
+ const { schema, description } = params.response_format.json_schema;
541
+ tools = [{
542
+ name: toolName,
543
+ description,
544
+ input_schema: schema
545
+ }];
501
546
  } else if (params.response_format?.type === "json_object") jsonInstruction = "Respond with valid JSON only, no prose or markdown fences.";
502
547
  const system = [systemMessage?.content, jsonInstruction].filter(Boolean).join("\n\n");
503
548
  const response = await anthropicClient.messages.create({
@@ -505,12 +550,23 @@ function fromAnthropic(anthropicClient) {
505
550
  max_tokens: params.max_tokens,
506
551
  temperature: params.temperature,
507
552
  system: system || void 0,
508
- messages: userMessages.map((m) => ({
509
- role: "user",
553
+ messages: conversationMessages.map((m) => ({
554
+ role: m.role,
510
555
  content: m.content
511
- }))
556
+ })),
557
+ ...tools ? {
558
+ tools,
559
+ tool_choice: {
560
+ type: "tool",
561
+ name: toolName
562
+ }
563
+ } : {}
512
564
  }, options);
513
- const text = response.content.find((block) => block.type === "text")?.text ?? "";
565
+ let text;
566
+ if (toolName) {
567
+ const toolUse = response.content.find((block) => block.type === "tool_use" && block.name === toolName);
568
+ text = toolUse ? JSON.stringify(toolUse.input) : "";
569
+ } else text = response.content.find((block) => block.type === "text")?.text ?? "";
514
570
  return {
515
571
  choices: [{ message: { content: text } }],
516
572
  usage: {
@@ -538,7 +594,7 @@ function fromAnthropic(anthropicClient) {
538
594
  function fromGemini(geminiClient) {
539
595
  return { chat: { completions: { async create(params, options) {
540
596
  const systemMessage = params.messages.find((m) => m.role === "system");
541
- const userMessages = params.messages.filter((m) => m.role === "user");
597
+ const conversationMessages = params.messages.filter((m) => m.role === "user" || m.role === "assistant");
542
598
  const wantsJson = Boolean(params.response_format);
543
599
  const generationConfig = {
544
600
  temperature: params.temperature,
@@ -548,8 +604,8 @@ function fromGemini(geminiClient) {
548
604
  if (params.response_format?.type === "json_schema") generationConfig.responseSchema = params.response_format.json_schema.schema;
549
605
  const response = await geminiClient.generateContent({
550
606
  model: params.model,
551
- contents: userMessages.map((m) => ({
552
- role: "user",
607
+ contents: conversationMessages.map((m) => ({
608
+ role: m.role === "assistant" ? "model" : "user",
553
609
  parts: [{ text: m.content }]
554
610
  })),
555
611
  systemInstruction: systemMessage ? { parts: [{ text: systemMessage.content }] } : void 0,
@@ -577,35 +633,53 @@ function fromGemini(geminiClient) {
577
633
  * regardless of which underlying model `modelId` points at, as long as
578
634
  * that model supports Converse (most current-generation ones do)
579
635
  *
580
- * Theres no uniform native JSON Schema enforcement across families here
581
- * (some support it via forced tool-use, which varies per model), so
582
- * `jsonSchema`/`jsonMode` are emulated via a system-prompt instruction, same
583
- * approach as the Anthropic adapter. `reasoning_effort` has no Converse
584
- * equivalent and is dropped
636
+ * `response_format: json_schema` is mapped to Converses `toolConfig`: a
637
+ * single tool is defined from the schema and `toolChoice` forces the model
638
+ * to call it, constraining output at generation time rather than merely
639
+ * instructing for it via prompt text. Native tool support varies by model
640
+ * family (most current-generation ones support it via Converse; check your
641
+ * specific `modelId` if a call fails with an unsupported-parameter error).
642
+ * `response_format: json_object` (no schema to build a tool from) and
643
+ * `reasoning_effort` (no Converse equivalent) fall back to a system-prompt
644
+ * instruction and are dropped respectively.
585
645
  */
586
646
  function fromBedrock(bedrockClient) {
587
647
  return { chat: { completions: { async create(params, options) {
588
648
  const systemMessage = params.messages.find((m) => m.role === "system");
589
- const userMessages = params.messages.filter((m) => m.role === "user");
649
+ const conversationMessages = params.messages.filter((m) => m.role === "user" || m.role === "assistant");
650
+ const toolName = params.response_format?.type === "json_schema" ? params.response_format.json_schema.name : void 0;
590
651
  let jsonInstruction;
591
- if (params.response_format?.type === "json_schema") {
592
- const { name, schema } = params.response_format.json_schema;
593
- jsonInstruction = `Respond with valid JSON only, no prose or markdown fences. The JSON must conform to this schema (name: "${name}"):\n${JSON.stringify(schema)}`;
652
+ let toolConfig;
653
+ if (params.response_format?.type === "json_schema" && toolName) {
654
+ const { schema, description } = params.response_format.json_schema;
655
+ toolConfig = {
656
+ tools: [{ toolSpec: {
657
+ name: toolName,
658
+ description,
659
+ inputSchema: { json: schema }
660
+ } }],
661
+ toolChoice: { tool: { name: toolName } }
662
+ };
594
663
  } else if (params.response_format?.type === "json_object") jsonInstruction = "Respond with valid JSON only, no prose or markdown fences.";
595
664
  const systemParts = [systemMessage?.content, jsonInstruction].filter((s) => Boolean(s));
596
665
  const response = await bedrockClient.converse({
597
666
  modelId: params.model,
598
- messages: userMessages.map((m) => ({
599
- role: "user",
667
+ messages: conversationMessages.map((m) => ({
668
+ role: m.role,
600
669
  content: [{ text: m.content }]
601
670
  })),
602
671
  system: systemParts.length ? systemParts.map((text$1) => ({ text: text$1 })) : void 0,
603
672
  inferenceConfig: {
604
673
  temperature: params.temperature,
605
674
  maxTokens: params.max_tokens
606
- }
675
+ },
676
+ ...toolConfig ? { toolConfig } : {}
607
677
  }, options);
608
- const text = response.output?.message?.content?.map((c) => c.text ?? "").join("") ?? "";
678
+ let text;
679
+ if (toolName) {
680
+ const toolUseBlock = response.output?.message?.content?.find((block) => block.toolUse?.name === toolName);
681
+ text = toolUseBlock?.toolUse ? JSON.stringify(toolUseBlock.toolUse.input) : "";
682
+ } else text = response.output?.message?.content?.map((c) => c.text ?? "").join("") ?? "";
609
683
  return {
610
684
  choices: [{ message: { content: text } }],
611
685
  usage: {