agent-accelerator 0.4.0 → 0.4.5
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/package.json +1 -1
- package/src/agent/agent.ts +16 -1
- package/src/agent/loop.ts +74 -1
- package/src/index.ts +19 -0
- package/src/models/catalog.ts +26 -0
- package/src/providers/google.ts +56 -7
- package/src/providers/openai-compat.ts +110 -20
- package/src/providers/openai.ts +128 -13
- package/src/providers/openrouter.ts +89 -15
- package/src/providers/shared.ts +63 -5
- package/src/providers.ts +256 -5
- package/src/session/store.ts +18 -9
- package/src/types/agent.ts +17 -2
- package/src/types/model.ts +21 -0
- package/src/types/response.ts +7 -0
- package/src/utils/env.ts +21 -7
- package/src/utils/errors.ts +15 -1
- package/src/utils/headers.ts +1 -1
package/src/types/agent.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
} from "./core.ts";
|
|
8
8
|
import type { ModelProviderInstance } from "../providers/registry.ts";
|
|
9
9
|
import type { Agent } from "../agent/agent.ts";
|
|
10
|
+
import type { z } from "zod";
|
|
10
11
|
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
12
13
|
// Q-52/Q-53/Q-54 canonical option types (all additive; nothing renamed).
|
|
@@ -61,6 +62,17 @@ export type ToolChoiceOption =
|
|
|
61
62
|
/** Canonical stop control (Q-54): sequence(s) halting generation. */
|
|
62
63
|
export type StopOption = string | string[];
|
|
63
64
|
|
|
65
|
+
/** Canonical structured-output input (Q-61). Zod, JSON Schema, or explicit form. */
|
|
66
|
+
export type StructuredOutputOption =
|
|
67
|
+
| z.ZodType
|
|
68
|
+
| Record<string, unknown>
|
|
69
|
+
| {
|
|
70
|
+
name?: string;
|
|
71
|
+
description?: string;
|
|
72
|
+
schema: z.ZodType | Record<string, unknown>;
|
|
73
|
+
strict?: boolean;
|
|
74
|
+
};
|
|
75
|
+
|
|
64
76
|
/** Configuration used to construct an {@link Agent}. */
|
|
65
77
|
export interface AgentConfig {
|
|
66
78
|
/** Display name used in tool and sub-agent metadata. */
|
|
@@ -142,9 +154,12 @@ export interface AgentConfig {
|
|
|
142
154
|
/** Deterministic seed, when the provider supports it. */
|
|
143
155
|
seed?: number;
|
|
144
156
|
/**
|
|
145
|
-
* Optional output schema (Zod
|
|
157
|
+
* Optional output schema (Zod, JSON Schema, or `{ name, schema, strict }`,
|
|
158
|
+
* see `StructuredOutputOption`, stored as `unknown` so `zod`
|
|
146
159
|
* stays optional for type-only consumers). Agent-level only; per-run
|
|
147
|
-
* overrides are intentionally unsupported.
|
|
160
|
+
* overrides are intentionally unsupported. When set, the model answer is
|
|
161
|
+
* constrained to the schema on all providers and `AgentResponse.parsed`
|
|
162
|
+
* carries the validated value.
|
|
148
163
|
*/
|
|
149
164
|
output?: unknown;
|
|
150
165
|
/** Retry policy for provider calls. */
|
package/src/types/model.ts
CHANGED
|
@@ -87,6 +87,7 @@ export interface ModelCapabilities {
|
|
|
87
87
|
supportsLongCacheRetention?: boolean;
|
|
88
88
|
supportsParallelToolCalls?: boolean;
|
|
89
89
|
supportsStreaming?: boolean;
|
|
90
|
+
supportsStructuredOutput?: boolean;
|
|
90
91
|
modalities?: ("text" | "image" | "audio" | "video" | "pdf")[];
|
|
91
92
|
// derived
|
|
92
93
|
supportsReasoningToggle?: boolean;
|
|
@@ -138,6 +139,24 @@ export interface ModelSpec {
|
|
|
138
139
|
raw?: RawModelData;
|
|
139
140
|
}
|
|
140
141
|
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// Structured outputs — normalized, provider-agnostic spec.
|
|
144
|
+
// Canonical input is `AgentConfig.output` (Zod, JSON Schema, or explicit
|
|
145
|
+
// `{ name, schema, strict }`); `normalizeStructuredOutput` in
|
|
146
|
+
// `src/providers.ts` produces this shape for adapters.
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
/** Normalized structured-output request passed from Agent to providers. */
|
|
149
|
+
export interface StructuredOutputSpec {
|
|
150
|
+
/** Format name (1-64 chars, `[a-zA-Z0-9_-]`). Defaults to `structured_output`. */
|
|
151
|
+
name: string;
|
|
152
|
+
/** JSON Schema for the final answer (already converted from Zod when needed). */
|
|
153
|
+
schema: Record<string, unknown>;
|
|
154
|
+
/** Strict schema adherence (OpenAI/OpenRouter only; ignored by Google). Defaults to true. */
|
|
155
|
+
strict?: boolean;
|
|
156
|
+
/** Optional description of what the format is for. */
|
|
157
|
+
description?: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
141
160
|
// ---------------------------------------------------------------------------
|
|
142
161
|
// Provider plumbing — unchanged API
|
|
143
162
|
// ---------------------------------------------------------------------------
|
|
@@ -156,6 +175,8 @@ export interface ProviderRequestOptions {
|
|
|
156
175
|
env?: Record<string, string>;
|
|
157
176
|
maxRetries?: number;
|
|
158
177
|
maxRetryDelayMs?: number;
|
|
178
|
+
/** Normalized structured-output spec (see `normalizeStructuredOutput`). */
|
|
179
|
+
output?: StructuredOutputSpec;
|
|
159
180
|
}
|
|
160
181
|
|
|
161
182
|
/** Auditable request/response wire payload captured in AgentResponse. */
|
package/src/types/response.ts
CHANGED
|
@@ -101,6 +101,8 @@ export function normalizeFinishReason(raw?: string): {
|
|
|
101
101
|
/** JSON representation returned by AgentResponse.toJSON(). */
|
|
102
102
|
export interface AgentResponseJSON {
|
|
103
103
|
text: string;
|
|
104
|
+
/** Validated structured-output value when `AgentConfig.output` was set. */
|
|
105
|
+
parsed?: unknown;
|
|
104
106
|
thinking?: string;
|
|
105
107
|
thoughtSignature?: string;
|
|
106
108
|
toolCalls?: ToolCallRecord[];
|
|
@@ -121,6 +123,8 @@ export interface AgentResponseJSON {
|
|
|
121
123
|
/** Normalized final result returned by every Agent run. */
|
|
122
124
|
export class AgentResponse {
|
|
123
125
|
readonly text: string;
|
|
126
|
+
/** Validated structured-output value when `AgentConfig.output` was set. */
|
|
127
|
+
readonly parsed?: unknown;
|
|
124
128
|
readonly thinking?: string;
|
|
125
129
|
readonly thoughtSignature?: string;
|
|
126
130
|
readonly toolCalls: ToolCallRecord[];
|
|
@@ -146,6 +150,7 @@ export class AgentResponse {
|
|
|
146
150
|
*/
|
|
147
151
|
constructor(data: {
|
|
148
152
|
text: string;
|
|
153
|
+
parsed?: unknown;
|
|
149
154
|
thinking?: string;
|
|
150
155
|
thoughtSignature?: string;
|
|
151
156
|
toolCalls?: ToolCallRecord[];
|
|
@@ -162,6 +167,7 @@ export class AgentResponse {
|
|
|
162
167
|
turns?: number;
|
|
163
168
|
}) {
|
|
164
169
|
this.text = data.text;
|
|
170
|
+
if (data.parsed !== undefined) (this as { parsed?: unknown }).parsed = data.parsed;
|
|
165
171
|
this.thinking = data.thinking;
|
|
166
172
|
this.thoughtSignature = data.thoughtSignature;
|
|
167
173
|
this.toolCalls = data.toolCalls ?? [];
|
|
@@ -187,6 +193,7 @@ export class AgentResponse {
|
|
|
187
193
|
toJSON(): AgentResponseJSON {
|
|
188
194
|
return {
|
|
189
195
|
text: this.text,
|
|
196
|
+
...(this.parsed !== undefined ? { parsed: this.parsed } : {}),
|
|
190
197
|
thinking: this.thinking,
|
|
191
198
|
thoughtSignature: this.thoughtSignature,
|
|
192
199
|
toolCalls: this.toolCalls.length > 0 ? this.toolCalls : undefined,
|
package/src/utils/env.ts
CHANGED
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export function getEnv(key: string, fallback?: string): string | undefined {
|
|
11
11
|
if (typeof process !== "undefined" && process.env && process.env[key]) {
|
|
12
|
-
|
|
12
|
+
// Trim quotes/whitespace from .env files (`sk-..."\n` -> 401 otherwise).
|
|
13
|
+
const raw = String(process.env[key]);
|
|
14
|
+
const trimmed = raw.trim().replace(/^["']|["']$/g, "").trim();
|
|
15
|
+
if (trimmed) return trimmed;
|
|
13
16
|
}
|
|
14
17
|
return fallback;
|
|
15
18
|
}
|
|
@@ -22,20 +25,31 @@ export type ProviderEnv = Record<string, string>;
|
|
|
22
25
|
* @example `const key = getApiKey("google");`
|
|
23
26
|
*/
|
|
24
27
|
export function getApiKey(provider: string, explicitKey?: string, env?: ProviderEnv): string | undefined {
|
|
25
|
-
|
|
28
|
+
const clean = (v: unknown): string | undefined => {
|
|
29
|
+
if (typeof v !== "string") return undefined;
|
|
30
|
+
const t = v.trim().replace(/^["']|["']$/g, "").trim();
|
|
31
|
+
return t || undefined;
|
|
32
|
+
};
|
|
33
|
+
const cleanedExplicit = clean(explicitKey);
|
|
34
|
+
if (cleanedExplicit) return cleanedExplicit;
|
|
26
35
|
// ProviderEnv override takes precedence (agent-accel inspiration, SDK-light)
|
|
27
36
|
if (env) {
|
|
28
37
|
const upper = `${provider.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_API_KEY`;
|
|
29
|
-
|
|
38
|
+
const fromEnv = clean(env[upper]);
|
|
39
|
+
if (fromEnv) return fromEnv;
|
|
30
40
|
// google aliases
|
|
31
41
|
if (provider.toLowerCase().startsWith("google") || provider.toLowerCase() === "gemini") {
|
|
32
|
-
|
|
33
|
-
if (
|
|
42
|
+
const g1 = clean(env["GEMINI_API_KEY"]);
|
|
43
|
+
if (g1) return g1;
|
|
44
|
+
const g2 = clean(env["GOOGLE_API_KEY"]);
|
|
45
|
+
if (g2) return g2;
|
|
34
46
|
}
|
|
35
47
|
// openai aliases
|
|
36
48
|
if (provider.toLowerCase() === "openai") {
|
|
37
|
-
|
|
38
|
-
if (
|
|
49
|
+
const o1 = clean(env["OPENAI_BASE_API_KEY"]);
|
|
50
|
+
if (o1) return o1;
|
|
51
|
+
const o2 = clean(env["OPENAI_API_KEY"]);
|
|
52
|
+
if (o2) return o2;
|
|
39
53
|
}
|
|
40
54
|
}
|
|
41
55
|
|
package/src/utils/errors.ts
CHANGED
|
@@ -54,7 +54,18 @@ export function toConciseProviderError(error: unknown, providerId: string, model
|
|
|
54
54
|
const err = error as any;
|
|
55
55
|
const status = readStatus(err);
|
|
56
56
|
const url = readUrl(err);
|
|
57
|
-
|
|
57
|
+
let detail = readProviderMessage(err);
|
|
58
|
+
// Append OpenRouter-style raw metadata once (pi api/openai-completions.ts:719
|
|
59
|
+
// rule): normalize already stringifies error.error, so only append raw when
|
|
60
|
+
// absent to avoid double-printing.
|
|
61
|
+
const rawMeta =
|
|
62
|
+
(typeof err?.raw === "string" && err.raw.trim() ? err.raw.trim() : undefined) ??
|
|
63
|
+
(typeof err?.error?.metadata?.raw === "string" && err.error.metadata.raw.trim()
|
|
64
|
+
? err.error.metadata.raw.trim()
|
|
65
|
+
: undefined);
|
|
66
|
+
if (rawMeta && !detail.includes(rawMeta.slice(0, 80))) {
|
|
67
|
+
detail = `${detail}\n${rawMeta.slice(0, 500)}`.slice(0, 800);
|
|
68
|
+
}
|
|
58
69
|
const concise = new Error(
|
|
59
70
|
`[${displayModel(providerId, modelId)}] request failed${status ? ` (${status})` : ""}: ${detail}`
|
|
60
71
|
);
|
|
@@ -75,6 +86,9 @@ export function toConciseProviderError(error: unknown, providerId: string, model
|
|
|
75
86
|
...(typeof err?.errorType === "string"
|
|
76
87
|
? { errorType: { value: err.errorType, enumerable: false } }
|
|
77
88
|
: {}),
|
|
89
|
+
...(typeof (err as { raw?: unknown })?.raw === "string"
|
|
90
|
+
? { raw: { value: (err as { raw: string }).raw.slice(0, 500), enumerable: false } }
|
|
91
|
+
: {}),
|
|
78
92
|
});
|
|
79
93
|
return concise;
|
|
80
94
|
}
|
package/src/utils/headers.ts
CHANGED
|
@@ -24,7 +24,7 @@ export function getPackageVersion(): string {
|
|
|
24
24
|
const v = (globalThis as any).process?.env?.npm_package_version;
|
|
25
25
|
if (typeof v === "string" && v) return v;
|
|
26
26
|
} catch {}
|
|
27
|
-
return "0.4.
|
|
27
|
+
return "0.4.5";
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function getAgentAccelUserAgent(): string {
|