melchizedek-agents 1.0.0 → 1.0.2
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/CHANGELOG.md +53 -0
- package/DOCUMENTATION.md +11 -9
- package/config/agents/examples/critic.yaml +12 -7
- package/config/agents/examples/image_production.yaml +2 -2
- package/config/agents/examples/librarian.yaml +1 -1
- package/config/agents/examples/pipeline.yaml +1 -1
- package/config/agents/examples/research.yaml +3 -2
- package/config/agents/examples/scribe.yaml +5 -4
- package/config/agents/examples/weather.yaml +2 -1
- package/config/agents/syndicateSchema.yaml +18 -15
- package/dist/lib/dispatch.d.ts +4 -4
- package/dist/lib/dispatch.js +4 -4
- package/dist/lib/syndicateSchema.js +6 -6
- package/package.json +2 -2
- package/skills/briefs/melchizedek-author.md +1 -1
- package/skills/melchizedek-author/SKILL.md +1 -1
- package/skills/melchizedek-author/assets/minimal.yaml +1 -1
- package/dist/lib/adkPeer.d.ts +0 -63
- package/dist/lib/adkPeer.js +0 -240
- package/dist/lib/compileAdk.d.ts +0 -32
- package/dist/lib/compileAdk.js +0 -142
- package/dist/lib/models/adkGeminiAdapter.d.ts +0 -90
- package/dist/lib/models/adkGeminiAdapter.js +0 -369
- package/dist/lib/models/adkShim.d.ts +0 -111
- package/dist/lib/models/adkShim.js +0 -136
- package/dist/lib/models/claudeLlm.d.ts +0 -79
- package/dist/lib/models/claudeLlm.js +0 -87
- package/dist/lib/models/fallback.d.ts +0 -48
- package/dist/lib/models/fallback.js +0 -116
- package/dist/lib/models/gatewayLlm.d.ts +0 -36
- package/dist/lib/models/gatewayLlm.js +0 -44
- package/dist/lib/models/gptLlm.d.ts +0 -99
- package/dist/lib/models/gptLlm.js +0 -129
- package/dist/lib/models/grokLlm.d.ts +0 -50
- package/dist/lib/models/grokLlm.js +0 -56
- package/dist/lib/models/kimiLlm.d.ts +0 -31
- package/dist/lib/models/kimiLlm.js +0 -35
- package/dist/lib/models/ollamaLlm.d.ts +0 -37
- package/dist/lib/models/ollamaLlm.js +0 -42
- package/dist/lib/models/openAiCompatibleLlm.d.ts +0 -96
- package/dist/lib/models/openAiCompatibleLlm.js +0 -156
- package/dist/lib/models/tracedGemini.d.ts +0 -41
- package/dist/lib/models/tracedGemini.js +0 -98
- package/dist/lib/runtime/adkMemoryBridge.d.ts +0 -46
- package/dist/lib/runtime/adkMemoryBridge.js +0 -68
- package/dist/lib/runtime/adkSessionBridge.d.ts +0 -78
- package/dist/lib/runtime/adkSessionBridge.js +0 -176
- package/dist/lib/tools/adkTool.d.ts +0 -81
- package/dist/lib/tools/adkTool.js +0 -268
- package/dist/lib/tools/collectionsSearchTool.d.ts +0 -56
- package/dist/lib/tools/collectionsSearchTool.js +0 -71
- package/dist/lib/tools/urlContextTool.d.ts +0 -32
- package/dist/lib/tools/urlContextTool.js +0 -43
- package/dist/lib/tools/webSearchTool.d.ts +0 -51
- package/dist/lib/tools/webSearchTool.js +0 -82
- package/dist/lib/tools/xSearchTool.d.ts +0 -59
- package/dist/lib/tools/xSearchTool.js +0 -74
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/grokLlm.ts — xAI Grok for ADK's LLMRegistry: GptLlm (the ADK
|
|
3
|
-
* shim around a Responses adapter) built on GrokAdapter
|
|
4
|
-
* (lib/models/grokAdapter.ts).
|
|
5
|
-
*
|
|
6
|
-
* WHY this file exists:
|
|
7
|
-
* Model optionality is a primary driver of this framework: the agent YAML
|
|
8
|
-
* declares `model`, and the registry routes it to the right provider.
|
|
9
|
-
* xAI's Agent Tools API is wire-compatible with OpenAI's Responses API, so
|
|
10
|
-
* GrokAdapter extends GptAdapter and overrides only the vendor hooks
|
|
11
|
-
* (endpoint, key, timeout, reasoning effort, native tools), and GrokLlm
|
|
12
|
-
* extends GptLlm, which keeps the ADK path's usage meaning and
|
|
13
|
-
* server-side tool record (ADR 0056). Grok gets:
|
|
14
|
-
* - native web_search (server-side, with source citations)
|
|
15
|
-
* - x_search (live X posts) and collections_search (hosted document
|
|
16
|
-
* stores via the file_search wire shape — see collectionsSearchTool.ts)
|
|
17
|
-
* - reasoning summaries surfaced as { thought: true } THINKING output
|
|
18
|
-
* - reasoning carried across a tool loop on grok-4.5, 4.6 and 4.7
|
|
19
|
-
* (encrypted reasoning items as providerState, store: false — ADR 0050)
|
|
20
|
-
* - SSE streaming (ADK RunConfig streamingMode: SSE → partial deltas)
|
|
21
|
-
* - structured outputs (YAML outputSchema → text.format json_schema)
|
|
22
|
-
* - function tools with call_id round-tripping, lowercase schemas
|
|
23
|
-
*
|
|
24
|
-
* HOW TO ENABLE:
|
|
25
|
-
* 1. Add your API key to .env as XAI_API_KEY (console.x.ai — paid).
|
|
26
|
-
* 2. Set model: "grok-4.7" (or any grok-* id) in your YAML.
|
|
27
|
-
* registerAvailableProviders() registers this adapter when the key is set.
|
|
28
|
-
* grok-4.5, 4.6 and 4.7 requests carry reasoning effort 'medium' unless the
|
|
29
|
-
* agent sets `reasoning:` — DEFAULT_GROK_REASONING_EFFORT (lib/config.ts).
|
|
30
|
-
*
|
|
31
|
-
* API-DRIFT NOTE: every xAI-specific choice is confined to GrokAdapter's
|
|
32
|
-
* overrides, so upstream drift stays a one-file fix. xAI's Responses endpoint
|
|
33
|
-
* reports the serving backend in the response `model` field (e.g.
|
|
34
|
-
* "grok-4.3"), which may differ from the requested id; invalid ids are
|
|
35
|
-
* rejected with "Model not found".
|
|
36
|
-
*/
|
|
37
|
-
import { GptLlm } from './gptLlm.ts';
|
|
38
|
-
import type { GptLlmOptions } from './gptLlm.ts';
|
|
39
|
-
import { GrokAdapter } from './grokAdapter.ts';
|
|
40
|
-
export { DEFAULT_GROK_TIMEOUT_MS, grokTimeoutMs } from './grokAdapter.ts';
|
|
41
|
-
export declare class GrokLlm extends GptLlm {
|
|
42
|
-
/** Any model: "grok-*" in a YAML config routes here after registration. */
|
|
43
|
-
static readonly supportedModels: Array<string | RegExp>;
|
|
44
|
-
protected static createAdapter(options: GptLlmOptions): GrokAdapter;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Registers GrokLlm with the ADK LLMRegistry. Called by
|
|
48
|
-
* registerAvailableProviders() when XAI_API_KEY is present.
|
|
49
|
-
*/
|
|
50
|
-
export declare function registerGrokLlm(): void;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/grokLlm.ts — xAI Grok for ADK's LLMRegistry: GptLlm (the ADK
|
|
3
|
-
* shim around a Responses adapter) built on GrokAdapter
|
|
4
|
-
* (lib/models/grokAdapter.ts).
|
|
5
|
-
*
|
|
6
|
-
* WHY this file exists:
|
|
7
|
-
* Model optionality is a primary driver of this framework: the agent YAML
|
|
8
|
-
* declares `model`, and the registry routes it to the right provider.
|
|
9
|
-
* xAI's Agent Tools API is wire-compatible with OpenAI's Responses API, so
|
|
10
|
-
* GrokAdapter extends GptAdapter and overrides only the vendor hooks
|
|
11
|
-
* (endpoint, key, timeout, reasoning effort, native tools), and GrokLlm
|
|
12
|
-
* extends GptLlm, which keeps the ADK path's usage meaning and
|
|
13
|
-
* server-side tool record (ADR 0056). Grok gets:
|
|
14
|
-
* - native web_search (server-side, with source citations)
|
|
15
|
-
* - x_search (live X posts) and collections_search (hosted document
|
|
16
|
-
* stores via the file_search wire shape — see collectionsSearchTool.ts)
|
|
17
|
-
* - reasoning summaries surfaced as { thought: true } THINKING output
|
|
18
|
-
* - reasoning carried across a tool loop on grok-4.5, 4.6 and 4.7
|
|
19
|
-
* (encrypted reasoning items as providerState, store: false — ADR 0050)
|
|
20
|
-
* - SSE streaming (ADK RunConfig streamingMode: SSE → partial deltas)
|
|
21
|
-
* - structured outputs (YAML outputSchema → text.format json_schema)
|
|
22
|
-
* - function tools with call_id round-tripping, lowercase schemas
|
|
23
|
-
*
|
|
24
|
-
* HOW TO ENABLE:
|
|
25
|
-
* 1. Add your API key to .env as XAI_API_KEY (console.x.ai — paid).
|
|
26
|
-
* 2. Set model: "grok-4.7" (or any grok-* id) in your YAML.
|
|
27
|
-
* registerAvailableProviders() registers this adapter when the key is set.
|
|
28
|
-
* grok-4.5, 4.6 and 4.7 requests carry reasoning effort 'medium' unless the
|
|
29
|
-
* agent sets `reasoning:` — DEFAULT_GROK_REASONING_EFFORT (lib/config.ts).
|
|
30
|
-
*
|
|
31
|
-
* API-DRIFT NOTE: every xAI-specific choice is confined to GrokAdapter's
|
|
32
|
-
* overrides, so upstream drift stays a one-file fix. xAI's Responses endpoint
|
|
33
|
-
* reports the serving backend in the response `model` field (e.g.
|
|
34
|
-
* "grok-4.3"), which may differ from the requested id; invalid ids are
|
|
35
|
-
* rejected with "Model not found".
|
|
36
|
-
*/
|
|
37
|
-
import { requireAdk } from '../adkPeer.js';
|
|
38
|
-
import { GptLlm } from './gptLlm.js';
|
|
39
|
-
import { GrokAdapter } from './grokAdapter.js';
|
|
40
|
-
export { DEFAULT_GROK_TIMEOUT_MS, grokTimeoutMs } from './grokAdapter.js';
|
|
41
|
-
// ── GrokLlm ───────────────────────────────────────────────────────────────────
|
|
42
|
-
export class GrokLlm extends GptLlm {
|
|
43
|
-
/** Any model: "grok-*" in a YAML config routes here after registration. */
|
|
44
|
-
static supportedModels = [/^grok-.+/];
|
|
45
|
-
static createAdapter(options) {
|
|
46
|
-
return new GrokAdapter(options);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// ── Registration helper ───────────────────────────────────────────────────────
|
|
50
|
-
/**
|
|
51
|
-
* Registers GrokLlm with the ADK LLMRegistry. Called by
|
|
52
|
-
* registerAvailableProviders() when XAI_API_KEY is present.
|
|
53
|
-
*/
|
|
54
|
-
export function registerGrokLlm() {
|
|
55
|
-
requireAdk("Registering a model class with ADK's LLMRegistry").LLMRegistry.register(GrokLlm);
|
|
56
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/kimiLlm.ts — Moonshot AI (Kimi), as an ADK BaseLlm for the
|
|
3
|
-
* LLMRegistry.
|
|
4
|
-
*
|
|
5
|
-
* WHY this file exists:
|
|
6
|
-
* The provider's work is KimiAdapter (lib/models/kimiAdapter.ts), on the
|
|
7
|
-
* engine's own model contract; its header covers the family, cost, the
|
|
8
|
-
* reasoning controls per generation, and reasoning_content on tool loops
|
|
9
|
-
* (ADR 0046). ADK still runs every turn, so this class runs the adapter
|
|
10
|
-
* under ADK: it is the chat-completions shim
|
|
11
|
-
* (lib/models/openAiCompatibleLlm.ts, ADR 0057), registered for any
|
|
12
|
-
* `kimi-*` id when MOONSHOT_API_KEY is set. The constructor and
|
|
13
|
-
* supportedModels are what they were before the adapter moved onto the
|
|
14
|
-
* contract, so lib/models/registry.ts and every caller are unchanged. On
|
|
15
|
-
* this path an agent's older spelling `reasoningEffort: max` still reaches
|
|
16
|
-
* K3, which the contract has no level for.
|
|
17
|
-
*/
|
|
18
|
-
import { OpenAiCompatibleLlm } from './openAiCompatibleLlm.ts';
|
|
19
|
-
export { MOONSHOT_BASE_URL, isKimiK3, wantsReasoningReplay } from './kimiAdapter.ts';
|
|
20
|
-
export declare class KimiLlm extends OpenAiCompatibleLlm {
|
|
21
|
-
/** Any model: "kimi-*" in a YAML config routes here after registration. */
|
|
22
|
-
static readonly supportedModels: Array<string | RegExp>;
|
|
23
|
-
/** `apiKey` defaults to MOONSHOT_API_KEY; `baseUrl` to MOONSHOT_BASE_URL, else https://api.moonshot.ai/v1. */
|
|
24
|
-
constructor({ model, apiKey, baseUrl }: {
|
|
25
|
-
model: string;
|
|
26
|
-
apiKey?: string;
|
|
27
|
-
baseUrl?: string;
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
/** Registers KimiLlm with the ADK LLMRegistry (called when MOONSHOT_API_KEY is set). */
|
|
31
|
-
export declare function registerKimiLlm(): void;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/kimiLlm.ts — Moonshot AI (Kimi), as an ADK BaseLlm for the
|
|
3
|
-
* LLMRegistry.
|
|
4
|
-
*
|
|
5
|
-
* WHY this file exists:
|
|
6
|
-
* The provider's work is KimiAdapter (lib/models/kimiAdapter.ts), on the
|
|
7
|
-
* engine's own model contract; its header covers the family, cost, the
|
|
8
|
-
* reasoning controls per generation, and reasoning_content on tool loops
|
|
9
|
-
* (ADR 0046). ADK still runs every turn, so this class runs the adapter
|
|
10
|
-
* under ADK: it is the chat-completions shim
|
|
11
|
-
* (lib/models/openAiCompatibleLlm.ts, ADR 0057), registered for any
|
|
12
|
-
* `kimi-*` id when MOONSHOT_API_KEY is set. The constructor and
|
|
13
|
-
* supportedModels are what they were before the adapter moved onto the
|
|
14
|
-
* contract, so lib/models/registry.ts and every caller are unchanged. On
|
|
15
|
-
* this path an agent's older spelling `reasoningEffort: max` still reaches
|
|
16
|
-
* K3, which the contract has no level for.
|
|
17
|
-
*/
|
|
18
|
-
import { requireAdk } from '../adkPeer.js';
|
|
19
|
-
import { KimiAdapter } from './kimiAdapter.js';
|
|
20
|
-
import { OpenAiCompatibleLlm } from './openAiCompatibleLlm.js';
|
|
21
|
-
export { MOONSHOT_BASE_URL, isKimiK3, wantsReasoningReplay } from './kimiAdapter.js';
|
|
22
|
-
// ── KimiLlm ───────────────────────────────────────────────────────────────────
|
|
23
|
-
export class KimiLlm extends OpenAiCompatibleLlm {
|
|
24
|
-
/** Any model: "kimi-*" in a YAML config routes here after registration. */
|
|
25
|
-
static supportedModels = [/^kimi-.+/];
|
|
26
|
-
/** `apiKey` defaults to MOONSHOT_API_KEY; `baseUrl` to MOONSHOT_BASE_URL, else https://api.moonshot.ai/v1. */
|
|
27
|
-
constructor({ model, apiKey, baseUrl }) {
|
|
28
|
-
super(new KimiAdapter({ model, apiKey, baseUrl }), { model });
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
// ── Registration helper ───────────────────────────────────────────────────────
|
|
32
|
-
/** Registers KimiLlm with the ADK LLMRegistry (called when MOONSHOT_API_KEY is set). */
|
|
33
|
-
export function registerKimiLlm() {
|
|
34
|
-
requireAdk("Registering a model class with ADK's LLMRegistry").LLMRegistry.register(KimiLlm);
|
|
35
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/ollamaLlm.ts — open-weight / local models served by Ollama, as
|
|
3
|
-
* an ADK BaseLlm for the LLMRegistry.
|
|
4
|
-
*
|
|
5
|
-
* WHY this file exists:
|
|
6
|
-
* The provider's work is OllamaAdapter (lib/models/ollamaAdapter.ts), on
|
|
7
|
-
* the engine's own model contract; its header says how to install Ollama,
|
|
8
|
-
* which model to pull, and what a local model cannot do. ADK still runs
|
|
9
|
-
* every turn, so this class runs the adapter under ADK: it is the
|
|
10
|
-
* chat-completions shim (lib/models/openAiCompatibleLlm.ts, ADR 0057),
|
|
11
|
-
* registered for any `ollama/<model>` id. The constructor and
|
|
12
|
-
* supportedModels are what they were before the adapter moved onto the
|
|
13
|
-
* contract, so lib/models/registry.ts and every caller are unchanged.
|
|
14
|
-
*/
|
|
15
|
-
import { OpenAiCompatibleLlm } from './openAiCompatibleLlm.ts';
|
|
16
|
-
export declare class OllamaLlm extends OpenAiCompatibleLlm {
|
|
17
|
-
/**
|
|
18
|
-
* Model ids namespaced "ollama/<model>" route here after registration,
|
|
19
|
-
* e.g. model: "ollama/qwen3:8b" in a syndicate YAML.
|
|
20
|
-
*/
|
|
21
|
-
static readonly supportedModels: Array<string | RegExp>;
|
|
22
|
-
/** `baseUrl` defaults to OLLAMA_BASE_URL, else http://localhost:11434/v1. */
|
|
23
|
-
constructor({ model, baseUrl }: {
|
|
24
|
-
model: string;
|
|
25
|
-
baseUrl?: string;
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Registers OllamaLlm with the ADK LLMRegistry.
|
|
30
|
-
*
|
|
31
|
-
* Unlike registerClaudeLlm(), this needs no key gate — a local provider has
|
|
32
|
-
* no credential to check. Registration is still explicit (not at import
|
|
33
|
-
* time) so entrypoints stay in control of which providers are active.
|
|
34
|
-
* If Ollama isn't running, agents fail at call time with a clear
|
|
35
|
-
* OLLAMA_UNREACHABLE message that says how to start it.
|
|
36
|
-
*/
|
|
37
|
-
export declare function registerOllamaLlm(): void;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/ollamaLlm.ts — open-weight / local models served by Ollama, as
|
|
3
|
-
* an ADK BaseLlm for the LLMRegistry.
|
|
4
|
-
*
|
|
5
|
-
* WHY this file exists:
|
|
6
|
-
* The provider's work is OllamaAdapter (lib/models/ollamaAdapter.ts), on
|
|
7
|
-
* the engine's own model contract; its header says how to install Ollama,
|
|
8
|
-
* which model to pull, and what a local model cannot do. ADK still runs
|
|
9
|
-
* every turn, so this class runs the adapter under ADK: it is the
|
|
10
|
-
* chat-completions shim (lib/models/openAiCompatibleLlm.ts, ADR 0057),
|
|
11
|
-
* registered for any `ollama/<model>` id. The constructor and
|
|
12
|
-
* supportedModels are what they were before the adapter moved onto the
|
|
13
|
-
* contract, so lib/models/registry.ts and every caller are unchanged.
|
|
14
|
-
*/
|
|
15
|
-
import { requireAdk } from '../adkPeer.js';
|
|
16
|
-
import { OllamaAdapter } from './ollamaAdapter.js';
|
|
17
|
-
import { OpenAiCompatibleLlm } from './openAiCompatibleLlm.js';
|
|
18
|
-
// ── OllamaLlm ─────────────────────────────────────────────────────────────────
|
|
19
|
-
export class OllamaLlm extends OpenAiCompatibleLlm {
|
|
20
|
-
/**
|
|
21
|
-
* Model ids namespaced "ollama/<model>" route here after registration,
|
|
22
|
-
* e.g. model: "ollama/qwen3:8b" in a syndicate YAML.
|
|
23
|
-
*/
|
|
24
|
-
static supportedModels = [/^ollama\/.+/];
|
|
25
|
-
/** `baseUrl` defaults to OLLAMA_BASE_URL, else http://localhost:11434/v1. */
|
|
26
|
-
constructor({ model, baseUrl }) {
|
|
27
|
-
super(new OllamaAdapter({ model, baseUrl }), { model });
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// ── Registration helper ───────────────────────────────────────────────────────
|
|
31
|
-
/**
|
|
32
|
-
* Registers OllamaLlm with the ADK LLMRegistry.
|
|
33
|
-
*
|
|
34
|
-
* Unlike registerClaudeLlm(), this needs no key gate — a local provider has
|
|
35
|
-
* no credential to check. Registration is still explicit (not at import
|
|
36
|
-
* time) so entrypoints stay in control of which providers are active.
|
|
37
|
-
* If Ollama isn't running, agents fail at call time with a clear
|
|
38
|
-
* OLLAMA_UNREACHABLE message that says how to start it.
|
|
39
|
-
*/
|
|
40
|
-
export function registerOllamaLlm() {
|
|
41
|
-
requireAdk("Registering a model class with ADK's LLMRegistry").LLMRegistry.register(OllamaLlm);
|
|
42
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/openAiCompatibleLlm.ts — the ADK shim base for every
|
|
3
|
-
* chat-completions adapter (Ollama, Kimi, the gateway).
|
|
4
|
-
*
|
|
5
|
-
* WHY this file exists:
|
|
6
|
-
* The chat-completions translation lives on the engine's own model
|
|
7
|
-
* contract, in lib/models/chatCompletionsAdapter.ts and one adapter per
|
|
8
|
-
* provider (ollamaAdapter.ts, kimiAdapter.ts, gatewayAdapter.ts). ADK
|
|
9
|
-
* still runs every turn (ADR 0045), so each adapter runs behind an ADK
|
|
10
|
-
* BaseLlm: OllamaLlm, KimiLlm and GatewayLlm, subclasses of this class,
|
|
11
|
-
* which is an AdkShim (lib/models/adkShim.ts, ADR 0053). The shim charges
|
|
12
|
-
* the turn, opens the llm.request span and maps the request and responses;
|
|
13
|
-
* the adapter does the provider's work.
|
|
14
|
-
*
|
|
15
|
-
* WHAT THIS CLASS ADDS TO THE SHIM (ADR 0057): the ADK path stays what it
|
|
16
|
-
* was before the adapters moved onto the contract.
|
|
17
|
-
* - The request: an agent's older generateContentConfig spelling that the
|
|
18
|
-
* contract leaves out rides beside it (olderSpellingOf): an effort word
|
|
19
|
-
* that is no contract level (Kimi K3's `max`). JSON mode without a
|
|
20
|
-
* schema is the contract's `outputFormat` (ADR 0061).
|
|
21
|
-
* - The response: the final keeps the shape these classes always yielded,
|
|
22
|
-
* which the ledger and FallbackLlm read. usageMetadata counts the
|
|
23
|
-
* reasoning inside candidatesTokenCount, as the provider's
|
|
24
|
-
* completion_tokens does, so llm.tokens.output and the turn's charge are
|
|
25
|
-
* unchanged (the shim's default is Gemini's meaning, which excludes it).
|
|
26
|
-
* finishReason is set only for a reply cut short (MAX_TOKENS); a final
|
|
27
|
-
* with no parts keeps its empty content; an HTTP failure keeps its
|
|
28
|
-
* top-level `status` and `retryable` beside the verdict in
|
|
29
|
-
* customMetadata.
|
|
30
|
-
*
|
|
31
|
-
* A /chat/completions provider of your own is a ChatCompletionsAdapter
|
|
32
|
-
* subclass (the endpoint, headers, wire name, reasoning field and error
|
|
33
|
-
* wording), run under ADK as `adkShim(adapter)` or as a subclass of this
|
|
34
|
-
* class.
|
|
35
|
-
*/
|
|
36
|
-
import type { GenerateContentConfig } from '@google/genai';
|
|
37
|
-
import type { LlmRequest, LlmResponse } from '@google/adk';
|
|
38
|
-
import { AdkShim } from './adkShim.ts';
|
|
39
|
-
import type { AdkShimOptions } from './adkShim.ts';
|
|
40
|
-
import type { ModelResponse, Usage } from './contract.ts';
|
|
41
|
-
import type { ModelRequestOptions } from './genaiMapping.ts';
|
|
42
|
-
import type { ChatCompletionsAdapter, ChatCompletionsRequest, ChatMessage, OlderSpelling } from './chatCompletionsAdapter.ts';
|
|
43
|
-
export { REASONING_CONTENT_KIND, splitThinkBlocks, ThinkStreamSplitter } from './chatCompletionsAdapter.ts';
|
|
44
|
-
/**
|
|
45
|
-
* What a generateContentConfig asks of a chat-completions provider that the
|
|
46
|
-
* contract has no field for, or undefined when it asks nothing more:
|
|
47
|
-
* `reasoningEffort` when it is a word no ReasoningSetting carries (`max`,
|
|
48
|
-
* `xhigh`), sent as written. JSON mode without a schema is no longer here:
|
|
49
|
-
* the genai mapping reads it as `outputFormat: 'json'` (ADR 0061).
|
|
50
|
-
*/
|
|
51
|
-
export declare function olderSpellingOf(config: GenerateContentConfig | undefined): OlderSpelling | undefined;
|
|
52
|
-
/**
|
|
53
|
-
* Usage as the chat-completions classes have always reported it on the ADK
|
|
54
|
-
* path: candidatesTokenCount is the provider's completion_tokens, reasoning
|
|
55
|
-
* included, and thoughtsTokenCount the reasoning part of it.
|
|
56
|
-
*/
|
|
57
|
-
export declare function chatUsageMetadata(usage: Usage): NonNullable<LlmResponse['usageMetadata']>;
|
|
58
|
-
export declare abstract class OpenAiCompatibleLlm extends AdkShim {
|
|
59
|
-
readonly adapter: ChatCompletionsAdapter;
|
|
60
|
-
constructor(adapter: ChatCompletionsAdapter, options?: AdkShimOptions);
|
|
61
|
-
/** Provider id for telemetry: the adapter's (a gateway reports the upstream provider). */
|
|
62
|
-
protected providerId(): string;
|
|
63
|
-
/** How the request reaches the provider: 'direct' or 'gateway:<id>' (llm.transport). */
|
|
64
|
-
protected transport(): string;
|
|
65
|
-
/** The chat messages the adapter sends for this LlmRequest. */
|
|
66
|
-
protected buildMessages(llmRequest: LlmRequest): ChatMessage[];
|
|
67
|
-
/** The function tools the adapter sends for this LlmRequest (lowercase schemas). */
|
|
68
|
-
protected buildTools(llmRequest: LlmRequest): unknown[];
|
|
69
|
-
/** The genai mapping's request, with the older spelling the contract leaves out. */
|
|
70
|
-
protected toModelRequest(llmRequest: LlmRequest, options: ModelRequestOptions): ChatCompletionsRequest;
|
|
71
|
-
/** The genai mapping's response, in the shape these classes have always yielded (see the header). */
|
|
72
|
-
protected toLlmResponse(response: ModelResponse): LlmResponse;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Stamps an HTTP error response with its numeric status and whether that
|
|
76
|
-
* status is transient, and the same verdict in customMetadata
|
|
77
|
-
* ('error.retryable', 'error.status'), where FallbackLlm reads it
|
|
78
|
-
* (lib/models/errorResponse.ts). The chat-completions shims take these
|
|
79
|
-
* fields from their adapter's error final instead (toLlmResponse).
|
|
80
|
-
*/
|
|
81
|
-
export declare function withHttpStatus(resp: LlmResponse, status: number): LlmResponse;
|
|
82
|
-
type GenaiUsage = NonNullable<ReturnType<typeof mapUsage>>;
|
|
83
|
-
/** Two genai usage records summed, field by field. */
|
|
84
|
-
export declare function addUsage(a: GenaiUsage | undefined, b: GenaiUsage | undefined): GenaiUsage | undefined;
|
|
85
|
-
/**
|
|
86
|
-
* OpenAI-style usage → GenAI usageMetadata in the ADK-path meaning
|
|
87
|
-
* (completion_tokens, reasoning included, as candidatesTokenCount), or
|
|
88
|
-
* undefined when absent. The contract's meaning is chatUsage in
|
|
89
|
-
* lib/models/chatCompletionsAdapter.ts.
|
|
90
|
-
*/
|
|
91
|
-
export declare function mapUsage(usage: any): {
|
|
92
|
-
promptTokenCount?: number;
|
|
93
|
-
candidatesTokenCount?: number;
|
|
94
|
-
thoughtsTokenCount?: number;
|
|
95
|
-
totalTokenCount?: number;
|
|
96
|
-
} | undefined;
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/openAiCompatibleLlm.ts — the ADK shim base for every
|
|
3
|
-
* chat-completions adapter (Ollama, Kimi, the gateway).
|
|
4
|
-
*
|
|
5
|
-
* WHY this file exists:
|
|
6
|
-
* The chat-completions translation lives on the engine's own model
|
|
7
|
-
* contract, in lib/models/chatCompletionsAdapter.ts and one adapter per
|
|
8
|
-
* provider (ollamaAdapter.ts, kimiAdapter.ts, gatewayAdapter.ts). ADK
|
|
9
|
-
* still runs every turn (ADR 0045), so each adapter runs behind an ADK
|
|
10
|
-
* BaseLlm: OllamaLlm, KimiLlm and GatewayLlm, subclasses of this class,
|
|
11
|
-
* which is an AdkShim (lib/models/adkShim.ts, ADR 0053). The shim charges
|
|
12
|
-
* the turn, opens the llm.request span and maps the request and responses;
|
|
13
|
-
* the adapter does the provider's work.
|
|
14
|
-
*
|
|
15
|
-
* WHAT THIS CLASS ADDS TO THE SHIM (ADR 0057): the ADK path stays what it
|
|
16
|
-
* was before the adapters moved onto the contract.
|
|
17
|
-
* - The request: an agent's older generateContentConfig spelling that the
|
|
18
|
-
* contract leaves out rides beside it (olderSpellingOf): an effort word
|
|
19
|
-
* that is no contract level (Kimi K3's `max`). JSON mode without a
|
|
20
|
-
* schema is the contract's `outputFormat` (ADR 0061).
|
|
21
|
-
* - The response: the final keeps the shape these classes always yielded,
|
|
22
|
-
* which the ledger and FallbackLlm read. usageMetadata counts the
|
|
23
|
-
* reasoning inside candidatesTokenCount, as the provider's
|
|
24
|
-
* completion_tokens does, so llm.tokens.output and the turn's charge are
|
|
25
|
-
* unchanged (the shim's default is Gemini's meaning, which excludes it).
|
|
26
|
-
* finishReason is set only for a reply cut short (MAX_TOKENS); a final
|
|
27
|
-
* with no parts keeps its empty content; an HTTP failure keeps its
|
|
28
|
-
* top-level `status` and `retryable` beside the verdict in
|
|
29
|
-
* customMetadata.
|
|
30
|
-
*
|
|
31
|
-
* A /chat/completions provider of your own is a ChatCompletionsAdapter
|
|
32
|
-
* subclass (the endpoint, headers, wire name, reasoning field and error
|
|
33
|
-
* wording), run under ADK as `adkShim(adapter)` or as a subclass of this
|
|
34
|
-
* class.
|
|
35
|
-
*/
|
|
36
|
-
import { FinishReason } from '@google/genai';
|
|
37
|
-
import { AdkShim } from './adkShim.js';
|
|
38
|
-
import { setLlmSpanAttribute } from '../observability/tracer.js';
|
|
39
|
-
import { isRetryableStatus } from './retry.js';
|
|
40
|
-
import { statusDecision, withRetryVerdict } from './errorResponse.js';
|
|
41
|
-
export { REASONING_CONTENT_KIND, splitThinkBlocks, ThinkStreamSplitter } from './chatCompletionsAdapter.js';
|
|
42
|
-
/** The effort words a contract ReasoningSetting carries (genaiMapping's reasoningOf); any other rides as the older spelling. */
|
|
43
|
-
const CONTRACT_EFFORT_WORDS = new Set(['none', 'minimal', 'low', 'medium', 'high']);
|
|
44
|
-
/**
|
|
45
|
-
* What a generateContentConfig asks of a chat-completions provider that the
|
|
46
|
-
* contract has no field for, or undefined when it asks nothing more:
|
|
47
|
-
* `reasoningEffort` when it is a word no ReasoningSetting carries (`max`,
|
|
48
|
-
* `xhigh`), sent as written. JSON mode without a schema is no longer here:
|
|
49
|
-
* the genai mapping reads it as `outputFormat: 'json'` (ADR 0061).
|
|
50
|
-
*/
|
|
51
|
-
export function olderSpellingOf(config) {
|
|
52
|
-
const cfg = (config ?? {});
|
|
53
|
-
const out = {};
|
|
54
|
-
const effort = cfg.reasoningEffort;
|
|
55
|
-
if (typeof effort === 'string' && !CONTRACT_EFFORT_WORDS.has(effort))
|
|
56
|
-
out.reasoningEffort = effort;
|
|
57
|
-
return Object.keys(out).length > 0 ? out : undefined;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Usage as the chat-completions classes have always reported it on the ADK
|
|
61
|
-
* path: candidatesTokenCount is the provider's completion_tokens, reasoning
|
|
62
|
-
* included, and thoughtsTokenCount the reasoning part of it.
|
|
63
|
-
*/
|
|
64
|
-
export function chatUsageMetadata(usage) {
|
|
65
|
-
return {
|
|
66
|
-
promptTokenCount: usage.inputTokens,
|
|
67
|
-
candidatesTokenCount: usage.outputTokens,
|
|
68
|
-
...(usage.thinkingTokens !== undefined ? { thoughtsTokenCount: usage.thinkingTokens } : {}),
|
|
69
|
-
totalTokenCount: usage.inputTokens + usage.outputTokens,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
// ── OpenAiCompatibleLlm ──────────────────────────────────────────────────────
|
|
73
|
-
export class OpenAiCompatibleLlm extends AdkShim {
|
|
74
|
-
constructor(adapter, options = {}) {
|
|
75
|
-
super(adapter, options);
|
|
76
|
-
}
|
|
77
|
-
/** Provider id for telemetry: the adapter's (a gateway reports the upstream provider). */
|
|
78
|
-
providerId() {
|
|
79
|
-
return this.adapter.provider;
|
|
80
|
-
}
|
|
81
|
-
/** How the request reaches the provider: 'direct' or 'gateway:<id>' (llm.transport). */
|
|
82
|
-
transport() {
|
|
83
|
-
return this.adapter.transport();
|
|
84
|
-
}
|
|
85
|
-
/** The chat messages the adapter sends for this LlmRequest. */
|
|
86
|
-
buildMessages(llmRequest) {
|
|
87
|
-
return this.adapter.messagesFor(this.toModelRequest(llmRequest, { model: this.model }));
|
|
88
|
-
}
|
|
89
|
-
/** The function tools the adapter sends for this LlmRequest (lowercase schemas). */
|
|
90
|
-
buildTools(llmRequest) {
|
|
91
|
-
return this.adapter.toolsFor(this.toModelRequest(llmRequest, { model: this.model }));
|
|
92
|
-
}
|
|
93
|
-
/** The genai mapping's request, with the older spelling the contract leaves out. */
|
|
94
|
-
toModelRequest(llmRequest, options) {
|
|
95
|
-
const request = super.toModelRequest(llmRequest, options);
|
|
96
|
-
const olderSpelling = olderSpellingOf(llmRequest.config);
|
|
97
|
-
return olderSpelling ? { ...request, olderSpelling } : request;
|
|
98
|
-
}
|
|
99
|
-
/** The genai mapping's response, in the shape these classes have always yielded (see the header). */
|
|
100
|
-
toLlmResponse(response) {
|
|
101
|
-
const mapped = super.toLlmResponse(response);
|
|
102
|
-
if (response.partial)
|
|
103
|
-
return mapped;
|
|
104
|
-
const { finishReason: _finish, usageMetadata: _usage, ...rest } = mapped;
|
|
105
|
-
const error = response.error;
|
|
106
|
-
return {
|
|
107
|
-
...(error ? {} : { content: { role: 'model', parts: [] } }),
|
|
108
|
-
...rest,
|
|
109
|
-
...(!error && response.finishReason === 'max_tokens' ? { finishReason: FinishReason.MAX_TOKENS } : {}),
|
|
110
|
-
...(response.usage ? { usageMetadata: chatUsageMetadata(response.usage) } : {}),
|
|
111
|
-
...(error?.status !== undefined ? { status: error.status, retryable: error.retryable } : {}),
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
// ── Kept for callers of the ADK-path helpers ─────────────────────────────────
|
|
116
|
-
/**
|
|
117
|
-
* Stamps an HTTP error response with its numeric status and whether that
|
|
118
|
-
* status is transient, and the same verdict in customMetadata
|
|
119
|
-
* ('error.retryable', 'error.status'), where FallbackLlm reads it
|
|
120
|
-
* (lib/models/errorResponse.ts). The chat-completions shims take these
|
|
121
|
-
* fields from their adapter's error final instead (toLlmResponse).
|
|
122
|
-
*/
|
|
123
|
-
export function withHttpStatus(resp, status) {
|
|
124
|
-
setLlmSpanAttribute('llm.http_status', status);
|
|
125
|
-
return { ...withRetryVerdict(resp, statusDecision(status)), status, retryable: isRetryableStatus(status) };
|
|
126
|
-
}
|
|
127
|
-
/** Two genai usage records summed, field by field. */
|
|
128
|
-
export function addUsage(a, b) {
|
|
129
|
-
if (!a)
|
|
130
|
-
return b;
|
|
131
|
-
if (!b)
|
|
132
|
-
return a;
|
|
133
|
-
const out = {};
|
|
134
|
-
for (const k of ['promptTokenCount', 'candidatesTokenCount', 'thoughtsTokenCount', 'totalTokenCount']) {
|
|
135
|
-
if (a[k] !== undefined || b[k] !== undefined)
|
|
136
|
-
out[k] = (a[k] ?? 0) + (b[k] ?? 0);
|
|
137
|
-
}
|
|
138
|
-
return out;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* OpenAI-style usage → GenAI usageMetadata in the ADK-path meaning
|
|
142
|
-
* (completion_tokens, reasoning included, as candidatesTokenCount), or
|
|
143
|
-
* undefined when absent. The contract's meaning is chatUsage in
|
|
144
|
-
* lib/models/chatCompletionsAdapter.ts.
|
|
145
|
-
*/
|
|
146
|
-
export function mapUsage(usage) {
|
|
147
|
-
if (!usage || typeof usage !== 'object')
|
|
148
|
-
return undefined;
|
|
149
|
-
const reasoning = usage.completion_tokens_details?.reasoning_tokens;
|
|
150
|
-
return {
|
|
151
|
-
...(usage.prompt_tokens !== undefined ? { promptTokenCount: usage.prompt_tokens } : {}),
|
|
152
|
-
...(usage.completion_tokens !== undefined ? { candidatesTokenCount: usage.completion_tokens } : {}),
|
|
153
|
-
...(reasoning !== undefined ? { thoughtsTokenCount: reasoning } : {}),
|
|
154
|
-
...(usage.total_tokens !== undefined ? { totalTokenCount: usage.total_tokens } : {}),
|
|
155
|
-
};
|
|
156
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/tracedGemini.ts — ADK's built-in Gemini, wrapped so Gemini calls
|
|
3
|
-
* emit the same per-request llm.request spans (tokens, latency) as every other
|
|
4
|
-
* provider, and get the shared transient-failure retries (lib/models/retry.ts).
|
|
5
|
-
*
|
|
6
|
-
* WHY its own module: two modules use it. lib/models/registry.ts registers it
|
|
7
|
-
* for every Gemini id on the ADK path and builds it in resolveModel, and the
|
|
8
|
-
* temporary AdkGeminiAdapter (lib/models/adkGeminiAdapter.ts) runs its calls
|
|
9
|
-
* through generateWithRetries. registry.ts also builds that adapter in
|
|
10
|
-
* resolveAdapter, so the class living in registry.ts would be an ESM import
|
|
11
|
-
* cycle. registry.ts re-exports it, so `TracedGemini` imports from there keep
|
|
12
|
-
* working.
|
|
13
|
-
*/
|
|
14
|
-
import { Gemini } from '../adkPeer.ts';
|
|
15
|
-
import type { GeminiParams, LlmRequest, LlmResponse } from '@google/adk';
|
|
16
|
-
import type { ProviderEndpoint } from './endpoints.ts';
|
|
17
|
-
export declare class TracedGemini extends Gemini {
|
|
18
|
-
#private;
|
|
19
|
-
static readonly supportedModels: Array<string | RegExp>;
|
|
20
|
-
/**
|
|
21
|
-
* The Gemini platform (ADR 0023) applies to every construction, the
|
|
22
|
-
* LLMRegistry's included: on Vertex AI the client authenticates with
|
|
23
|
-
* Google Application Default Credentials for the configured project and
|
|
24
|
-
* location, and an AI Studio key (the environment's or a caller's) is not
|
|
25
|
-
* sent. `endpoint` overrides the environment's (the credentials plug point).
|
|
26
|
-
*/
|
|
27
|
-
constructor(params?: GeminiParams & {
|
|
28
|
-
endpoint?: ProviderEndpoint;
|
|
29
|
-
});
|
|
30
|
-
generateContentAsync(llmRequest: LlmRequest, stream?: boolean, abortSignal?: AbortSignal): AsyncGenerator<LlmResponse, void>;
|
|
31
|
-
/**
|
|
32
|
-
* One call through ADK's Gemini with the shared retries, tagging whatever
|
|
33
|
-
* llm.request span is active (llm.web_search.native for Gemini grounding,
|
|
34
|
-
* llm.retries, llm.http_status). generateContentAsync opens that span
|
|
35
|
-
* around it; AdkGeminiAdapter (lib/models/adkGeminiAdapter.ts) runs it
|
|
36
|
-
* inside the span its own caller opens (ADR 0053). A failed call throws,
|
|
37
|
-
* as ADK's Gemini does. The abort signal is forwarded so a canceled turn stops the
|
|
38
|
-
* request in flight (ADK's Gemini puts it on the genai request config).
|
|
39
|
-
*/
|
|
40
|
-
generateWithRetries(llmRequest: LlmRequest, stream?: boolean, abortSignal?: AbortSignal): AsyncGenerator<LlmResponse, void>;
|
|
41
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/models/tracedGemini.ts — ADK's built-in Gemini, wrapped so Gemini calls
|
|
3
|
-
* emit the same per-request llm.request spans (tokens, latency) as every other
|
|
4
|
-
* provider, and get the shared transient-failure retries (lib/models/retry.ts).
|
|
5
|
-
*
|
|
6
|
-
* WHY its own module: two modules use it. lib/models/registry.ts registers it
|
|
7
|
-
* for every Gemini id on the ADK path and builds it in resolveModel, and the
|
|
8
|
-
* temporary AdkGeminiAdapter (lib/models/adkGeminiAdapter.ts) runs its calls
|
|
9
|
-
* through generateWithRetries. registry.ts also builds that adapter in
|
|
10
|
-
* resolveAdapter, so the class living in registry.ts would be an ESM import
|
|
11
|
-
* cycle. registry.ts re-exports it, so `TracedGemini` imports from there keep
|
|
12
|
-
* working.
|
|
13
|
-
*/
|
|
14
|
-
import { Gemini } from '../adkPeer.js';
|
|
15
|
-
import { endpointFromEnv, platformModel } from './endpoints.js';
|
|
16
|
-
import { llmRequestToModelRequest } from './genaiMapping.js';
|
|
17
|
-
import { errorStatus, retryUntilFirstYield } from './retry.js';
|
|
18
|
-
import { setLlmSpanAttribute, traceLlmGeneration } from '../observability/tracer.js';
|
|
19
|
-
import { currentTurnSignal } from '../runtime/turnControl.js';
|
|
20
|
-
export class TracedGemini extends Gemini {
|
|
21
|
-
// CRITICAL: reuse Gemini's exact regex instances. The LLMRegistry dict is
|
|
22
|
-
// keyed by the regex OBJECT — registering the same instances REPLACES the
|
|
23
|
-
// built-in Gemini entries instead of adding shadowed duplicates.
|
|
24
|
-
static supportedModels = Gemini.supportedModels;
|
|
25
|
-
/**
|
|
26
|
-
* The Gemini platform (ADR 0023) applies to every construction, the
|
|
27
|
-
* LLMRegistry's included: on Vertex AI the client authenticates with
|
|
28
|
-
* Google Application Default Credentials for the configured project and
|
|
29
|
-
* location, and an AI Studio key (the environment's or a caller's) is not
|
|
30
|
-
* sent. `endpoint` overrides the environment's (the credentials plug point).
|
|
31
|
-
*/
|
|
32
|
-
constructor(params = {}) {
|
|
33
|
-
const { endpoint: given, ...rest } = params;
|
|
34
|
-
const e = given ?? endpointFromEnv('gemini');
|
|
35
|
-
const model = rest.model ? platformModel(e, rest.model) : rest.model;
|
|
36
|
-
super(e.platform === 'vertex'
|
|
37
|
-
? { ...rest, model, apiKey: e.apiKey, vertexai: true, project: e.project, location: e.location }
|
|
38
|
-
: { ...rest, model, ...(e.apiKey && !rest.apiKey ? { apiKey: e.apiKey } : {}) });
|
|
39
|
-
this.#vertex = e.platform === 'vertex';
|
|
40
|
-
}
|
|
41
|
-
/** True when the client runs on Vertex AI (ADR 0023). */
|
|
42
|
-
#vertex;
|
|
43
|
-
async *generateContentAsync(llmRequest, stream, abortSignal) {
|
|
44
|
-
yield* traceLlmGeneration({
|
|
45
|
-
provider: 'gemini',
|
|
46
|
-
model: this.model,
|
|
47
|
-
request: () => llmRequestToModelRequest(llmRequest, { model: llmRequest.model || this.model, stream }),
|
|
48
|
-
}, this.generateWithRetries(llmRequest, stream, abortSignal ?? currentTurnSignal()));
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* One call through ADK's Gemini with the shared retries, tagging whatever
|
|
52
|
-
* llm.request span is active (llm.web_search.native for Gemini grounding,
|
|
53
|
-
* llm.retries, llm.http_status). generateContentAsync opens that span
|
|
54
|
-
* around it; AdkGeminiAdapter (lib/models/adkGeminiAdapter.ts) runs it
|
|
55
|
-
* inside the span its own caller opens (ADR 0053). A failed call throws,
|
|
56
|
-
* as ADK's Gemini does. The abort signal is forwarded so a canceled turn stops the
|
|
57
|
-
* request in flight (ADK's Gemini puts it on the genai request config).
|
|
58
|
-
*/
|
|
59
|
-
async *generateWithRetries(llmRequest, stream, abortSignal) {
|
|
60
|
-
// The compiler asks every agent's config for includeServerSideToolInvocations
|
|
61
|
-
// (lib/compile.ts), which the Gemini API needs beside function
|
|
62
|
-
// declarations. @google/genai refuses it on Vertex AI before any request
|
|
63
|
-
// is sent ("only supported in Gemini Developer API mode"), so on Vertex
|
|
64
|
-
// it is left off, and the call goes out as it did before the flag.
|
|
65
|
-
const toolConfig = llmRequest.config?.toolConfig;
|
|
66
|
-
if (this.#vertex && toolConfig && 'includeServerSideToolInvocations' in toolConfig) {
|
|
67
|
-
const { includeServerSideToolInvocations: _vertexRefuses, ...kept } = toolConfig;
|
|
68
|
-
llmRequest.config = { ...llmRequest.config, toolConfig: kept };
|
|
69
|
-
}
|
|
70
|
-
const hasGrounding = (llmRequest.config?.tools ?? []).some((t) => t && (t.googleSearch || t.googleSearchRetrieval));
|
|
71
|
-
if (hasGrounding)
|
|
72
|
-
setLlmSpanAttribute('llm.web_search.native', true);
|
|
73
|
-
// Retries live here, not in genai's own httpOptions.retryOptions: that
|
|
74
|
-
// hook (p-retry 4, client-level only) ignores the abort signal — it
|
|
75
|
-
// sleeps and re-sends after a canceled turn — honours no Retry-After,
|
|
76
|
-
// does not retry Node's "fetch failed" resets, and replaces a 4xx's
|
|
77
|
-
// error body (e.g. "API key not valid") with a bare statusText. Wrapping
|
|
78
|
-
// the call keeps genai's ApiError intact and applies the same policy as
|
|
79
|
-
// every other adapter. A retry is only made while nothing has been
|
|
80
|
-
// yielded, so a stream that fails mid-reply is surfaced, not replayed.
|
|
81
|
-
// ADK's request preprocessing is idempotent, so re-sending the same
|
|
82
|
-
// llmRequest is safe. The registry class, resolveModel()'s per-request
|
|
83
|
-
// instances and AdkGeminiAdapter's are all TracedGemini, so all get this.
|
|
84
|
-
try {
|
|
85
|
-
yield* retryUntilFirstYield(() => super.generateContentAsync(llmRequest, stream, abortSignal), {
|
|
86
|
-
signal: abortSignal,
|
|
87
|
-
onRetry: ({ retries }) => setLlmSpanAttribute('llm.retries', retries),
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
// genai's ApiError carries the status; put it where the ledger reads.
|
|
92
|
-
const status = errorStatus(err);
|
|
93
|
-
if (status !== undefined)
|
|
94
|
-
setLlmSpanAttribute('llm.http_status', status);
|
|
95
|
-
throw err;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|