@jambonz/llm 0.5.6 → 0.6.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.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-BEgQaQIb.cjs';
2
- export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-BEgQaQIb.cjs';
1
+ import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-Y0o6rN3B.cjs';
2
+ export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-Y0o6rN3B.cjs';
3
3
 
4
4
  /**
5
5
  * The loose "DB-shape" input accepted by `normalizeAuth`.
@@ -73,6 +73,7 @@ declare function pickAuthKind(vendor: string, raw: RawCredentialLoose): AuthKind
73
73
  * - `model` is a non-empty string.
74
74
  * - `messages` is a non-empty array.
75
75
  * - `messages` does not contain `role: 'system'` turns (use `system` top-level).
76
+ * - `cacheKey`, when present, is a non-empty string.
76
77
  */
77
78
  declare function assertValidRequest(req: PromptRequest): void;
78
79
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-BEgQaQIb.js';
2
- export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-BEgQaQIb.js';
1
+ import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-Y0o6rN3B.js';
2
+ export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-Y0o6rN3B.js';
3
3
 
4
4
  /**
5
5
  * The loose "DB-shape" input accepted by `normalizeAuth`.
@@ -73,6 +73,7 @@ declare function pickAuthKind(vendor: string, raw: RawCredentialLoose): AuthKind
73
73
  * - `model` is a non-empty string.
74
74
  * - `messages` is a non-empty array.
75
75
  * - `messages` does not contain `role: 'system'` turns (use `system` top-level).
76
+ * - `cacheKey`, when present, is a non-empty string.
76
77
  */
77
78
  declare function assertValidRequest(req: PromptRequest): void;
78
79
 
package/dist/index.js CHANGED
@@ -56,6 +56,9 @@ function assertValidRequest(req) {
56
56
  "PromptRequest.messages must not contain role: 'system'. Pass the system prompt via PromptRequest.system instead."
57
57
  );
58
58
  }
59
+ if (req.cacheKey !== void 0 && (typeof req.cacheKey !== "string" || req.cacheKey.length === 0)) {
60
+ throw new Error("PromptRequest.cacheKey must be a non-empty string");
61
+ }
59
62
  }
60
63
 
61
64
  // src/adapters/openai/_streaming.ts
@@ -80,11 +83,20 @@ async function* streamFromOpenAI(client, req, options) {
80
83
  body.tool_choice = "auto";
81
84
  }
82
85
  if (req.temperature !== void 0) body.temperature = req.temperature;
86
+ if (req.cacheKey && options.includeCacheKey !== false) {
87
+ body.prompt_cache_key = req.cacheKey;
88
+ }
83
89
  const effectiveMaxTokens = req.maxTokens ?? options.defaultMaxTokens;
84
90
  if (effectiveMaxTokens !== void 0) {
85
91
  const param = options.tokensParam ?? (needsMaxCompletionTokens(req.model) ? "max_completion_tokens" : "max_tokens");
86
92
  body[param] = effectiveMaxTokens;
87
93
  }
94
+ if (req.providerParams) {
95
+ const bodyRecord = body;
96
+ for (const [key, value] of Object.entries(req.providerParams)) {
97
+ if (!(key in bodyRecord)) bodyRecord[key] = value;
98
+ }
99
+ }
88
100
  const t0 = process.hrtime.bigint();
89
101
  let t1;
90
102
  let t2;
@@ -127,10 +139,12 @@ async function* streamFromOpenAI(client, req, options) {
127
139
  throw new Error(`OpenAI-compatible stream returned an error: ${message}`);
128
140
  }
129
141
  if (chunk.usage) {
142
+ const cachedTokens = chunk.usage.prompt_tokens_details?.cached_tokens;
130
143
  usage = {
131
- ...chunk.usage.prompt_tokens !== void 0 ? { inputTokens: chunk.usage.prompt_tokens } : {},
144
+ ...chunk.usage.prompt_tokens !== void 0 ? { inputTokens: chunk.usage.prompt_tokens - (cachedTokens ?? 0) } : {},
132
145
  ...chunk.usage.completion_tokens !== void 0 ? { outputTokens: chunk.usage.completion_tokens } : {},
133
- ...chunk.usage.total_tokens !== void 0 ? { totalTokens: chunk.usage.total_tokens } : {}
146
+ ...chunk.usage.total_tokens !== void 0 ? { totalTokens: chunk.usage.total_tokens } : {},
147
+ ...cachedTokens !== void 0 ? { cacheReadTokens: cachedTokens } : {}
134
148
  };
135
149
  }
136
150
  const choice = chunk.choices?.[0];
@@ -1183,6 +1197,16 @@ var AnthropicAdapter = class {
1183
1197
  if (req.system) body.system = req.system;
1184
1198
  if (tools) body.tools = tools;
1185
1199
  if (req.temperature !== void 0) body.temperature = req.temperature;
1200
+ if (req.cacheKey) {
1201
+ if (req.system) {
1202
+ body.system = [{ type: "text", text: req.system, cache_control: { type: "ephemeral" } }];
1203
+ }
1204
+ if (tools) {
1205
+ const lastTool = tools[tools.length - 1];
1206
+ lastTool.cache_control = { type: "ephemeral" };
1207
+ }
1208
+ markLastMessageForCaching(messages);
1209
+ }
1186
1210
  let stream;
1187
1211
  let responseHeaders;
1188
1212
  try {
@@ -1210,6 +1234,8 @@ var AnthropicAdapter = class {
1210
1234
  let stopReason;
1211
1235
  let inputTokens;
1212
1236
  let outputTokens;
1237
+ let cacheReadTokens;
1238
+ let cacheWriteTokens;
1213
1239
  try {
1214
1240
  for await (const event of stream) {
1215
1241
  if (req.signal?.aborted) {
@@ -1219,6 +1245,8 @@ var AnthropicAdapter = class {
1219
1245
  switch (event.type) {
1220
1246
  case "message_start":
1221
1247
  inputTokens = event.message?.usage?.input_tokens;
1248
+ cacheReadTokens = event.message?.usage?.cache_read_input_tokens;
1249
+ cacheWriteTokens = event.message?.usage?.cache_creation_input_tokens;
1222
1250
  break;
1223
1251
  case "content_block_start": {
1224
1252
  const block = event.content_block;
@@ -1300,7 +1328,11 @@ var AnthropicAdapter = class {
1300
1328
  const usage = inputTokens !== void 0 || outputTokens !== void 0 ? {
1301
1329
  ...inputTokens !== void 0 ? { inputTokens } : {},
1302
1330
  ...outputTokens !== void 0 ? { outputTokens } : {},
1303
- ...inputTokens !== void 0 && outputTokens !== void 0 ? { totalTokens: inputTokens + outputTokens } : {}
1331
+ ...inputTokens !== void 0 && outputTokens !== void 0 ? {
1332
+ totalTokens: inputTokens + outputTokens + (cacheReadTokens ?? 0) + (cacheWriteTokens ?? 0)
1333
+ } : {},
1334
+ ...cacheReadTokens !== void 0 ? { cacheReadTokens } : {},
1335
+ ...cacheWriteTokens !== void 0 ? { cacheWriteTokens } : {}
1304
1336
  } : void 0;
1305
1337
  const endEvent = {
1306
1338
  type: "end",
@@ -1399,6 +1431,23 @@ function buildWireMessages2(req) {
1399
1431
  }
1400
1432
  return out;
1401
1433
  }
1434
+ function markLastMessageForCaching(messages) {
1435
+ if (messages.length === 0) return;
1436
+ const last = messages[messages.length - 1];
1437
+ const cacheControl = { cache_control: { type: "ephemeral" } };
1438
+ if (typeof last.content === "string" && last.content.length > 0) {
1439
+ messages[messages.length - 1] = {
1440
+ ...last,
1441
+ content: [{ type: "text", text: last.content, ...cacheControl }]
1442
+ };
1443
+ } else if (Array.isArray(last.content) && last.content.length > 0) {
1444
+ const blocks = last.content;
1445
+ messages[messages.length - 1] = {
1446
+ ...last,
1447
+ content: [...blocks.slice(0, -1), { ...blocks[blocks.length - 1], ...cacheControl }]
1448
+ };
1449
+ }
1450
+ }
1402
1451
  function formatTools2(tools) {
1403
1452
  return tools.map((t) => ({
1404
1453
  name: t.name,
@@ -1461,6 +1510,11 @@ async function* streamFromGemini(client, req) {
1461
1510
  if (req.temperature !== void 0) config.temperature = req.temperature;
1462
1511
  if (req.maxTokens !== void 0) config.maxOutputTokens = req.maxTokens;
1463
1512
  if (req.signal) config.abortSignal = req.signal;
1513
+ if (req.providerParams) {
1514
+ for (const [key, value] of Object.entries(req.providerParams)) {
1515
+ if (!(key in config)) config[key] = value;
1516
+ }
1517
+ }
1464
1518
  let stream;
1465
1519
  try {
1466
1520
  stream = await client.models.generateContentStream({
@@ -1481,6 +1535,7 @@ async function* streamFromGemini(client, req) {
1481
1535
  let inputTokens;
1482
1536
  let outputTokens;
1483
1537
  let totalTokens;
1538
+ let cacheReadTokens;
1484
1539
  try {
1485
1540
  for await (const chunk of stream) {
1486
1541
  if (req.signal?.aborted) {
@@ -1489,7 +1544,12 @@ async function* streamFromGemini(client, req) {
1489
1544
  }
1490
1545
  const usage2 = chunk.usageMetadata;
1491
1546
  if (usage2) {
1492
- if (usage2.promptTokenCount !== void 0) inputTokens = usage2.promptTokenCount;
1547
+ if (usage2.cachedContentTokenCount !== void 0) {
1548
+ cacheReadTokens = usage2.cachedContentTokenCount;
1549
+ }
1550
+ if (usage2.promptTokenCount !== void 0) {
1551
+ inputTokens = usage2.promptTokenCount - (usage2.cachedContentTokenCount ?? 0);
1552
+ }
1493
1553
  if (usage2.candidatesTokenCount !== void 0) outputTokens = usage2.candidatesTokenCount;
1494
1554
  if (usage2.totalTokenCount !== void 0) totalTokens = usage2.totalTokenCount;
1495
1555
  }
@@ -1543,7 +1603,8 @@ async function* streamFromGemini(client, req) {
1543
1603
  const usage = inputTokens !== void 0 || outputTokens !== void 0 || totalTokens !== void 0 ? {
1544
1604
  ...inputTokens !== void 0 ? { inputTokens } : {},
1545
1605
  ...outputTokens !== void 0 ? { outputTokens } : {},
1546
- ...totalTokens !== void 0 ? { totalTokens } : {}
1606
+ ...totalTokens !== void 0 ? { totalTokens } : {},
1607
+ ...cacheReadTokens !== void 0 ? { cacheReadTokens } : {}
1547
1608
  } : void 0;
1548
1609
  const endEvent = {
1549
1610
  type: "end",
@@ -1685,6 +1746,39 @@ function isAbortError3(err) {
1685
1746
 
1686
1747
  // src/adapters/google/manifest.ts
1687
1748
  var GOOGLE_KNOWN_MODELS = [
1749
+ {
1750
+ id: "gemini-3.6-flash",
1751
+ displayName: "Gemini 3.6 Flash",
1752
+ capabilities: {
1753
+ streaming: true,
1754
+ tools: true,
1755
+ vision: true,
1756
+ systemPrompt: true,
1757
+ maxContextTokens: 1e6
1758
+ }
1759
+ },
1760
+ {
1761
+ id: "gemini-3.5-flash",
1762
+ displayName: "Gemini 3.5 Flash",
1763
+ capabilities: {
1764
+ streaming: true,
1765
+ tools: true,
1766
+ vision: true,
1767
+ systemPrompt: true,
1768
+ maxContextTokens: 1e6
1769
+ }
1770
+ },
1771
+ {
1772
+ id: "gemini-3.5-flash-lite",
1773
+ displayName: "Gemini 3.5 Flash-Lite",
1774
+ capabilities: {
1775
+ streaming: true,
1776
+ tools: true,
1777
+ vision: true,
1778
+ systemPrompt: true,
1779
+ maxContextTokens: 1e6
1780
+ }
1781
+ },
1688
1782
  {
1689
1783
  id: "gemini-2.5-pro",
1690
1784
  displayName: "Gemini 2.5 Pro",
@@ -1828,6 +1922,39 @@ import { GoogleGenAI as GoogleGenAI2 } from "@google/genai";
1828
1922
 
1829
1923
  // src/adapters/vertex-gemini/manifest.ts
1830
1924
  var VERTEX_GEMINI_KNOWN_MODELS = [
1925
+ {
1926
+ id: "gemini-3.6-flash",
1927
+ displayName: "Gemini 3.6 Flash",
1928
+ capabilities: {
1929
+ streaming: true,
1930
+ tools: true,
1931
+ vision: true,
1932
+ systemPrompt: true,
1933
+ maxContextTokens: 1e6
1934
+ }
1935
+ },
1936
+ {
1937
+ id: "gemini-3.5-flash",
1938
+ displayName: "Gemini 3.5 Flash",
1939
+ capabilities: {
1940
+ streaming: true,
1941
+ tools: true,
1942
+ vision: true,
1943
+ systemPrompt: true,
1944
+ maxContextTokens: 1e6
1945
+ }
1946
+ },
1947
+ {
1948
+ id: "gemini-3.5-flash-lite",
1949
+ displayName: "Gemini 3.5 Flash-Lite",
1950
+ capabilities: {
1951
+ streaming: true,
1952
+ tools: true,
1953
+ vision: true,
1954
+ systemPrompt: true,
1955
+ maxContextTokens: 1e6
1956
+ }
1957
+ },
1831
1958
  {
1832
1959
  id: "gemini-2.5-pro",
1833
1960
  displayName: "Gemini 2.5 Pro",
@@ -2517,6 +2644,15 @@ var BedrockAdapter = class {
2517
2644
  if (Object.keys(inferenceConfig).length > 0) {
2518
2645
  commandInput.inferenceConfig = inferenceConfig;
2519
2646
  }
2647
+ if (req.cacheKey) {
2648
+ if (commandInput.system) {
2649
+ commandInput.system.push({ cachePoint: { type: "default" } });
2650
+ }
2651
+ if (tools) {
2652
+ tools.tools.push({ cachePoint: { type: "default" } });
2653
+ }
2654
+ markLastMessageForCaching2(messages);
2655
+ }
2520
2656
  const command = new ConverseStreamCommand(
2521
2657
  commandInput
2522
2658
  );
@@ -2540,6 +2676,8 @@ var BedrockAdapter = class {
2540
2676
  let inputTokens;
2541
2677
  let outputTokens;
2542
2678
  let totalTokens;
2679
+ let cacheReadTokens;
2680
+ let cacheWriteTokens;
2543
2681
  try {
2544
2682
  for await (const event of response.stream) {
2545
2683
  if (req.signal?.aborted) {
@@ -2592,6 +2730,8 @@ var BedrockAdapter = class {
2592
2730
  inputTokens = event.metadata.usage.inputTokens;
2593
2731
  outputTokens = event.metadata.usage.outputTokens;
2594
2732
  totalTokens = event.metadata.usage.totalTokens;
2733
+ cacheReadTokens = event.metadata.usage.cacheReadInputTokens;
2734
+ cacheWriteTokens = event.metadata.usage.cacheWriteInputTokens;
2595
2735
  }
2596
2736
  }
2597
2737
  }
@@ -2618,7 +2758,9 @@ var BedrockAdapter = class {
2618
2758
  const usage = inputTokens !== void 0 || outputTokens !== void 0 || totalTokens !== void 0 ? {
2619
2759
  ...inputTokens !== void 0 ? { inputTokens } : {},
2620
2760
  ...outputTokens !== void 0 ? { outputTokens } : {},
2621
- ...totalTokens !== void 0 ? { totalTokens } : {}
2761
+ ...totalTokens !== void 0 ? { totalTokens } : {},
2762
+ ...cacheReadTokens !== void 0 ? { cacheReadTokens } : {},
2763
+ ...cacheWriteTokens !== void 0 ? { cacheWriteTokens } : {}
2622
2764
  } : void 0;
2623
2765
  const endEvent = {
2624
2766
  type: "end",
@@ -2726,6 +2868,16 @@ function buildWireMessages3(req) {
2726
2868
  }
2727
2869
  return out;
2728
2870
  }
2871
+ function markLastMessageForCaching2(messages) {
2872
+ if (messages.length === 0) return;
2873
+ const last = messages[messages.length - 1];
2874
+ if (Array.isArray(last.content) && last.content.length > 0) {
2875
+ messages[messages.length - 1] = {
2876
+ ...last,
2877
+ content: [...last.content, { cachePoint: { type: "default" } }]
2878
+ };
2879
+ }
2880
+ }
2729
2881
  function formatTools4(tools) {
2730
2882
  return tools.map((t) => ({
2731
2883
  toolSpec: {
@@ -3081,7 +3233,10 @@ var GroqAdapter = class extends OpenAIAdapter {
3081
3233
  stream(req) {
3082
3234
  return streamFromOpenAI(this.ensureClient(), req, {
3083
3235
  knownModels: groqManifest.knownModels,
3084
- vendorMetadataExtractor: GROQ_METADATA_EXTRACTOR
3236
+ vendorMetadataExtractor: GROQ_METADATA_EXTRACTOR,
3237
+ // Groq caches automatically server-side and rejects/ignores undocumented
3238
+ // OpenAI params — do not forward prompt_cache_key.
3239
+ includeCacheKey: false
3085
3240
  });
3086
3241
  }
3087
3242
  };