@stigg/agent-sdk-js 0.1.0 → 0.2.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.
@@ -7,7 +7,7 @@
7
7
  * `fromFlatTokenUsage` is read by every vendor that counts that way, not by one of them.
8
8
  */
9
9
  import { type Measurement, type Metrics, type MetricsMapper, type TokenUsage } from '../../types';
10
- import type { BedrockLikeUsage, FlatTokenUsage, GeminiLikeUsage, LangChainLikeUsage, MistralLikeUsage, OllamaLikeUsage, OpenAILikeUsage, ResponsesLikeUsage } from './types';
10
+ import type { BedrockLikeUsage, FlatTokenUsage, GeminiLikeUsage, LangChainLikeUsage, MistralLikeUsage, DatabricksLikeUsage, DatabricksQueryLikeUsage, OllamaLikeUsage, OpenAILikeUsage, ResponsesLikeUsage } from './types';
11
11
  export declare function fromFlatTokenUsage(usage: FlatTokenUsage | null | undefined): TokenUsage;
12
12
  export declare function fromOpenAIUsage(usage: OpenAILikeUsage | null | undefined): TokenUsage;
13
13
  /**
@@ -140,6 +140,21 @@ export declare const OLLAMA_METRICS: readonly ["prompt_eval_count", "eval_count"
140
140
  export declare const OPENAI_METRICS: readonly ["prompt_tokens", "completion_tokens", "input_tokens", "output_tokens", "cached_tokens", "total_tokens"];
141
141
  /** A gateway speaks the OpenAI shape and adds the price it charged, under its own field name. */
142
142
  export declare const GATEWAY_METRICS: readonly ["prompt_tokens", "completion_tokens", "input_tokens", "output_tokens", "cached_tokens", "total_tokens", "cost"];
143
+ /**
144
+ * A gateway that forwards the upstream body untouched, and so reports in two vocabularies.
145
+ *
146
+ * Unlike LiteLLM, which normalises every upstream to the OpenAI wire, Cloudflare AI Gateway's
147
+ * provider-native routes pass the provider's own body straight through - so `/openai` returns
148
+ * OpenAI's counter names and `/anthropic` returns Anthropic's. One recipe serves both wires, so
149
+ * this is the union of what its surfaces can report, which is what `metrics` is defined to be.
150
+ *
151
+ * No `cost`, and that is the defining fact rather than an oversight. Cloudflare states no price on
152
+ * any response: its figure lives in the gateway's own log, is explicitly an estimate, and is zero
153
+ * on a cache hit. So the recipe carries the log id as a dimension and lets spend be reconciled out
154
+ * of band, exactly as the gateway reference prescribes for a price that is only available
155
+ * asynchronously.
156
+ */
157
+ export declare const CLOUDFLARE_METRICS: readonly ["prompt_tokens", "completion_tokens", "input_tokens", "output_tokens", "cached_tokens", "total_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"];
143
158
  /**
144
159
  * Bedrock's five, under its own names and with no price among them.
145
160
  *
@@ -154,6 +169,93 @@ export declare const GATEWAY_METRICS: readonly ["prompt_tokens", "completion_tok
154
169
  export declare const BEDROCK_PATHS: readonly ["inputTokens", "outputTokens", "cacheReadInputTokens", "cacheWriteInputTokens", "totalTokens"];
155
170
  /** Those five. Flat, so the paths are the names. */
156
171
  export declare const BEDROCK_METRICS: readonly ["inputTokens", "outputTokens", "cacheReadInputTokens", "cacheWriteInputTokens", "totalTokens"];
172
+ /**
173
+ * Databricks' six, under its own names - and its own names are two vendors' names at once.
174
+ *
175
+ * The first three are OpenAI's spelling, because the serving endpoints speak the OpenAI wire. The
176
+ * two cache counters are *Anthropic's* spelling, flat on the usage block rather than nested under
177
+ * `prompt_tokens_details` where an OpenAI-shaped reader would look for them, and `reasoning_tokens`
178
+ * is Databricks' own. Reported exactly as Databricks spells them, per the rule that a number has to
179
+ * reconcile against the vendor's own dashboard - renaming the cache pair to `cached_tokens` would
180
+ * make one account read as two vocabularies and find nothing where it looked.
181
+ *
182
+ * No `cost`, and that is the fact that most shapes this binding: Databricks states no price on any
183
+ * response, on either route. See `databricks-recipe.ts` for what that costs a run.
184
+ */
185
+ export declare const DATABRICKS_PATHS: readonly ["prompt_tokens", "completion_tokens", "total_tokens", "reasoning_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"];
186
+ /**
187
+ * The same counters as the Responses API spells them.
188
+ *
189
+ * Databricks serves both OpenAI surfaces, and they do not share field names: Chat Completions
190
+ * sends `prompt_tokens`/`completion_tokens` and Responses sends `input_tokens`/`output_tokens`.
191
+ * Reading a Responses body with the list above finds neither, so the call would report its total
192
+ * and nothing else - a number with no breakdown under it, which prices wrongly rather than
193
+ * visibly. Each surface reads its own list.
194
+ */
195
+ export declare const DATABRICKS_RESPONSES_PATHS: readonly ["input_tokens", "output_tokens", "total_tokens", "reasoning_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"];
196
+ /** The union across both surfaces: what a Databricks call can report, which is what `metrics` is. */
197
+ export declare const DATABRICKS_METRICS: readonly ["prompt_tokens", "completion_tokens", "input_tokens", "output_tokens", "total_tokens", "reasoning_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"];
198
+ /**
199
+ * Where the **first-party client's** counters are read and what each is reported as.
200
+ *
201
+ * The second map in this file, and it exists for precisely the reason the Mistral one does.
202
+ * `@databricks/sdk-modelservingquery` is generated, and its zod schema parses `prompt_tokens` off
203
+ * the wire and transforms it to `promptTokens` before the caller ever sees it - so following the
204
+ * key it was read from would report a camelCase feature id for a call that the *same workspace*
205
+ * reports in snake_case when the application holds an `OpenAI` client instead.
206
+ *
207
+ * That is not a cosmetic difference. It is one Databricks account producing two different feature
208
+ * ids depending on which package the application happened to import, splitting one bill across two
209
+ * meters - which is the failure `pickRenamedMetrics` was built to prevent. Three entries rather
210
+ * than six because `ExternalModelUsageElement` carries only three; the cache pair and
211
+ * `reasoning_tokens` have no field on it, and a counter with no field is absent rather than zero.
212
+ */
213
+ export declare const DATABRICKS_QUERY_METRIC_NAME_MAP: {
214
+ readonly promptTokens: "prompt_tokens";
215
+ readonly completionTokens: "completion_tokens";
216
+ readonly totalTokens: "total_tokens";
217
+ };
218
+ /**
219
+ * Workers AI's three, and only three.
220
+ *
221
+ * OpenAI's spelling, flat, with no cache detail nested underneath - so this is a narrower list
222
+ * than `OPENAI_CHAT_METRICS` rather than a reuse of it. Declaring `cached_tokens` here would type
223
+ * a pricing table against a counter Workers AI never sends.
224
+ *
225
+ * No neurons either, which is the counter a reader might expect. Cloudflare bills Workers AI in
226
+ * Neurons, and publishes none of them on any response - binding or REST - so the conversion from
227
+ * tokens is a price list this SDK does not hold. Tokens are what the response states and tokens
228
+ * are what this reports.
229
+ */
230
+ export declare const WORKERS_AI_PATHS: readonly ["prompt_tokens", "completion_tokens", "total_tokens"];
231
+ /** Those three. Flat, so the paths are the names. */
232
+ export declare const WORKERS_AI_METRICS: readonly ["prompt_tokens", "completion_tokens", "total_tokens"];
233
+ /**
234
+ * Databricks' usage block -> the neutral digest.
235
+ *
236
+ * `input` is `prompt_tokens` verbatim, *not* reduced by the cache reads the way `fromOpenAIUsage`
237
+ * reduces its own. OpenAI documents its cached tokens as counted inside `prompt_tokens`, so
238
+ * subtracting there is undoing a documented overlap. Databricks documents no such thing, and the
239
+ * spelling it chose for the pair is Anthropic's - whose cache counters sit *beside* the input
240
+ * count rather than inside it. So the Anthropic convention is the better guess and the overlap is
241
+ * left alone; the stated total is read rather than computed, which keeps the one number that gets
242
+ * invoiced right whichever way the overlap actually runs. The README's overlap table says the
243
+ * direction is unverified for Databricks, because it is.
244
+ */
245
+ export declare function fromDatabricksUsage(usage: DatabricksLikeUsage | null | undefined): TokenUsage;
246
+ /**
247
+ * The same block as read through the first-party client -> the neutral digest.
248
+ *
249
+ * Its own reader rather than a call into `fromDatabricksUsage`, because the field names genuinely
250
+ * differ: the generated client camelCases the wire on the way in, so a snake_case reader finds
251
+ * none of these and returns an all-zero digest without throwing. That is the shape of failure the
252
+ * invariants call out - an extractor that meters every call at nothing and trips no test.
253
+ *
254
+ * No cache arithmetic to get wrong here, which is the one simplification over the wire-shaped
255
+ * reader: `ExternalModelUsageElement` declares no cache counters at all, so there is no overlap of
256
+ * unknown direction to leave alone. The stated total is still read rather than recomputed.
257
+ */
258
+ export declare function fromDatabricksQueryUsage(usage: DatabricksQueryLikeUsage | null | undefined): TokenUsage;
157
259
  /** The leaf a dotted path reports under - `prompt_tokens_details.cached_tokens` -> `cached_tokens`. */
158
260
  export declare const metricName: (path: string) => string;
159
261
  /**
@@ -188,6 +290,9 @@ export declare const METRIC_PATHS: {
188
290
  readonly typesafe: readonly ["input_tokens", "output_tokens"];
189
291
  readonly gemini: readonly ["promptTokenCount", "candidatesTokenCount", "cachedContentTokenCount", "thoughtsTokenCount", "toolUsePromptTokenCount", "totalTokenCount"];
190
292
  readonly bedrock: readonly ["inputTokens", "outputTokens", "cacheReadInputTokens", "cacheWriteInputTokens", "totalTokens"];
293
+ readonly databricks: readonly ["prompt_tokens", "completion_tokens", "total_tokens", "reasoning_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"];
294
+ readonly databricksResponses: readonly ["input_tokens", "output_tokens", "total_tokens", "reasoning_tokens", "cache_read_input_tokens", "cache_creation_input_tokens"];
295
+ readonly workersAi: readonly ["prompt_tokens", "completion_tokens", "total_tokens"];
191
296
  readonly ollama: readonly ["prompt_eval_count", "eval_count"];
192
297
  };
193
298
  /**
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizedMetrics = exports.addMetrics = exports.METRIC_PATHS = exports.metricNamesMatchPaths = exports.COMPUTED_TOTALS = exports.metricName = exports.BEDROCK_METRICS = exports.BEDROCK_PATHS = exports.GATEWAY_METRICS = exports.OPENAI_METRICS = exports.OLLAMA_METRICS = exports.OLLAMA_COMPONENT_METRICS = exports.TYPESAFE_METRICS = exports.TYPESAFE_COMPONENT_METRICS = exports.MISTRAL_METRICS = exports.MISTRAL_METRIC_NAME_MAP = exports.OPENAI_RESPONSES_METRICS = exports.OPENAI_CHAT_METRICS = exports.GEMINI_COMPONENT_METRICS = exports.GEMINI_METRICS = exports.ANTHROPIC_METRICS = exports.ANTHROPIC_COMPONENT_METRICS = exports.TOTAL_TOKENS = exports.addTokenUsage = void 0;
3
+ exports.normalizedMetrics = exports.addMetrics = exports.METRIC_PATHS = exports.metricNamesMatchPaths = exports.COMPUTED_TOTALS = exports.metricName = exports.WORKERS_AI_METRICS = exports.WORKERS_AI_PATHS = exports.DATABRICKS_QUERY_METRIC_NAME_MAP = exports.DATABRICKS_METRICS = exports.DATABRICKS_RESPONSES_PATHS = exports.DATABRICKS_PATHS = exports.BEDROCK_METRICS = exports.BEDROCK_PATHS = exports.CLOUDFLARE_METRICS = exports.GATEWAY_METRICS = exports.OPENAI_METRICS = exports.OLLAMA_METRICS = exports.OLLAMA_COMPONENT_METRICS = exports.TYPESAFE_METRICS = exports.TYPESAFE_COMPONENT_METRICS = exports.MISTRAL_METRICS = exports.MISTRAL_METRIC_NAME_MAP = exports.OPENAI_RESPONSES_METRICS = exports.OPENAI_CHAT_METRICS = exports.GEMINI_COMPONENT_METRICS = exports.GEMINI_METRICS = exports.ANTHROPIC_METRICS = exports.ANTHROPIC_COMPONENT_METRICS = exports.TOTAL_TOKENS = exports.addTokenUsage = void 0;
4
4
  exports.fromFlatTokenUsage = fromFlatTokenUsage;
5
5
  exports.fromOpenAIUsage = fromOpenAIUsage;
6
6
  exports.fromResponsesUsage = fromResponsesUsage;
@@ -10,6 +10,8 @@ exports.fromGeminiUsage = fromGeminiUsage;
10
10
  exports.fromMistralUsage = fromMistralUsage;
11
11
  exports.fromOllamaUsage = fromOllamaUsage;
12
12
  exports.normalizeUsage = normalizeUsage;
13
+ exports.fromDatabricksUsage = fromDatabricksUsage;
14
+ exports.fromDatabricksQueryUsage = fromDatabricksQueryUsage;
13
15
  exports.withComputedTotal = withComputedTotal;
14
16
  exports.pickMetrics = pickMetrics;
15
17
  exports.pickRenamedMetrics = pickRenamedMetrics;
@@ -404,6 +406,25 @@ exports.OPENAI_METRICS = [
404
406
  ];
405
407
  /** A gateway speaks the OpenAI shape and adds the price it charged, under its own field name. */
406
408
  exports.GATEWAY_METRICS = [...exports.OPENAI_METRICS, 'cost'];
409
+ /**
410
+ * A gateway that forwards the upstream body untouched, and so reports in two vocabularies.
411
+ *
412
+ * Unlike LiteLLM, which normalises every upstream to the OpenAI wire, Cloudflare AI Gateway's
413
+ * provider-native routes pass the provider's own body straight through - so `/openai` returns
414
+ * OpenAI's counter names and `/anthropic` returns Anthropic's. One recipe serves both wires, so
415
+ * this is the union of what its surfaces can report, which is what `metrics` is defined to be.
416
+ *
417
+ * No `cost`, and that is the defining fact rather than an oversight. Cloudflare states no price on
418
+ * any response: its figure lives in the gateway's own log, is explicitly an estimate, and is zero
419
+ * on a cache hit. So the recipe carries the log id as a dimension and lets spend be reconciled out
420
+ * of band, exactly as the gateway reference prescribes for a price that is only available
421
+ * asynchronously.
422
+ */
423
+ exports.CLOUDFLARE_METRICS = [
424
+ ...exports.OPENAI_METRICS,
425
+ 'cache_read_input_tokens',
426
+ 'cache_creation_input_tokens',
427
+ ];
407
428
  /**
408
429
  * Bedrock's five, under its own names and with no price among them.
409
430
  *
@@ -424,6 +445,143 @@ exports.BEDROCK_PATHS = [
424
445
  ];
425
446
  /** Those five. Flat, so the paths are the names. */
426
447
  exports.BEDROCK_METRICS = exports.BEDROCK_PATHS;
448
+ /**
449
+ * Databricks' six, under its own names - and its own names are two vendors' names at once.
450
+ *
451
+ * The first three are OpenAI's spelling, because the serving endpoints speak the OpenAI wire. The
452
+ * two cache counters are *Anthropic's* spelling, flat on the usage block rather than nested under
453
+ * `prompt_tokens_details` where an OpenAI-shaped reader would look for them, and `reasoning_tokens`
454
+ * is Databricks' own. Reported exactly as Databricks spells them, per the rule that a number has to
455
+ * reconcile against the vendor's own dashboard - renaming the cache pair to `cached_tokens` would
456
+ * make one account read as two vocabularies and find nothing where it looked.
457
+ *
458
+ * No `cost`, and that is the fact that most shapes this binding: Databricks states no price on any
459
+ * response, on either route. See `databricks-recipe.ts` for what that costs a run.
460
+ */
461
+ exports.DATABRICKS_PATHS = [
462
+ 'prompt_tokens',
463
+ 'completion_tokens',
464
+ 'total_tokens',
465
+ 'reasoning_tokens',
466
+ 'cache_read_input_tokens',
467
+ 'cache_creation_input_tokens',
468
+ ];
469
+ /**
470
+ * The same counters as the Responses API spells them.
471
+ *
472
+ * Databricks serves both OpenAI surfaces, and they do not share field names: Chat Completions
473
+ * sends `prompt_tokens`/`completion_tokens` and Responses sends `input_tokens`/`output_tokens`.
474
+ * Reading a Responses body with the list above finds neither, so the call would report its total
475
+ * and nothing else - a number with no breakdown under it, which prices wrongly rather than
476
+ * visibly. Each surface reads its own list.
477
+ */
478
+ exports.DATABRICKS_RESPONSES_PATHS = [
479
+ 'input_tokens',
480
+ 'output_tokens',
481
+ 'total_tokens',
482
+ 'reasoning_tokens',
483
+ 'cache_read_input_tokens',
484
+ 'cache_creation_input_tokens',
485
+ ];
486
+ /** The union across both surfaces: what a Databricks call can report, which is what `metrics` is. */
487
+ exports.DATABRICKS_METRICS = [
488
+ 'prompt_tokens',
489
+ 'completion_tokens',
490
+ 'input_tokens',
491
+ 'output_tokens',
492
+ 'total_tokens',
493
+ 'reasoning_tokens',
494
+ 'cache_read_input_tokens',
495
+ 'cache_creation_input_tokens',
496
+ ];
497
+ /**
498
+ * Where the **first-party client's** counters are read and what each is reported as.
499
+ *
500
+ * The second map in this file, and it exists for precisely the reason the Mistral one does.
501
+ * `@databricks/sdk-modelservingquery` is generated, and its zod schema parses `prompt_tokens` off
502
+ * the wire and transforms it to `promptTokens` before the caller ever sees it - so following the
503
+ * key it was read from would report a camelCase feature id for a call that the *same workspace*
504
+ * reports in snake_case when the application holds an `OpenAI` client instead.
505
+ *
506
+ * That is not a cosmetic difference. It is one Databricks account producing two different feature
507
+ * ids depending on which package the application happened to import, splitting one bill across two
508
+ * meters - which is the failure `pickRenamedMetrics` was built to prevent. Three entries rather
509
+ * than six because `ExternalModelUsageElement` carries only three; the cache pair and
510
+ * `reasoning_tokens` have no field on it, and a counter with no field is absent rather than zero.
511
+ */
512
+ exports.DATABRICKS_QUERY_METRIC_NAME_MAP = {
513
+ promptTokens: 'prompt_tokens',
514
+ completionTokens: 'completion_tokens',
515
+ totalTokens: 'total_tokens',
516
+ };
517
+ /**
518
+ * Workers AI's three, and only three.
519
+ *
520
+ * OpenAI's spelling, flat, with no cache detail nested underneath - so this is a narrower list
521
+ * than `OPENAI_CHAT_METRICS` rather than a reuse of it. Declaring `cached_tokens` here would type
522
+ * a pricing table against a counter Workers AI never sends.
523
+ *
524
+ * No neurons either, which is the counter a reader might expect. Cloudflare bills Workers AI in
525
+ * Neurons, and publishes none of them on any response - binding or REST - so the conversion from
526
+ * tokens is a price list this SDK does not hold. Tokens are what the response states and tokens
527
+ * are what this reports.
528
+ */
529
+ exports.WORKERS_AI_PATHS = ['prompt_tokens', 'completion_tokens', 'total_tokens'];
530
+ /** Those three. Flat, so the paths are the names. */
531
+ exports.WORKERS_AI_METRICS = exports.WORKERS_AI_PATHS;
532
+ /**
533
+ * Databricks' usage block -> the neutral digest.
534
+ *
535
+ * `input` is `prompt_tokens` verbatim, *not* reduced by the cache reads the way `fromOpenAIUsage`
536
+ * reduces its own. OpenAI documents its cached tokens as counted inside `prompt_tokens`, so
537
+ * subtracting there is undoing a documented overlap. Databricks documents no such thing, and the
538
+ * spelling it chose for the pair is Anthropic's - whose cache counters sit *beside* the input
539
+ * count rather than inside it. So the Anthropic convention is the better guess and the overlap is
540
+ * left alone; the stated total is read rather than computed, which keeps the one number that gets
541
+ * invoiced right whichever way the overlap actually runs. The README's overlap table says the
542
+ * direction is unverified for Databricks, because it is.
543
+ */
544
+ function fromDatabricksUsage(usage) {
545
+ if (!usage)
546
+ return (0, types_1.emptyTokenUsage)();
547
+ return {
548
+ // Read, never computed: Databricks states a total, and a stated total beats a reassembled one
549
+ // precisely because the overlap above is unknown.
550
+ ...withTotal(n(usage.total_tokens)),
551
+ // Both spellings, because one Databricks workspace serves both OpenAI surfaces: Chat
552
+ // Completions sends `prompt_tokens`/`completion_tokens` and Responses sends
553
+ // `input_tokens`/`output_tokens`. A body carries one pair or the other, never both, so the
554
+ // fallback cannot double-count - and reading only the chat pair left `normalizedMetrics` and
555
+ // every custom `TokenUsage` mapper seeing zeroes for a Responses call.
556
+ input: n(usage.prompt_tokens ?? usage.input_tokens),
557
+ output: n(usage.completion_tokens ?? usage.output_tokens),
558
+ cacheRead: n(usage.cache_read_input_tokens),
559
+ cacheCreate: n(usage.cache_creation_input_tokens),
560
+ };
561
+ }
562
+ /**
563
+ * The same block as read through the first-party client -> the neutral digest.
564
+ *
565
+ * Its own reader rather than a call into `fromDatabricksUsage`, because the field names genuinely
566
+ * differ: the generated client camelCases the wire on the way in, so a snake_case reader finds
567
+ * none of these and returns an all-zero digest without throwing. That is the shape of failure the
568
+ * invariants call out - an extractor that meters every call at nothing and trips no test.
569
+ *
570
+ * No cache arithmetic to get wrong here, which is the one simplification over the wire-shaped
571
+ * reader: `ExternalModelUsageElement` declares no cache counters at all, so there is no overlap of
572
+ * unknown direction to leave alone. The stated total is still read rather than recomputed.
573
+ */
574
+ function fromDatabricksQueryUsage(usage) {
575
+ if (!usage)
576
+ return (0, types_1.emptyTokenUsage)();
577
+ return {
578
+ ...withTotal(n(usage.totalTokens)),
579
+ input: n(usage.promptTokens),
580
+ output: n(usage.completionTokens),
581
+ cacheRead: 0,
582
+ cacheCreate: 0,
583
+ };
584
+ }
427
585
  /** The leaf a dotted path reports under - `prompt_tokens_details.cached_tokens` -> `cached_tokens`. */
428
586
  const metricName = (path) => path.split('.').pop();
429
587
  exports.metricName = metricName;
@@ -470,6 +628,9 @@ exports.METRIC_PATHS = {
470
628
  typesafe: TYPESAFE_PATHS,
471
629
  gemini: GEMINI_PATHS,
472
630
  bedrock: exports.BEDROCK_PATHS,
631
+ databricks: exports.DATABRICKS_PATHS,
632
+ databricksResponses: exports.DATABRICKS_RESPONSES_PATHS,
633
+ workersAi: exports.WORKERS_AI_PATHS,
473
634
  ollama: exports.OLLAMA_COMPONENT_METRICS,
474
635
  };
475
636
  /**
@@ -31,6 +31,47 @@ export type OpenAILikeUsage = {
31
31
  cache_write_tokens?: number | null;
32
32
  } | null;
33
33
  };
34
+ /**
35
+ * Databricks model serving `usage` - OpenAI's three counters, with Anthropic's spelling for cache.
36
+ *
37
+ * The mixed vocabulary is Databricks' own and is reported verbatim rather than normalised to one
38
+ * side or the other. The first three come back from every serving endpoint; the last three are
39
+ * Foundation Model API extensions and are absent on the external-model route, where the body is
40
+ * whatever the upstream provider's counters normalise to.
41
+ */
42
+ export type DatabricksLikeUsage = {
43
+ prompt_tokens?: number | null;
44
+ completion_tokens?: number | null;
45
+ /** Databricks states its own total, so it is read rather than reassembled from the parts. */
46
+ total_tokens?: number | null;
47
+ /** Reasoning models only. */
48
+ reasoning_tokens?: number | null;
49
+ cache_read_input_tokens?: number | null;
50
+ cache_creation_input_tokens?: number | null;
51
+ };
52
+ /**
53
+ * The same block as above, as `@databricks/sdk-modelservingquery` hands it over.
54
+ *
55
+ * Databricks' own `ExternalModelUsageElement`. The **wire** is the snake_case one above - the
56
+ * generated client's zod schema parses `prompt_tokens` and transforms it to `promptTokens` on the
57
+ * way in, exactly as Mistral's generated client does to `UsageInfo`. So this is a second spelling
58
+ * of one vendor's counters rather than a second set of counters, and it is read through
59
+ * `DATABRICKS_QUERY_METRIC_NAME_MAP` so both spellings report under the wire's names.
60
+ *
61
+ * Three, not six: the cache pair and `reasoning_tokens` have no field on this type at all, so a
62
+ * call made through the first-party client reports the three it can and nothing more. Absent, not
63
+ * zero - and the reason the native surface's metric list is a subset of the recipe's.
64
+ *
65
+ * Written out rather than aliased to {@link MistralLikeUsage}, which it currently matches
66
+ * field-for-field: these are two unrelated vendor contracts that happen to agree today, and
67
+ * collapsing them would make a change on either side look like a change to both.
68
+ */
69
+ export type DatabricksQueryLikeUsage = {
70
+ promptTokens?: number | null;
71
+ completionTokens?: number | null;
72
+ /** Databricks states its own total here too, so it is read rather than reassembled. */
73
+ totalTokens?: number | null;
74
+ };
34
75
  /** OpenAI's Responses API `usage` - the same counts as above under different names. */
35
76
  export type ResponsesLikeUsage = {
36
77
  input_tokens?: number | null;
package/dist/index.d.ts CHANGED
@@ -46,9 +46,15 @@ export { mistralRecipe } from './bindings/client/providers/mistral/mistral-recip
46
46
  export type { MistralMetric, MistralMetrics } from './bindings/client/providers/mistral/mistral-recipe';
47
47
  export { ollamaRecipe } from './bindings/client/providers/ollama/ollama-recipe';
48
48
  export type { OllamaMetric, OllamaMetrics } from './bindings/client/providers/ollama/ollama-recipe';
49
+ export { databricksRecipe, databricksExternalRecipe } from './bindings/client/gateways/databricks/databricks-recipe';
50
+ export type { DatabricksMetricName, DatabricksMetrics } from './bindings/client/gateways/databricks/databricks-recipe';
51
+ export type { DatabricksRecipeOptions } from './bindings/client/gateways/databricks/types';
49
52
  export { bedrockRecipe } from './bindings/client/gateways/bedrock/bedrock-recipe';
50
53
  export type { BedrockMetricName, BedrockMetrics } from './bindings/client/gateways/bedrock/bedrock-recipe';
51
54
  export type { BedrockRecipeOptions } from './bindings/client/gateways/bedrock/types';
55
+ export { cloudflareRecipe } from './bindings/client/gateways/cloudflare/cloudflare-recipe';
56
+ export type { CloudflareMetricName, CloudflareMetrics } from './bindings/client/gateways/cloudflare/cloudflare-recipe';
57
+ export type { CloudflareRecipeOptions } from './bindings/client/gateways/cloudflare/types';
52
58
  export { typesafeRecipe, estimateFromState } from './bindings/client/providers/typesafe/typesafe-recipe';
53
59
  export type { TypeSafeMetric, TypeSafeMetrics } from './bindings/client/providers/typesafe/typesafe-recipe';
54
60
  export { weightedMetrics } from './bindings/shared/weighted-metrics';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizeUsage = exports.normalizedMetrics = exports.weightedMetrics = exports.estimateFromState = exports.typesafeRecipe = exports.bedrockRecipe = exports.ollamaRecipe = exports.mistralRecipe = exports.groqRecipe = exports.litellmRecipe = exports.openrouterRecipe = exports.estimateFromMaxOutputTokens = exports.geminiChatRecipe = exports.geminiRecipe = exports.openAIRecipe = exports.estimateFromMaxTokens = exports.anthropicRecipe = exports.hasMethod = exports.createClientRegistry = exports.wrapClient = exports.toMeasurement = exports.entitlementRef = exports.entitlementKind = exports.entitlementId = exports.emptyTokenUsage = exports.vendorMetrics = exports.unitsPerTokens = exports.looksLikeGovernanceNotEnabled = exports.isGovernanceNotEnabled = exports.isAccessDenied = exports.isEngineError = exports.GovernanceNotEnabledError = exports.AccessDeniedError = exports.EngineError = exports.noopLogger = exports.consoleLogger = exports.parseGovernanceHeaders = exports.GOVERNANCE_HEADERS = exports.remedyMessage = exports.describeDecision = exports.flattenRaw = exports.RAW_PREFIX = exports.StiggAgentSDK = void 0;
3
+ exports.normalizeUsage = exports.normalizedMetrics = exports.weightedMetrics = exports.estimateFromState = exports.typesafeRecipe = exports.cloudflareRecipe = exports.bedrockRecipe = exports.databricksExternalRecipe = exports.databricksRecipe = exports.ollamaRecipe = exports.mistralRecipe = exports.groqRecipe = exports.litellmRecipe = exports.openrouterRecipe = exports.estimateFromMaxOutputTokens = exports.geminiChatRecipe = exports.geminiRecipe = exports.openAIRecipe = exports.estimateFromMaxTokens = exports.anthropicRecipe = exports.hasMethod = exports.createClientRegistry = exports.wrapClient = exports.toMeasurement = exports.entitlementRef = exports.entitlementKind = exports.entitlementId = exports.emptyTokenUsage = exports.vendorMetrics = exports.unitsPerTokens = exports.looksLikeGovernanceNotEnabled = exports.isGovernanceNotEnabled = exports.isAccessDenied = exports.isEngineError = exports.GovernanceNotEnabledError = exports.AccessDeniedError = exports.EngineError = exports.noopLogger = exports.consoleLogger = exports.parseGovernanceHeaders = exports.GOVERNANCE_HEADERS = exports.remedyMessage = exports.describeDecision = exports.flattenRaw = exports.RAW_PREFIX = exports.StiggAgentSDK = void 0;
4
4
  /**
5
5
  * Public surface.
6
6
  *
@@ -92,10 +92,28 @@ Object.defineProperty(exports, "ollamaRecipe", { enumerable: true, get: function
92
92
  // than a method tree, so the recipe gates `send` and reads the command to tell inference from the
93
93
  // rest of the API; it reports Bedrock's own token counters and no `cost`, because there is none on
94
94
  // the response to report. See the recipe for what that means for a run that wanted to bill spend.
95
+ // Databricks model serving, as two recipes for two payers over one wire. `databricksRecipe` is a
96
+ // default, matched on the workspace URL: Foundation Model API traffic, billed to your Databricks
97
+ // account in DBUs. `databricksExternalRecipe` is the same wire reaching an endpoint configured
98
+ // with your own upstream key, where the upstream provider invoices - it is opt-in because the two
99
+ // are indistinguishable from the client and naming it is an assertion about your own workspace,
100
+ // not something the SDK detected. Neither reports a `cost`: Databricks states no price on any
101
+ // response, on either route. See the recipe header for what a wrong assertion costs.
102
+ var databricks_recipe_1 = require("./bindings/client/gateways/databricks/databricks-recipe");
103
+ Object.defineProperty(exports, "databricksRecipe", { enumerable: true, get: function () { return databricks_recipe_1.databricksRecipe; } });
104
+ Object.defineProperty(exports, "databricksExternalRecipe", { enumerable: true, get: function () { return databricks_recipe_1.databricksExternalRecipe; } });
95
105
  var bedrock_recipe_1 = require("./bindings/client/gateways/bedrock/bedrock-recipe");
96
106
  Object.defineProperty(exports, "bedrockRecipe", { enumerable: true, get: function () { return bedrock_recipe_1.bedrockRecipe; } });
97
107
  // Built in as well. One method, no stream, and two counters - see the recipe for why a
98
108
  // question-answering API has neither a cache counter nor a cost to report.
109
+ // Cloudflare Workers AI - a provider, not a gateway: Cloudflare runs these models on its own GPUs
110
+ // and invoices them, and `@cf/<author>/…` names who made the weights rather than who bills. A
111
+ // default, matched on `api.cloudflare.com`, covering both the OpenAI-compatible route and the
112
+ // `cloudflare` package's own `ai.run`. It reports tokens and no `cost` - Cloudflare bills in
113
+ // Neurons and publishes none of them on any response. See the recipe for the streamed `ai.run`
114
+ // limitation.
115
+ var cloudflare_recipe_1 = require("./bindings/client/gateways/cloudflare/cloudflare-recipe");
116
+ Object.defineProperty(exports, "cloudflareRecipe", { enumerable: true, get: function () { return cloudflare_recipe_1.cloudflareRecipe; } });
99
117
  var typesafe_recipe_1 = require("./bindings/client/providers/typesafe/typesafe-recipe");
100
118
  Object.defineProperty(exports, "typesafeRecipe", { enumerable: true, get: function () { return typesafe_recipe_1.typesafeRecipe; } });
101
119
  Object.defineProperty(exports, "estimateFromState", { enumerable: true, get: function () { return typesafe_recipe_1.estimateFromState; } });
@@ -26,7 +26,7 @@ export { noCustomer, overrideContext, resolveContext, isEnforced } from './core/
26
26
  export type { ResolvedContext } from './core/context';
27
27
  export { GovernanceSession } from './core/session';
28
28
  export type { SessionDeps } from './core/session';
29
- export { ANTHROPIC_METRICS, GEMINI_METRICS, MISTRAL_METRICS, MISTRAL_METRIC_NAME_MAP, OLLAMA_METRICS, TYPESAFE_METRICS, GATEWAY_METRICS, OPENAI_CHAT_METRICS, OPENAI_METRICS, OPENAI_RESPONSES_METRICS, METRIC_PATHS, metricName, metricNamesMatchPaths, pickMetrics, pickRenamedMetrics, addMetrics, addTokenUsage, fromFlatTokenUsage, fromGeminiUsage, fromLangChainUsage, fromMistralUsage, fromOllamaUsage, fromOpenAIUsage, fromResponsesUsage, observedMeasurement, } from './bindings/shared/token-usage';
29
+ export { ANTHROPIC_METRICS, GEMINI_METRICS, MISTRAL_METRICS, MISTRAL_METRIC_NAME_MAP, OLLAMA_METRICS, TYPESAFE_METRICS, GATEWAY_METRICS, DATABRICKS_METRICS, DATABRICKS_QUERY_METRIC_NAME_MAP, WORKERS_AI_METRICS, OPENAI_CHAT_METRICS, OPENAI_METRICS, OPENAI_RESPONSES_METRICS, METRIC_PATHS, metricName, metricNamesMatchPaths, pickMetrics, pickRenamedMetrics, addMetrics, addTokenUsage, fromFlatTokenUsage, fromGeminiUsage, fromLangChainUsage, fromMistralUsage, fromOllamaUsage, fromOpenAIUsage, fromResponsesUsage, observedMeasurement, } from './bindings/shared/token-usage';
30
30
  export type { ObservedVendor } from './bindings/shared/token-usage';
31
31
  export { DEFAULT_RECIPES } from './stigg-agent-sdk';
32
32
  export { meterStream } from './bindings/shared/meter-stream';
package/dist/internal.js CHANGED
@@ -11,7 +11,8 @@
11
11
  * can do from the public barrel, do from there instead.
12
12
  */
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.eventNameFor = exports.meterStream = exports.DEFAULT_RECIPES = exports.observedMeasurement = exports.fromResponsesUsage = exports.fromOpenAIUsage = exports.fromOllamaUsage = exports.fromMistralUsage = exports.fromLangChainUsage = exports.fromGeminiUsage = exports.fromFlatTokenUsage = exports.addTokenUsage = exports.addMetrics = exports.pickRenamedMetrics = exports.pickMetrics = exports.metricNamesMatchPaths = exports.metricName = exports.METRIC_PATHS = exports.OPENAI_RESPONSES_METRICS = exports.OPENAI_METRICS = exports.OPENAI_CHAT_METRICS = exports.GATEWAY_METRICS = exports.TYPESAFE_METRICS = exports.OLLAMA_METRICS = exports.MISTRAL_METRIC_NAME_MAP = exports.MISTRAL_METRICS = exports.GEMINI_METRICS = exports.ANTHROPIC_METRICS = exports.GovernanceSession = exports.isEnforced = exports.resolveContext = exports.overrideContext = exports.noCustomer = exports.prefixed = exports.asEngineError = exports.isMeterMismatchError = exports.isTransportFailure = exports.resolveConfig = exports.unenforcedDecision = exports.toDecision = exports.remedyFor = exports.policyDecision = exports.withDecisionText = exports.describeResolution = exports.RestGovernanceEngine = exports.NodeSdkEngine = exports.CompositeEngine = exports.createGovernanceEngine = void 0;
14
+ exports.meterStream = exports.DEFAULT_RECIPES = exports.observedMeasurement = exports.fromResponsesUsage = exports.fromOpenAIUsage = exports.fromOllamaUsage = exports.fromMistralUsage = exports.fromLangChainUsage = exports.fromGeminiUsage = exports.fromFlatTokenUsage = exports.addTokenUsage = exports.addMetrics = exports.pickRenamedMetrics = exports.pickMetrics = exports.metricNamesMatchPaths = exports.metricName = exports.METRIC_PATHS = exports.OPENAI_RESPONSES_METRICS = exports.OPENAI_METRICS = exports.OPENAI_CHAT_METRICS = exports.WORKERS_AI_METRICS = exports.DATABRICKS_QUERY_METRIC_NAME_MAP = exports.DATABRICKS_METRICS = exports.GATEWAY_METRICS = exports.TYPESAFE_METRICS = exports.OLLAMA_METRICS = exports.MISTRAL_METRIC_NAME_MAP = exports.MISTRAL_METRICS = exports.GEMINI_METRICS = exports.ANTHROPIC_METRICS = exports.GovernanceSession = exports.isEnforced = exports.resolveContext = exports.overrideContext = exports.noCustomer = exports.prefixed = exports.asEngineError = exports.isMeterMismatchError = exports.isTransportFailure = exports.resolveConfig = exports.unenforcedDecision = exports.toDecision = exports.remedyFor = exports.policyDecision = exports.withDecisionText = exports.describeResolution = exports.RestGovernanceEngine = exports.NodeSdkEngine = exports.CompositeEngine = exports.createGovernanceEngine = void 0;
15
+ exports.eventNameFor = void 0;
15
16
  // The engine seam's implementations. The interface itself is public - see `index.ts`.
16
17
  var create_engine_1 = require("./engine/create-engine");
17
18
  Object.defineProperty(exports, "createGovernanceEngine", { enumerable: true, get: function () { return create_engine_1.createGovernanceEngine; } });
@@ -58,6 +59,9 @@ Object.defineProperty(exports, "MISTRAL_METRIC_NAME_MAP", { enumerable: true, ge
58
59
  Object.defineProperty(exports, "OLLAMA_METRICS", { enumerable: true, get: function () { return token_usage_1.OLLAMA_METRICS; } });
59
60
  Object.defineProperty(exports, "TYPESAFE_METRICS", { enumerable: true, get: function () { return token_usage_1.TYPESAFE_METRICS; } });
60
61
  Object.defineProperty(exports, "GATEWAY_METRICS", { enumerable: true, get: function () { return token_usage_1.GATEWAY_METRICS; } });
62
+ Object.defineProperty(exports, "DATABRICKS_METRICS", { enumerable: true, get: function () { return token_usage_1.DATABRICKS_METRICS; } });
63
+ Object.defineProperty(exports, "DATABRICKS_QUERY_METRIC_NAME_MAP", { enumerable: true, get: function () { return token_usage_1.DATABRICKS_QUERY_METRIC_NAME_MAP; } });
64
+ Object.defineProperty(exports, "WORKERS_AI_METRICS", { enumerable: true, get: function () { return token_usage_1.WORKERS_AI_METRICS; } });
61
65
  Object.defineProperty(exports, "OPENAI_CHAT_METRICS", { enumerable: true, get: function () { return token_usage_1.OPENAI_CHAT_METRICS; } });
62
66
  Object.defineProperty(exports, "OPENAI_METRICS", { enumerable: true, get: function () { return token_usage_1.OPENAI_METRICS; } });
63
67
  Object.defineProperty(exports, "OPENAI_RESPONSES_METRICS", { enumerable: true, get: function () { return token_usage_1.OPENAI_RESPONSES_METRICS; } });
@@ -77,7 +77,7 @@ export declare const DEFAULT_RECIPES: ({
77
77
  } | undefined;
78
78
  attachStream: (stream: any, ingest: (measurement: import("./types").Measurement) => void) => void;
79
79
  }[];
80
- } | import("./bindings/client/core/types").ClientRecipe<"cached_tokens" | "prompt_tokens" | "completion_tokens" | "input_tokens" | "output_tokens" | "total_tokens" | "cost"> | {
80
+ } | import("./bindings/client/core/types").ClientRecipe<"cached_tokens" | "prompt_tokens" | "completion_tokens" | "input_tokens" | "output_tokens" | "total_tokens" | "cost"> | import("./bindings/client/core/types").ClientRecipe<"prompt_tokens" | "completion_tokens" | "input_tokens" | "output_tokens" | "cache_read_input_tokens" | "cache_creation_input_tokens" | "total_tokens" | "reasoning_tokens"> | import("./bindings/client/core/types").ClientRecipe<"cached_tokens" | "prompt_tokens" | "completion_tokens" | "input_tokens" | "output_tokens" | "cache_read_input_tokens" | "cache_creation_input_tokens" | "total_tokens"> | {
81
81
  vendor: string;
82
82
  metrics: readonly ["prompt_tokens", "completion_tokens", "cached_tokens", "total_tokens"];
83
83
  totalTokensMetric: "total_tokens";
@@ -25,6 +25,8 @@ const dimensions_1 = require("./core/dimensions");
25
25
  const anthropic_recipe_1 = require("./bindings/client/providers/anthropic/anthropic-recipe");
26
26
  const gemini_recipe_1 = require("./bindings/client/providers/gemini/gemini-recipe");
27
27
  const litellm_recipe_1 = require("./bindings/client/gateways/litellm/litellm-recipe");
28
+ const databricks_recipe_1 = require("./bindings/client/gateways/databricks/databricks-recipe");
29
+ const cloudflare_recipe_1 = require("./bindings/client/gateways/cloudflare/cloudflare-recipe");
28
30
  const groq_recipe_1 = require("./bindings/client/providers/groq/groq-recipe");
29
31
  const mistral_recipe_1 = require("./bindings/client/providers/mistral/mistral-recipe");
30
32
  const ollama_recipe_1 = require("./bindings/client/providers/ollama/ollama-recipe");
@@ -55,9 +57,20 @@ const types_1 = require("./types");
55
57
  * tokens is that mapper's business, and stays the caller's to decide.
56
58
  */
57
59
  exports.DEFAULT_RECIPES = [
60
+ // First, and that position is load-bearing. Cloudflare AI Gateway forwards the upstream body
61
+ // untouched, so an `Anthropic` client pointed at it is an Anthropic client by shape and only the
62
+ // hostname says otherwise - and `anthropicRecipe` has no base-URL guard, so asked first it would
63
+ // claim that client and meter gateway traffic as direct Anthropic traffic. The same argument puts
64
+ // it ahead of `openAIRecipe` for its OpenAI-shaped routes and for Workers AI's compatible one.
65
+ (0, cloudflare_recipe_1.cloudflareRecipe)(),
58
66
  anthropic_recipe_1.anthropicRecipe,
59
67
  (0, openrouter_recipe_1.openrouterRecipe)(),
60
68
  (0, litellm_recipe_1.litellmRecipe)(),
69
+ // The Databricks workspace route, matched on host *and* serving path - the host families alone
70
+ // are every Databricks API there is, most of which are not inference. Only the hosted recipe is
71
+ // here: `databricksExternalRecipe` covers the same wire reaching an endpoint billed by somebody
72
+ // else, which no matcher can tell apart, so it is named at `wrap` rather than guessed at.
73
+ (0, databricks_recipe_1.databricksRecipe)(),
61
74
  // Ahead of `openAIRecipe`, like the gateways above and for the same reason: shape cannot tell a
62
75
  // Groq client from any other OpenAI-compatible one, so the hostname decides, and the recipe that
63
76
  // reads the hostname has to be asked first or the generic one claims the client.
package/dist/types.d.ts CHANGED
@@ -454,6 +454,14 @@ export type ChatGatedPath = ['sendMessage'] | ['sendMessageStream'];
454
454
  * `ollamaRecipe.matches` requires.
455
455
  */
456
456
  export type OllamaGatedPath = ['chat'] | ['generate'];
457
+ /**
458
+ * Databricks' first-party client, whose whole surface is `query`. Out of {@link GatedPath} for the
459
+ * same reason as the two above, and more urgently: `query` is not merely a common method name, it
460
+ * is the one every database client in the ecosystem already owns. In the fallback list it would
461
+ * type `stiggContext` onto a `pg`, `mysql2`, Snowflake or BigQuery client - objects no recipe
462
+ * matches - and that context would be forwarded to the driver as an unknown field.
463
+ */
464
+ export type DatabricksGatedPath = ['query'];
457
465
  /**
458
466
  * The paths to overlay when no recipe was named, given what the client actually looks like.
459
467
  *
@@ -509,9 +517,35 @@ type GatedVendorShape = {
509
517
  * the vendor as an unknown field. So anything the registry would claim first is excluded here,
510
518
  * mirroring that precedence.
511
519
  */
512
- export type ChatOf<T> = T extends GatedVendorShape ? GatedPath : T extends OllamaShape ? GatedPath | OllamaGatedPath : T extends {
520
+ export type ChatOf<T> = T extends GatedVendorShape ? GatedPath : T extends OllamaShape ? GatedPath | OllamaGatedPath : T extends DatabricksQueryShape ? GatedPath | DatabricksGatedPath : T extends {
513
521
  getHistory: (...args: any[]) => any;
514
522
  } ? GatedPath | ChatGatedPath : GatedPath;
523
+ /**
524
+ * What `databricksRecipe.matches` looks for, as near as a type can get - and the gap is the point.
525
+ *
526
+ * The runtime guard is `query` **plus** a `userAgent` naming the Databricks SDK. That second
527
+ * marker cannot be written here: `userAgent` is declared `private` in the client's `.d.ts`, and a
528
+ * `private` member makes a class non-assignable to any structural type naming it. So unlike
529
+ * {@link OllamaShape}, which mirrors its matcher exactly, this keys on the one thing the client
530
+ * does publish - the shape of what `query` resolves to.
531
+ *
532
+ * That still discriminates, which was checked rather than assumed: `QueryEndpointResponse` has no
533
+ * required property, so a target of all-optional fields would normally be a weak type that
534
+ * anything satisfies - but a `pg` or Snowflake result shares *none* of these names, and TypeScript's
535
+ * weak-type rule rejects exactly that case. `created?: bigint` is the field doing most of the work;
536
+ * nothing else in the ecosystem returns a bigint timestamp beside a `servedModelName`.
537
+ *
538
+ * The residual gap is a `query` typed as `Promise<any>`, which matches everything by construction.
539
+ * That costs a context offered on a method the runtime will decline to gate - the type is wider
540
+ * than the matcher, never narrower, so nothing is gated that was not typed.
541
+ */
542
+ type DatabricksQueryShape = {
543
+ query: (...args: any[]) => Promise<{
544
+ servedModelName?: string | undefined;
545
+ predictions?: unknown;
546
+ created?: bigint | undefined;
547
+ }>;
548
+ };
515
549
  /** What `ollamaRecipe.matches` looks for, as a type. Kept in step with it by hand. */
516
550
  type OllamaShape = {
517
551
  chat: (...args: any[]) => any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigg/agent-sdk-js",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Stigg agent SDK (JS) - run-lifecycle governance for agentic stacks, with examples per layer",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -40,12 +40,15 @@
40
40
  "example-client-ollama": "tsx examples/client/ollama.ts",
41
41
  "example-client-openrouter": "tsx examples/client/openrouter.ts",
42
42
  "example-client-litellm": "tsx examples/client/litellm.ts",
43
+ "example-client-databricks": "tsx examples/client/databricks.ts",
43
44
  "example-client-typesafe": "tsx examples/client/typesafe.ts",
44
45
  "example-two-agents": "tsx examples/client/two-agents.ts",
45
46
  "example-gateway": "tsx examples/gateway/openrouter.ts",
46
47
  "example-gateway-openrouter": "tsx examples/gateway/openrouter.ts",
47
48
  "example-gateway-litellm": "tsx examples/gateway/litellm.ts",
48
- "example-gateway-bedrock": "tsx examples/gateway/bedrock.ts"
49
+ "example-gateway-cloudflare": "tsx examples/gateway/cloudflare.ts",
50
+ "example-gateway-bedrock": "tsx examples/gateway/bedrock.ts",
51
+ "example-gateway-databricks": "tsx examples/gateway/databricks.ts"
49
52
  },
50
53
  "nx": {
51
54
  "includedScripts": [
@@ -68,10 +71,12 @@
68
71
  "devDependencies": {
69
72
  "@anthropic-ai/sdk": "^0.124.0",
70
73
  "@aws-sdk/client-bedrock-runtime": "^3.1150.0",
74
+ "@databricks/sdk-modelservingquery": "0.25.0",
71
75
  "@google/genai": "^2.28.0",
72
76
  "@mistralai/mistralai": "^2.7.0",
73
77
  "@openrouter/sdk": "^1.4.25",
74
78
  "@typesafe-ai/sdk": "^0.6.0",
79
+ "cloudflare": "^7.3.0",
75
80
  "dotenv": "^17.4.2",
76
81
  "groq-sdk": "^1.6.0",
77
82
  "ollama": "^0.6.4",