melchizedek-agents 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +19 -0
- package/AGENT_SETUP.md +3 -1
- package/CHANGELOG.md +373 -0
- package/DOCUMENTATION.md +193 -21
- package/ONBOARDING.md +378 -0
- package/QUICKSTART.md +15 -2
- package/README.md +26 -3
- package/config/agents/examples/connectors.yaml +82 -0
- package/config/agents/examples/council.yaml +1 -1
- package/config/agents/examples/critic.yaml +8 -8
- package/config/agents/examples/image_production.yaml +4 -3
- package/config/agents/syndicate.schema.json +389 -33
- package/config/agents/syndicateSchema.yaml +18 -6
- package/config/agents/templates/intake_extractor.yaml +3 -2
- package/config/agents/templates/systems_operator.yaml +5 -2
- package/dist/lib/a2a/app.d.ts +12 -0
- package/dist/lib/a2a/app.js +25 -11
- package/dist/lib/a2a/executor.js +14 -6
- package/dist/lib/a2a/oauthSetup.d.ts +16 -0
- package/dist/lib/a2a/oauthSetup.js +77 -8
- package/dist/lib/agentDialect.d.ts +18 -8
- package/dist/lib/agentDialect.js +36 -19
- package/dist/lib/chatgpt/adapter.d.ts +50 -0
- package/dist/lib/chatgpt/adapter.js +107 -0
- package/dist/lib/chatgpt/cli.d.ts +23 -0
- package/dist/lib/chatgpt/cli.js +77 -0
- package/dist/lib/chatgpt/oauth.d.ts +103 -0
- package/dist/lib/chatgpt/oauth.js +448 -0
- package/dist/lib/chatgpt/state.d.ts +98 -0
- package/dist/lib/chatgpt/state.js +145 -0
- package/dist/lib/chatgpt/store.d.ts +24 -0
- package/dist/lib/chatgpt/store.js +94 -0
- package/dist/lib/compile.d.ts +38 -7
- package/dist/lib/compile.js +97 -62
- package/dist/lib/compileNative.d.ts +11 -3
- package/dist/lib/compileNative.js +18 -1
- package/dist/lib/dispatch.js +6 -2
- package/dist/lib/doctor.d.ts +107 -0
- package/dist/lib/doctor.js +217 -7
- package/dist/lib/loadSyndicate.d.ts +15 -0
- package/dist/lib/mcp/server.d.ts +195 -0
- package/dist/lib/mcp/server.js +564 -0
- package/dist/lib/memory/supabaseMemoryService.js +2 -2
- package/dist/lib/models/adapterResolver.js +6 -1
- package/dist/lib/models/capabilities.d.ts +9 -0
- package/dist/lib/models/capabilities.js +24 -0
- package/dist/lib/models/chatCompletionsAdapter.d.ts +11 -3
- package/dist/lib/models/chatCompletionsAdapter.js +19 -5
- package/dist/lib/models/claudeAdapter.js +4 -0
- package/dist/lib/models/contract.d.ts +5 -2
- package/dist/lib/models/gateway.d.ts +3 -2
- package/dist/lib/models/gateway.js +8 -4
- package/dist/lib/models/gatewayAdapter.d.ts +7 -1
- package/dist/lib/models/gatewayAdapter.js +8 -0
- package/dist/lib/models/geminiAdapter.js +8 -2
- package/dist/lib/models/genaiMapping.d.ts +8 -4
- package/dist/lib/models/genaiMapping.js +23 -9
- package/dist/lib/models/gptAdapter.d.ts +4 -2
- package/dist/lib/models/gptAdapter.js +11 -4
- package/dist/lib/models/grokAdapter.d.ts +3 -1
- package/dist/lib/models/grokAdapter.js +11 -3
- package/dist/lib/models/kimiAdapter.d.ts +2 -1
- package/dist/lib/models/kimiAdapter.js +3 -3
- package/dist/lib/models/reasoning.d.ts +30 -2
- package/dist/lib/models/reasoning.js +56 -5
- package/dist/lib/onboarding.d.ts +135 -0
- package/dist/lib/onboarding.js +578 -0
- package/dist/lib/runtime/approvals.d.ts +2 -0
- package/dist/lib/runtime/approvals.js +4 -3
- package/dist/lib/runtime/credentials.d.ts +6 -0
- package/dist/lib/runtime/native/agentLoop.d.ts +5 -2
- package/dist/lib/runtime/native/agentLoop.js +2 -0
- package/dist/lib/runtime/native/checkpoint.d.ts +12 -5
- package/dist/lib/runtime/native/checkpoint.js +13 -19
- package/dist/lib/runtime/native/delegate.d.ts +82 -1
- package/dist/lib/runtime/native/delegate.js +157 -2
- package/dist/lib/runtime/native/interrupts.d.ts +88 -5
- package/dist/lib/runtime/native/interrupts.js +220 -30
- package/dist/lib/runtime/syndicateTurn.d.ts +4 -2
- package/dist/lib/runtime/syndicateTurn.js +324 -77
- package/dist/lib/runtime/turnControl.d.ts +41 -0
- package/dist/lib/session/transcript.d.ts +9 -0
- package/dist/lib/session/transcript.js +20 -1
- package/dist/lib/skills.d.ts +18 -0
- package/dist/lib/skills.js +73 -1
- package/dist/lib/storage/postgres/index.d.ts +6 -1
- package/dist/lib/storage/postgres/index.js +1 -1
- package/dist/lib/storage/postgres/taskQueue.d.ts +7 -3
- package/dist/lib/storage/postgres/taskQueue.js +10 -3
- package/dist/lib/syndicateSchema.d.ts +184 -9
- package/dist/lib/syndicateSchema.js +143 -29
- package/dist/lib/tools/auth.d.ts +13 -1
- package/dist/lib/tools/auth.js +10 -2
- package/dist/lib/tools/credentialHosts.d.ts +88 -0
- package/dist/lib/tools/credentialHosts.js +165 -0
- package/dist/lib/tools/credentialUses.d.ts +98 -0
- package/dist/lib/tools/credentialUses.js +120 -0
- package/dist/lib/tools/generateImageTool.js +2 -1
- package/dist/lib/tools/inspectImageTool.js +1 -1
- package/dist/lib/tools/mcpToolFactory.d.ts +29 -1
- package/dist/lib/tools/mcpToolFactory.js +72 -26
- package/dist/lib/tools/mcpTransports.d.ts +12 -0
- package/dist/lib/tools/mcpTransports.js +11 -0
- package/dist/lib/tools/oauthConsent.d.ts +18 -3
- package/dist/lib/tools/oauthConsent.js +57 -15
- package/dist/lib/tools/oauthDiscovery.d.ts +202 -0
- package/dist/lib/tools/oauthDiscovery.js +616 -0
- package/dist/lib/tools/oauthHosts.d.ts +2 -0
- package/dist/lib/tools/oauthHosts.js +2 -2
- package/dist/lib/tools/oauthTools.d.ts +54 -13
- package/dist/lib/tools/oauthTools.js +106 -23
- package/dist/lib/tools/openapiTools.d.ts +7 -0
- package/dist/lib/tools/openapiTools.js +49 -3
- package/dist/lib/tools/taskTools.d.ts +32 -2
- package/dist/lib/tools/taskTools.js +93 -33
- package/dist/lib/tools/xApiSearchTool.js +2 -2
- package/dist/lib/workflow/turn.d.ts +22 -3
- package/dist/lib/workflow/turn.js +151 -31
- package/dist/lib/workflow.d.ts +10 -7
- package/dist/lib/workflow.js +10 -7
- package/dist/scripts/a2a_server.d.ts +2 -2
- package/dist/scripts/a2a_server.js +19 -2
- package/dist/scripts/assistant_worker.d.ts +2 -0
- package/dist/scripts/assistant_worker.js +24 -5
- package/dist/scripts/doctor.d.ts +4 -2
- package/dist/scripts/doctor.js +6 -4
- package/dist/scripts/mcp_server.d.ts +12 -0
- package/dist/scripts/mcp_server.js +345 -0
- package/dist/scripts/setup.d.ts +25 -0
- package/dist/scripts/setup.js +181 -0
- package/dist/scripts/skills_install.d.ts +3 -1
- package/dist/scripts/skills_install.js +17 -2
- package/dist/scripts/syndicate_chat.js +12 -3
- package/dist/scripts/yaml_codemod.d.ts +12 -2
- package/dist/scripts/yaml_codemod.js +115 -33
- package/package.json +8 -2
- package/skills/README.md +11 -2
- package/skills/briefs/_shared.md +1 -1
- package/skills/briefs/melchizedek-models.md +4 -2
- package/skills/briefs/skills-readme.md +3 -1
- package/skills/melchizedek-models/SKILL.md +6 -2
- package/skills/melchizedek-onboard/SKILL.md +71 -0
- package/skills/melchizedek-onboard-cloud/SKILL.md +38 -0
- package/skills/melchizedek-onboard-keys/SKILL.md +47 -0
- package/skills/melchizedek-onboard-local/SKILL.md +41 -0
- package/skills/melchizedek-onboard-serve/SKILL.md +43 -0
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
* ADR 0053): llm.transport, llm.finish_reason, llm.http_status,
|
|
55
55
|
* llm.retries, llm.retry_without_thinking, and the search and drop marks.
|
|
56
56
|
*/
|
|
57
|
-
import type { ModelAdapter, ModelRequest, ModelResponse, ReasoningSetting, ToolChoiceMode, Usage } from './contract.ts';
|
|
57
|
+
import type { ModelAdapter, ModelRequest, ModelResponse, ReasoningLevel, ReasoningSetting, ToolChoiceMode, Usage } from './contract.ts';
|
|
58
58
|
type ChatContentPart = {
|
|
59
59
|
type: 'text';
|
|
60
60
|
text: string;
|
|
@@ -190,10 +190,18 @@ export declare abstract class ChatCompletionsAdapter implements ModelAdapter {
|
|
|
190
190
|
/**
|
|
191
191
|
* The body fields for the request's reasoning. Default: `reasoning_effort`
|
|
192
192
|
* as the effort word ADR 0047 gives this model (lib/models/reasoning.ts),
|
|
193
|
-
* the field every chat-completions provider and gateway reads
|
|
194
|
-
* when the request sets no reasoning.
|
|
193
|
+
* the field every chat-completions provider and gateway reads, held at
|
|
194
|
+
* `reasoningCeiling(model)`; nothing when the request sets no reasoning.
|
|
195
195
|
*/
|
|
196
196
|
protected reasoningFields(model: string, setting: ReasoningSetting | undefined): Record<string, unknown>;
|
|
197
|
+
/**
|
|
198
|
+
* The highest reasoning level this adapter sends as asked for `model`
|
|
199
|
+
* (ADR 0117). Default: the direct provider's (lib/models/reasoning.ts
|
|
200
|
+
* effortCeiling); the gateway holds every id at `high`.
|
|
201
|
+
*/
|
|
202
|
+
protected reasoningCeiling(model: string): ReasoningLevel;
|
|
203
|
+
/** The effort word for one setting, held at reasoningCeiling; a held level is marked on the span (`llm.reasoning.weakened`). */
|
|
204
|
+
protected effortFor(model: string, setting: ReasoningSetting): string;
|
|
197
205
|
/** Provider-specific body fields, merged last. */
|
|
198
206
|
protected extraBodyFields(_request: ModelRequest): Record<string, unknown>;
|
|
199
207
|
/**
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
*/
|
|
57
57
|
import { errorDecision, errorText, statusDecision } from './errorResponse.js';
|
|
58
58
|
import { currentTurnStart, providerStateOf } from './providerState.js';
|
|
59
|
-
import {
|
|
59
|
+
import { effortCeiling as effortCeilingOf, effortWord } from './reasoning.js';
|
|
60
60
|
import { fetchWithRetry } from './retry.js';
|
|
61
61
|
import { toStrictJsonSchema } from './schemaNormalize.js';
|
|
62
62
|
import { setLlmSpanAttribute } from '../observability/tracer.js';
|
|
@@ -327,12 +327,26 @@ export class ChatCompletionsAdapter {
|
|
|
327
327
|
/**
|
|
328
328
|
* The body fields for the request's reasoning. Default: `reasoning_effort`
|
|
329
329
|
* as the effort word ADR 0047 gives this model (lib/models/reasoning.ts),
|
|
330
|
-
* the field every chat-completions provider and gateway reads
|
|
331
|
-
* when the request sets no reasoning.
|
|
330
|
+
* the field every chat-completions provider and gateway reads, held at
|
|
331
|
+
* `reasoningCeiling(model)`; nothing when the request sets no reasoning.
|
|
332
332
|
*/
|
|
333
333
|
reasoningFields(model, setting) {
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
return setting !== undefined ? { reasoning_effort: this.effortFor(model, setting) } : {};
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* The highest reasoning level this adapter sends as asked for `model`
|
|
338
|
+
* (ADR 0117). Default: the direct provider's (lib/models/reasoning.ts
|
|
339
|
+
* effortCeiling); the gateway holds every id at `high`.
|
|
340
|
+
*/
|
|
341
|
+
reasoningCeiling(model) {
|
|
342
|
+
return effortCeilingOf(model);
|
|
343
|
+
}
|
|
344
|
+
/** The effort word for one setting, held at reasoningCeiling; a held level is marked on the span (`llm.reasoning.weakened`). */
|
|
345
|
+
effortFor(model, setting) {
|
|
346
|
+
const { word, weakened } = effortWord(model, setting, this.reasoningCeiling(model));
|
|
347
|
+
if (weakened)
|
|
348
|
+
setLlmSpanAttribute('llm.reasoning.weakened', weakened);
|
|
349
|
+
return word;
|
|
336
350
|
}
|
|
337
351
|
/** Provider-specific body fields, merged last. */
|
|
338
352
|
extraBodyFields(_request) {
|
|
@@ -46,6 +46,7 @@ import { claudeClientSpec, endpointFromEnv, endpointLabel, instantiateClient, na
|
|
|
46
46
|
import { currentTurnStart, providerStateOf, withProviderState } from './providerState.js';
|
|
47
47
|
import { errorDecision, errorText } from './errorResponse.js';
|
|
48
48
|
import { adaptiveThinkingFor, claudeGeneration, claudeReasoningOf, claudeUrlImagesOn, THINKING_BINDING_BETA } from './claudeModels.js';
|
|
49
|
+
import { isAboveHigh } from './reasoning.js';
|
|
49
50
|
/** The provider id this adapter reports and writes its state under (lib/models/providerMap.ts). */
|
|
50
51
|
export const ANTHROPIC_PROVIDER = 'anthropic';
|
|
51
52
|
/** The providerState kind this adapter writes: the signed blocks that preceded a part. */
|
|
@@ -393,6 +394,9 @@ export class ClaudeAdapter {
|
|
|
393
394
|
else {
|
|
394
395
|
const requestedBudget = reasoning.budget;
|
|
395
396
|
thinkingConfigured = typeof requestedBudget === 'number' && requestedBudget > 0;
|
|
397
|
+
// The budget generations stop at `high`'s budget (ADR 0117).
|
|
398
|
+
if (isAboveHigh(request.reasoning))
|
|
399
|
+
setLlmSpanAttribute('llm.reasoning.weakened', request.reasoning);
|
|
396
400
|
if (thinkingConfigured && continuesUnsignedToolLoop(messages)) {
|
|
397
401
|
// The tool call this step answers carries no signed thinking (another
|
|
398
402
|
// provider or model made it, or its state was lost), and Anthropic
|
|
@@ -181,9 +181,12 @@ export type ToolChoice = 'auto' | 'none' | 'required' | {
|
|
|
181
181
|
/**
|
|
182
182
|
* How hard an agent reasons, on any provider (ADR 0047): a level, or a token
|
|
183
183
|
* budget. A budget of 0 is `none`, and `none` means as little reasoning as
|
|
184
|
-
* the model allows.
|
|
184
|
+
* the model allows. `xhigh` and `max` are the levels above `high` that some
|
|
185
|
+
* models take (ADR 0117): an adapter whose model stops lower sends its
|
|
186
|
+
* highest setting and marks the span `llm.reasoning.weakened`; a budget
|
|
187
|
+
* never reads as either.
|
|
185
188
|
*/
|
|
186
|
-
export type ReasoningLevel = 'none' | 'low' | 'medium' | 'high';
|
|
189
|
+
export type ReasoningLevel = 'none' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
187
190
|
export type ReasoningSetting = ReasoningLevel | {
|
|
188
191
|
budget_tokens: number;
|
|
189
192
|
};
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* native search. lib/models/capabilities.ts turns that into a per-agent
|
|
25
25
|
* report the doctor, the A2A startup log and the ledger all read.
|
|
26
26
|
*
|
|
27
|
-
* WHY a leaf (imports providerMap and
|
|
27
|
+
* WHY a leaf (imports providerMap, endpoints and lib/chatgpt/state.ts only):
|
|
28
28
|
* The registry, the gateway adapter, the capability report and the
|
|
29
29
|
* doctor all need this decision; keeping it free of adapter imports
|
|
30
30
|
* avoids the cycle model-routing warns about.
|
|
@@ -70,7 +70,8 @@ export interface GatewayConfig {
|
|
|
70
70
|
*/
|
|
71
71
|
export declare function gatewayConfig(): GatewayConfig | null;
|
|
72
72
|
/** A human-readable misconfiguration, or undefined when the gateway is
|
|
73
|
-
* either off or usable.
|
|
73
|
+
* either off or usable. An unrecognised value is named as such and never
|
|
74
|
+
* repeated, since it may be a secret pasted into the wrong variable. */
|
|
74
75
|
export declare function gatewayProblem(): string | undefined;
|
|
75
76
|
/** True when a gateway is configured well enough to serve requests. */
|
|
76
77
|
export declare function gatewayUsable(): boolean;
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* native search. lib/models/capabilities.ts turns that into a per-agent
|
|
25
25
|
* report the doctor, the A2A startup log and the ledger all read.
|
|
26
26
|
*
|
|
27
|
-
* WHY a leaf (imports providerMap and
|
|
27
|
+
* WHY a leaf (imports providerMap, endpoints and lib/chatgpt/state.ts only):
|
|
28
28
|
* The registry, the gateway adapter, the capability report and the
|
|
29
29
|
* doctor all need this decision; keeping it free of adapter imports
|
|
30
30
|
* avoids the cycle model-routing warns about.
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
* MODEL_GATEWAY_MODEL_MAP optional "from=to,from=to" wire-name overrides
|
|
38
38
|
* for ids the default mapper gets wrong
|
|
39
39
|
*/
|
|
40
|
+
import { chatGptSignInRoutesOpenAi } from '../chatgpt/state.js';
|
|
40
41
|
import { providerReady } from './endpoints.js';
|
|
41
42
|
import { PROVIDERS, providerForModel } from './providerMap.js';
|
|
42
43
|
import { trimTrailingSlashes } from './urls.js';
|
|
@@ -81,14 +82,16 @@ export function gatewayConfig() {
|
|
|
81
82
|
};
|
|
82
83
|
}
|
|
83
84
|
/** A human-readable misconfiguration, or undefined when the gateway is
|
|
84
|
-
* either off or usable.
|
|
85
|
+
* either off or usable. An unrecognised value is named as such and never
|
|
86
|
+
* repeated, since it may be a secret pasted into the wrong variable. */
|
|
85
87
|
export function gatewayProblem() {
|
|
86
88
|
const id = (process.env[GATEWAY_ENV] ?? '').trim();
|
|
87
89
|
if (!id)
|
|
88
90
|
return undefined;
|
|
89
91
|
const cfg = gatewayConfig();
|
|
90
92
|
if (!cfg) {
|
|
91
|
-
|
|
93
|
+
// The value is never echoed: a key pasted into the wrong variable is still a secret.
|
|
94
|
+
return `${GATEWAY_ENV} is set to an unrecognised value (not shown); it must be one of: ${Object.keys(GATEWAYS).join(', ')}`;
|
|
92
95
|
}
|
|
93
96
|
if (!cfg.keyPresent)
|
|
94
97
|
return `${GATEWAY_ENV}=${cfg.gateway.id} is set but ${GATEWAY_KEY_ENV} is not`;
|
|
@@ -146,7 +149,8 @@ export function gatewayWireModel(model, gateway) {
|
|
|
146
149
|
export function planTransport(model, opts = {}) {
|
|
147
150
|
const provider = providerForModel(model);
|
|
148
151
|
const keyEnv = PROVIDERS[provider].keyEnv;
|
|
149
|
-
|
|
152
|
+
// A Sign in with ChatGPT credential funds OpenAI directly when no key does (ADR 0126).
|
|
153
|
+
const direct = providerReady(provider) || !!opts.callerKey || (provider === 'openai' && chatGptSignInRoutesOpenAi());
|
|
150
154
|
if (direct || provider === 'ollama') {
|
|
151
155
|
return { provider, transport: 'direct', funded: true, keyEnv };
|
|
152
156
|
}
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* adapter replays no providerState: a chat-completions wire has no place
|
|
29
29
|
* for Claude's signed blocks or OpenAI's reasoning items.
|
|
30
30
|
*/
|
|
31
|
-
import type { ToolChoiceMode } from './contract.ts';
|
|
31
|
+
import type { ReasoningLevel, ToolChoiceMode } from './contract.ts';
|
|
32
32
|
import { ChatCompletionsAdapter } from './chatCompletionsAdapter.ts';
|
|
33
33
|
import type { ChatFailure } from './chatCompletionsAdapter.ts';
|
|
34
34
|
export interface GatewayAdapterOptions {
|
|
@@ -44,6 +44,12 @@ export declare class GatewayAdapter extends ChatCompletionsAdapter {
|
|
|
44
44
|
protected endpointUrl(): string;
|
|
45
45
|
protected headers(): Record<string, string>;
|
|
46
46
|
protected wireModelName(model: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* A gateway reads `reasoning_effort` up to `high` whatever the id: the
|
|
49
|
+
* words above it (`xhigh`, `max`) are not accepted across gateways, so
|
|
50
|
+
* they go as `high`, marked on the span (ADR 0117).
|
|
51
|
+
*/
|
|
52
|
+
protected reasoningCeiling(): ReasoningLevel;
|
|
47
53
|
/** A gateway passes tool_choice to the upstream as asked. */
|
|
48
54
|
protected toolChoiceModes(): readonly ToolChoiceMode[];
|
|
49
55
|
protected missingRequirement(): ChatFailure | undefined;
|
|
@@ -52,6 +52,14 @@ export class GatewayAdapter extends ChatCompletionsAdapter {
|
|
|
52
52
|
wireModelName(model) {
|
|
53
53
|
return this.#cfg ? gatewayWireModel(model, this.#cfg.gateway) : model;
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* A gateway reads `reasoning_effort` up to `high` whatever the id: the
|
|
57
|
+
* words above it (`xhigh`, `max`) are not accepted across gateways, so
|
|
58
|
+
* they go as `high`, marked on the span (ADR 0117).
|
|
59
|
+
*/
|
|
60
|
+
reasoningCeiling() {
|
|
61
|
+
return 'high';
|
|
62
|
+
}
|
|
55
63
|
/** A gateway passes tool_choice to the upstream as asked. */
|
|
56
64
|
toolChoiceModes() {
|
|
57
65
|
return ['auto', 'none', 'required', 'named'];
|
|
@@ -50,7 +50,7 @@ import { endpointFromEnv, endpointProblems, platformModel } from './endpoints.js
|
|
|
50
50
|
import { CARRIED_PARTS_KIND, GEMINI_PROVIDER, GENAI_PART_KIND, MINTED_CALL_ID_PREFIX, PLACEHOLDER_THOUGHT_SIGNATURE, THOUGHT_SIGNATURE_KIND, isCarriedWirePart, } from './geminiState.js';
|
|
51
51
|
import { currentTurnStart, providerStateOf } from './providerState.js';
|
|
52
52
|
import { classifyError, errorStatus, retryUntilFirstYield } from './retry.js';
|
|
53
|
-
import { reasoningConfig } from './reasoning.js';
|
|
53
|
+
import { isAboveHigh, reasoningConfig } from './reasoning.js';
|
|
54
54
|
import { setLlmSpanAttribute } from '../observability/tracer.js';
|
|
55
55
|
/**
|
|
56
56
|
* The provider id this adapter reports and writes its state under, and the
|
|
@@ -445,11 +445,17 @@ function toolConfigFor(request) {
|
|
|
445
445
|
: undefined;
|
|
446
446
|
return mode ? { functionCallingConfig: { mode } } : undefined;
|
|
447
447
|
}
|
|
448
|
-
/**
|
|
448
|
+
/**
|
|
449
|
+
* ADR 0047's mapping for this model, with the thoughts asked for unless the
|
|
450
|
+
* setting is `none`. Gemini's top is `HIGH` (or `high`'s budget on 2.x), so
|
|
451
|
+
* `xhigh` and `max` go as that, marked on the span (ADR 0117).
|
|
452
|
+
*/
|
|
449
453
|
function thinkingConfigFor(model, setting) {
|
|
450
454
|
const mapped = reasoningConfig(model, setting).thinkingConfig;
|
|
451
455
|
if (!mapped)
|
|
452
456
|
return undefined;
|
|
457
|
+
if (isAboveHigh(setting))
|
|
458
|
+
setLlmSpanAttribute('llm.reasoning.weakened', setting);
|
|
453
459
|
const none = setting === 'none' || (typeof setting === 'object' && setting.budget_tokens <= 0);
|
|
454
460
|
return none ? { ...mapped } : { ...mapped, includeThoughts: true };
|
|
455
461
|
}
|
|
@@ -271,11 +271,15 @@ export interface ModelRequestOptions {
|
|
|
271
271
|
* which every adapter maps to what the budget maps to today (0 included).
|
|
272
272
|
* - else `reasoningEffort`: a level word is that level, and `minimal` is
|
|
273
273
|
* `none` (ADR 0047's rendering of it on the first GPT-5 generation).
|
|
274
|
+
* The words above `high` (`xhigh`, `max`) win over a thinkingConfig that
|
|
275
|
+
* says `high` (`HIGH`, or `high`'s budget of 16,384), which is what the
|
|
276
|
+
* compiler writes beside them (ADR 0117); a thinkingConfig that says less
|
|
277
|
+
* keeps its own reading.
|
|
274
278
|
* Lossy, and absent: a budget of -1 (Gemini's dynamic thinking, which is
|
|
275
|
-
* the provider's default), `THINKING_LEVEL_UNSPECIFIED`,
|
|
276
|
-
* `
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
+
* the provider's default), `THINKING_LEVEL_UNSPECIFIED`, and
|
|
280
|
+
* `includeThoughts`. The compiler writes the effort word beside
|
|
281
|
+
* thinkingConfig from one setting, so preferring thinkingConfig loses
|
|
282
|
+
* nothing it wrote; only the older spelling can set the two apart.
|
|
279
283
|
*/
|
|
280
284
|
export declare function reasoningOf(config: GenerateContentConfig | undefined): ReasoningSetting | undefined;
|
|
281
285
|
/** The function-calling mode as a ToolChoice, and VALIDATED as strict tools. The native request builder reads an agent's config through it too. */
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
import { FinishReason, FunctionCallingConfigMode } from '@google/genai';
|
|
153
153
|
import { ERROR_RETRYABLE_KEY, ERROR_STATUS_KEY, errorText, withRetryVerdict } from './errorResponse.js';
|
|
154
154
|
import { CARRIED_PARTS_KIND, GEMINI_PROVIDER, GENAI_PART_KIND, MINTED_CALL_ID_PREFIX, THOUGHT_SIGNATURE_KIND } from './geminiState.js';
|
|
155
|
-
import { reasoningConfig } from './reasoning.js';
|
|
155
|
+
import { REASONING_BUDGETS, reasoningConfig } from './reasoning.js';
|
|
156
156
|
import { contractToolDeclaration, nativeToolOf, toContractJsonSchema } from './schemaNormalize.js';
|
|
157
157
|
import { MAX_VALUE_DEPTH, nestedDeeperThan } from '../runtime/valueDepth.js';
|
|
158
158
|
/**
|
|
@@ -473,7 +473,15 @@ export function messagesToContents(history) {
|
|
|
473
473
|
}
|
|
474
474
|
// Maps, not object literals: a config value such as `constructor` must read as nothing.
|
|
475
475
|
const THINKING_LEVELS = new Map([['MINIMAL', 'none'], ['LOW', 'low'], ['MEDIUM', 'medium'], ['HIGH', 'high']]);
|
|
476
|
-
const EFFORT_LEVELS = new Map([
|
|
476
|
+
const EFFORT_LEVELS = new Map([
|
|
477
|
+
['none', 'none'],
|
|
478
|
+
['minimal', 'none'],
|
|
479
|
+
['low', 'low'],
|
|
480
|
+
['medium', 'medium'],
|
|
481
|
+
['high', 'high'],
|
|
482
|
+
['xhigh', 'xhigh'],
|
|
483
|
+
['max', 'max'],
|
|
484
|
+
]);
|
|
477
485
|
/**
|
|
478
486
|
* The ReasoningSetting a generateContentConfig asks for, where one is exact:
|
|
479
487
|
* - `thinkingConfig.thinkingLevel`: `MINIMAL` is `none` (ADR 0047's
|
|
@@ -482,24 +490,30 @@ const EFFORT_LEVELS = new Map([['none', 'none'], ['minimal', 'none'], ['low', 'l
|
|
|
482
490
|
* which every adapter maps to what the budget maps to today (0 included).
|
|
483
491
|
* - else `reasoningEffort`: a level word is that level, and `minimal` is
|
|
484
492
|
* `none` (ADR 0047's rendering of it on the first GPT-5 generation).
|
|
493
|
+
* The words above `high` (`xhigh`, `max`) win over a thinkingConfig that
|
|
494
|
+
* says `high` (`HIGH`, or `high`'s budget of 16,384), which is what the
|
|
495
|
+
* compiler writes beside them (ADR 0117); a thinkingConfig that says less
|
|
496
|
+
* keeps its own reading.
|
|
485
497
|
* Lossy, and absent: a budget of -1 (Gemini's dynamic thinking, which is
|
|
486
|
-
* the provider's default), `THINKING_LEVEL_UNSPECIFIED`,
|
|
487
|
-
* `
|
|
488
|
-
*
|
|
489
|
-
*
|
|
498
|
+
* the provider's default), `THINKING_LEVEL_UNSPECIFIED`, and
|
|
499
|
+
* `includeThoughts`. The compiler writes the effort word beside
|
|
500
|
+
* thinkingConfig from one setting, so preferring thinkingConfig loses
|
|
501
|
+
* nothing it wrote; only the older spelling can set the two apart.
|
|
490
502
|
*/
|
|
491
503
|
export function reasoningOf(config) {
|
|
492
504
|
const cfg = (config ?? {});
|
|
505
|
+
const word = EFFORT_LEVELS.get(cfg.reasoningEffort);
|
|
506
|
+
const above = word === 'xhigh' || word === 'max' ? word : undefined;
|
|
493
507
|
const thinking = cfg.thinkingConfig;
|
|
494
508
|
if (isObject(thinking)) {
|
|
495
509
|
const level = THINKING_LEVELS.get(thinking.thinkingLevel);
|
|
496
510
|
if (level)
|
|
497
|
-
return level;
|
|
511
|
+
return above && level === 'high' ? above : level;
|
|
498
512
|
const budget = thinking.thinkingBudget;
|
|
499
513
|
if (typeof budget === 'number' && Number.isInteger(budget) && budget >= 0)
|
|
500
|
-
return { budget_tokens: budget };
|
|
514
|
+
return above && budget === REASONING_BUDGETS.high ? above : { budget_tokens: budget };
|
|
501
515
|
}
|
|
502
|
-
return
|
|
516
|
+
return word;
|
|
503
517
|
}
|
|
504
518
|
function nativeToolsOf(llmRequest) {
|
|
505
519
|
const tools = new Set();
|
|
@@ -187,8 +187,10 @@ export declare class GptAdapter implements ModelAdapter {
|
|
|
187
187
|
* The `reasoning` request field for one setting (ADR 0047), or undefined to
|
|
188
188
|
* send none. OpenAI's reasoning ids ask for summaries, plus the effort in
|
|
189
189
|
* that model's own word (`reasoningConfig`: `none` is `minimal` on the
|
|
190
|
-
* first GPT-5 generation and `low` on the o-series)
|
|
191
|
-
*
|
|
190
|
+
* first GPT-5 generation and `low` on the o-series), held at the model's
|
|
191
|
+
* ceiling (`xhigh` from GPT-5.2, else `high`; ADR 0117), a held level
|
|
192
|
+
* marked on the span. Other ids: nothing. A 400 on the field is retried
|
|
193
|
+
* once without it.
|
|
192
194
|
*/
|
|
193
195
|
reasoningParam(setting: ReasoningSetting | undefined, model?: string): Record<string, unknown> | undefined;
|
|
194
196
|
/**
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
import { endpointFromEnv, entraTokenSource, nativeSearchOn, platformModel } from './endpoints.js';
|
|
46
46
|
import { errorDecision, errorText, statusDecision } from './errorResponse.js';
|
|
47
47
|
import { currentTurnStart, providerStateOf } from './providerState.js';
|
|
48
|
-
import {
|
|
48
|
+
import { effortWord } from './reasoning.js';
|
|
49
49
|
import { toContractJsonSchema } from './schemaNormalize.js';
|
|
50
50
|
import { setLlmSpanAttribute } from '../observability/tracer.js';
|
|
51
51
|
/** The providerState kind the Responses adapters write: the reasoning output items that preceded a part (ADR 0046, ADR 0050). */
|
|
@@ -423,13 +423,20 @@ export class GptAdapter {
|
|
|
423
423
|
* The `reasoning` request field for one setting (ADR 0047), or undefined to
|
|
424
424
|
* send none. OpenAI's reasoning ids ask for summaries, plus the effort in
|
|
425
425
|
* that model's own word (`reasoningConfig`: `none` is `minimal` on the
|
|
426
|
-
* first GPT-5 generation and `low` on the o-series)
|
|
427
|
-
*
|
|
426
|
+
* first GPT-5 generation and `low` on the o-series), held at the model's
|
|
427
|
+
* ceiling (`xhigh` from GPT-5.2, else `high`; ADR 0117), a held level
|
|
428
|
+
* marked on the span. Other ids: nothing. A 400 on the field is retried
|
|
429
|
+
* once without it.
|
|
428
430
|
*/
|
|
429
431
|
reasoningParam(setting, model = this.model) {
|
|
430
432
|
if (!isOpenAiReasoningModel(model))
|
|
431
433
|
return undefined;
|
|
432
|
-
|
|
434
|
+
if (setting === undefined)
|
|
435
|
+
return { summary: 'auto' };
|
|
436
|
+
const { word, weakened } = effortWord(model, setting);
|
|
437
|
+
if (weakened)
|
|
438
|
+
setLlmSpanAttribute('llm.reasoning.weakened', weakened);
|
|
439
|
+
return { summary: 'auto', effort: word };
|
|
433
440
|
}
|
|
434
441
|
/**
|
|
435
442
|
* Whether this id carries its reasoning across the steps of a tool loop
|
|
@@ -63,7 +63,9 @@ export declare class GrokAdapter extends GptAdapter {
|
|
|
63
63
|
* `high`; xAI's own default is `high`, and reasoning cannot be turned off).
|
|
64
64
|
* The request's setting maps through ADR 0047's table, which sends `none`
|
|
65
65
|
* as `low`; with none set, DEFAULT_GROK_REASONING_EFFORT (medium) is pinned,
|
|
66
|
-
* since effort is part of the price.
|
|
66
|
+
* since effort is part of the price. grok-4.7 also takes `xhigh`; `max`,
|
|
67
|
+
* and `xhigh` on 4.5 and 4.6, go as the model's highest word, marked on the
|
|
68
|
+
* span (ADR 0117). Other grok ids take no field.
|
|
67
69
|
*/
|
|
68
70
|
reasoningParam(setting: ReasoningSetting | undefined, model?: string): Record<string, unknown> | undefined;
|
|
69
71
|
/**
|
|
@@ -26,8 +26,9 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import { DEFAULT_GROK_REASONING_EFFORT } from '../config.js';
|
|
28
28
|
import { GptAdapter } from './gptAdapter.js';
|
|
29
|
-
import {
|
|
29
|
+
import { effortWord } from './reasoning.js';
|
|
30
30
|
import { collectionIdsFromEnv, collectionsMaxResultsFromEnv, xaiWebSearchParamsFromEnv, xSearchParamsFromEnv, } from '../tools/xaiSearchParams.js';
|
|
31
|
+
import { setLlmSpanAttribute } from '../observability/tracer.js';
|
|
31
32
|
export const XAI_BASE_URL = 'https://api.x.ai/v1';
|
|
32
33
|
/**
|
|
33
34
|
* The ids that take a reasoning effort and return encrypted reasoning:
|
|
@@ -81,12 +82,19 @@ export class GrokAdapter extends GptAdapter {
|
|
|
81
82
|
* `high`; xAI's own default is `high`, and reasoning cannot be turned off).
|
|
82
83
|
* The request's setting maps through ADR 0047's table, which sends `none`
|
|
83
84
|
* as `low`; with none set, DEFAULT_GROK_REASONING_EFFORT (medium) is pinned,
|
|
84
|
-
* since effort is part of the price.
|
|
85
|
+
* since effort is part of the price. grok-4.7 also takes `xhigh`; `max`,
|
|
86
|
+
* and `xhigh` on 4.5 and 4.6, go as the model's highest word, marked on the
|
|
87
|
+
* span (ADR 0117). Other grok ids take no field.
|
|
85
88
|
*/
|
|
86
89
|
reasoningParam(setting, model = this.model) {
|
|
87
90
|
if (!GROK_REASONING_IDS.test(model))
|
|
88
91
|
return undefined;
|
|
89
|
-
|
|
92
|
+
if (setting === undefined)
|
|
93
|
+
return { effort: DEFAULT_GROK_REASONING_EFFORT };
|
|
94
|
+
const { word, weakened } = effortWord(model, setting);
|
|
95
|
+
if (weakened)
|
|
96
|
+
setLlmSpanAttribute('llm.reasoning.weakened', weakened);
|
|
97
|
+
return { effort: word };
|
|
90
98
|
}
|
|
91
99
|
/**
|
|
92
100
|
* grok-4.5, grok-4.6 and grok-4.7 carry their reasoning across a tool loop
|
|
@@ -68,7 +68,8 @@
|
|
|
68
68
|
* goes as its Kimi word (`medium` → `high`, a budget → the level that
|
|
69
69
|
* covers it), `none` as `low` since K3 cannot switch thinking off, and a
|
|
70
70
|
* request with none pins DEFAULT_KIMI_REASONING_EFFORT (lib/config.ts).
|
|
71
|
-
* `max`
|
|
71
|
+
* `reasoning: max` sends `max`, and `xhigh` rounds up to it (ADR 0117):
|
|
72
|
+
* Moonshot's costliest effort, and its default, which the pin avoids.
|
|
72
73
|
* K2.x models take no reasoning_effort: a `thinking: { type }` switch
|
|
73
74
|
* instead, so `none` (or a budget of 0) sends `disabled` and any other
|
|
74
75
|
* setting sends nothing. K2.7 Code (and its highspeed variant) cannot
|
|
@@ -68,7 +68,8 @@
|
|
|
68
68
|
* goes as its Kimi word (`medium` → `high`, a budget → the level that
|
|
69
69
|
* covers it), `none` as `low` since K3 cannot switch thinking off, and a
|
|
70
70
|
* request with none pins DEFAULT_KIMI_REASONING_EFFORT (lib/config.ts).
|
|
71
|
-
* `max`
|
|
71
|
+
* `reasoning: max` sends `max`, and `xhigh` rounds up to it (ADR 0117):
|
|
72
|
+
* Moonshot's costliest effort, and its default, which the pin avoids.
|
|
72
73
|
* K2.x models take no reasoning_effort: a `thinking: { type }` switch
|
|
73
74
|
* instead, so `none` (or a budget of 0) sends `disabled` and any other
|
|
74
75
|
* setting sends nothing. K2.7 Code (and its highspeed variant) cannot
|
|
@@ -118,7 +119,6 @@
|
|
|
118
119
|
*/
|
|
119
120
|
import { DEFAULT_KIMI_REASONING_EFFORT } from '../config.js';
|
|
120
121
|
import { ChatCompletionsAdapter, reasonsNotAtAll } from './chatCompletionsAdapter.js';
|
|
121
|
-
import { reasoningConfig } from './reasoning.js';
|
|
122
122
|
import { trimTrailingSlashes } from './urls.js';
|
|
123
123
|
export const MOONSHOT_BASE_URL = 'https://api.moonshot.ai/v1';
|
|
124
124
|
/** The flagship takes `reasoning_effort`; the K2 generation takes a `thinking` switch. */
|
|
@@ -191,7 +191,7 @@ export class KimiAdapter extends ChatCompletionsAdapter {
|
|
|
191
191
|
if (isKimiK3(model)) {
|
|
192
192
|
if (setting === undefined)
|
|
193
193
|
return { reasoning_effort: DEFAULT_KIMI_REASONING_EFFORT };
|
|
194
|
-
const word =
|
|
194
|
+
const word = this.effortFor(model, setting);
|
|
195
195
|
return { reasoning_effort: word === 'none' ? 'low' : word }; // K3 cannot switch thinking off
|
|
196
196
|
}
|
|
197
197
|
// K2.7 Code always thinks, and Moonshot refuses `disabled` for it.
|
|
@@ -12,15 +12,43 @@ import type { ReasoningLevel, ReasoningSetting } from './contract.ts';
|
|
|
12
12
|
/**
|
|
13
13
|
* Thinking tokens per level, for the providers that take a budget (Claude,
|
|
14
14
|
* Gemini 2.x). The same table rounds a `budget_tokens` value up to a level
|
|
15
|
-
* for the providers that take only a level or an effort word.
|
|
15
|
+
* for the providers that take only a level or an effort word. `xhigh` and
|
|
16
|
+
* `max` take `high`'s budget (ADR 0117): above it a non-streaming Claude
|
|
17
|
+
* request passes the Anthropic SDK's ceiling (ADR 0047), so a budget path
|
|
18
|
+
* sends them as `high`, and a budget never rounds up to either.
|
|
16
19
|
*/
|
|
17
20
|
export declare const REASONING_BUDGETS: Readonly<Record<ReasoningLevel, number>>;
|
|
21
|
+
/** The levels in order of how hard they ask the model to think. */
|
|
22
|
+
export declare const REASONING_ORDER: readonly ReasoningLevel[];
|
|
23
|
+
/** The levels above `high`, which only some models take (ADR 0117). */
|
|
24
|
+
export declare const isAboveHigh: (setting: ReasoningSetting | undefined) => setting is 'xhigh' | 'max';
|
|
25
|
+
/**
|
|
26
|
+
* The highest level the direct adapter for `model` sends as asked (ADR
|
|
27
|
+
* 0117); a level above it goes as this one. `max` where every level
|
|
28
|
+
* passes: Claude's adaptive generations (the Claude adapter sends its budget
|
|
29
|
+
* generations `high`'s budget) and Kimi K3. OpenAI's GPT-5.2 and later and
|
|
30
|
+
* grok-4.7 stop at `xhigh`; other OpenAI and Grok ids, Gemini and Ollama at
|
|
31
|
+
* `high`. A gateway stops at `high` whatever the id (gatewayAdapter.ts).
|
|
32
|
+
*/
|
|
33
|
+
export declare function effortCeiling(model: string): ReasoningLevel;
|
|
34
|
+
/**
|
|
35
|
+
* The effort word an adapter sends for one setting: ADR 0047's word for the
|
|
36
|
+
* model, held at `ceiling` (default effortCeiling(model)). `weakened` is the
|
|
37
|
+
* level asked for when the word sent is below it; the adapter marks the span
|
|
38
|
+
* `llm.reasoning.weakened` with it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function effortWord(model: string, setting: ReasoningSetting, ceiling?: ReasoningLevel): {
|
|
41
|
+
word: string;
|
|
42
|
+
weakened?: ReasoningLevel;
|
|
43
|
+
};
|
|
18
44
|
/**
|
|
19
45
|
* The generateContentConfig fields a `reasoning:` setting becomes for one
|
|
20
46
|
* model (ADR 0047). `reasoningEffort` is always set, so the gateway (which
|
|
21
47
|
* may serve any id) carries the level too; the Claude adapter reads it first
|
|
22
48
|
* on the adaptive generations (ADR 0049), and the genai SDK drops it from a
|
|
23
49
|
* Gemini request. Claude and Gemini also get the `thinkingConfig` their
|
|
24
|
-
* adapters read.
|
|
50
|
+
* adapters read. `xhigh` and `max` are written as asked (Kimi's `xhigh` as
|
|
51
|
+
* `max`), beside `high`'s thinkingConfig: the adapter holds the word at its
|
|
52
|
+
* model's ceiling (effortWord), so the setting reaches it intact (ADR 0117).
|
|
25
53
|
*/
|
|
26
54
|
export declare function reasoningConfig(model: string, setting: ReasoningSetting): Record<string, unknown>;
|
|
@@ -2,10 +2,25 @@ import { providerForModel } from './providerMap.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Thinking tokens per level, for the providers that take a budget (Claude,
|
|
4
4
|
* Gemini 2.x). The same table rounds a `budget_tokens` value up to a level
|
|
5
|
-
* for the providers that take only a level or an effort word.
|
|
5
|
+
* for the providers that take only a level or an effort word. `xhigh` and
|
|
6
|
+
* `max` take `high`'s budget (ADR 0117): above it a non-streaming Claude
|
|
7
|
+
* request passes the Anthropic SDK's ceiling (ADR 0047), so a budget path
|
|
8
|
+
* sends them as `high`, and a budget never rounds up to either.
|
|
6
9
|
*/
|
|
7
|
-
export const REASONING_BUDGETS = { none: 0, low: 2048, medium: 8192, high: 16384 };
|
|
8
|
-
const GEMINI_THINKING_LEVEL = { none: 'MINIMAL', low: 'LOW', medium: 'MEDIUM', high: 'HIGH' };
|
|
10
|
+
export const REASONING_BUDGETS = { none: 0, low: 2048, medium: 8192, high: 16384, xhigh: 16384, max: 16384 };
|
|
11
|
+
const GEMINI_THINKING_LEVEL = { none: 'MINIMAL', low: 'LOW', medium: 'MEDIUM', high: 'HIGH', xhigh: 'HIGH', max: 'HIGH' };
|
|
12
|
+
/** The levels in order of how hard they ask the model to think. */
|
|
13
|
+
export const REASONING_ORDER = ['none', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
14
|
+
/** The levels above `high`, which only some models take (ADR 0117). */
|
|
15
|
+
export const isAboveHigh = (setting) => setting === 'xhigh' || setting === 'max';
|
|
16
|
+
/** An OpenAI id that takes `xhigh`: GPT-5.2 and later (the o-series and GPT-5 and 5.1 stop at `high`). */
|
|
17
|
+
function openAiTakesXhigh(model) {
|
|
18
|
+
const m = /^gpt-(\d{1,3})(?:\.(\d{1,3}))?/.exec(model);
|
|
19
|
+
if (!m)
|
|
20
|
+
return false;
|
|
21
|
+
const major = Number(m[1]);
|
|
22
|
+
return major > 5 || (major === 5 && Number(m[2] ?? 0) >= 2);
|
|
23
|
+
}
|
|
9
24
|
/** The smallest level whose budget covers the setting: never less thought than asked. */
|
|
10
25
|
function reasoningLevel(setting) {
|
|
11
26
|
if (typeof setting === 'string')
|
|
@@ -29,18 +44,54 @@ function reasoningEffort(model, level) {
|
|
|
29
44
|
case 'xai':
|
|
30
45
|
return level === 'none' ? 'low' : level; // Grok 4.5/4.7 cannot stop reasoning
|
|
31
46
|
case 'moonshot':
|
|
32
|
-
|
|
47
|
+
// K3 has low | high | max: a missing word rounds up.
|
|
48
|
+
return level === 'medium' ? 'high' : level === 'xhigh' ? 'max' : level;
|
|
33
49
|
default:
|
|
34
50
|
return level;
|
|
35
51
|
}
|
|
36
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* The highest level the direct adapter for `model` sends as asked (ADR
|
|
55
|
+
* 0117); a level above it goes as this one. `max` where every level
|
|
56
|
+
* passes: Claude's adaptive generations (the Claude adapter sends its budget
|
|
57
|
+
* generations `high`'s budget) and Kimi K3. OpenAI's GPT-5.2 and later and
|
|
58
|
+
* grok-4.7 stop at `xhigh`; other OpenAI and Grok ids, Gemini and Ollama at
|
|
59
|
+
* `high`. A gateway stops at `high` whatever the id (gatewayAdapter.ts).
|
|
60
|
+
*/
|
|
61
|
+
export function effortCeiling(model) {
|
|
62
|
+
switch (providerForModel(model)) {
|
|
63
|
+
case 'anthropic':
|
|
64
|
+
case 'moonshot':
|
|
65
|
+
return 'max';
|
|
66
|
+
case 'openai':
|
|
67
|
+
return openAiTakesXhigh(model) ? 'xhigh' : 'high';
|
|
68
|
+
case 'xai':
|
|
69
|
+
return /^grok-4\.7(?!\d)/.test(model) ? 'xhigh' : 'high';
|
|
70
|
+
default:
|
|
71
|
+
return 'high';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The effort word an adapter sends for one setting: ADR 0047's word for the
|
|
76
|
+
* model, held at `ceiling` (default effortCeiling(model)). `weakened` is the
|
|
77
|
+
* level asked for when the word sent is below it; the adapter marks the span
|
|
78
|
+
* `llm.reasoning.weakened` with it.
|
|
79
|
+
*/
|
|
80
|
+
export function effortWord(model, setting, ceiling = effortCeiling(model)) {
|
|
81
|
+
const word = reasoningConfig(model, setting).reasoningEffort;
|
|
82
|
+
if (!isAboveHigh(setting) || REASONING_ORDER.indexOf(word) <= REASONING_ORDER.indexOf(ceiling))
|
|
83
|
+
return { word };
|
|
84
|
+
return { word: ceiling, weakened: setting };
|
|
85
|
+
}
|
|
37
86
|
/**
|
|
38
87
|
* The generateContentConfig fields a `reasoning:` setting becomes for one
|
|
39
88
|
* model (ADR 0047). `reasoningEffort` is always set, so the gateway (which
|
|
40
89
|
* may serve any id) carries the level too; the Claude adapter reads it first
|
|
41
90
|
* on the adaptive generations (ADR 0049), and the genai SDK drops it from a
|
|
42
91
|
* Gemini request. Claude and Gemini also get the `thinkingConfig` their
|
|
43
|
-
* adapters read.
|
|
92
|
+
* adapters read. `xhigh` and `max` are written as asked (Kimi's `xhigh` as
|
|
93
|
+
* `max`), beside `high`'s thinkingConfig: the adapter holds the word at its
|
|
94
|
+
* model's ceiling (effortWord), so the setting reaches it intact (ADR 0117).
|
|
44
95
|
*/
|
|
45
96
|
export function reasoningConfig(model, setting) {
|
|
46
97
|
const level = reasoningLevel(setting);
|