@adaptic/lumic-utils 1.0.28 → 1.0.29
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/{apollo-client.client-KzZx5slz.js → apollo-client.client-BQLzKbg9.js} +4 -4
- package/dist/{apollo-client.client-KzZx5slz.js.map → apollo-client.client-BQLzKbg9.js.map} +1 -1
- package/dist/{apollo-client.client-CzTlfziA.js → apollo-client.client-C1dwHT2X.js} +3 -3
- package/dist/{apollo-client.client-CzTlfziA.js.map → apollo-client.client-C1dwHT2X.js.map} +1 -1
- package/dist/{apollo-client.server-Bv2rQsCw.js → apollo-client.server-Crk0lXFR.js} +3 -3
- package/dist/{apollo-client.server-Bv2rQsCw.js.map → apollo-client.server-Crk0lXFR.js.map} +1 -1
- package/dist/{apollo-client.server-DQPc4Iam.js → apollo-client.server-DoI6FK_-.js} +3 -3
- package/dist/{apollo-client.server-DQPc4Iam.js.map → apollo-client.server-DoI6FK_-.js.map} +1 -1
- package/dist/{index-I-0uzUiF.js → index-CV8HlDp8.js} +719 -50
- package/dist/{index-FqzV71J4.js.map → index-CV8HlDp8.js.map} +1 -1
- package/dist/{index-FqzV71J4.js → index-CtY-7qjs.js} +720 -49
- package/dist/{index-I-0uzUiF.js.map → index-CtY-7qjs.js.map} +1 -1
- package/dist/{index-Cjy8RH6E.js → index-DA066GXe.js} +2 -2
- package/dist/{index-Cjy8RH6E.js.map → index-DA066GXe.js.map} +1 -1
- package/dist/{index-QMP2OpYn.js → index-IAFN9E4Q.js} +2 -2
- package/dist/{index-QMP2OpYn.js.map → index-IAFN9E4Q.js.map} +1 -1
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/test.cjs +1 -1
- package/dist/test.mjs +1 -1
- package/dist/types/config/secrets.d.ts +10 -0
- package/dist/types/functions/__tests__/gpt56-model-release-layer.test.d.ts +1 -0
- package/dist/types/functions/__tests__/llm-openai-responses-routing.test.d.ts +1 -0
- package/dist/types/functions/llm-config.d.ts +8 -6
- package/dist/types/functions/llm-openai.d.ts +125 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/schemas/openai-schemas.d.ts +30 -30
- package/dist/types/schemas/perplexity-schemas.d.ts +40 -40
- package/dist/types/types/openai-types.d.ts +42 -5
- package/dist/types/utils/config.d.ts +12 -1
- package/dist/types/utils/llm-cost-tracker.d.ts +2 -2
- package/package.json +1 -1
|
@@ -100,9 +100,14 @@ const OPENAI_COMPATIBLE_PROVIDERS = {
|
|
|
100
100
|
*/
|
|
101
101
|
const SUPPORTED_MODELS = {
|
|
102
102
|
// ── OpenAI GPT-5.6 series (current flagship) ─────────────────────────
|
|
103
|
-
// sol / terra / luna are the 2026 flagship trio
|
|
104
|
-
// api/docs/models/all).
|
|
105
|
-
//
|
|
103
|
+
// sol / terra / luna are the 2026 flagship reasoning trio
|
|
104
|
+
// (developers.openai.com/api/docs/models/all). They are REASONING models
|
|
105
|
+
// (isReasoningModel: true) and — like all reasoning models — do not accept a
|
|
106
|
+
// custom temperature. Critically, OpenAI rejects function tools for them on
|
|
107
|
+
// Chat Completions ("Function tools with reasoning_effort are not supported
|
|
108
|
+
// for gpt-5.6-sol in /v1/chat/completions"), so `requiresResponsesApiForTools`
|
|
109
|
+
// routes tool-bearing calls to the Responses API. Both flags are corrected
|
|
110
|
+
// here from their initial (registration-time) `false` values.
|
|
106
111
|
'gpt-5.6-sol': {
|
|
107
112
|
provider: 'openai',
|
|
108
113
|
supportsTools: true,
|
|
@@ -110,7 +115,8 @@ const SUPPORTED_MODELS = {
|
|
|
110
115
|
supportsStructuredOutput: true,
|
|
111
116
|
supportsDeveloperPrompt: true,
|
|
112
117
|
supportsTemperature: false,
|
|
113
|
-
isReasoningModel:
|
|
118
|
+
isReasoningModel: true,
|
|
119
|
+
requiresResponsesApiForTools: true,
|
|
114
120
|
},
|
|
115
121
|
'gpt-5.6-terra': {
|
|
116
122
|
provider: 'openai',
|
|
@@ -119,7 +125,8 @@ const SUPPORTED_MODELS = {
|
|
|
119
125
|
supportsStructuredOutput: true,
|
|
120
126
|
supportsDeveloperPrompt: true,
|
|
121
127
|
supportsTemperature: false,
|
|
122
|
-
isReasoningModel:
|
|
128
|
+
isReasoningModel: true,
|
|
129
|
+
requiresResponsesApiForTools: true,
|
|
123
130
|
},
|
|
124
131
|
'gpt-5.6-luna': {
|
|
125
132
|
provider: 'openai',
|
|
@@ -128,7 +135,8 @@ const SUPPORTED_MODELS = {
|
|
|
128
135
|
supportsStructuredOutput: true,
|
|
129
136
|
supportsDeveloperPrompt: true,
|
|
130
137
|
supportsTemperature: false,
|
|
131
|
-
isReasoningModel:
|
|
138
|
+
isReasoningModel: true,
|
|
139
|
+
requiresResponsesApiForTools: true,
|
|
132
140
|
},
|
|
133
141
|
// ── OpenAI GPT-5.5 series ────────────────────────────────────────────
|
|
134
142
|
// GPT-5.x series: OpenAI's 2026 API constraint — only the default
|
|
@@ -611,24 +619,33 @@ function getModelProvider(model) {
|
|
|
611
619
|
return SUPPORTED_MODELS[model].provider;
|
|
612
620
|
}
|
|
613
621
|
/**
|
|
614
|
-
* Default model tiers per provider for use with
|
|
622
|
+
* Default model tiers per provider for use with the
|
|
623
|
+
* LLM_MODEL_MINI/NORMAL/ADVANCED/CRITICAL env vars.
|
|
624
|
+
*
|
|
625
|
+
* Four tiers, increasing in capability/cost: `mini` (high-volume, cheap) →
|
|
626
|
+
* `normal` (default) → `advanced` → `critical` (most-capable). The tier a caller
|
|
627
|
+
* lands on is resolved in `../utils/config` (see `LLM_MODEL_*`).
|
|
615
628
|
*/
|
|
616
629
|
const PROVIDER_DEFAULT_MODELS = {
|
|
617
|
-
//
|
|
618
|
-
//
|
|
619
|
-
//
|
|
620
|
-
//
|
|
621
|
-
//
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
//
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
630
|
+
// OpenAI now leads with the GPT-5.6 reasoning trio. The historical blocker
|
|
631
|
+
// (gpt-5.6-* returning 400 on Chat-Completions + tools) is resolved by the
|
|
632
|
+
// Responses-API routing (`requiresResponsesApiForTools` +
|
|
633
|
+
// `makeOpenAIChatCompletionCall`), so the intended canary is live:
|
|
634
|
+
// normal → gpt-5.6-luna (cheapest of the trio)
|
|
635
|
+
// advanced → gpt-5.6-terra (flips off the temporary gpt-5.5 pin)
|
|
636
|
+
// critical → gpt-5.6-sol (most capable; in/out priced like gpt-5.5)
|
|
637
|
+
// `mini` stays on gpt-5.4-nano — the high-volume summarizer tier where the
|
|
638
|
+
// trio's reasoning cost is not warranted.
|
|
639
|
+
openai: { mini: 'gpt-5.4-nano', normal: 'gpt-5.6-luna', advanced: 'gpt-5.6-terra', critical: 'gpt-5.6-sol' },
|
|
640
|
+
// Non-OpenAI providers: `critical` mirrors `advanced` (each provider's
|
|
641
|
+
// most-capable model), so the new tier is a no-op for them until a distinct
|
|
642
|
+
// critical-tier model is chosen.
|
|
643
|
+
anthropic: { mini: 'claude-haiku-4-5', normal: 'claude-sonnet-4-6', advanced: 'claude-opus-4-7', critical: 'claude-opus-4-7' },
|
|
644
|
+
deepseek: { mini: 'deepseek-v4-flash', normal: 'deepseek-v4-flash', advanced: 'deepseek-v4-pro', critical: 'deepseek-v4-pro' },
|
|
645
|
+
kimi: { mini: 'kimi-k2-0905-preview', normal: 'kimi-k2.5', advanced: 'kimi-k2.6', critical: 'kimi-k2.6' },
|
|
646
|
+
qwen: { mini: 'qwen3.5-flash', normal: 'qwen3.5-plus', advanced: 'qwen3-max', critical: 'qwen3-max' },
|
|
647
|
+
xai: { mini: 'grok-4.1-fast', normal: 'grok-4-fast-non-reasoning', advanced: 'grok-4.3', critical: 'grok-4.3' },
|
|
648
|
+
gemini: { mini: 'gemini-3.1-flash-lite-preview', normal: 'gemini-3-flash-preview', advanced: 'gemini-3.1-pro-preview', critical: 'gemini-3.1-pro-preview' },
|
|
632
649
|
};
|
|
633
650
|
|
|
634
651
|
// Default implementation using console (backward compatible)
|
|
@@ -703,9 +720,11 @@ const lumicSecretsSchema = zod.z.object({
|
|
|
703
720
|
llmMiniProvider: zod.z.string().optional(),
|
|
704
721
|
llmNormalProvider: zod.z.string().optional(),
|
|
705
722
|
llmAdvancedProvider: zod.z.string().optional(),
|
|
723
|
+
llmCriticalProvider: zod.z.string().optional(),
|
|
706
724
|
llmModelMini: zod.z.string().optional(),
|
|
707
725
|
llmModelNormal: zod.z.string().optional(),
|
|
708
726
|
llmModelAdvanced: zod.z.string().optional(),
|
|
727
|
+
llmModelCritical: zod.z.string().optional(),
|
|
709
728
|
lumicDebug: zod.z.boolean().default(false),
|
|
710
729
|
allowedUploadPaths: zod.z.string().default('/tmp'),
|
|
711
730
|
}),
|
|
@@ -768,9 +787,11 @@ function loadSecrets() {
|
|
|
768
787
|
llmMiniProvider: process.env.LLM_MINI_PROVIDER,
|
|
769
788
|
llmNormalProvider: process.env.LLM_NORMAL_PROVIDER,
|
|
770
789
|
llmAdvancedProvider: process.env.LLM_ADVANCED_PROVIDER,
|
|
790
|
+
llmCriticalProvider: process.env.LLM_CRITICAL_PROVIDER,
|
|
771
791
|
llmModelMini: process.env.LLM_MODEL_MINI,
|
|
772
792
|
llmModelNormal: process.env.LLM_MODEL_NORMAL,
|
|
773
793
|
llmModelAdvanced: process.env.LLM_MODEL_ADVANCED,
|
|
794
|
+
llmModelCritical: process.env.LLM_MODEL_CRITICAL,
|
|
774
795
|
lumicDebug: process.env.LUMIC_DEBUG === 'true' ||
|
|
775
796
|
process.env.lumic_debug === 'true',
|
|
776
797
|
allowedUploadPaths: process.env.LUMIC_ALLOWED_UPLOAD_PATHS || '/tmp',
|
|
@@ -870,6 +891,7 @@ const LLM_DEFAULT_PROVIDER = parseProvider(getSecrets().config.llmDefaultProvide
|
|
|
870
891
|
const LLM_MINI_PROVIDER = parseProvider(getSecrets().config.llmMiniProvider) || LLM_DEFAULT_PROVIDER;
|
|
871
892
|
const LLM_NORMAL_PROVIDER = parseProvider(getSecrets().config.llmNormalProvider) || LLM_DEFAULT_PROVIDER;
|
|
872
893
|
const LLM_ADVANCED_PROVIDER = parseProvider(getSecrets().config.llmAdvancedProvider) || LLM_DEFAULT_PROVIDER;
|
|
894
|
+
const LLM_CRITICAL_PROVIDER = parseProvider(getSecrets().config.llmCriticalProvider) || LLM_DEFAULT_PROVIDER;
|
|
873
895
|
// Keep backward compat — LLM_PROVIDER is the default provider
|
|
874
896
|
const LLM_PROVIDER = LLM_DEFAULT_PROVIDER;
|
|
875
897
|
/**
|
|
@@ -889,13 +911,14 @@ const DEFAULT_MODEL = (() => {
|
|
|
889
911
|
* Model tier values resolved from env vars.
|
|
890
912
|
*
|
|
891
913
|
* Resolution order per tier:
|
|
892
|
-
* 1. LLM_MODEL_MINI / LLM_MODEL_NORMAL / LLM_MODEL_ADVANCED (explicit model override)
|
|
914
|
+
* 1. LLM_MODEL_MINI / LLM_MODEL_NORMAL / LLM_MODEL_ADVANCED / LLM_MODEL_CRITICAL (explicit model override)
|
|
893
915
|
* 2. PROVIDER_DEFAULT_MODELS[tier-specific provider][tier] (provider default for tier)
|
|
894
916
|
*
|
|
895
917
|
* The tier-specific provider is:
|
|
896
918
|
* LLM_MINI_PROVIDER → falls back to LLM_DEFAULT_PROVIDER
|
|
897
919
|
* LLM_NORMAL_PROVIDER → falls back to LLM_DEFAULT_PROVIDER
|
|
898
920
|
* LLM_ADVANCED_PROVIDER → falls back to LLM_DEFAULT_PROVIDER
|
|
921
|
+
* LLM_CRITICAL_PROVIDER → falls back to LLM_DEFAULT_PROVIDER
|
|
899
922
|
*/
|
|
900
923
|
const LLM_MODEL_MINI = (() => {
|
|
901
924
|
const env = getSecrets().config.llmModelMini;
|
|
@@ -924,6 +947,21 @@ const LLM_MODEL_ADVANCED = (() => {
|
|
|
924
947
|
}
|
|
925
948
|
return PROVIDER_DEFAULT_MODELS[LLM_ADVANCED_PROVIDER].advanced;
|
|
926
949
|
})();
|
|
950
|
+
/**
|
|
951
|
+
* The most-capable ("critical") model tier — reserved for the highest-stakes
|
|
952
|
+
* calls. Resolves from LLM_MODEL_CRITICAL, else the critical-tier default of the
|
|
953
|
+
* resolved LLM_CRITICAL_PROVIDER (see PROVIDER_DEFAULT_MODELS). For OpenAI this
|
|
954
|
+
* is gpt-5.6-sol; for other providers it mirrors their advanced tier.
|
|
955
|
+
*/
|
|
956
|
+
const LLM_MODEL_CRITICAL = (() => {
|
|
957
|
+
const env = getSecrets().config.llmModelCritical;
|
|
958
|
+
if (env) {
|
|
959
|
+
const resolved = resolveModelName(env);
|
|
960
|
+
if (resolved)
|
|
961
|
+
return resolved;
|
|
962
|
+
}
|
|
963
|
+
return PROVIDER_DEFAULT_MODELS[LLM_CRITICAL_PROVIDER].critical;
|
|
964
|
+
})();
|
|
927
965
|
const PERPLEXITY_MODEL = getSecrets().config.perplexityModel || DEFAULT_PERPLEXITY_MODEL;
|
|
928
966
|
const PERPLEXITY_API_URL = 'https://api.perplexity.ai/chat/completions';
|
|
929
967
|
|
|
@@ -936,15 +974,40 @@ const DEFAULT_DEVELOPER_PROMPT = `
|
|
|
936
974
|
Respond only with final content (e.g. code, a json or yaml object, a formatted string, or a markdown document) and nothing else. Do not reply with a preamble, introduction, or conclusion.
|
|
937
975
|
`;
|
|
938
976
|
/**
|
|
939
|
-
* Token costs in USD per token. Last updated
|
|
977
|
+
* Token costs in USD per token. Last updated July 2026.
|
|
940
978
|
*
|
|
941
|
-
* `cacheHitCost` reflects
|
|
942
|
-
* standard input rate per OpenAI's prompt
|
|
943
|
-
*
|
|
944
|
-
*
|
|
945
|
-
*
|
|
979
|
+
* `cacheHitCost` reflects each model's cached-input billing rate. For most
|
|
980
|
+
* models this is ~50% of the standard input rate (per OpenAI's prompt-caching
|
|
981
|
+
* documentation); the GPT-5.6 reasoning trio discounts cached input more
|
|
982
|
+
* aggressively, to 10% of the input rate. When set, `calculateCost` splits
|
|
983
|
+
* prompt tokens into cached vs non-cached buckets and applies the discount; when
|
|
984
|
+
* omitted, cached tokens are billed at the full input rate (a silent cost
|
|
985
|
+
* overstatement for cache-friendly workloads).
|
|
946
986
|
*/
|
|
947
987
|
const openAiModelCosts = {
|
|
988
|
+
// GPT-5.6 reasoning trio (sol/terra/luna). Tiered per-1M-token pricing,
|
|
989
|
+
// verified against OpenAI's published price sheet on 2026-07-13:
|
|
990
|
+
// sol — $5.00 in / $0.50 cached / $30.00 out (in/out identical to gpt-5.5)
|
|
991
|
+
// terra — $2.50 in / $0.25 cached / $15.00 out
|
|
992
|
+
// luna — $1.00 in / $0.10 cached / $6.00 out
|
|
993
|
+
// Cached input is 10% of the input rate across the trio. Reasoning tokens are
|
|
994
|
+
// a SUBSET of output tokens and are billed at the output rate inside
|
|
995
|
+
// `calculateCost`, so callers must not add them on top of the output count.
|
|
996
|
+
'gpt-5.6-sol': {
|
|
997
|
+
inputCost: 5 / 1_000_000,
|
|
998
|
+
cacheHitCost: 0.5 / 1_000_000,
|
|
999
|
+
outputCost: 30 / 1_000_000,
|
|
1000
|
+
},
|
|
1001
|
+
'gpt-5.6-terra': {
|
|
1002
|
+
inputCost: 2.5 / 1_000_000,
|
|
1003
|
+
cacheHitCost: 0.25 / 1_000_000,
|
|
1004
|
+
outputCost: 15 / 1_000_000,
|
|
1005
|
+
},
|
|
1006
|
+
'gpt-5.6-luna': {
|
|
1007
|
+
inputCost: 1 / 1_000_000,
|
|
1008
|
+
cacheHitCost: 0.1 / 1_000_000,
|
|
1009
|
+
outputCost: 6 / 1_000_000,
|
|
1010
|
+
},
|
|
948
1011
|
'gpt-5.5': {
|
|
949
1012
|
inputCost: 5 / 1_000_000,
|
|
950
1013
|
cacheHitCost: 2.5 / 1_000_000,
|
|
@@ -2276,12 +2339,18 @@ class LLMCostTracker {
|
|
|
2276
2339
|
* @param provider - The LLM provider ('openai' or 'deepseek')
|
|
2277
2340
|
* @param model - The model name (e.g., 'gpt-5', 'deepseek-chat')
|
|
2278
2341
|
* @param inputTokens - Number of input/prompt tokens
|
|
2279
|
-
* @param outputTokens -
|
|
2280
|
-
* @param reasoningTokens -
|
|
2342
|
+
* @param outputTokens - Total output/completion tokens, INCLUDING reasoning tokens
|
|
2343
|
+
* @param reasoningTokens - Reasoning tokens, a subset of outputTokens (default: 0). Billed at the output rate, not on top of it.
|
|
2281
2344
|
* @param cacheHitTokens - Number of cache hit tokens (default: 0)
|
|
2282
2345
|
*/
|
|
2283
2346
|
trackUsage(provider, model, inputTokens, outputTokens, reasoningTokens = 0, cacheHitTokens = 0) {
|
|
2284
|
-
|
|
2347
|
+
// Reasoning tokens are a SUBSET of output tokens for every provider tracked
|
|
2348
|
+
// here (they are counted within completion/output tokens and billed at the
|
|
2349
|
+
// output rate). calculateCost bills output AND reasoning separately, so cost
|
|
2350
|
+
// the non-reasoning remainder to avoid billing reasoning twice; the stored
|
|
2351
|
+
// record keeps the full outputTokens/reasoningTokens for reporting. For
|
|
2352
|
+
// non-reasoning calls reasoningTokens is 0, so this is a no-op.
|
|
2353
|
+
const cost = calculateCost(provider, model, inputTokens, outputTokens - reasoningTokens, reasoningTokens, cacheHitTokens);
|
|
2285
2354
|
const record = {
|
|
2286
2355
|
provider,
|
|
2287
2356
|
model,
|
|
@@ -2598,6 +2667,112 @@ function isReasoningModel(model) {
|
|
|
2598
2667
|
}
|
|
2599
2668
|
return getModelCapabilities(model).isReasoningModel;
|
|
2600
2669
|
}
|
|
2670
|
+
/**
|
|
2671
|
+
* Checks whether a model must use the OpenAI Responses API (`/v1/responses`)
|
|
2672
|
+
* for function-tool calls rather than Chat Completions (`/v1/chat/completions`).
|
|
2673
|
+
*
|
|
2674
|
+
* Driven entirely by the {@link ModelCapabilities.requiresResponsesApiForTools}
|
|
2675
|
+
* flag in the model registry — there are no hardcoded model-name checks here.
|
|
2676
|
+
* Unknown models and models without the flag return `false` (stay on Chat
|
|
2677
|
+
* Completions).
|
|
2678
|
+
*
|
|
2679
|
+
* @param model The model to check.
|
|
2680
|
+
* @returns True when tool-bearing calls for this model must be routed to the
|
|
2681
|
+
* Responses API, false otherwise.
|
|
2682
|
+
*/
|
|
2683
|
+
function requiresResponsesApiForTools(model) {
|
|
2684
|
+
if (!isValidModel(model)) {
|
|
2685
|
+
return false;
|
|
2686
|
+
}
|
|
2687
|
+
return getModelCapabilities(model).requiresResponsesApiForTools ?? false;
|
|
2688
|
+
}
|
|
2689
|
+
/**
|
|
2690
|
+
* OpenAI's `reasoning_effort` ladder, ordered from least to most effort. This is
|
|
2691
|
+
* the full 2026 ladder (developers.openai.com); NOTE there is no `'max'` level.
|
|
2692
|
+
* Mirrors the widened {@link LLMOptions.reasoning_effort} union.
|
|
2693
|
+
*/
|
|
2694
|
+
const REASONING_EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh'];
|
|
2695
|
+
/**
|
|
2696
|
+
* Per-model `reasoning_effort` support window for OpenAI reasoning models,
|
|
2697
|
+
* expressed on {@link REASONING_EFFORT_LADDER}. `min`/`max` are the lowest and
|
|
2698
|
+
* highest effort each model's API accepts; a request below `min` clamps up and
|
|
2699
|
+
* above `max` clamps down, so an over/under-shoot degrades gracefully instead of
|
|
2700
|
+
* returning HTTP 400.
|
|
2701
|
+
*
|
|
2702
|
+
* Reasoning models ABSENT from this table omit `reasoning_effort` entirely —
|
|
2703
|
+
* notably `o1-mini`, which does not accept the parameter at all. The windows
|
|
2704
|
+
* record TRUE API support; the wire value is additionally narrowed to
|
|
2705
|
+
* {@link SdkReasoningEffort} in {@link toSdkReasoningEffort}, so when the SDK
|
|
2706
|
+
* widens only that mapping (not these windows) needs revisiting.
|
|
2707
|
+
*/
|
|
2708
|
+
const MODEL_REASONING_EFFORT_SUPPORT = {
|
|
2709
|
+
// GPT-5.6 reasoning trio — full ladder (developers.openai.com/api/docs/models).
|
|
2710
|
+
'gpt-5.6-sol': { min: 'minimal', max: 'xhigh' },
|
|
2711
|
+
'gpt-5.6-terra': { min: 'minimal', max: 'xhigh' },
|
|
2712
|
+
'gpt-5.6-luna': { min: 'minimal', max: 'xhigh' },
|
|
2713
|
+
// o-series reasoning models accept low|medium|high (no none/minimal/xhigh).
|
|
2714
|
+
o1: { min: 'low', max: 'high' },
|
|
2715
|
+
o3: { min: 'low', max: 'high' },
|
|
2716
|
+
'o3-mini': { min: 'low', max: 'high' },
|
|
2717
|
+
'o4-mini': { min: 'low', max: 'high' },
|
|
2718
|
+
// o1-mini is intentionally omitted — it rejects reasoning_effort outright.
|
|
2719
|
+
};
|
|
2720
|
+
/**
|
|
2721
|
+
* Folds a full-ladder effort level onto the nearest value the installed OpenAI
|
|
2722
|
+
* SDK can send ({@link SdkReasoningEffort}). Levels below `low` map to `low`,
|
|
2723
|
+
* levels above `high` map to `high`. Exhaustive over the ladder so the compiler
|
|
2724
|
+
* flags any future ladder addition. Widen this mapping when the SDK's
|
|
2725
|
+
* `ReasoningEffort` type gains `none`/`minimal`/`xhigh`.
|
|
2726
|
+
*
|
|
2727
|
+
* @param level A level on {@link REASONING_EFFORT_LADDER}.
|
|
2728
|
+
* @returns The nearest SDK-sendable effort.
|
|
2729
|
+
*/
|
|
2730
|
+
function toSdkReasoningEffort(level) {
|
|
2731
|
+
switch (level) {
|
|
2732
|
+
case 'none':
|
|
2733
|
+
case 'minimal':
|
|
2734
|
+
case 'low':
|
|
2735
|
+
return 'low';
|
|
2736
|
+
case 'medium':
|
|
2737
|
+
return 'medium';
|
|
2738
|
+
case 'high':
|
|
2739
|
+
case 'xhigh':
|
|
2740
|
+
return 'high';
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
/**
|
|
2744
|
+
* Clamps a requested {@link LLMOptions.reasoning_effort} to a value the target
|
|
2745
|
+
* model — and the installed OpenAI SDK — will accept, degrading gracefully so an
|
|
2746
|
+
* unsupported (too-high or too-low) level never returns HTTP 400.
|
|
2747
|
+
*
|
|
2748
|
+
* Resolution:
|
|
2749
|
+
* 1. Models without an entry in {@link MODEL_REASONING_EFFORT_SUPPORT}
|
|
2750
|
+
* (non-reasoning models, or reasoning models like `o1-mini` that reject the
|
|
2751
|
+
* parameter) ⇒ `undefined`, i.e. omit `reasoning_effort` from the request.
|
|
2752
|
+
* 2. Clamp the requested level into the model's `[min, max]` window.
|
|
2753
|
+
* 3. Fold onto the SDK-sendable range via {@link toSdkReasoningEffort}.
|
|
2754
|
+
*
|
|
2755
|
+
* Shared by BOTH OpenAI transports so the Chat and Responses paths clamp
|
|
2756
|
+
* identically.
|
|
2757
|
+
*
|
|
2758
|
+
* @param requested The caller's requested effort (full ladder).
|
|
2759
|
+
* @param model The normalized model name the request targets.
|
|
2760
|
+
* @returns An SDK-safe effort, or `undefined` when the field must be omitted.
|
|
2761
|
+
*/
|
|
2762
|
+
function clampReasoningEffort(requested, model) {
|
|
2763
|
+
const support = MODEL_REASONING_EFFORT_SUPPORT[model];
|
|
2764
|
+
if (!support) {
|
|
2765
|
+
return undefined;
|
|
2766
|
+
}
|
|
2767
|
+
const requestedIdx = REASONING_EFFORT_LADDER.indexOf(requested);
|
|
2768
|
+
if (requestedIdx < 0) {
|
|
2769
|
+
return undefined;
|
|
2770
|
+
}
|
|
2771
|
+
const minIdx = REASONING_EFFORT_LADDER.indexOf(support.min);
|
|
2772
|
+
const maxIdx = REASONING_EFFORT_LADDER.indexOf(support.max);
|
|
2773
|
+
const clampedIdx = Math.min(Math.max(requestedIdx, minIdx), maxIdx);
|
|
2774
|
+
return toSdkReasoningEffort(REASONING_EFFORT_LADDER[clampedIdx]);
|
|
2775
|
+
}
|
|
2601
2776
|
/**
|
|
2602
2777
|
* Normalizes the response format option based on model compatibility.
|
|
2603
2778
|
* @param responseFormat The desired response format.
|
|
@@ -2729,6 +2904,18 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
|
|
|
2729
2904
|
if (options.max_completion_tokens !== undefined) {
|
|
2730
2905
|
queryOptions.max_completion_tokens = options.max_completion_tokens;
|
|
2731
2906
|
}
|
|
2907
|
+
// Forward reasoning_effort on the Chat path for reasoning models. Chat
|
|
2908
|
+
// Completions accepts reasoning_effort for reasoning models (only tools +
|
|
2909
|
+
// effort together 400 on GPT-5.6, and those tool-bearing calls are already
|
|
2910
|
+
// routed to the Responses API), so this is safe. The value is clamped per
|
|
2911
|
+
// model so an unsupported level degrades gracefully instead of 400-ing;
|
|
2912
|
+
// clampReasoningEffort returns undefined for models that reject the parameter.
|
|
2913
|
+
if (options.reasoning_effort !== undefined && isReasoningModel(normalizedModel)) {
|
|
2914
|
+
const effort = clampReasoningEffort(options.reasoning_effort, normalizedModel);
|
|
2915
|
+
if (effort !== undefined) {
|
|
2916
|
+
queryOptions.reasoning_effort = effort;
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2732
2919
|
// Only set response_format when it's not the default 'text' type
|
|
2733
2920
|
// (sending response_format: {type: 'text'} is redundant and may cause issues)
|
|
2734
2921
|
const responseFormatOption = getResponseFormatOption(responseFormat, normalizedModel);
|
|
@@ -2804,6 +2991,9 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
|
|
|
2804
2991
|
completion_tokens: completion.usage?.completion_tokens ?? 0,
|
|
2805
2992
|
total_tokens: completion.usage?.total_tokens ?? 0,
|
|
2806
2993
|
cached_tokens: cachedTokens,
|
|
2994
|
+
// Non-reasoning Chat-Completions models report no reasoning tokens; read
|
|
2995
|
+
// defensively so the field is always present and correct.
|
|
2996
|
+
reasoning_tokens: completion.usage?.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
2807
2997
|
},
|
|
2808
2998
|
system_fingerprint: completion.system_fingerprint,
|
|
2809
2999
|
service_tier: options.service_tier,
|
|
@@ -2812,9 +3002,383 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
|
|
|
2812
3002
|
};
|
|
2813
3003
|
return response;
|
|
2814
3004
|
}
|
|
3005
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3006
|
+
// Transparent Chat-Completions → Responses API routing (GPT-5.6 reasoning trio)
|
|
3007
|
+
//
|
|
3008
|
+
// OpenAI's GPT-5.6 reasoning models (sol/terra/luna) return HTTP 400 for
|
|
3009
|
+
// function tools on `/v1/chat/completions`
|
|
3010
|
+
// ("Function tools with reasoning_effort are not supported for gpt-5.6-sol in
|
|
3011
|
+
// /v1/chat/completions"); they require the Responses API (`/v1/responses`).
|
|
3012
|
+
// The helpers below convert a Chat-Completions-style request into a Responses
|
|
3013
|
+
// request and normalize the Responses result back into the SAME internal
|
|
3014
|
+
// {@link CompletionResponse}, so callers of {@link makeOpenAIChatCompletionCall}
|
|
3015
|
+
// receive a byte-identical {@link LLMResponse} envelope regardless of which
|
|
3016
|
+
// endpoint served the call. The routing decision is data-driven via
|
|
3017
|
+
// {@link requiresResponsesApiForTools}.
|
|
3018
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3019
|
+
/**
|
|
3020
|
+
* Coerces a Chat-Completions message `content` value (string, content-part
|
|
3021
|
+
* array, or null) into a plain string. Mirrors the text-extraction rule used
|
|
3022
|
+
* elsewhere in this module: array parts contribute their `text` field, all
|
|
3023
|
+
* other shapes contribute nothing.
|
|
3024
|
+
*
|
|
3025
|
+
* @param content The message content in any of its Chat-Completions shapes.
|
|
3026
|
+
* @returns The concatenated text, or an empty string when there is none.
|
|
3027
|
+
*/
|
|
3028
|
+
function coerceMessageText(content) {
|
|
3029
|
+
if (typeof content === 'string') {
|
|
3030
|
+
return content;
|
|
3031
|
+
}
|
|
3032
|
+
if (Array.isArray(content)) {
|
|
3033
|
+
return content
|
|
3034
|
+
.map((part) => typeof part === 'object' && part !== null && 'text' in part &&
|
|
3035
|
+
typeof part.text === 'string'
|
|
3036
|
+
? part.text
|
|
3037
|
+
: '')
|
|
3038
|
+
.join('');
|
|
3039
|
+
}
|
|
3040
|
+
return '';
|
|
3041
|
+
}
|
|
3042
|
+
/**
|
|
3043
|
+
* Converts Chat-Completions user content (string or multi-modal content parts)
|
|
3044
|
+
* into the Responses API content shape. String content passes through
|
|
3045
|
+
* unchanged; content-part arrays map `text` → `input_text` and `image_url` →
|
|
3046
|
+
* `input_image`. Unsupported part kinds (audio/file) are skipped rather than
|
|
3047
|
+
* emitted in an incompatible shape — no tool-calling caller uses them today.
|
|
3048
|
+
*
|
|
3049
|
+
* @param content The Chat-Completions user content.
|
|
3050
|
+
* @returns A string or an array of Responses input-content parts.
|
|
3051
|
+
*/
|
|
3052
|
+
function chatContentToResponsesContent(content) {
|
|
3053
|
+
if (typeof content === 'string') {
|
|
3054
|
+
return content;
|
|
3055
|
+
}
|
|
3056
|
+
const parts = [];
|
|
3057
|
+
for (const part of content) {
|
|
3058
|
+
if (part.type === 'text') {
|
|
3059
|
+
parts.push({ type: 'input_text', text: part.text });
|
|
3060
|
+
}
|
|
3061
|
+
else if (part.type === 'image_url') {
|
|
3062
|
+
parts.push({
|
|
3063
|
+
type: 'input_image',
|
|
3064
|
+
image_url: part.image_url.url,
|
|
3065
|
+
detail: part.image_url.detail ?? 'auto',
|
|
3066
|
+
});
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
return parts;
|
|
3070
|
+
}
|
|
3071
|
+
/**
|
|
3072
|
+
* Converts a single Chat-Completions message into zero or more Responses API
|
|
3073
|
+
* input items. Assistant tool calls become `function_call` items and `tool`
|
|
3074
|
+
* results become `function_call_output` items — both keyed by the SAME id the
|
|
3075
|
+
* chat envelope exposed as `tool_call.id` / `tool_call_id`, so a multi-turn
|
|
3076
|
+
* tool conversation round-trips correctly through the Responses transport.
|
|
3077
|
+
*
|
|
3078
|
+
* @param message The Chat-Completions message to convert.
|
|
3079
|
+
* @returns The equivalent Responses input items (may be empty).
|
|
3080
|
+
*/
|
|
3081
|
+
function chatMessageToResponsesInput(message) {
|
|
3082
|
+
switch (message.role) {
|
|
3083
|
+
case 'system':
|
|
3084
|
+
return [{ role: 'system', content: coerceMessageText(message.content) }];
|
|
3085
|
+
case 'developer':
|
|
3086
|
+
return [{ role: 'developer', content: coerceMessageText(message.content) }];
|
|
3087
|
+
case 'user':
|
|
3088
|
+
return [{ role: 'user', content: chatContentToResponsesContent(message.content) }];
|
|
3089
|
+
case 'assistant': {
|
|
3090
|
+
const items = [];
|
|
3091
|
+
const text = coerceMessageText(message.content);
|
|
3092
|
+
if (text.length > 0) {
|
|
3093
|
+
items.push({ role: 'assistant', content: text });
|
|
3094
|
+
}
|
|
3095
|
+
if (message.tool_calls) {
|
|
3096
|
+
for (const toolCall of message.tool_calls) {
|
|
3097
|
+
if (toolCall.type === 'function') {
|
|
3098
|
+
items.push({
|
|
3099
|
+
type: 'function_call',
|
|
3100
|
+
call_id: toolCall.id,
|
|
3101
|
+
name: toolCall.function.name,
|
|
3102
|
+
arguments: toolCall.function.arguments,
|
|
3103
|
+
});
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
return items;
|
|
3108
|
+
}
|
|
3109
|
+
case 'tool':
|
|
3110
|
+
return [{
|
|
3111
|
+
type: 'function_call_output',
|
|
3112
|
+
call_id: message.tool_call_id,
|
|
3113
|
+
output: coerceMessageText(message.content),
|
|
3114
|
+
}];
|
|
3115
|
+
default:
|
|
3116
|
+
// Deprecated `function`-role messages carry no call_id to correlate; keep
|
|
3117
|
+
// the text so history stays coherent. No current caller emits these.
|
|
3118
|
+
return [{ role: 'assistant', content: coerceMessageText(message.content) }];
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
/**
|
|
3122
|
+
* Converts a Chat-Completions function tool (`{ type:'function', function:{…} }`)
|
|
3123
|
+
* into a Responses API function tool (`{ type:'function', name, parameters,
|
|
3124
|
+
* strict, description }`). `strict` defaults to `false` to preserve Chat
|
|
3125
|
+
* Completions' effective default (non-strict) — the Responses API otherwise
|
|
3126
|
+
* defaults function tools to strict, which would silently change model
|
|
3127
|
+
* behaviour and could reject payloads the Chat path accepted.
|
|
3128
|
+
*
|
|
3129
|
+
* @param tool The Chat-Completions function tool.
|
|
3130
|
+
* @returns The equivalent Responses API function tool.
|
|
3131
|
+
*/
|
|
3132
|
+
function chatToolToResponsesFunctionTool(tool) {
|
|
3133
|
+
return {
|
|
3134
|
+
type: 'function',
|
|
3135
|
+
name: tool.function.name,
|
|
3136
|
+
description: tool.function.description,
|
|
3137
|
+
parameters: tool.function.parameters ?? {},
|
|
3138
|
+
strict: tool.function.strict ?? false,
|
|
3139
|
+
};
|
|
3140
|
+
}
|
|
3141
|
+
/**
|
|
3142
|
+
* Maps an {@link OpenAIResponseFormat} onto the Responses API `text.format`
|
|
3143
|
+
* config, applying the same model-capability gates as the Chat path
|
|
3144
|
+
* ({@link getResponseFormatOption}): `'text'` yields `undefined` (omit
|
|
3145
|
+
* `text.format`), `'json'` yields `json_object` only when the model supports
|
|
3146
|
+
* JSON mode, and a `json_schema` request yields the flat Responses
|
|
3147
|
+
* `json_schema` format (name/schema at the top level, unlike Chat's nested
|
|
3148
|
+
* `json_schema` wrapper).
|
|
3149
|
+
*
|
|
3150
|
+
* @param responseFormat The requested response format.
|
|
3151
|
+
* @param normalizedModel The normalized model name.
|
|
3152
|
+
* @returns The `text.format` config, or `undefined` when none should be sent.
|
|
3153
|
+
* @throws Error when a `json_schema` format is requested for an incompatible model.
|
|
3154
|
+
*/
|
|
3155
|
+
function getResponsesTextFormat(responseFormat, normalizedModel) {
|
|
3156
|
+
if (responseFormat === 'text') {
|
|
3157
|
+
return undefined;
|
|
3158
|
+
}
|
|
3159
|
+
if (responseFormat === 'json') {
|
|
3160
|
+
return supportsJsonMode(normalizedModel) ? { type: 'json_object' } : undefined;
|
|
3161
|
+
}
|
|
3162
|
+
if (typeof responseFormat === 'object' && responseFormat.type === 'json_schema') {
|
|
3163
|
+
if (!isStructuredOutputCompatibleModel(normalizedModel)) {
|
|
3164
|
+
throw new Error(`${normalizedModel} is not compatible with structured outputs / json object.`);
|
|
3165
|
+
}
|
|
3166
|
+
return {
|
|
3167
|
+
type: 'json_schema',
|
|
3168
|
+
name: 'Response',
|
|
3169
|
+
schema: {
|
|
3170
|
+
type: 'object',
|
|
3171
|
+
properties: responseFormat.schema.properties,
|
|
3172
|
+
required: responseFormat.schema.required || [],
|
|
3173
|
+
},
|
|
3174
|
+
};
|
|
3175
|
+
}
|
|
3176
|
+
throw new Error(`Invalid response format: ${String(responseFormat)}`);
|
|
3177
|
+
}
|
|
3178
|
+
/**
|
|
3179
|
+
* Builds an OpenAI Responses API request body from the exact same arguments a
|
|
3180
|
+
* caller passes to {@link makeOpenAIChatCompletionCall}. This is the request
|
|
3181
|
+
* half of the transparent routing layer.
|
|
3182
|
+
*
|
|
3183
|
+
* The mapping deliberately mirrors {@link createCompletion}'s Chat request
|
|
3184
|
+
* one-for-one so request semantics are preserved across transports:
|
|
3185
|
+
* - `developerPrompt` (+ context messages + user `content`) → `input` items
|
|
3186
|
+
* (chat `tool_calls`/`tool` messages become `function_call`/
|
|
3187
|
+
* `function_call_output` items).
|
|
3188
|
+
* - chat `tools` → Responses `tools` (function tools only).
|
|
3189
|
+
* - `temperature` → `temperature`, gated by {@link supportsTemperature} exactly
|
|
3190
|
+
* as the Chat path (dropped for GPT-5.6/o-series reasoning models).
|
|
3191
|
+
* - `max_completion_tokens` → `max_output_tokens`.
|
|
3192
|
+
* - {@link OpenAIResponseFormat} → `text.format`.
|
|
3193
|
+
* - `reasoning_effort` → `reasoning.effort`, clamped per-model via
|
|
3194
|
+
* {@link clampReasoningEffort} and gated on {@link isReasoningModel} exactly as
|
|
3195
|
+
* the Chat path, so the two transports clamp identically. Only set when the
|
|
3196
|
+
* caller explicitly supplies it — parity is preserved for callers (like the
|
|
3197
|
+
* engine decision path) that do not.
|
|
3198
|
+
*
|
|
3199
|
+
* Parameters the Chat path does not forward (`top_p`, `parallel_tool_calls`,
|
|
3200
|
+
* `tool_choice`, `metadata`, `store`) are intentionally omitted here too, so the
|
|
3201
|
+
* request semantics stay identical to today's production Chat behaviour.
|
|
3202
|
+
*
|
|
3203
|
+
* @param content The user content (string or multi-modal content parts).
|
|
3204
|
+
* @param responseFormat The desired response format.
|
|
3205
|
+
* @param options The Chat-Completions-style options bag.
|
|
3206
|
+
* @param normalizedModel The normalized model name to target.
|
|
3207
|
+
* @returns A ready-to-send non-streaming Responses API request body.
|
|
3208
|
+
* @throws Error when a `json_schema` format is requested for an incompatible model.
|
|
3209
|
+
*/
|
|
3210
|
+
function buildResponsesRequestFromChatOptions(content, responseFormat, options, normalizedModel) {
|
|
3211
|
+
const input = [];
|
|
3212
|
+
if (options.developerPrompt && supportsDeveloperPrompt(normalizedModel)) {
|
|
3213
|
+
input.push({ role: 'developer', content: options.developerPrompt });
|
|
3214
|
+
}
|
|
3215
|
+
if (options.context) {
|
|
3216
|
+
for (const message of options.context) {
|
|
3217
|
+
input.push(...chatMessageToResponsesInput(message));
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
input.push({ role: 'user', content: chatContentToResponsesContent(content) });
|
|
3221
|
+
const requestBody = {
|
|
3222
|
+
model: normalizedModel,
|
|
3223
|
+
input,
|
|
3224
|
+
};
|
|
3225
|
+
if (options.tools && options.tools.length > 0) {
|
|
3226
|
+
const functionTools = options.tools
|
|
3227
|
+
.filter((tool) => tool.type === 'function')
|
|
3228
|
+
.map(chatToolToResponsesFunctionTool);
|
|
3229
|
+
if (functionTools.length > 0) {
|
|
3230
|
+
requestBody.tools = functionTools;
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
if (options.temperature !== undefined && supportsTemperature(normalizedModel)) {
|
|
3234
|
+
requestBody.temperature = options.temperature;
|
|
3235
|
+
}
|
|
3236
|
+
if (options.max_completion_tokens !== undefined) {
|
|
3237
|
+
requestBody.max_output_tokens = options.max_completion_tokens;
|
|
3238
|
+
}
|
|
3239
|
+
const textFormat = getResponsesTextFormat(responseFormat, normalizedModel);
|
|
3240
|
+
if (textFormat) {
|
|
3241
|
+
requestBody.text = { format: textFormat };
|
|
3242
|
+
}
|
|
3243
|
+
if (options.reasoning_effort !== undefined && isReasoningModel(normalizedModel)) {
|
|
3244
|
+
const effort = clampReasoningEffort(options.reasoning_effort, normalizedModel);
|
|
3245
|
+
if (effort !== undefined) {
|
|
3246
|
+
requestBody.reasoning = { effort };
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
return requestBody;
|
|
3250
|
+
}
|
|
3251
|
+
/**
|
|
3252
|
+
* Normalizes an OpenAI Responses API result into the internal
|
|
3253
|
+
* {@link CompletionResponse} shape. This is the response half of the
|
|
3254
|
+
* transparent routing layer and is the single most correctness-critical mapping
|
|
3255
|
+
* in this module: the returned `tool_calls` MUST be byte-identical to what the
|
|
3256
|
+
* Chat path produces so downstream consumers (notably the engine decision path,
|
|
3257
|
+
* which reads `tool_call.function.arguments` as a JSON string) parse it
|
|
3258
|
+
* unchanged.
|
|
3259
|
+
*
|
|
3260
|
+
* Mapping:
|
|
3261
|
+
* - `function_call` output items → `{ id: call_id, type:'function',
|
|
3262
|
+
* function:{ name, arguments } }` with `arguments` kept as the raw JSON
|
|
3263
|
+
* string (never pre-parsed) — exactly the Chat `ChatCompletionMessageToolCall`
|
|
3264
|
+
* shape. `id` is sourced from `call_id` (not the item `id`) so it round-trips
|
|
3265
|
+
* as the `tool_call_id` in a multi-turn conversation.
|
|
3266
|
+
* - `message` output items → concatenated `output_text` parts (refusals and
|
|
3267
|
+
* non-text parts contribute nothing, matching the Chat path's null-content →
|
|
3268
|
+
* empty-string behaviour).
|
|
3269
|
+
* - usage: `input_tokens`→prompt, `output_tokens`→completion,
|
|
3270
|
+
* `input_tokens_details.cached_tokens`→cached,
|
|
3271
|
+
* `output_tokens_details.reasoning_tokens`→reasoning.
|
|
3272
|
+
*
|
|
3273
|
+
* `system_fingerprint` is `undefined` — the Responses API does not return one
|
|
3274
|
+
* (the Chat path forwards it; consumers already treat it as optional).
|
|
3275
|
+
*
|
|
3276
|
+
* @param response The raw OpenAI Responses API result.
|
|
3277
|
+
* @param normalizedModel The normalized model name the request targeted.
|
|
3278
|
+
* @param serviceTier The caller's requested service tier, echoed through as on
|
|
3279
|
+
* the Chat path.
|
|
3280
|
+
* @returns A {@link CompletionResponse} structurally identical to the Chat path's.
|
|
3281
|
+
*/
|
|
3282
|
+
function normalizeResponsesToCompletion(response, normalizedModel, serviceTier) {
|
|
3283
|
+
const toolCalls = response.output
|
|
3284
|
+
?.filter((item) => item.type === 'function_call')
|
|
3285
|
+
.map((toolCall) => ({
|
|
3286
|
+
id: toolCall.call_id,
|
|
3287
|
+
type: 'function',
|
|
3288
|
+
function: {
|
|
3289
|
+
name: toolCall.name,
|
|
3290
|
+
arguments: toolCall.arguments,
|
|
3291
|
+
},
|
|
3292
|
+
}));
|
|
3293
|
+
const content = response.output
|
|
3294
|
+
?.filter((item) => item.type === 'message')
|
|
3295
|
+
.map((item) => item.content
|
|
3296
|
+
.filter((part) => part.type === 'output_text')
|
|
3297
|
+
.map((part) => part.text)
|
|
3298
|
+
.join(''))
|
|
3299
|
+
.join('') || '';
|
|
3300
|
+
return {
|
|
3301
|
+
id: response.id,
|
|
3302
|
+
content,
|
|
3303
|
+
tool_calls: toolCalls && toolCalls.length > 0 ? toolCalls : undefined,
|
|
3304
|
+
usage: {
|
|
3305
|
+
prompt_tokens: response.usage?.input_tokens ?? 0,
|
|
3306
|
+
completion_tokens: response.usage?.output_tokens ?? 0,
|
|
3307
|
+
total_tokens: response.usage?.total_tokens ?? 0,
|
|
3308
|
+
cached_tokens: response.usage?.input_tokens_details?.cached_tokens ?? 0,
|
|
3309
|
+
reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens ?? 0,
|
|
3310
|
+
},
|
|
3311
|
+
system_fingerprint: undefined,
|
|
3312
|
+
service_tier: serviceTier,
|
|
3313
|
+
provider: 'openai',
|
|
3314
|
+
model: normalizedModel,
|
|
3315
|
+
};
|
|
3316
|
+
}
|
|
3317
|
+
/**
|
|
3318
|
+
* Executes an OpenAI Responses API call for a Chat-Completions-style request and
|
|
3319
|
+
* returns the internal {@link CompletionResponse}. Mirrors {@link createCompletion}'s
|
|
3320
|
+
* transport concerns exactly — API-key resolution, timeout, `AbortSignal`
|
|
3321
|
+
* plumbing, the shared retry policy, and metadata-only failure logging — so the
|
|
3322
|
+
* two producers differ ONLY in the endpoint they hit.
|
|
3323
|
+
*
|
|
3324
|
+
* @param content The user content (string or multi-modal content parts).
|
|
3325
|
+
* @param responseFormat The desired response format.
|
|
3326
|
+
* @param options The Chat-Completions-style options bag.
|
|
3327
|
+
* @returns The normalized completion, identical in shape to the Chat path.
|
|
3328
|
+
* @throws Error when the API key is missing or the API call ultimately fails.
|
|
3329
|
+
*/
|
|
3330
|
+
async function createResponsesCompletion(content, responseFormat, options = DEFAULT_OPTIONS$1) {
|
|
3331
|
+
const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);
|
|
3332
|
+
const apiKey = options.apiKey || getSecrets().openai.apiKey;
|
|
3333
|
+
if (!apiKey) {
|
|
3334
|
+
throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
|
|
3335
|
+
}
|
|
3336
|
+
const openai = new OpenAI({
|
|
3337
|
+
apiKey: apiKey,
|
|
3338
|
+
timeout: options.timeout ?? LLM_TIMEOUT_MS,
|
|
3339
|
+
});
|
|
3340
|
+
const requestBody = buildResponsesRequestFromChatOptions(content, responseFormat, options, normalizedModel);
|
|
3341
|
+
let response;
|
|
3342
|
+
try {
|
|
3343
|
+
response = await withRetry(
|
|
3344
|
+
// Same AbortSignal plumbing as the Chat path — a fired signal tears down
|
|
3345
|
+
// the in-flight Responses request and releases its body buffer.
|
|
3346
|
+
() => openai.responses.create(requestBody, options.signal ? { signal: options.signal } : undefined), {
|
|
3347
|
+
maxRetries: 3,
|
|
3348
|
+
baseDelayMs: 2000,
|
|
3349
|
+
maxDelayMs: 30000,
|
|
3350
|
+
retryableErrors: isRetryableLLMError,
|
|
3351
|
+
signal: options.signal,
|
|
3352
|
+
}, `OpenAI-Responses:${normalizedModel}`);
|
|
3353
|
+
}
|
|
3354
|
+
catch (error) {
|
|
3355
|
+
// Metadata-only failure snapshot (no message content, no API key), matching
|
|
3356
|
+
// the Chat path's defensive observability.
|
|
3357
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3358
|
+
getLumicLogger().error(`OpenAI Responses call failed for model ${normalizedModel}`, {
|
|
3359
|
+
model: normalizedModel,
|
|
3360
|
+
errorMessage,
|
|
3361
|
+
inputItemCount: Array.isArray(requestBody.input) ? requestBody.input.length : 1,
|
|
3362
|
+
toolCount: requestBody.tools?.length ?? 0,
|
|
3363
|
+
hasTemperature: requestBody.temperature !== undefined && requestBody.temperature !== null,
|
|
3364
|
+
hasTextFormat: requestBody.text?.format !== undefined,
|
|
3365
|
+
hasMaxOutputTokens: requestBody.max_output_tokens !== undefined && requestBody.max_output_tokens !== null,
|
|
3366
|
+
hasReasoningEffort: requestBody.reasoning?.effort !== undefined && requestBody.reasoning?.effort !== null,
|
|
3367
|
+
});
|
|
3368
|
+
throw error;
|
|
3369
|
+
}
|
|
3370
|
+
return normalizeResponsesToCompletion(response, normalizedModel, options.service_tier);
|
|
3371
|
+
}
|
|
2815
3372
|
/**
|
|
2816
3373
|
* Makes a call to the Lumic LLM interface, either to the default model or to one specified.
|
|
2817
3374
|
*
|
|
3375
|
+
* Transport is chosen transparently: models flagged
|
|
3376
|
+
* {@link ModelCapabilities.requiresResponsesApiForTools} (the GPT-5.6 reasoning
|
|
3377
|
+
* trio) that are called WITH function tools are routed to the OpenAI Responses
|
|
3378
|
+
* API; every other call stays on Chat Completions. The returned
|
|
3379
|
+
* {@link LLMResponse} envelope — `response`, `tool_calls`, and `usage` — is
|
|
3380
|
+
* byte-identical across both transports, so callers require no changes.
|
|
3381
|
+
*
|
|
2818
3382
|
* @param content The content to pass to the LLM.
|
|
2819
3383
|
* @param responseFormat The format of the response. Defaults to 'text'.
|
|
2820
3384
|
* @param options The options for the LLM call. Defaults to an empty object.
|
|
@@ -2825,11 +3389,28 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
|
|
|
2825
3389
|
...DEFAULT_OPTIONS$1,
|
|
2826
3390
|
...options,
|
|
2827
3391
|
};
|
|
2828
|
-
|
|
3392
|
+
// Transparent transport routing. GPT-5.6 reasoning models 400 on
|
|
3393
|
+
// Chat-Completions + function tools, so route tool-bearing calls for such
|
|
3394
|
+
// models to the Responses API. `createResponsesCompletion` returns the SAME
|
|
3395
|
+
// CompletionResponse shape, so all cost-tracking and envelope construction
|
|
3396
|
+
// below is shared and the caller-facing result is identical.
|
|
3397
|
+
const normalizedModel = normalizeModelName(mergedOptions.model || DEFAULT_MODEL);
|
|
3398
|
+
const hasTools = !!(mergedOptions.tools && mergedOptions.tools.length > 0);
|
|
3399
|
+
const completion = requiresResponsesApiForTools(normalizedModel) && hasTools
|
|
3400
|
+
? await createResponsesCompletion(content, responseFormat, mergedOptions)
|
|
3401
|
+
: await createCompletion(content, responseFormat, mergedOptions);
|
|
2829
3402
|
// Track cost in the global cost tracker. Pass cached tokens through so the
|
|
2830
3403
|
// tracker applies the discounted cached-input rate (typically ~50% of the
|
|
2831
3404
|
// standard input rate) instead of billing every input token at full price.
|
|
2832
|
-
|
|
3405
|
+
// reasoning_tokens is 0 on the Chat path and the real count on the Responses
|
|
3406
|
+
// path, so reasoning-heavy models are billed accurately.
|
|
3407
|
+
getLLMCostTracker().trackUsage('openai', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, completion.usage.reasoning_tokens, completion.usage.cached_tokens);
|
|
3408
|
+
// Reasoning tokens are a SUBSET of completion (output) tokens. `calculateCost`
|
|
3409
|
+
// bills output AND reasoning at the output rate, so passing the full
|
|
3410
|
+
// completion_tokens alongside reasoning_tokens would bill reasoning twice.
|
|
3411
|
+
// Cost the non-reasoning remainder here and let calculateCost add reasoning
|
|
3412
|
+
// back once; the reported usage below keeps the full completion_tokens.
|
|
3413
|
+
const nonReasoningOutputTokens = completion.usage.completion_tokens - completion.usage.reasoning_tokens;
|
|
2833
3414
|
// Handle tool calls differently
|
|
2834
3415
|
if (completion.tool_calls && completion.tool_calls.length > 0) {
|
|
2835
3416
|
const toolCallResponse = {
|
|
@@ -2844,11 +3425,11 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
|
|
|
2844
3425
|
usage: {
|
|
2845
3426
|
prompt_tokens: completion.usage.prompt_tokens,
|
|
2846
3427
|
completion_tokens: completion.usage.completion_tokens,
|
|
2847
|
-
reasoning_tokens:
|
|
3428
|
+
reasoning_tokens: completion.usage.reasoning_tokens,
|
|
2848
3429
|
provider: 'openai',
|
|
2849
3430
|
model: completion.model,
|
|
2850
3431
|
cached_tokens: completion.usage.cached_tokens,
|
|
2851
|
-
cost: calculateCost('openai', completion.model, completion.usage.prompt_tokens, completion.usage.
|
|
3432
|
+
cost: calculateCost('openai', completion.model, completion.usage.prompt_tokens, nonReasoningOutputTokens, completion.usage.reasoning_tokens, completion.usage.cached_tokens),
|
|
2852
3433
|
},
|
|
2853
3434
|
tool_calls: completion.tool_calls,
|
|
2854
3435
|
};
|
|
@@ -2863,11 +3444,11 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
|
|
|
2863
3444
|
usage: {
|
|
2864
3445
|
prompt_tokens: completion.usage.prompt_tokens,
|
|
2865
3446
|
completion_tokens: completion.usage.completion_tokens,
|
|
2866
|
-
reasoning_tokens:
|
|
3447
|
+
reasoning_tokens: completion.usage.reasoning_tokens,
|
|
2867
3448
|
provider: 'openai',
|
|
2868
3449
|
model: completion.model,
|
|
2869
3450
|
cached_tokens: completion.usage.cached_tokens,
|
|
2870
|
-
cost: calculateCost('openai', completion.model, completion.usage.prompt_tokens, completion.usage.
|
|
3451
|
+
cost: calculateCost('openai', completion.model, completion.usage.prompt_tokens, nonReasoningOutputTokens, completion.usage.reasoning_tokens, completion.usage.cached_tokens),
|
|
2871
3452
|
},
|
|
2872
3453
|
tool_calls: completion.tool_calls,
|
|
2873
3454
|
};
|
|
@@ -2926,8 +3507,14 @@ const makeResponsesAPICall = async (input, options = {}) => {
|
|
|
2926
3507
|
// Responses API exposes cached input tokens under `input_tokens_details.cached_tokens`
|
|
2927
3508
|
// (the equivalent of Chat Completions' `prompt_tokens_details.cached_tokens`).
|
|
2928
3509
|
const responsesCachedTokens = response.usage?.input_tokens_details?.cached_tokens || 0;
|
|
3510
|
+
const responsesOutputTokens = response.usage?.output_tokens || 0;
|
|
3511
|
+
const responsesReasoningTokens = response.usage?.output_tokens_details?.reasoning_tokens || 0;
|
|
3512
|
+
// Reasoning tokens are a SUBSET of output tokens; cost the non-reasoning
|
|
3513
|
+
// remainder so calculateCost does not bill reasoning twice (same rationale as
|
|
3514
|
+
// makeOpenAIChatCompletionCall). Reported usage keeps the full output/reasoning counts.
|
|
3515
|
+
const responsesNonReasoningOutputTokens = responsesOutputTokens - responsesReasoningTokens;
|
|
2929
3516
|
// Track cost in the global cost tracker
|
|
2930
|
-
getLLMCostTracker().trackUsage('openai', normalizedModel, response.usage?.input_tokens || 0,
|
|
3517
|
+
getLLMCostTracker().trackUsage('openai', normalizedModel, response.usage?.input_tokens || 0, responsesOutputTokens, responsesReasoningTokens, responsesCachedTokens);
|
|
2931
3518
|
// Extract tool calls from the output
|
|
2932
3519
|
const toolCalls = response.output
|
|
2933
3520
|
?.filter((item) => item.type === 'function_call')
|
|
@@ -2964,12 +3551,12 @@ const makeResponsesAPICall = async (input, options = {}) => {
|
|
|
2964
3551
|
response: toolCallResponse,
|
|
2965
3552
|
usage: {
|
|
2966
3553
|
prompt_tokens: response.usage?.input_tokens || 0,
|
|
2967
|
-
completion_tokens:
|
|
2968
|
-
reasoning_tokens:
|
|
3554
|
+
completion_tokens: responsesOutputTokens,
|
|
3555
|
+
reasoning_tokens: responsesReasoningTokens,
|
|
2969
3556
|
provider: 'openai',
|
|
2970
3557
|
model: normalizedModel,
|
|
2971
3558
|
cached_tokens: responsesCachedTokens,
|
|
2972
|
-
cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0,
|
|
3559
|
+
cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, responsesNonReasoningOutputTokens, responsesReasoningTokens, responsesCachedTokens),
|
|
2973
3560
|
},
|
|
2974
3561
|
tool_calls: toolCalls,
|
|
2975
3562
|
...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),
|
|
@@ -2997,12 +3584,12 @@ const makeResponsesAPICall = async (input, options = {}) => {
|
|
|
2997
3584
|
response: parsedResponse,
|
|
2998
3585
|
usage: {
|
|
2999
3586
|
prompt_tokens: response.usage?.input_tokens || 0,
|
|
3000
|
-
completion_tokens:
|
|
3001
|
-
reasoning_tokens:
|
|
3587
|
+
completion_tokens: responsesOutputTokens,
|
|
3588
|
+
reasoning_tokens: responsesReasoningTokens,
|
|
3002
3589
|
provider: 'openai',
|
|
3003
3590
|
model: normalizedModel,
|
|
3004
3591
|
cached_tokens: responsesCachedTokens,
|
|
3005
|
-
cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0,
|
|
3592
|
+
cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, responsesNonReasoningOutputTokens, responsesReasoningTokens, responsesCachedTokens),
|
|
3006
3593
|
},
|
|
3007
3594
|
tool_calls: toolCalls,
|
|
3008
3595
|
...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),
|
|
@@ -23231,11 +23818,11 @@ let poolConfig = DEFAULT_POOL_CONFIG;
|
|
|
23231
23818
|
async function loadApolloModules() {
|
|
23232
23819
|
if (typeof window === "undefined" || process.env.AWS_EXECUTION_ENV) {
|
|
23233
23820
|
// Server-side (or Lambda): load the CommonJS‑based implementation.
|
|
23234
|
-
return (await Promise.resolve().then(function () { return require('./apollo-client.server-
|
|
23821
|
+
return (await Promise.resolve().then(function () { return require('./apollo-client.server-DoI6FK_-.js'); }));
|
|
23235
23822
|
}
|
|
23236
23823
|
else {
|
|
23237
23824
|
// Client-side: load the ESM‑based implementation.
|
|
23238
|
-
return (await Promise.resolve().then(function () { return require('./apollo-client.client-
|
|
23825
|
+
return (await Promise.resolve().then(function () { return require('./apollo-client.client-C1dwHT2X.js'); }));
|
|
23239
23826
|
}
|
|
23240
23827
|
}
|
|
23241
23828
|
/**
|
|
@@ -80486,11 +81073,93 @@ const tools = [
|
|
|
80486
81073
|
}
|
|
80487
81074
|
}
|
|
80488
81075
|
},
|
|
81076
|
+
{
|
|
81077
|
+
"type": "function",
|
|
81078
|
+
"function": {
|
|
81079
|
+
"name": "requiresResponsesApiForTools",
|
|
81080
|
+
"description": "Checks whether a model must use the OpenAI Responses API (`/v1/responses`) for function-tool calls rather than Chat Completions (`/v1/chat/completions`). Driven entirely by the {@link ModelCapabilities.requiresResponsesApiForTools} flag in the model registry — there are no hardcoded model-name checks here. Unknown models and models without the flag return `false` (stay on Chat Completions).",
|
|
81081
|
+
"parameters": {
|
|
81082
|
+
"type": "object",
|
|
81083
|
+
"properties": {
|
|
81084
|
+
"model": {
|
|
81085
|
+
"type": "string",
|
|
81086
|
+
"description": "The model to check."
|
|
81087
|
+
}
|
|
81088
|
+
},
|
|
81089
|
+
"required": [
|
|
81090
|
+
"model"
|
|
81091
|
+
]
|
|
81092
|
+
}
|
|
81093
|
+
}
|
|
81094
|
+
},
|
|
81095
|
+
{
|
|
81096
|
+
"type": "function",
|
|
81097
|
+
"function": {
|
|
81098
|
+
"name": "buildResponsesRequestFromChatOptions",
|
|
81099
|
+
"description": "Builds an OpenAI Responses API request body from the exact same arguments a caller passes to {@link makeOpenAIChatCompletionCall}. This is the request half of the transparent routing layer. The mapping deliberately mirrors {@link createCompletion}'s Chat request one-for-one so request semantics are preserved across transports: - `developerPrompt` (+ context messages + user `content`) → `input` items (chat `tool_calls`/`tool` messages become `function_call`/ `function_call_output` items). - chat `tools` → Responses `tools` (function tools only). - `temperature` → `temperature`, gated by {@link supportsTemperature} exactly as the Chat path (dropped for GPT-5.6/o-series reasoning models). - `max_completion_tokens` → `max_output_tokens`. - {@link OpenAIResponseFormat} → `text.format`. - `reasoning_effort` → `reasoning.effort`, clamped per-model via {@link clampReasoningEffort} and gated on {@link isReasoningModel} exactly as the Chat path, so the two transports clamp identically. Only set when the caller explicitly supplies it — parity is preserved for callers (like the engine decision path) that do not. Parameters the Chat path does not forward (`top_p`, `parallel_tool_calls`, `tool_choice`, `metadata`, `store`) are intentionally omitted here too, so the request semantics stay identical to today's production Chat behaviour.",
|
|
81100
|
+
"parameters": {
|
|
81101
|
+
"type": "object",
|
|
81102
|
+
"properties": {
|
|
81103
|
+
"content": {
|
|
81104
|
+
"type": "string",
|
|
81105
|
+
"description": "The user content (string or multi-modal content parts)."
|
|
81106
|
+
},
|
|
81107
|
+
"responseFormat": {
|
|
81108
|
+
"type": "string",
|
|
81109
|
+
"description": "The desired response format."
|
|
81110
|
+
},
|
|
81111
|
+
"options": {
|
|
81112
|
+
"type": "string",
|
|
81113
|
+
"description": "The Chat-Completions-style options bag."
|
|
81114
|
+
},
|
|
81115
|
+
"normalizedModel": {
|
|
81116
|
+
"type": "string",
|
|
81117
|
+
"description": "The normalized model name to target."
|
|
81118
|
+
}
|
|
81119
|
+
},
|
|
81120
|
+
"required": [
|
|
81121
|
+
"content",
|
|
81122
|
+
"responseFormat",
|
|
81123
|
+
"options",
|
|
81124
|
+
"normalizedModel"
|
|
81125
|
+
]
|
|
81126
|
+
}
|
|
81127
|
+
}
|
|
81128
|
+
},
|
|
81129
|
+
{
|
|
81130
|
+
"type": "function",
|
|
81131
|
+
"function": {
|
|
81132
|
+
"name": "normalizeResponsesToCompletion",
|
|
81133
|
+
"description": "Normalizes an OpenAI Responses API result into the internal {@link CompletionResponse} shape. This is the response half of the transparent routing layer and is the single most correctness-critical mapping in this module: the returned `tool_calls` MUST be byte-identical to what the Chat path produces so downstream consumers (notably the engine decision path, which reads `tool_call.function.arguments` as a JSON string) parse it unchanged. Mapping: - `function_call` output items → `{ id: call_id, type:'function', function:{ name, arguments } }` with `arguments` kept as the raw JSON string (never pre-parsed) — exactly the Chat `ChatCompletionMessageToolCall` shape. `id` is sourced from `call_id` (not the item `id`) so it round-trips as the `tool_call_id` in a multi-turn conversation. - `message` output items → concatenated `output_text` parts (refusals and non-text parts contribute nothing, matching the Chat path's null-content → empty-string behaviour). - usage: `input_tokens`→prompt, `output_tokens`→completion, `input_tokens_details.cached_tokens`→cached, `output_tokens_details.reasoning_tokens`→reasoning. `system_fingerprint` is `undefined` — the Responses API does not return one (the Chat path forwards it; consumers already treat it as optional).",
|
|
81134
|
+
"parameters": {
|
|
81135
|
+
"type": "object",
|
|
81136
|
+
"properties": {
|
|
81137
|
+
"response": {
|
|
81138
|
+
"type": "string",
|
|
81139
|
+
"description": "The raw OpenAI Responses API result."
|
|
81140
|
+
},
|
|
81141
|
+
"normalizedModel": {
|
|
81142
|
+
"type": "string",
|
|
81143
|
+
"description": "The normalized model name the request targeted."
|
|
81144
|
+
},
|
|
81145
|
+
"serviceTier": {
|
|
81146
|
+
"type": "string",
|
|
81147
|
+
"description": "The caller's requested service tier, echoed through as on the Chat path."
|
|
81148
|
+
}
|
|
81149
|
+
},
|
|
81150
|
+
"required": [
|
|
81151
|
+
"response",
|
|
81152
|
+
"normalizedModel",
|
|
81153
|
+
"serviceTier"
|
|
81154
|
+
]
|
|
81155
|
+
}
|
|
81156
|
+
}
|
|
81157
|
+
},
|
|
80489
81158
|
{
|
|
80490
81159
|
"type": "function",
|
|
80491
81160
|
"function": {
|
|
80492
81161
|
"name": "makeOpenAIChatCompletionCall",
|
|
80493
|
-
"description": "Makes a call to the Lumic LLM interface, either to the default model or to one specified.",
|
|
81162
|
+
"description": "Makes a call to the Lumic LLM interface, either to the default model or to one specified. Transport is chosen transparently: models flagged {@link ModelCapabilities.requiresResponsesApiForTools} (the GPT-5.6 reasoning trio) that are called WITH function tools are routed to the OpenAI Responses API; every other call stays on Chat Completions. The returned {@link LLMResponse} envelope — `response`, `tool_calls`, and `usage` — is byte-identical across both transports, so callers require no changes.",
|
|
80494
81163
|
"parameters": {
|
|
80495
81164
|
"type": "object",
|
|
80496
81165
|
"properties": {
|
|
@@ -81789,9 +82458,11 @@ exports.JsonParseError = JsonParseError;
|
|
|
81789
82458
|
exports.LLMCostTracker = LLMCostTracker;
|
|
81790
82459
|
exports.LLMError = LLMError;
|
|
81791
82460
|
exports.LLM_ADVANCED_PROVIDER = LLM_ADVANCED_PROVIDER;
|
|
82461
|
+
exports.LLM_CRITICAL_PROVIDER = LLM_CRITICAL_PROVIDER;
|
|
81792
82462
|
exports.LLM_DEFAULT_PROVIDER = LLM_DEFAULT_PROVIDER;
|
|
81793
82463
|
exports.LLM_MINI_PROVIDER = LLM_MINI_PROVIDER;
|
|
81794
82464
|
exports.LLM_MODEL_ADVANCED = LLM_MODEL_ADVANCED;
|
|
82465
|
+
exports.LLM_MODEL_CRITICAL = LLM_MODEL_CRITICAL;
|
|
81795
82466
|
exports.LLM_MODEL_MINI = LLM_MODEL_MINI;
|
|
81796
82467
|
exports.LLM_MODEL_NORMAL = LLM_MODEL_NORMAL;
|
|
81797
82468
|
exports.LLM_NORMAL_PROVIDER = LLM_NORMAL_PROVIDER;
|
|
@@ -81946,4 +82617,4 @@ exports.withCorrelationId = withCorrelationId;
|
|
|
81946
82617
|
exports.withMetrics = withMetrics;
|
|
81947
82618
|
exports.withRateLimit = withRateLimit;
|
|
81948
82619
|
exports.withRetry = withRetry;
|
|
81949
|
-
//# sourceMappingURL=index-
|
|
82620
|
+
//# sourceMappingURL=index-CtY-7qjs.js.map
|