@agentionai/agents 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/BaseAgent.d.ts +35 -0
- package/dist/agents/anthropic/ClaudeAgent.d.ts +56 -4
- package/dist/agents/anthropic/ClaudeAgent.js +20 -7
- package/dist/agents/google/GeminiAgent.d.ts +45 -4
- package/dist/agents/google/GeminiAgent.js +47 -5
- package/dist/agents/llamacpp/LlamaCppAgent.d.ts +4 -1
- package/dist/agents/llamacpp/LlamaCppAgent.js +7 -1
- package/dist/agents/mistral/MistralAgent.d.ts +9 -2
- package/dist/agents/mistral/MistralAgent.js +16 -2
- package/dist/agents/openai/OpenAiAgent.js +11 -7
- package/dist/agents/openai/openai-strict.d.ts +27 -0
- package/dist/agents/openai/openai-strict.js +50 -0
- package/dist/gemini.d.ts +2 -2
- package/dist/gemini.js +2 -1
- package/dist/history/transformers.js +27 -4
- package/dist/history/types.d.ts +10 -1
- package/dist/history/types.js +10 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/package.json +1 -1
|
@@ -67,6 +67,25 @@ export type TokenUsage = {
|
|
|
67
67
|
*/
|
|
68
68
|
outputTokensPerSecond?: number;
|
|
69
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* What a model can do, as reported by its provider.
|
|
72
|
+
*
|
|
73
|
+
* Every flag is three-valued: `true` and `false` are the provider's answer,
|
|
74
|
+
* `undefined` means it does not report on that capability at all — which is the
|
|
75
|
+
* common case, since no provider covers all four. Filter with `!== false` when
|
|
76
|
+
* you want "not known to be unsupported", and with `=== true` when you need
|
|
77
|
+
* positive confirmation.
|
|
78
|
+
*/
|
|
79
|
+
export type ModelCapabilities = {
|
|
80
|
+
/** Conversational generation — what an agent needs to run at all. */
|
|
81
|
+
chat?: boolean;
|
|
82
|
+
/** Function / tool calling. */
|
|
83
|
+
tools?: boolean;
|
|
84
|
+
/** Image input. */
|
|
85
|
+
vision?: boolean;
|
|
86
|
+
/** Extended thinking / reasoning. */
|
|
87
|
+
thinking?: boolean;
|
|
88
|
+
};
|
|
70
89
|
/**
|
|
71
90
|
* A model as reported by a provider's models endpoint, in a shape that is the
|
|
72
91
|
* same on every provider.
|
|
@@ -89,6 +108,22 @@ export type ModelInfo<TRaw = unknown> = {
|
|
|
89
108
|
ownedBy?: string;
|
|
90
109
|
/** Maximum input context in tokens, where the provider reports one. */
|
|
91
110
|
contextLength?: number;
|
|
111
|
+
/** Maximum tokens in a single response, where the provider reports one. */
|
|
112
|
+
maxOutputTokens?: number;
|
|
113
|
+
/**
|
|
114
|
+
* What the provider says this model supports. Absent flags mean "not
|
|
115
|
+
* reported", never "unsupported" — see {@link ModelCapabilities}.
|
|
116
|
+
*/
|
|
117
|
+
capabilities?: ModelCapabilities;
|
|
118
|
+
/**
|
|
119
|
+
* When the provider plans to retire the model, where it publishes a date.
|
|
120
|
+
* Only Mistral does today; note that a model can stop working before any
|
|
121
|
+
* announced date, and Google in particular retires models that its listing
|
|
122
|
+
* still advertises.
|
|
123
|
+
*/
|
|
124
|
+
deprecatedAt?: Date;
|
|
125
|
+
/** Model the provider recommends in its place, where it names one. */
|
|
126
|
+
replacedBy?: string;
|
|
92
127
|
/**
|
|
93
128
|
* Whether the model is currently held in memory, on servers that distinguish
|
|
94
129
|
* "offered" from "loaded" — llama.cpp's model router being the case in point,
|
|
@@ -6,6 +6,52 @@ import { BaseAgent, BaseAgentConfig, ModelInfo, TokenUsage } from "../BaseAgent"
|
|
|
6
6
|
import { History, MessageContent } from "../../history/History";
|
|
7
7
|
import { StreamChunk } from "../openai-compatible/OpenAICompatibleAgent";
|
|
8
8
|
import { ClaudeModel } from "../model-types";
|
|
9
|
+
/** A capability node in Anthropic's model card — always at least `supported`. */
|
|
10
|
+
type AnthropicSupported = {
|
|
11
|
+
supported: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* One entry from Anthropic's `/v1/models`.
|
|
15
|
+
*
|
|
16
|
+
* Declared here rather than taken from the SDK, whose `ModelInfo` still covers
|
|
17
|
+
* only `id`/`type`/`display_name`/`created_at`. The API also returns token
|
|
18
|
+
* limits and a capability tree — verified on the wire on 2026-08-11 — and those
|
|
19
|
+
* are what `contextLength`, `maxOutputTokens` and `capabilities` are read from.
|
|
20
|
+
* Everything past the four SDK fields is optional so that an older API version,
|
|
21
|
+
* or a gateway that trims the response, still typechecks.
|
|
22
|
+
*/
|
|
23
|
+
export type AnthropicModelCard = AnthropicModelInfo & {
|
|
24
|
+
/** Context window in tokens. */
|
|
25
|
+
max_input_tokens?: number;
|
|
26
|
+
/** Largest `max_tokens` the model accepts for a response. */
|
|
27
|
+
max_tokens?: number;
|
|
28
|
+
capabilities?: {
|
|
29
|
+
batch?: AnthropicSupported;
|
|
30
|
+
citations?: AnthropicSupported;
|
|
31
|
+
code_execution?: AnthropicSupported;
|
|
32
|
+
/** Server-side context editing; the dated keys are individual strategies. */
|
|
33
|
+
context_management?: AnthropicSupported & {
|
|
34
|
+
[strategy: string]: AnthropicSupported | boolean | undefined;
|
|
35
|
+
};
|
|
36
|
+
/** Which effort levels the model accepts — the live answer to what `model-types.ts` hardcodes. */
|
|
37
|
+
effort?: AnthropicSupported & {
|
|
38
|
+
low?: AnthropicSupported;
|
|
39
|
+
medium?: AnthropicSupported;
|
|
40
|
+
high?: AnthropicSupported;
|
|
41
|
+
xhigh?: AnthropicSupported;
|
|
42
|
+
max?: AnthropicSupported;
|
|
43
|
+
};
|
|
44
|
+
image_input?: AnthropicSupported;
|
|
45
|
+
pdf_input?: AnthropicSupported;
|
|
46
|
+
structured_outputs?: AnthropicSupported;
|
|
47
|
+
thinking?: AnthropicSupported & {
|
|
48
|
+
types?: {
|
|
49
|
+
enabled?: AnthropicSupported;
|
|
50
|
+
adaptive?: AnthropicSupported;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
};
|
|
9
55
|
type AgentConfig = BaseAgentConfig & {
|
|
10
56
|
apiKey: string;
|
|
11
57
|
model?: ClaudeModel;
|
|
@@ -58,11 +104,17 @@ export declare class ClaudeAgent extends BaseAgent {
|
|
|
58
104
|
/**
|
|
59
105
|
* List the models available to this API key, newest first.
|
|
60
106
|
*
|
|
61
|
-
* Anthropic reports
|
|
62
|
-
* so `
|
|
63
|
-
*
|
|
107
|
+
* Anthropic reports token limits and a capability tree that the SDK's own
|
|
108
|
+
* type omits, so `raw` is typed as {@link AnthropicModelCard} — which is also
|
|
109
|
+
* where `contextLength` (`max_input_tokens`), `maxOutputTokens` and the
|
|
110
|
+
* vision/thinking flags come from. `capabilities.effort` on `raw` states which
|
|
111
|
+
* effort levels each model accepts. Tool support is not reported; every model
|
|
112
|
+
* the endpoint lists supports tools, so `capabilities.tools` stays undefined
|
|
113
|
+
* rather than being asserted.
|
|
114
|
+
*
|
|
115
|
+
* The result is fully paginated — the endpoint pages at 1000 models.
|
|
64
116
|
*/
|
|
65
|
-
listModels(): Promise<ModelInfo<
|
|
117
|
+
listModels(): Promise<ModelInfo<AnthropicModelCard>[]>;
|
|
66
118
|
/**
|
|
67
119
|
* Combine locally-executed tool definitions with provider-defined
|
|
68
120
|
* (server-side) built-in tools, in the shape Anthropic's API expects.
|
|
@@ -65,19 +65,32 @@ class ClaudeAgent extends BaseAgent_1.BaseAgent {
|
|
|
65
65
|
/**
|
|
66
66
|
* List the models available to this API key, newest first.
|
|
67
67
|
*
|
|
68
|
-
* Anthropic reports
|
|
69
|
-
* so `
|
|
70
|
-
*
|
|
68
|
+
* Anthropic reports token limits and a capability tree that the SDK's own
|
|
69
|
+
* type omits, so `raw` is typed as {@link AnthropicModelCard} — which is also
|
|
70
|
+
* where `contextLength` (`max_input_tokens`), `maxOutputTokens` and the
|
|
71
|
+
* vision/thinking flags come from. `capabilities.effort` on `raw` states which
|
|
72
|
+
* effort levels each model accepts. Tool support is not reported; every model
|
|
73
|
+
* the endpoint lists supports tools, so `capabilities.tools` stays undefined
|
|
74
|
+
* rather than being asserted.
|
|
75
|
+
*
|
|
76
|
+
* The result is fully paginated — the endpoint pages at 1000 models.
|
|
71
77
|
*/
|
|
72
78
|
async listModels() {
|
|
73
79
|
try {
|
|
74
80
|
const models = [];
|
|
75
81
|
for await (const model of this.client.models.list({ limit: 1000 })) {
|
|
82
|
+
const card = model;
|
|
76
83
|
models.push({
|
|
77
|
-
id:
|
|
78
|
-
displayName:
|
|
79
|
-
created: new Date(
|
|
80
|
-
|
|
84
|
+
id: card.id,
|
|
85
|
+
displayName: card.display_name,
|
|
86
|
+
created: new Date(card.created_at),
|
|
87
|
+
contextLength: card.max_input_tokens,
|
|
88
|
+
maxOutputTokens: card.max_tokens,
|
|
89
|
+
capabilities: {
|
|
90
|
+
vision: card.capabilities?.image_input?.supported,
|
|
91
|
+
thinking: card.capabilities?.thinking?.supported,
|
|
92
|
+
},
|
|
93
|
+
raw: card,
|
|
81
94
|
});
|
|
82
95
|
}
|
|
83
96
|
return models;
|
|
@@ -2,6 +2,36 @@ import { FunctionDeclarationsTool, GenerateContentResult, Schema } from "@google
|
|
|
2
2
|
import { BaseAgent, BaseAgentConfig, ModelInfo, TokenUsage } from "../BaseAgent";
|
|
3
3
|
import { History, MessageContent } from "../../history/History";
|
|
4
4
|
import { GeminiModel } from "../model-types";
|
|
5
|
+
/**
|
|
6
|
+
* Models that `models.list` still advertises but the API no longer serves.
|
|
7
|
+
*
|
|
8
|
+
* Google leaves retired models in the listing, fully described and claiming
|
|
9
|
+
* `generateContent`; calling one fails with `404 — "This model is no longer
|
|
10
|
+
* available to new users"`. Nothing in the listing distinguishes them, and the
|
|
11
|
+
* stable `v1` endpoint carries them too, so the only way to keep them out of
|
|
12
|
+
* `listModels()` is to name them.
|
|
13
|
+
*
|
|
14
|
+
* A retirement is permanent, so this list only ever grows — an entry never
|
|
15
|
+
* needs revisiting, and one that disappears from the API's listing costs
|
|
16
|
+
* nothing to keep.
|
|
17
|
+
*
|
|
18
|
+
* Every entry is confirmed by probing `countTokens` (free, and it 404s the same
|
|
19
|
+
* way), most recently on 2026-08-11. Note that retirement is per-model, not per
|
|
20
|
+
* family: `gemini-2.5-flash-image`, `gemini-2.5-*-preview-tts` and
|
|
21
|
+
* `gemini-2.5-computer-use-preview-10-2025` were all still live at that date,
|
|
22
|
+
* which is why these are listed individually rather than matched by prefix.
|
|
23
|
+
*
|
|
24
|
+
* Pass `{ includeRetired: true }` to `listModels()` to see them anyway.
|
|
25
|
+
*/
|
|
26
|
+
export declare const GEMINI_RETIRED_MODELS: readonly string[];
|
|
27
|
+
/** Options for {@link GeminiAgent.listModels}. */
|
|
28
|
+
export type GeminiListModelsOptions = {
|
|
29
|
+
/**
|
|
30
|
+
* Include models known to have been retired. Off by default: they are listed
|
|
31
|
+
* by the API but fail at call time.
|
|
32
|
+
*/
|
|
33
|
+
includeRetired?: boolean;
|
|
34
|
+
};
|
|
5
35
|
/**
|
|
6
36
|
* One entry from the Generative Language API's `models.list` response.
|
|
7
37
|
*
|
|
@@ -17,8 +47,14 @@ export type GeminiModelCard = {
|
|
|
17
47
|
description?: string;
|
|
18
48
|
inputTokenLimit?: number;
|
|
19
49
|
outputTokenLimit?: number;
|
|
20
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* e.g. `["generateContent", "countTokens"]`. Embedding models have
|
|
52
|
+
* `embedContent`, Imagen `predict`, Veo `predictLongRunning`, and the live
|
|
53
|
+
* models only `bidiGenerateContent` — none of which an agent can drive.
|
|
54
|
+
*/
|
|
21
55
|
supportedGenerationMethods?: string[];
|
|
56
|
+
/** Whether the model reasons before answering. */
|
|
57
|
+
thinking?: boolean;
|
|
22
58
|
temperature?: number;
|
|
23
59
|
maxTemperature?: number;
|
|
24
60
|
topP?: number;
|
|
@@ -64,10 +100,15 @@ export declare class GeminiAgent extends BaseAgent {
|
|
|
64
100
|
* page is followed, and the `"models/"` prefix is stripped from `id` so the
|
|
65
101
|
* value can be passed straight back as an agent's `model`.
|
|
66
102
|
*
|
|
67
|
-
* The list
|
|
68
|
-
* `
|
|
103
|
+
* The list covers everything the key can reach, including embedding, image
|
|
104
|
+
* and live-audio models — `capabilities.chat` marks the ones an agent can
|
|
105
|
+
* actually drive.
|
|
106
|
+
*
|
|
107
|
+
* Models known to have been retired are left out, since the API lists them
|
|
108
|
+
* but no longer serves them — see {@link GEMINI_RETIRED_MODELS}. Pass
|
|
109
|
+
* `{ includeRetired: true }` for the listing exactly as Google returns it.
|
|
69
110
|
*/
|
|
70
|
-
listModels(): Promise<ModelInfo<GeminiModelCard>[]>;
|
|
111
|
+
listModels(options?: GeminiListModelsOptions): Promise<ModelInfo<GeminiModelCard>[]>;
|
|
71
112
|
protected getToolDefinitionsForGemini(): FunctionDeclarationsTool | undefined;
|
|
72
113
|
/**
|
|
73
114
|
* Convert JSON Schema to Gemini's FunctionDeclarationSchema format
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GeminiAgent = void 0;
|
|
3
|
+
exports.GeminiAgent = exports.GEMINI_RETIRED_MODELS = void 0;
|
|
4
4
|
const generative_ai_1 = require("@google/generative-ai");
|
|
5
5
|
const BaseAgent_1 = require("../BaseAgent");
|
|
6
6
|
const AgentEvent_1 = require("../AgentEvent");
|
|
@@ -10,6 +10,34 @@ const VizReporter_1 = require("../../viz/VizReporter");
|
|
|
10
10
|
const VizConfig_1 = require("../../viz/VizConfig");
|
|
11
11
|
/** Base URL of the Generative Language API, matching the SDK's own default. */
|
|
12
12
|
const GEMINI_API_BASE = "https://generativelanguage.googleapis.com";
|
|
13
|
+
/**
|
|
14
|
+
* Models that `models.list` still advertises but the API no longer serves.
|
|
15
|
+
*
|
|
16
|
+
* Google leaves retired models in the listing, fully described and claiming
|
|
17
|
+
* `generateContent`; calling one fails with `404 — "This model is no longer
|
|
18
|
+
* available to new users"`. Nothing in the listing distinguishes them, and the
|
|
19
|
+
* stable `v1` endpoint carries them too, so the only way to keep them out of
|
|
20
|
+
* `listModels()` is to name them.
|
|
21
|
+
*
|
|
22
|
+
* A retirement is permanent, so this list only ever grows — an entry never
|
|
23
|
+
* needs revisiting, and one that disappears from the API's listing costs
|
|
24
|
+
* nothing to keep.
|
|
25
|
+
*
|
|
26
|
+
* Every entry is confirmed by probing `countTokens` (free, and it 404s the same
|
|
27
|
+
* way), most recently on 2026-08-11. Note that retirement is per-model, not per
|
|
28
|
+
* family: `gemini-2.5-flash-image`, `gemini-2.5-*-preview-tts` and
|
|
29
|
+
* `gemini-2.5-computer-use-preview-10-2025` were all still live at that date,
|
|
30
|
+
* which is why these are listed individually rather than matched by prefix.
|
|
31
|
+
*
|
|
32
|
+
* Pass `{ includeRetired: true }` to `listModels()` to see them anyway.
|
|
33
|
+
*/
|
|
34
|
+
exports.GEMINI_RETIRED_MODELS = [
|
|
35
|
+
// Retired for new users some time before 2026-08-11
|
|
36
|
+
"gemini-2.5-flash",
|
|
37
|
+
"gemini-2.5-pro",
|
|
38
|
+
"gemini-2.5-flash-lite",
|
|
39
|
+
];
|
|
40
|
+
const GEMINI_RETIRED = new Set(exports.GEMINI_RETIRED_MODELS);
|
|
13
41
|
/**
|
|
14
42
|
* Agent for Google Gemini models.
|
|
15
43
|
*
|
|
@@ -62,10 +90,15 @@ class GeminiAgent extends BaseAgent_1.BaseAgent {
|
|
|
62
90
|
* page is followed, and the `"models/"` prefix is stripped from `id` so the
|
|
63
91
|
* value can be passed straight back as an agent's `model`.
|
|
64
92
|
*
|
|
65
|
-
* The list
|
|
66
|
-
* `
|
|
93
|
+
* The list covers everything the key can reach, including embedding, image
|
|
94
|
+
* and live-audio models — `capabilities.chat` marks the ones an agent can
|
|
95
|
+
* actually drive.
|
|
96
|
+
*
|
|
97
|
+
* Models known to have been retired are left out, since the API lists them
|
|
98
|
+
* but no longer serves them — see {@link GEMINI_RETIRED_MODELS}. Pass
|
|
99
|
+
* `{ includeRetired: true }` for the listing exactly as Google returns it.
|
|
67
100
|
*/
|
|
68
|
-
async listModels() {
|
|
101
|
+
async listModels(options) {
|
|
69
102
|
try {
|
|
70
103
|
const models = [];
|
|
71
104
|
let pageToken;
|
|
@@ -86,10 +119,19 @@ class GeminiAgent extends BaseAgent_1.BaseAgent {
|
|
|
86
119
|
}
|
|
87
120
|
const body = (await response.json());
|
|
88
121
|
for (const model of body.models ?? []) {
|
|
122
|
+
const id = model.name.replace(/^models\//, "");
|
|
123
|
+
if (!options?.includeRetired && GEMINI_RETIRED.has(id)) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
89
126
|
models.push({
|
|
90
|
-
id
|
|
127
|
+
id,
|
|
91
128
|
displayName: model.displayName,
|
|
92
129
|
contextLength: model.inputTokenLimit,
|
|
130
|
+
maxOutputTokens: model.outputTokenLimit,
|
|
131
|
+
capabilities: {
|
|
132
|
+
chat: model.supportedGenerationMethods?.includes("generateContent"),
|
|
133
|
+
thinking: model.thinking,
|
|
134
|
+
},
|
|
93
135
|
raw: model,
|
|
94
136
|
});
|
|
95
137
|
}
|
|
@@ -93,7 +93,10 @@ export declare class LlamaCppAgent extends OpenAICompatibleAgent {
|
|
|
93
93
|
* with, falling back to the trained ceiling `n_ctx_train`. Only loaded
|
|
94
94
|
* models carry `meta`.
|
|
95
95
|
*
|
|
96
|
-
*
|
|
96
|
+
* `capabilities.vision` follows from the declared input modalities. Tool
|
|
97
|
+
* support is not reported — it depends on the chat template, not the server —
|
|
98
|
+
* so it stays undefined. The rest, launch args and presets and quantization
|
|
99
|
+
* included, is on `raw`.
|
|
97
100
|
*/
|
|
98
101
|
listModels(): Promise<ModelInfo<LlamaCppModelCard>[]>;
|
|
99
102
|
}
|
|
@@ -50,7 +50,10 @@ class LlamaCppAgent extends OpenAICompatibleAgent_1.OpenAICompatibleAgent {
|
|
|
50
50
|
* with, falling back to the trained ceiling `n_ctx_train`. Only loaded
|
|
51
51
|
* models carry `meta`.
|
|
52
52
|
*
|
|
53
|
-
*
|
|
53
|
+
* `capabilities.vision` follows from the declared input modalities. Tool
|
|
54
|
+
* support is not reported — it depends on the chat template, not the server —
|
|
55
|
+
* so it stays undefined. The rest, launch args and presets and quantization
|
|
56
|
+
* included, is on `raw`.
|
|
54
57
|
*/
|
|
55
58
|
async listModels() {
|
|
56
59
|
const models = (await super.listModels());
|
|
@@ -60,6 +63,9 @@ class LlamaCppAgent extends OpenAICompatibleAgent_1.OpenAICompatibleAgent {
|
|
|
60
63
|
? model.raw.status.value === "loaded"
|
|
61
64
|
: undefined,
|
|
62
65
|
contextLength: model.raw.meta?.n_ctx ?? model.raw.meta?.n_ctx_train,
|
|
66
|
+
capabilities: {
|
|
67
|
+
vision: model.raw.architecture?.input_modalities?.includes("image"),
|
|
68
|
+
},
|
|
63
69
|
}));
|
|
64
70
|
}
|
|
65
71
|
}
|
|
@@ -53,8 +53,15 @@ export declare class MistralAgent extends BaseAgent {
|
|
|
53
53
|
/**
|
|
54
54
|
* List the models available to this API key, base and fine-tuned alike.
|
|
55
55
|
*
|
|
56
|
-
* Mistral
|
|
57
|
-
*
|
|
56
|
+
* Mistral is the most forthcoming of the providers: it reports a context
|
|
57
|
+
* window, a full capability set, and a retirement date with a replacement
|
|
58
|
+
* model. All of that is mapped onto the neutral fields.
|
|
59
|
+
*
|
|
60
|
+
* Note that `raw` here is the SDK's parsed view, not the wire response — the
|
|
61
|
+
* Mistral SDK validates against a schema that drops fields it does not know,
|
|
62
|
+
* so capabilities the API has added since the installed SDK version (as of
|
|
63
|
+
* `1.13.0`: `reasoning`, the audio flags) are gone before this code sees
|
|
64
|
+
* them. Every other agent's `raw` is the untouched response.
|
|
58
65
|
*/
|
|
59
66
|
listModels(): Promise<ModelInfo<MistralModelCard>[]>;
|
|
60
67
|
protected getToolDefinitions(): Tool[];
|
|
@@ -83,8 +83,15 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
83
83
|
/**
|
|
84
84
|
* List the models available to this API key, base and fine-tuned alike.
|
|
85
85
|
*
|
|
86
|
-
* Mistral
|
|
87
|
-
*
|
|
86
|
+
* Mistral is the most forthcoming of the providers: it reports a context
|
|
87
|
+
* window, a full capability set, and a retirement date with a replacement
|
|
88
|
+
* model. All of that is mapped onto the neutral fields.
|
|
89
|
+
*
|
|
90
|
+
* Note that `raw` here is the SDK's parsed view, not the wire response — the
|
|
91
|
+
* Mistral SDK validates against a schema that drops fields it does not know,
|
|
92
|
+
* so capabilities the API has added since the installed SDK version (as of
|
|
93
|
+
* `1.13.0`: `reasoning`, the audio flags) are gone before this code sees
|
|
94
|
+
* them. Every other agent's `raw` is the untouched response.
|
|
88
95
|
*/
|
|
89
96
|
async listModels() {
|
|
90
97
|
try {
|
|
@@ -95,6 +102,13 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
95
102
|
created: model.created ? new Date(model.created * 1000) : undefined,
|
|
96
103
|
ownedBy: model.ownedBy,
|
|
97
104
|
contextLength: model.maxContextLength,
|
|
105
|
+
capabilities: {
|
|
106
|
+
chat: model.capabilities.completionChat,
|
|
107
|
+
tools: model.capabilities.functionCalling,
|
|
108
|
+
vision: model.capabilities.vision,
|
|
109
|
+
},
|
|
110
|
+
deprecatedAt: model.deprecation ?? undefined,
|
|
111
|
+
replacedBy: model.deprecationReplacementModel ?? undefined,
|
|
98
112
|
raw: model,
|
|
99
113
|
}));
|
|
100
114
|
}
|
|
@@ -13,6 +13,7 @@ const transformers_1 = require("../../history/transformers");
|
|
|
13
13
|
const VizReporter_1 = require("../../viz/VizReporter");
|
|
14
14
|
const VizConfig_1 = require("../../viz/VizConfig");
|
|
15
15
|
const model_types_1 = require("../model-types");
|
|
16
|
+
const openai_strict_1 = require("./openai-strict");
|
|
16
17
|
/**
|
|
17
18
|
* Lowest `reasoning.effort` the given model accepts, used to resolve
|
|
18
19
|
* `disableReasoning`. Returns `undefined` when the model has no reasoning to turn
|
|
@@ -111,17 +112,20 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
111
112
|
getToolDefinitions() {
|
|
112
113
|
return Array.from(this.tools.values()).map((tool) => {
|
|
113
114
|
const prompt = tool.getPrompt();
|
|
115
|
+
const parameters = {
|
|
116
|
+
type: prompt.input_schema.type,
|
|
117
|
+
properties: prompt.input_schema.properties,
|
|
118
|
+
required: prompt.input_schema.required,
|
|
119
|
+
additionalProperties: false,
|
|
120
|
+
};
|
|
114
121
|
return {
|
|
115
122
|
type: "function",
|
|
116
123
|
name: prompt.name,
|
|
117
124
|
description: prompt.description,
|
|
118
|
-
parameters
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
additionalProperties: false,
|
|
123
|
-
},
|
|
124
|
-
strict: true,
|
|
125
|
+
parameters,
|
|
126
|
+
// Per tool, not unconditional: strict mode requires `required` to name
|
|
127
|
+
// every property, so one optional parameter would 400 the whole request
|
|
128
|
+
strict: (0, openai_strict_1.canUseStrictSchema)(parameters),
|
|
125
129
|
};
|
|
126
130
|
});
|
|
127
131
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI strict function schemas.
|
|
3
|
+
*
|
|
4
|
+
* `strict: true` is a stronger contract than JSON Schema: OpenAI requires
|
|
5
|
+
* `required` to list *every* key in `properties`, so a tool with an optional
|
|
6
|
+
* parameter is rejected with a 400 before the model ever runs. Sending it
|
|
7
|
+
* unconditionally makes any such tool break the whole request — and since the
|
|
8
|
+
* tool belt is identical on every retry, every request of the session fails.
|
|
9
|
+
*
|
|
10
|
+
* The alternative fix is to declare optional parameters as nullable and require
|
|
11
|
+
* them anyway, per OpenAI's own guidance. In a library that is worse: it
|
|
12
|
+
* changes the schema every *other* provider sees (Gemini does not accept a
|
|
13
|
+
* `["string", "null"]` type union), and it makes each tool responsible for
|
|
14
|
+
* telling an explicit null from an omitted argument. Deciding `strict` per tool
|
|
15
|
+
* leaves the schemas untouched and keeps the guarantee for the tools that can
|
|
16
|
+
* already honour it.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Whether OpenAI will accept this parameter schema under `strict: true`.
|
|
20
|
+
*
|
|
21
|
+
* Conservative on purpose: a false negative costs the schema-adherence
|
|
22
|
+
* guarantee for one tool, a false positive costs the whole request. MCP tools
|
|
23
|
+
* come from servers the host does not control, so "unrecognised shape" has to
|
|
24
|
+
* mean no.
|
|
25
|
+
*/
|
|
26
|
+
export declare function canUseStrictSchema(parameters: unknown): boolean;
|
|
27
|
+
//# sourceMappingURL=openai-strict.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI strict function schemas.
|
|
4
|
+
*
|
|
5
|
+
* `strict: true` is a stronger contract than JSON Schema: OpenAI requires
|
|
6
|
+
* `required` to list *every* key in `properties`, so a tool with an optional
|
|
7
|
+
* parameter is rejected with a 400 before the model ever runs. Sending it
|
|
8
|
+
* unconditionally makes any such tool break the whole request — and since the
|
|
9
|
+
* tool belt is identical on every retry, every request of the session fails.
|
|
10
|
+
*
|
|
11
|
+
* The alternative fix is to declare optional parameters as nullable and require
|
|
12
|
+
* them anyway, per OpenAI's own guidance. In a library that is worse: it
|
|
13
|
+
* changes the schema every *other* provider sees (Gemini does not accept a
|
|
14
|
+
* `["string", "null"]` type union), and it makes each tool responsible for
|
|
15
|
+
* telling an explicit null from an omitted argument. Deciding `strict` per tool
|
|
16
|
+
* leaves the schemas untouched and keeps the guarantee for the tools that can
|
|
17
|
+
* already honour it.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.canUseStrictSchema = canUseStrictSchema;
|
|
21
|
+
/**
|
|
22
|
+
* Whether OpenAI will accept this parameter schema under `strict: true`.
|
|
23
|
+
*
|
|
24
|
+
* Conservative on purpose: a false negative costs the schema-adherence
|
|
25
|
+
* guarantee for one tool, a false positive costs the whole request. MCP tools
|
|
26
|
+
* come from servers the host does not control, so "unrecognised shape" has to
|
|
27
|
+
* mean no.
|
|
28
|
+
*/
|
|
29
|
+
function canUseStrictSchema(parameters) {
|
|
30
|
+
if (!parameters || typeof parameters !== "object")
|
|
31
|
+
return false;
|
|
32
|
+
const schema = parameters;
|
|
33
|
+
const properties = schema.properties && typeof schema.properties === "object"
|
|
34
|
+
? schema.properties
|
|
35
|
+
: {};
|
|
36
|
+
const required = Array.isArray(schema.required) ? schema.required : [];
|
|
37
|
+
// Strict mode also wants `additionalProperties: false` on every nested
|
|
38
|
+
// object, which `getToolDefinitions()` only sets at the top level. Rather
|
|
39
|
+
// than rewrite anyone's schema, treat a nested object as reason enough to
|
|
40
|
+
// drop the guarantee.
|
|
41
|
+
const isNested = (property) => {
|
|
42
|
+
if (!property || typeof property !== "object")
|
|
43
|
+
return false;
|
|
44
|
+
const value = property;
|
|
45
|
+
return value.type === "object" || isNested(value.items);
|
|
46
|
+
};
|
|
47
|
+
return (Object.keys(properties).every((key) => required.includes(key)) &&
|
|
48
|
+
!Object.values(properties).some(isNested));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=openai-strict.js.map
|
package/dist/gemini.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * from "./core";
|
|
2
|
-
export { GeminiAgent } from "./agents/google/GeminiAgent";
|
|
3
|
-
export type { GeminiModelCard } from "./agents/google/GeminiAgent";
|
|
2
|
+
export { GeminiAgent, GEMINI_RETIRED_MODELS, } from "./agents/google/GeminiAgent";
|
|
3
|
+
export type { GeminiModelCard, GeminiListModelsOptions, } from "./agents/google/GeminiAgent";
|
|
4
4
|
export { geminiTransformer } from "./history/transformers";
|
|
5
5
|
//# sourceMappingURL=gemini.d.ts.map
|
package/dist/gemini.js
CHANGED
|
@@ -14,11 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.geminiTransformer = exports.GeminiAgent = void 0;
|
|
17
|
+
exports.geminiTransformer = exports.GEMINI_RETIRED_MODELS = exports.GeminiAgent = void 0;
|
|
18
18
|
// Gemini Agent Entry Point
|
|
19
19
|
__exportStar(require("./core"), exports);
|
|
20
20
|
var GeminiAgent_1 = require("./agents/google/GeminiAgent");
|
|
21
21
|
Object.defineProperty(exports, "GeminiAgent", { enumerable: true, get: function () { return GeminiAgent_1.GeminiAgent; } });
|
|
22
|
+
Object.defineProperty(exports, "GEMINI_RETIRED_MODELS", { enumerable: true, get: function () { return GeminiAgent_1.GEMINI_RETIRED_MODELS; } });
|
|
22
23
|
var transformers_1 = require("./history/transformers");
|
|
23
24
|
Object.defineProperty(exports, "geminiTransformer", { enumerable: true, get: function () { return transformers_1.geminiTransformer; } });
|
|
24
25
|
//# sourceMappingURL=gemini.js.map
|
|
@@ -449,17 +449,34 @@ exports.geminiTransformer = {
|
|
|
449
449
|
name: block.name,
|
|
450
450
|
args: block.input,
|
|
451
451
|
},
|
|
452
|
+
// Gemini 3 requires its own reasoning token back on the part it came
|
|
453
|
+
// from, or it rejects the follow-up request outright
|
|
454
|
+
...(block.thoughtSignature
|
|
455
|
+
? { thoughtSignature: block.thoughtSignature }
|
|
456
|
+
: {}),
|
|
452
457
|
});
|
|
453
458
|
}
|
|
454
459
|
// Add function response parts (for user messages with tool results)
|
|
455
460
|
for (const block of toolResultBlocks) {
|
|
456
|
-
//
|
|
461
|
+
// `functionResponse.response` is a protobuf Struct, so it has to be a
|
|
462
|
+
// JSON *object*. Parsing alone is not enough: a tool returning a plain
|
|
463
|
+
// string is stored as `JSON.stringify(result)`, which parses back to a
|
|
464
|
+
// string rather than throwing, so a bare scalar would go out and Gemini
|
|
465
|
+
// would answer 400 with the tool output quoted back. Anything that is
|
|
466
|
+
// not already an object is nested under `result` — the same shape the
|
|
467
|
+
// parse-failure path produces, so the model sees no difference and no
|
|
468
|
+
// tool has to know about any of this.
|
|
457
469
|
let responseData;
|
|
458
470
|
try {
|
|
459
471
|
responseData = JSON.parse(block.content);
|
|
460
472
|
}
|
|
461
473
|
catch {
|
|
462
|
-
responseData =
|
|
474
|
+
responseData = block.content;
|
|
475
|
+
}
|
|
476
|
+
if (typeof responseData !== "object" ||
|
|
477
|
+
responseData === null ||
|
|
478
|
+
Array.isArray(responseData)) {
|
|
479
|
+
responseData = { result: responseData ?? "" };
|
|
463
480
|
}
|
|
464
481
|
parts.push({
|
|
465
482
|
functionResponse: {
|
|
@@ -485,8 +502,14 @@ exports.geminiTransformer = {
|
|
|
485
502
|
}
|
|
486
503
|
if ("functionCall" in part && part.functionCall) {
|
|
487
504
|
const fc = part.functionCall;
|
|
488
|
-
normalizedContent.push((0, types_1.toolUse)(
|
|
489
|
-
|
|
505
|
+
normalizedContent.push((0, types_1.toolUse)(
|
|
506
|
+
// Deliberately the name, not the `id` the live response also
|
|
507
|
+
// carries: `toProvider` sends a tool result as
|
|
508
|
+
// `functionResponse.name = block.tool_use_id`, and Gemini requires
|
|
509
|
+
// that to be the function name. Keying the block by Gemini's id
|
|
510
|
+
// would desynchronise the tool_use/tool_result pair without
|
|
511
|
+
// buying anything — the id is never echoed back.
|
|
512
|
+
fc.name, fc.name, (fc.args || {}), part.thoughtSignature));
|
|
490
513
|
}
|
|
491
514
|
}
|
|
492
515
|
return {
|
package/dist/history/types.d.ts
CHANGED
|
@@ -19,6 +19,15 @@ export type ToolUseContent = {
|
|
|
19
19
|
id: string;
|
|
20
20
|
name: string;
|
|
21
21
|
input: Record<string, unknown>;
|
|
22
|
+
/**
|
|
23
|
+
* Provider-opaque reasoning token that has to be echoed back verbatim.
|
|
24
|
+
*
|
|
25
|
+
* Gemini 3 returns one beside every `functionCall` and rejects any later
|
|
26
|
+
* request in the conversation that omits it — "Function call is missing a
|
|
27
|
+
* thought_signature in functionCall parts". Nothing reads its contents; it
|
|
28
|
+
* only has to survive the round trip through history.
|
|
29
|
+
*/
|
|
30
|
+
thoughtSignature?: string;
|
|
22
31
|
};
|
|
23
32
|
/**
|
|
24
33
|
* Result of a tool execution
|
|
@@ -174,7 +183,7 @@ export declare function text(value: string): TextContent;
|
|
|
174
183
|
/**
|
|
175
184
|
* Create a tool use content block
|
|
176
185
|
*/
|
|
177
|
-
export declare function toolUse(id: string, name: string, input: Record<string, unknown
|
|
186
|
+
export declare function toolUse(id: string, name: string, input: Record<string, unknown>, thoughtSignature?: string): ToolUseContent;
|
|
178
187
|
/**
|
|
179
188
|
* Create a thinking content block. Pass `redactedData` for redacted thinking.
|
|
180
189
|
*/
|
package/dist/history/types.js
CHANGED
|
@@ -56,8 +56,16 @@ function text(value) {
|
|
|
56
56
|
/**
|
|
57
57
|
* Create a tool use content block
|
|
58
58
|
*/
|
|
59
|
-
function toolUse(id, name, input) {
|
|
60
|
-
|
|
59
|
+
function toolUse(id, name, input, thoughtSignature) {
|
|
60
|
+
// Only set the key when there is one, so a block stored without a signature
|
|
61
|
+
// serializes exactly as it did before the field existed
|
|
62
|
+
return {
|
|
63
|
+
type: "tool_use",
|
|
64
|
+
id,
|
|
65
|
+
name,
|
|
66
|
+
input,
|
|
67
|
+
...(thoughtSignature ? { thoughtSignature } : {}),
|
|
68
|
+
};
|
|
61
69
|
}
|
|
62
70
|
/**
|
|
63
71
|
* Create a thinking content block. Pass `redactedData` for redacted thinking.
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export * from "./agents/anthropic/ClaudeAgent";
|
|
|
3
3
|
export { OpenAiAgent } from "./agents/openai/OpenAiAgent";
|
|
4
4
|
export { MistralAgent } from "./agents/mistral/MistralAgent";
|
|
5
5
|
export type { MistralModelCard } from "./agents/mistral/MistralAgent";
|
|
6
|
-
export { GeminiAgent } from "./agents/google/GeminiAgent";
|
|
7
|
-
export type { GeminiModelCard } from "./agents/google/GeminiAgent";
|
|
6
|
+
export { GeminiAgent, GEMINI_RETIRED_MODELS, } from "./agents/google/GeminiAgent";
|
|
7
|
+
export type { GeminiModelCard, GeminiListModelsOptions, } from "./agents/google/GeminiAgent";
|
|
8
8
|
export { OllamaAgent } from "./agents/ollama/OllamaAgent";
|
|
9
9
|
export type { OllamaModelInfo } from "./agents/ollama/OllamaAgent";
|
|
10
10
|
export { LlamaCppAgent } from "./agents/llamacpp/LlamaCppAgent";
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
22
22
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.chatCompletionsTransformer = exports.ollamaTransformer = exports.geminiTransformer = exports.mistralTransformer = exports.openAiTransformer = exports.anthropicTransformer = exports.OpenAICompatibleAgent = exports.LlamaCppAgent = exports.OllamaAgent = exports.GeminiAgent = exports.MistralAgent = exports.OpenAiAgent = void 0;
|
|
25
|
+
exports.chatCompletionsTransformer = exports.ollamaTransformer = exports.geminiTransformer = exports.mistralTransformer = exports.openAiTransformer = exports.anthropicTransformer = exports.OpenAICompatibleAgent = exports.LlamaCppAgent = exports.OllamaAgent = exports.GEMINI_RETIRED_MODELS = exports.GeminiAgent = exports.MistralAgent = exports.OpenAiAgent = void 0;
|
|
26
26
|
// Agents
|
|
27
27
|
__exportStar(require("./agents/BaseAgent"), exports);
|
|
28
28
|
__exportStar(require("./agents/anthropic/ClaudeAgent"), exports);
|
|
@@ -32,6 +32,7 @@ var MistralAgent_1 = require("./agents/mistral/MistralAgent");
|
|
|
32
32
|
Object.defineProperty(exports, "MistralAgent", { enumerable: true, get: function () { return MistralAgent_1.MistralAgent; } });
|
|
33
33
|
var GeminiAgent_1 = require("./agents/google/GeminiAgent");
|
|
34
34
|
Object.defineProperty(exports, "GeminiAgent", { enumerable: true, get: function () { return GeminiAgent_1.GeminiAgent; } });
|
|
35
|
+
Object.defineProperty(exports, "GEMINI_RETIRED_MODELS", { enumerable: true, get: function () { return GeminiAgent_1.GEMINI_RETIRED_MODELS; } });
|
|
35
36
|
var OllamaAgent_1 = require("./agents/ollama/OllamaAgent");
|
|
36
37
|
Object.defineProperty(exports, "OllamaAgent", { enumerable: true, get: function () { return OllamaAgent_1.OllamaAgent; } });
|
|
37
38
|
var LlamaCppAgent_1 = require("./agents/llamacpp/LlamaCppAgent");
|