@~lyre/ai-agents 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Britam Trust Services / Lyre
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # @lyre/ai-agents
2
+
3
+ Multi-provider AI agents SDK for SvelteKit and Node. Thin agent/tool/run/runStream API on top of the [Vercel AI SDK](https://ai-sdk.dev/) — supports OpenAI, Anthropic, Google Gemini, Mistral, Cohere, and any other provider the AI SDK targets.
4
+
5
+ ## Why
6
+
7
+ The original `@kigathi/ai-agents` v1.1.0 (in `belva/axis/packages/lyre-ai-agents-node`) was OpenAI-only and built directly on `openai.responses.create()`. Locking the AI advisor to one vendor is bad insurance — when Anthropic ships a 10× cheaper model, you want to switch in a config line. This package preserves the original's developer-facing API (`createClient` → `registerTool` / `createAgent` / `run` / `runStream`) but routes everything through the AI SDK's provider-agnostic `generateText` / `streamText`.
8
+
9
+ ## Quick start
10
+
11
+ ```bash
12
+ pnpm add @lyre/ai-agents ai zod
13
+ pnpm add @ai-sdk/anthropic # or @ai-sdk/openai, @ai-sdk/google, etc.
14
+ ```
15
+
16
+ ```ts
17
+ import { createClient } from '@lyre/ai-agents';
18
+ import { z } from 'zod';
19
+
20
+ const ai = createClient();
21
+
22
+ ai.registerTool({
23
+ name: 'book_advisor_call',
24
+ description: 'Capture the user\'s intent to speak with a human advisor.',
25
+ inputSchema: z.object({
26
+ reason: z.string(),
27
+ preferred_time: z.string().optional()
28
+ }),
29
+ execute: async (input, { app }) => {
30
+ // app.userId, app.guestUuid, app.locale, etc. — whatever you put in RunParams.context
31
+ return { booked: true, ticketId: 'demo-1234' };
32
+ }
33
+ });
34
+
35
+ ai.createAgent({
36
+ name: 'advisor',
37
+ model: 'anthropic/claude-sonnet-4.5',
38
+ instructions: 'You are a calm wealth advisor...',
39
+ tools: ['book_advisor_call'],
40
+ temperature: 0.7,
41
+ providerOptions: {
42
+ anthropic: { cacheControl: { type: 'ephemeral' } } // prompt caching
43
+ }
44
+ });
45
+
46
+ // Non-streaming
47
+ const result = await ai.run({
48
+ agent: 'advisor',
49
+ message: 'Should I write a will?',
50
+ history: [],
51
+ context: { userId: 'u_123' }
52
+ });
53
+ console.log(result.text);
54
+
55
+ // Streaming
56
+ for await (const ev of ai.runStream({ agent: 'advisor', message: 'Hi' })) {
57
+ if (ev.type === 'text-delta') process.stdout.write(ev.text);
58
+ if (ev.type === 'tool-call') console.log('\ntool-call:', ev.toolName, ev.input);
59
+ if (ev.type === 'tool-result') console.log('tool-result:', ev.toolName, ev.output);
60
+ if (ev.type === 'finish') console.log('\nusage:', ev.usage);
61
+ }
62
+ ```
63
+
64
+ Provider authentication uses environment variables (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY`, …). To use a non-standard endpoint or test fixture, pass a constructed `LanguageModel` object to `createAgent({ model })` instead of a string.
65
+
66
+ ## What's different from `@kigathi/ai-agents`
67
+
68
+ | Surface | `@kigathi/ai-agents` v1.1.0 | `@lyre/ai-agents` |
69
+ |---|---|---|
70
+ | Providers | OpenAI only (Responses API) | OpenAI, Anthropic, Google, Mistral, Cohere, … (Vercel AI SDK) |
71
+ | Streaming events | Text deltas only | Full event stream: `text-delta`, `tool-call`, `tool-result`, `tool-error`, `finish`, `error` |
72
+ | Tool schemas | Loose JSON schema | Zod-typed `inputSchema`, type-safe `execute` |
73
+ | Modes (direct / proxy / persistence) | Built in | **Dropped** — apps own their persistence and routing |
74
+ | TTS, read-aloud | Built in | **Dropped** for the POC. Re-add if needed. |
75
+ | Conversation state | In-memory `Map` | **Dropped** — apps own their conversation persistence |
76
+ | Prompt caching | Not exposed | Forwarded via `agent.providerOptions` |
77
+ | Language | JavaScript | TypeScript |
78
+
79
+ If you need TTS or the read-aloud UI from the original, port those modules separately — they're orthogonal to the agent runtime.
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@~lyre/ai-agents",
3
+ "version": "0.1.0",
4
+ "description": "Multi-provider AI agents SDK for SvelteKit + Node. Thin agent/tool/run/runStream surface over the Vercel AI SDK — OpenAI, Anthropic, Google Gemini, Mistral, Cohere. Zod-typed tools, full streaming event surface, optional HTML sanitizer.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "license": "MIT",
8
+ "author": "Britam Trust Services / Lyre",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/REPLACE_ME/britam-legacy.git",
12
+ "directory": "packages/ai-agents"
13
+ },
14
+ "homepage": "https://github.com/REPLACE_ME/britam-legacy/tree/main/packages/ai-agents#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/REPLACE_ME/britam-legacy/issues"
17
+ },
18
+ "keywords": [
19
+ "ai",
20
+ "llm",
21
+ "openai",
22
+ "anthropic",
23
+ "google-gemini",
24
+ "vercel-ai-sdk",
25
+ "tools",
26
+ "agents",
27
+ "streaming",
28
+ "sveltekit",
29
+ "lyre"
30
+ ],
31
+ "main": "./src/index.ts",
32
+ "types": "./src/index.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./src/index.ts",
36
+ "import": "./src/index.ts"
37
+ },
38
+ "./sanitize": {
39
+ "types": "./src/sanitize.ts",
40
+ "import": "./src/sanitize.ts"
41
+ }
42
+ },
43
+ "files": [
44
+ "src",
45
+ "README.md",
46
+ "LICENSE"
47
+ ],
48
+ "scripts": {
49
+ "check": "tsc --noEmit"
50
+ },
51
+ "peerDependencies": {
52
+ "ai": "^6.0.0",
53
+ "zod": "^3.23.0 || ^4.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^22",
57
+ "ai": "^6.0.0",
58
+ "typescript": "^6.0.2",
59
+ "zod": "^4.0.0"
60
+ },
61
+ "publishConfig": {
62
+ "access": "public"
63
+ }
64
+ }
package/src/agents.ts ADDED
@@ -0,0 +1,53 @@
1
+ import type { Agent, AgentDefinition, ToolDefinition } from './types';
2
+
3
+ /**
4
+ * In-memory registry of agents and tools. One per `Client`.
5
+ */
6
+ export class Registry {
7
+ readonly tools = new Map<string, ToolDefinition>();
8
+ readonly agents = new Map<string, Agent>();
9
+
10
+ registerTool<I, O>(tool: ToolDefinition<I, O>): ToolDefinition<I, O> {
11
+ this.tools.set(tool.name, tool as unknown as ToolDefinition);
12
+ return tool;
13
+ }
14
+
15
+ createAgent(definition: AgentDefinition): Agent {
16
+ const agent: Agent = {
17
+ id: definition.id ?? definition.name,
18
+ name: definition.name,
19
+ model: definition.model,
20
+ instructions: definition.instructions ?? '',
21
+ temperature: definition.temperature,
22
+ maxOutputTokens: definition.maxOutputTokens,
23
+ tools: definition.tools,
24
+ providerOptions: definition.providerOptions,
25
+ metadata: definition.metadata
26
+ };
27
+
28
+ this.agents.set(agent.id, agent);
29
+ // Also key by name when distinct from id, so consumers can look up by either.
30
+ if (agent.name !== agent.id) this.agents.set(agent.name, agent);
31
+ return agent;
32
+ }
33
+
34
+ resolveAgent(input: string | AgentDefinition): Agent {
35
+ if (typeof input !== 'string') {
36
+ // Allow callers to pass a fully-formed definition for one-off calls.
37
+ return this.createAgent(input);
38
+ }
39
+ const found = this.agents.get(input);
40
+ if (!found) throw new Error(`Unknown agent: ${input}`);
41
+ return found;
42
+ }
43
+
44
+ resolveTools(agent: Agent): ToolDefinition[] {
45
+ const names = agent.tools && agent.tools.length > 0 ? agent.tools : [...this.tools.keys()];
46
+ const out: ToolDefinition[] = [];
47
+ for (const name of names) {
48
+ const tool = this.tools.get(name);
49
+ if (tool) out.push(tool);
50
+ }
51
+ return out;
52
+ }
53
+ }
package/src/client.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { Registry } from './agents';
2
+ import { run, runStream } from './run';
3
+ import type {
4
+ Agent,
5
+ AgentDefinition,
6
+ RunParams,
7
+ RunResult,
8
+ StreamEvent,
9
+ ToolDefinition
10
+ } from './types';
11
+
12
+ /**
13
+ * AI agents client. Stateless besides the agent/tool registry; create one per app
14
+ * (or per request — they're cheap).
15
+ */
16
+ export class AiAgentsClient {
17
+ private readonly registry: Registry;
18
+
19
+ constructor() {
20
+ this.registry = new Registry();
21
+ }
22
+
23
+ registerTool<I, O>(tool: ToolDefinition<I, O>): ToolDefinition<I, O> {
24
+ return this.registry.registerTool(tool);
25
+ }
26
+
27
+ createAgent(definition: AgentDefinition): Agent {
28
+ return this.registry.createAgent(definition);
29
+ }
30
+
31
+ async run(params: RunParams): Promise<RunResult> {
32
+ return run(this.registry, params);
33
+ }
34
+
35
+ runStream(params: RunParams): AsyncGenerator<StreamEvent, void, unknown> {
36
+ return runStream(this.registry, params);
37
+ }
38
+
39
+ /** Direct access to the underlying registry for advanced introspection. */
40
+ get raw(): Registry {
41
+ return this.registry;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Factory. Provider auth comes from environment variables. To explicitly configure
47
+ * provider clients (e.g., for testing), pass `LanguageModel` instances to
48
+ * `createAgent({ model })` instead of string identifiers.
49
+ */
50
+ export function createClient(): AiAgentsClient {
51
+ return new AiAgentsClient();
52
+ }
package/src/index.ts ADDED
@@ -0,0 +1,19 @@
1
+ // Public API
2
+ export { createClient, AiAgentsClient } from './client';
3
+ export { Registry } from './agents';
4
+ export { run, runStream } from './run';
5
+ export { sanitizeRichHtml } from './sanitize';
6
+
7
+ // Types
8
+ export type {
9
+ ModelId,
10
+ ModelLike,
11
+ Message,
12
+ ToolDefinition,
13
+ ToolContext,
14
+ AgentDefinition,
15
+ Agent,
16
+ RunParams,
17
+ RunResult,
18
+ StreamEvent
19
+ } from './types';
package/src/run.ts ADDED
@@ -0,0 +1,153 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ import { generateText, streamText, tool, type ModelMessage, type Tool } from 'ai';
3
+ import type { Registry } from './agents';
4
+ import type {
5
+ Message,
6
+ RunParams,
7
+ RunResult,
8
+ StreamEvent,
9
+ Agent,
10
+ ToolDefinition
11
+ } from './types';
12
+
13
+ function buildMessages(agent: Agent, params: RunParams): ModelMessage[] {
14
+ const messages: ModelMessage[] = [];
15
+
16
+ const history = params.history ?? [];
17
+ const hasSystem = history.some((m) => m.role === 'system');
18
+ if (!hasSystem && agent.instructions) {
19
+ messages.push({ role: 'system', content: agent.instructions });
20
+ }
21
+
22
+ for (const m of history) messages.push(m as unknown as ModelMessage);
23
+
24
+ if (params.message) {
25
+ messages.push({ role: 'user', content: params.message });
26
+ }
27
+
28
+ return messages;
29
+ }
30
+
31
+ function buildTools(
32
+ registry: Registry,
33
+ agent: Agent,
34
+ context: Record<string, unknown>
35
+ ): Record<string, Tool> {
36
+ const defs = registry.resolveTools(agent);
37
+ const out: Record<string, Tool> = {};
38
+ for (const def of defs as ToolDefinition[]) {
39
+ out[def.name] = tool({
40
+ description: def.description,
41
+ inputSchema: def.inputSchema,
42
+ execute: async (input, opts: { toolCallId: string }) =>
43
+ def.execute(input, { toolCallId: opts.toolCallId, app: context })
44
+ });
45
+ }
46
+ return out;
47
+ }
48
+
49
+ export async function run(registry: Registry, params: RunParams): Promise<RunResult> {
50
+ const agent = registry.resolveAgent(params.agent);
51
+ const messages = buildMessages(agent, params);
52
+ const tools = buildTools(registry, agent, params.context ?? {});
53
+
54
+ const result = await generateText({
55
+ model: agent.model,
56
+ messages,
57
+ tools,
58
+ temperature: params.temperature ?? agent.temperature,
59
+ maxOutputTokens: params.maxOutputTokens ?? agent.maxOutputTokens,
60
+ stopWhen: ({ steps }) => steps.length >= (params.maxSteps ?? 8),
61
+ providerOptions: agent.providerOptions
62
+ });
63
+
64
+ return {
65
+ text: result.text,
66
+ finishReason: result.finishReason as string,
67
+ usage: {
68
+ inputTokens: result.usage?.inputTokens ?? 0,
69
+ outputTokens: result.usage?.outputTokens ?? 0,
70
+ totalTokens: result.usage?.totalTokens ?? 0
71
+ },
72
+ toolCalls: (result.toolCalls ?? []).map((c) => ({
73
+ toolCallId: c.toolCallId,
74
+ toolName: c.toolName,
75
+ input: c.input
76
+ })),
77
+ toolResults: (result.toolResults ?? []).map((r) => ({
78
+ toolCallId: r.toolCallId,
79
+ toolName: r.toolName,
80
+ output: (r as { output: unknown }).output
81
+ })),
82
+ raw: result
83
+ };
84
+ }
85
+
86
+ export async function* runStream(
87
+ registry: Registry,
88
+ params: RunParams
89
+ ): AsyncGenerator<StreamEvent, void, unknown> {
90
+ const agent = registry.resolveAgent(params.agent);
91
+ const messages = buildMessages(agent, params);
92
+ const tools = buildTools(registry, agent, params.context ?? {});
93
+
94
+ const result = streamText({
95
+ model: agent.model,
96
+ messages,
97
+ tools,
98
+ temperature: params.temperature ?? agent.temperature,
99
+ maxOutputTokens: params.maxOutputTokens ?? agent.maxOutputTokens,
100
+ stopWhen: ({ steps }) => steps.length >= (params.maxSteps ?? 8),
101
+ providerOptions: agent.providerOptions
102
+ });
103
+
104
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
105
+ for await (const part of result.fullStream as AsyncIterable<any>) {
106
+ switch (part.type) {
107
+ case 'text-delta':
108
+ yield { type: 'text-delta', text: part.text ?? part.delta ?? '' };
109
+ break;
110
+ case 'tool-call':
111
+ yield {
112
+ type: 'tool-call',
113
+ toolCallId: part.toolCallId,
114
+ toolName: part.toolName,
115
+ input: part.input ?? part.args
116
+ };
117
+ break;
118
+ case 'tool-result':
119
+ yield {
120
+ type: 'tool-result',
121
+ toolCallId: part.toolCallId,
122
+ toolName: part.toolName,
123
+ output: part.output ?? part.result
124
+ };
125
+ break;
126
+ case 'tool-error':
127
+ yield {
128
+ type: 'tool-error',
129
+ toolCallId: part.toolCallId,
130
+ toolName: part.toolName,
131
+ error: part.error
132
+ };
133
+ break;
134
+ case 'finish':
135
+ yield {
136
+ type: 'finish',
137
+ finishReason: part.finishReason,
138
+ usage: {
139
+ inputTokens: part.usage?.inputTokens ?? 0,
140
+ outputTokens: part.usage?.outputTokens ?? 0,
141
+ totalTokens: part.usage?.totalTokens ?? 0
142
+ }
143
+ };
144
+ break;
145
+ case 'error':
146
+ yield { type: 'error', error: part.error };
147
+ break;
148
+ // Silently drop other chunk types (start/step boundaries, raw text accumulators, etc.).
149
+ }
150
+ }
151
+ }
152
+
153
+ export type { Message };
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Minimal HTML sanitizer for AI-generated rich text. Strips script/style/iframe and
3
+ * inline event handlers; keeps a small allowlist of tags and attributes suitable for
4
+ * advisor output.
5
+ *
6
+ * Ported from @kigathi/ai-agents v1.1.0 with minor TS typing tweaks.
7
+ */
8
+
9
+ const ALLOWED_TAGS = new Set([
10
+ 'a',
11
+ 'b',
12
+ 'blockquote',
13
+ 'br',
14
+ 'code',
15
+ 'div',
16
+ 'em',
17
+ 'h1',
18
+ 'h2',
19
+ 'h3',
20
+ 'h4',
21
+ 'h5',
22
+ 'h6',
23
+ 'hr',
24
+ 'i',
25
+ 'li',
26
+ 'ol',
27
+ 'p',
28
+ 'pre',
29
+ 'span',
30
+ 'strong',
31
+ 'table',
32
+ 'tbody',
33
+ 'td',
34
+ 'th',
35
+ 'thead',
36
+ 'tr',
37
+ 'u',
38
+ 'ul'
39
+ ]);
40
+
41
+ const ALLOWED_ATTRS: Record<string, Set<string>> = {
42
+ a: new Set(['href', 'title', 'target', 'rel']),
43
+ '*': new Set(['class'])
44
+ };
45
+
46
+ const UNSAFE_PROTOCOLS = /^\s*(javascript|data|vbscript):/i;
47
+
48
+ export function sanitizeRichHtml(input: string | null | undefined): string {
49
+ if (!input) return '';
50
+ let html = String(input);
51
+
52
+ // Strip dangerous tags wholesale.
53
+ html = html.replace(/<\s*(script|style|iframe|object|embed|link|meta)[^>]*>[\s\S]*?<\s*\/\s*\1\s*>/gi, '');
54
+ html = html.replace(/<\s*(script|style|iframe|object|embed|link|meta)[^>]*\/?\s*>/gi, '');
55
+
56
+ // Strip on* attributes.
57
+ html = html.replace(/\s+on[a-z]+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, '');
58
+
59
+ // Strip unsafe href/src values.
60
+ html = html.replace(
61
+ /\s+(href|src)\s*=\s*("(?:[^"]*?)"|'(?:[^']*?)'|[^\s>]+)/gi,
62
+ (match, attr: string, value: string) => {
63
+ const v = value.replace(/^['"]|['"]$/g, '');
64
+ if (UNSAFE_PROTOCOLS.test(v)) return '';
65
+ return ` ${attr}="${v.replace(/"/g, '&quot;')}"`;
66
+ }
67
+ );
68
+
69
+ // Optional: drop tags not in allowlist. We do this last so attribute stripping above
70
+ // applies to the broader HTML stream first.
71
+ html = html.replace(/<\s*\/?\s*([a-zA-Z][a-zA-Z0-9]*)\b[^>]*>/g, (match, tagName: string) => {
72
+ const lower = tagName.toLowerCase();
73
+ if (ALLOWED_TAGS.has(lower)) return match;
74
+ return '';
75
+ });
76
+
77
+ return html;
78
+ }
79
+
80
+ export { ALLOWED_TAGS, ALLOWED_ATTRS };
package/src/types.ts ADDED
@@ -0,0 +1,110 @@
1
+ import type { z } from 'zod';
2
+
3
+ /**
4
+ * A model identifier. Vercel AI SDK v6 accepts strings like `'openai/gpt-4o'`,
5
+ * `'anthropic/claude-sonnet-4.5'`, `'google/gemini-2.5-flash'`. Provider auth comes
6
+ * from environment variables (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`,
7
+ * `GOOGLE_GENERATIVE_AI_API_KEY`) unless you wire an explicit provider object.
8
+ */
9
+ export type ModelId = string;
10
+
11
+ /**
12
+ * Anything `streamText` / `generateText` accepts as `model`. Use a string for
13
+ * registry-resolved providers; pass a `LanguageModel` instance for custom wiring.
14
+ */
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ export type ModelLike = ModelId | { specificationVersion: string; [k: string]: any };
17
+
18
+ export type ToolDefinition<Input = unknown, Output = unknown> = {
19
+ name: string;
20
+ description: string;
21
+ /**
22
+ * Zod schema for the tool's input arguments. The AI SDK uses this to constrain
23
+ * the model's function-call output and to type the `execute` callback.
24
+ */
25
+ inputSchema: z.ZodSchema<Input>;
26
+ execute: (input: Input, context: ToolContext) => Promise<Output> | Output;
27
+ };
28
+
29
+ export type ToolContext = {
30
+ /** Unique tool call id from the model, useful for correlating tool-call → tool-result. */
31
+ toolCallId: string;
32
+ /** Forwarded from RunParams.context — apps thread per-request state (user id, locale, etc.). */
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ app: Record<string, any>;
35
+ };
36
+
37
+ export type Message =
38
+ | { role: 'system'; content: string }
39
+ | { role: 'user'; content: string }
40
+ | { role: 'assistant'; content: string };
41
+
42
+ export type AgentDefinition = {
43
+ /** Stable identifier; used as the lookup key. Defaults to `name`. */
44
+ id?: string;
45
+ name: string;
46
+ model: ModelLike;
47
+ /** System prompt. Inserted as a `system` message when no system message is in the history. */
48
+ instructions?: string;
49
+ temperature?: number;
50
+ maxOutputTokens?: number;
51
+ /**
52
+ * Tool names this agent may call. If omitted, all globally-registered tools are available.
53
+ */
54
+ tools?: readonly string[];
55
+ /**
56
+ * Provider-specific options. Forwarded to Vercel AI SDK's `providerOptions`.
57
+ * Example: `{ anthropic: { cacheControl: { type: 'ephemeral' } } }`.
58
+ */
59
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
+ providerOptions?: Record<string, Record<string, any>>;
61
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
+ metadata?: Record<string, any>;
63
+ };
64
+
65
+ export type Agent = Required<Pick<AgentDefinition, 'id' | 'name' | 'model' | 'instructions'>> &
66
+ Omit<AgentDefinition, 'id' | 'name' | 'model' | 'instructions'>;
67
+
68
+ export type RunParams = {
69
+ /** Agent id, name, or definition object. */
70
+ agent: string | AgentDefinition;
71
+ /** The new user message. Combined with `history` to form the full conversation. */
72
+ message?: string;
73
+ /** Prior conversation. The agent's `instructions` is prepended as a system message. */
74
+ history?: readonly Message[];
75
+ /** Override `maxOutputTokens` per call. */
76
+ maxOutputTokens?: number;
77
+ /** Override `temperature` per call. */
78
+ temperature?: number;
79
+ /** Max number of tool-call iterations before bailing. Default 8. */
80
+ maxSteps?: number;
81
+ /** Forwarded to tool `execute(input, context)`. */
82
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
83
+ context?: Record<string, any>;
84
+ };
85
+
86
+ export type RunResult = {
87
+ text: string;
88
+ finishReason: string;
89
+ usage: {
90
+ inputTokens: number;
91
+ outputTokens: number;
92
+ totalTokens: number;
93
+ };
94
+ toolCalls: { toolCallId: string; toolName: string; input: unknown }[];
95
+ toolResults: { toolCallId: string; toolName: string; output: unknown }[];
96
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
97
+ raw: any;
98
+ };
99
+
100
+ export type StreamEvent =
101
+ | { type: 'text-delta'; text: string }
102
+ | { type: 'tool-call'; toolCallId: string; toolName: string; input: unknown }
103
+ | { type: 'tool-result'; toolCallId: string; toolName: string; output: unknown }
104
+ | { type: 'tool-error'; toolCallId: string; toolName: string; error: unknown }
105
+ | {
106
+ type: 'finish';
107
+ finishReason: string;
108
+ usage: { inputTokens: number; outputTokens: number; totalTokens: number };
109
+ }
110
+ | { type: 'error'; error: unknown };