@ai-sdk-tool/harness 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.
@@ -0,0 +1,3 @@
1
+ import type { Agent, AgentConfig } from "./types";
2
+ export declare function createAgent(config: AgentConfig): Agent;
3
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,KAAK,EACL,WAAW,EAGZ,MAAM,SAAS,CAAC;AAEjB,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CA6BtD"}
package/dist/agent.js ADDED
@@ -0,0 +1,29 @@
1
+ import { stepCountIs, streamText } from "ai";
2
+ export function createAgent(config) {
3
+ return {
4
+ config,
5
+ stream(opts) {
6
+ const system = opts.system ??
7
+ (typeof config.instructions === "string"
8
+ ? config.instructions
9
+ : undefined);
10
+ const result = streamText({
11
+ model: config.model,
12
+ tools: config.tools,
13
+ system,
14
+ messages: opts.messages,
15
+ providerOptions: opts.providerOptions,
16
+ maxOutputTokens: opts.maxOutputTokens,
17
+ stopWhen: stepCountIs(config.maxStepsPerTurn ?? 1),
18
+ abortSignal: opts.abortSignal,
19
+ experimental_repairToolCall: config.experimental_repairToolCall,
20
+ });
21
+ return {
22
+ finishReason: result.finishReason,
23
+ fullStream: result.fullStream,
24
+ response: result.response,
25
+ };
26
+ },
27
+ };
28
+ }
29
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAQ7C,MAAM,UAAU,WAAW,CAAC,MAAmB;IAC7C,OAAO;QACL,MAAM;QACN,MAAM,CAAC,IAAwB;YAC7B,MAAM,MAAM,GACV,IAAI,CAAC,MAAM;gBACX,CAAC,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ;oBACtC,CAAC,CAAC,MAAM,CAAC,YAAY;oBACrB,CAAC,CAAC,SAAS,CAAC,CAAC;YAEjB,MAAM,MAAM,GAAG,UAAU,CAAC;gBACxB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,MAAM;gBACN,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,eAAe,IAAI,CAAC,CAAC;gBAClD,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,2BAA2B,EAAE,MAAM,CAAC,2BAA2B;aAChE,CAAC,CAAC;YAEH,OAAO;gBACL,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;aAC1B,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { createAgent } from "./agent";
2
+ export { runAgentLoop } from "./loop";
3
+ export type { Message, MessageHistoryOptions } from "./message-history";
4
+ export { MessageHistory } from "./message-history";
5
+ export { MANUAL_TOOL_LOOP_MAX_STEPS, normalizeFinishReason, shouldContinueManualToolLoop, } from "./tool-loop-control";
6
+ export type * from "./types";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,YAAY,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC;AAC7B,mBAAmB,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { createAgent } from "./agent";
2
+ export { runAgentLoop } from "./loop";
3
+ export { MessageHistory } from "./message-history";
4
+ export { MANUAL_TOOL_LOOP_MAX_STEPS, normalizeFinishReason, shouldContinueManualToolLoop, } from "./tool-loop-control";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC"}
package/dist/loop.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { RunAgentLoopOptions, RunAgentLoopResult } from "./types";
2
+ export declare function runAgentLoop(options: RunAgentLoopOptions): Promise<RunAgentLoopResult>;
3
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA8D7B"}
package/dist/loop.js ADDED
@@ -0,0 +1,53 @@
1
+ import { MANUAL_TOOL_LOOP_MAX_STEPS, shouldContinueManualToolLoop, } from "./tool-loop-control";
2
+ export async function runAgentLoop(options) {
3
+ const { agent, abortSignal, onError, onStepComplete, onToolCall } = options;
4
+ const shouldContinue = options.shouldContinue ?? shouldContinueManualToolLoop;
5
+ const maxIterations = options.maxIterations ?? MANUAL_TOOL_LOOP_MAX_STEPS;
6
+ const messages = [...options.messages];
7
+ let iteration = 0;
8
+ let lastFinishReason = "stop";
9
+ while (iteration < maxIterations) {
10
+ if (abortSignal?.aborted) {
11
+ break;
12
+ }
13
+ const context = { iteration, messages };
14
+ try {
15
+ const instructions = agent.config.instructions;
16
+ const system = typeof instructions === "function"
17
+ ? await instructions()
18
+ : instructions;
19
+ const stream = agent.stream({ messages, abortSignal, system });
20
+ for await (const part of stream.fullStream) {
21
+ if (part.type === "tool-call") {
22
+ await onToolCall?.(part, context);
23
+ }
24
+ }
25
+ const [response, finishReason] = await Promise.all([
26
+ stream.response,
27
+ stream.finishReason,
28
+ ]);
29
+ messages.push(...response.messages);
30
+ lastFinishReason = finishReason;
31
+ await onStepComplete?.({
32
+ finishReason: lastFinishReason,
33
+ iteration,
34
+ messages,
35
+ response,
36
+ });
37
+ iteration += 1;
38
+ if (!shouldContinue(lastFinishReason, context)) {
39
+ break;
40
+ }
41
+ }
42
+ catch (error) {
43
+ await onError?.(error, context);
44
+ throw error;
45
+ }
46
+ }
47
+ return {
48
+ messages,
49
+ iterations: iteration,
50
+ finishReason: lastFinishReason,
51
+ };
52
+ }
53
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAA4B;IAE5B,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAC5E,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,4BAA4B,CAAC;IAC9E,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,0BAA0B,CAAC;IAC1E,MAAM,QAAQ,GAAG,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEvC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,gBAAgB,GAAsB,MAAM,CAAC;IAEjD,OAAO,SAAS,GAAG,aAAa,EAAE,CAAC;QACjC,IAAI,WAAW,EAAE,OAAO,EAAE,CAAC;YACzB,MAAM;QACR,CAAC;QAED,MAAM,OAAO,GAAwB,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;QAE7D,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC;YAC/C,MAAM,MAAM,GACV,OAAO,YAAY,KAAK,UAAU;gBAChC,CAAC,CAAC,MAAM,YAAY,EAAE;gBACtB,CAAC,CAAC,YAAY,CAAC;YAEnB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;YAE/D,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC3C,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBAC9B,MAAM,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YAED,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACjD,MAAM,CAAC,QAAQ;gBACf,MAAM,CAAC,YAAY;aACpB,CAAC,CAAC;YAEH,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpC,gBAAgB,GAAG,YAAY,CAAC;YAEhC,MAAM,cAAc,EAAE,CAAC;gBACrB,YAAY,EAAE,gBAAgB;gBAC9B,SAAS;gBACT,QAAQ;gBACR,QAAQ;aACT,CAAC,CAAC;YAEH,SAAS,IAAI,CAAC,CAAC;YAEf,IAAI,CAAC,cAAc,CAAC,gBAAgB,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC/C,MAAM;YACR,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAChC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ;QACR,UAAU,EAAE,SAAS;QACrB,YAAY,EAAE,gBAAgB;KAC/B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { ModelMessage } from "ai";
2
+ export interface Message {
3
+ createdAt: Date;
4
+ id: string;
5
+ modelMessage: ModelMessage;
6
+ originalContent?: string;
7
+ }
8
+ export interface MessageHistoryOptions {
9
+ /**
10
+ * Maximum number of messages to retain. When exceeded, older messages
11
+ * are trimmed from the front while preserving the initial user message
12
+ * for context continuity. Defaults to 1000.
13
+ */
14
+ maxMessages?: number;
15
+ }
16
+ export declare class MessageHistory {
17
+ private messages;
18
+ private readonly maxMessages;
19
+ constructor(options?: MessageHistoryOptions);
20
+ getAll(): Message[];
21
+ clear(): void;
22
+ addUserMessage(content: string, originalContent?: string): Message;
23
+ addModelMessages(messages: ModelMessage[]): Message[];
24
+ private enforceLimit;
25
+ private sanitizeMessage;
26
+ private serializeValue;
27
+ toModelMessages(): ModelMessage[];
28
+ }
29
+ //# sourceMappingURL=message-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-history.d.ts","sourceRoot":"","sources":["../src/message-history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA4B,MAAM,IAAI,CAAC;AAiDjE,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAYD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,OAAO,CAAC,EAAE,qBAAqB;IAU3C,MAAM,IAAI,OAAO,EAAE;IAInB,KAAK,IAAI,IAAI;IAIb,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO;IAelE,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,OAAO,EAAE;IAmBrD,OAAO,CAAC,YAAY;IAkDpB,OAAO,CAAC,eAAe;IAmCvB,OAAO,CAAC,cAAc;IA6BtB,eAAe,IAAI,YAAY,EAAE;CAGlC"}
@@ -0,0 +1,189 @@
1
+ const TRAILING_NEWLINES = /\n+$/;
2
+ function trimTrailingNewlines(message) {
3
+ if (message.role !== "assistant") {
4
+ return message;
5
+ }
6
+ const content = message.content;
7
+ if (typeof content === "string") {
8
+ const trimmed = content.replace(TRAILING_NEWLINES, "");
9
+ if (trimmed === content) {
10
+ return message;
11
+ }
12
+ return { ...message, content: trimmed };
13
+ }
14
+ if (!Array.isArray(content) || content.length === 0) {
15
+ return message;
16
+ }
17
+ let lastTextIndex = -1;
18
+ for (let i = content.length - 1; i >= 0; i--) {
19
+ const part = content[i];
20
+ if (part && typeof part === "object" && part.type === "text") {
21
+ lastTextIndex = i;
22
+ break;
23
+ }
24
+ }
25
+ if (lastTextIndex === -1) {
26
+ return message;
27
+ }
28
+ const textPart = content[lastTextIndex];
29
+ const trimmedText = textPart.text.replace(TRAILING_NEWLINES, "");
30
+ if (trimmedText === textPart.text) {
31
+ return message;
32
+ }
33
+ const newContent = [...content];
34
+ newContent[lastTextIndex] = { ...textPart, text: trimmedText };
35
+ return { ...message, content: newContent };
36
+ }
37
+ const createMessageId = (() => {
38
+ let counter = 0;
39
+ return () => {
40
+ counter += 1;
41
+ return `msg_${counter}`;
42
+ };
43
+ })();
44
+ const DEFAULT_MAX_MESSAGES = 1000;
45
+ export class MessageHistory {
46
+ messages = [];
47
+ maxMessages;
48
+ constructor(options) {
49
+ const max = options?.maxMessages ?? DEFAULT_MAX_MESSAGES;
50
+ if (!Number.isFinite(max) || max < 1 || max !== Math.floor(max)) {
51
+ throw new RangeError(`maxMessages must be a positive integer >= 1, got ${max}`);
52
+ }
53
+ this.maxMessages = max;
54
+ }
55
+ getAll() {
56
+ return [...this.messages];
57
+ }
58
+ clear() {
59
+ this.messages = [];
60
+ }
61
+ addUserMessage(content, originalContent) {
62
+ const message = {
63
+ id: createMessageId(),
64
+ createdAt: new Date(),
65
+ modelMessage: {
66
+ role: "user",
67
+ content,
68
+ },
69
+ originalContent,
70
+ };
71
+ this.messages.push(message);
72
+ this.enforceLimit();
73
+ return message;
74
+ }
75
+ addModelMessages(messages) {
76
+ const created = [];
77
+ for (const modelMessage of messages) {
78
+ const processedMessage = trimTrailingNewlines(modelMessage);
79
+ const sanitizedMessage = this.sanitizeMessage(processedMessage);
80
+ const message = {
81
+ id: createMessageId(),
82
+ createdAt: new Date(),
83
+ modelMessage: sanitizedMessage,
84
+ };
85
+ created.push(message);
86
+ }
87
+ this.messages.push(...created);
88
+ this.enforceLimit();
89
+ return created;
90
+ }
91
+ enforceLimit() {
92
+ if (this.messages.length <= this.maxMessages) {
93
+ return;
94
+ }
95
+ if (this.maxMessages === 1) {
96
+ this.messages = [this.messages[this.messages.length - 1]];
97
+ return;
98
+ }
99
+ const turnBoundaries = [];
100
+ for (let i = 1; i < this.messages.length; i++) {
101
+ if (this.messages[i].modelMessage.role === "user") {
102
+ turnBoundaries.push(i);
103
+ }
104
+ }
105
+ if (turnBoundaries.length === 0) {
106
+ this.messages = [
107
+ this.messages[0],
108
+ ...this.messages.slice(-(this.maxMessages - 1)),
109
+ ];
110
+ return;
111
+ }
112
+ for (const boundary of turnBoundaries) {
113
+ const keptCount = 1 + (this.messages.length - boundary);
114
+ if (keptCount <= this.maxMessages) {
115
+ this.messages = [this.messages[0], ...this.messages.slice(boundary)];
116
+ return;
117
+ }
118
+ }
119
+ const lastBoundary = turnBoundaries[turnBoundaries.length - 1];
120
+ const lastBoundaryCandidate = [
121
+ this.messages[0],
122
+ ...this.messages.slice(lastBoundary),
123
+ ];
124
+ if (lastBoundaryCandidate.length <= this.maxMessages) {
125
+ this.messages = lastBoundaryCandidate;
126
+ return;
127
+ }
128
+ this.messages = [
129
+ this.messages[0],
130
+ ...this.messages.slice(-(this.maxMessages - 1)),
131
+ ];
132
+ }
133
+ sanitizeMessage(message) {
134
+ if (message.role !== "tool") {
135
+ return message;
136
+ }
137
+ if (!Array.isArray(message.content)) {
138
+ return message;
139
+ }
140
+ const sanitizedContent = message.content.map((part) => {
141
+ if (part.type !== "tool-result") {
142
+ return part;
143
+ }
144
+ const sanitizedOutput = this.serializeValue(part.output);
145
+ if (sanitizedOutput === part.output) {
146
+ return part;
147
+ }
148
+ // SAFETY: serializeValue preserves the ToolResultOutput discriminated union structure.
149
+ // It only transforms Error instances (which shouldn't appear in ToolResultOutput's
150
+ // JSON-serializable variants). The cast narrows unknown -> ToolResultOutput.
151
+ return {
152
+ ...part,
153
+ output: sanitizedOutput,
154
+ };
155
+ });
156
+ return {
157
+ ...message,
158
+ content: sanitizedContent,
159
+ };
160
+ }
161
+ serializeValue(value) {
162
+ if (value === null || value === undefined) {
163
+ return value;
164
+ }
165
+ if (value instanceof Error) {
166
+ return {
167
+ __error: true,
168
+ name: value.name,
169
+ message: value.message,
170
+ stack: value.stack,
171
+ };
172
+ }
173
+ if (Array.isArray(value)) {
174
+ return value.map((item) => this.serializeValue(item));
175
+ }
176
+ if (typeof value === "object" && value.constructor === Object) {
177
+ const result = {};
178
+ for (const [key, val] of Object.entries(value)) {
179
+ result[key] = this.serializeValue(val);
180
+ }
181
+ return result;
182
+ }
183
+ return value;
184
+ }
185
+ toModelMessages() {
186
+ return this.messages.map((message) => message.modelMessage);
187
+ }
188
+ }
189
+ //# sourceMappingURL=message-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-history.js","sourceRoot":"","sources":["../src/message-history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare const MANUAL_TOOL_LOOP_MAX_STEPS = 200;
2
+ export declare const normalizeFinishReason: (finishReason: string) => string;
3
+ export declare const shouldContinueManualToolLoop: (finishReason: string) => boolean;
4
+ //# sourceMappingURL=tool-loop-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-loop-control.d.ts","sourceRoot":"","sources":["../src/tool-loop-control.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAS9C,eAAO,MAAM,qBAAqB,GAAI,cAAc,MAAM,KAAG,MAG5D,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAI,cAAc,MAAM,KAAG,OAEnE,CAAC"}
@@ -0,0 +1,15 @@
1
+ export const MANUAL_TOOL_LOOP_MAX_STEPS = 200;
2
+ const CONTINUATION_FINISH_REASONS = new Set(["tool-calls"]);
3
+ const FINISH_REASON_ALIASES = new Map([
4
+ ["tool_calls", "tool-calls"],
5
+ ["tool_use", "tool-calls"],
6
+ ["function_call", "tool-calls"],
7
+ ]);
8
+ export const normalizeFinishReason = (finishReason) => {
9
+ const normalized = finishReason.trim().toLowerCase();
10
+ return FINISH_REASON_ALIASES.get(normalized) ?? normalized;
11
+ };
12
+ export const shouldContinueManualToolLoop = (finishReason) => {
13
+ return CONTINUATION_FINISH_REASONS.has(normalizeFinishReason(finishReason));
14
+ };
15
+ //# sourceMappingURL=tool-loop-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-loop-control.js","sourceRoot":"","sources":["../src/tool-loop-control.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAE9C,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AAC5D,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,CAAC,YAAY,EAAE,YAAY,CAAC;IAC5B,CAAC,UAAU,EAAE,YAAY,CAAC;IAC1B,CAAC,eAAe,EAAE,YAAY,CAAC;CAChC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,YAAoB,EAAU,EAAE;IACpE,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrD,OAAO,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC;AAC7D,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,YAAoB,EAAW,EAAE;IAC5E,OAAO,2BAA2B,CAAC,GAAG,CAAC,qBAAqB,CAAC,YAAY,CAAC,CAAC,CAAC;AAC9E,CAAC,CAAC"}
@@ -0,0 +1,57 @@
1
+ import type { LanguageModel, ModelMessage, streamText, Tool, ToolCallPart, ToolSet } from "ai";
2
+ type CoreStreamResult = ReturnType<typeof streamText>;
3
+ type StreamTextOptions = Parameters<typeof streamText>[0];
4
+ export type { LanguageModel, ModelMessage, Tool, ToolSet };
5
+ export type AgentInstructions = string | (() => Promise<string>);
6
+ export interface AgentConfig {
7
+ experimental_repairToolCall?: StreamTextOptions["experimental_repairToolCall"];
8
+ instructions?: AgentInstructions;
9
+ maxStepsPerTurn?: number;
10
+ model: LanguageModel;
11
+ tools?: ToolSet;
12
+ }
13
+ export interface Agent {
14
+ config: AgentConfig;
15
+ stream(opts: AgentStreamOptions): AgentStreamResult;
16
+ }
17
+ export interface AgentStreamOptions {
18
+ abortSignal?: AbortSignal;
19
+ maxOutputTokens?: StreamTextOptions["maxOutputTokens"];
20
+ messages: ModelMessage[];
21
+ providerOptions?: StreamTextOptions["providerOptions"];
22
+ system?: string;
23
+ }
24
+ export interface AgentStreamResult {
25
+ finishReason: CoreStreamResult["finishReason"];
26
+ fullStream: CoreStreamResult["fullStream"];
27
+ response: CoreStreamResult["response"];
28
+ }
29
+ export type AgentFinishReason = Awaited<AgentStreamResult["finishReason"]>;
30
+ export interface LoopContinueContext {
31
+ iteration: number;
32
+ messages: ModelMessage[];
33
+ }
34
+ export interface LoopStepInfo {
35
+ finishReason: Awaited<AgentStreamResult["finishReason"]>;
36
+ iteration: number;
37
+ messages: ModelMessage[];
38
+ response: Awaited<AgentStreamResult["response"]>;
39
+ }
40
+ export interface LoopHooks {
41
+ onError?: (error: unknown, context: LoopContinueContext) => void | Promise<void>;
42
+ onStepComplete?: (step: LoopStepInfo) => void | Promise<void>;
43
+ onToolCall?: (call: ToolCallPart, context: LoopContinueContext) => void | Promise<void>;
44
+ shouldContinue?: (finishReason: AgentFinishReason, context: LoopContinueContext) => boolean;
45
+ }
46
+ export interface RunAgentLoopOptions extends LoopHooks {
47
+ abortSignal?: AbortSignal;
48
+ agent: Agent;
49
+ maxIterations?: number;
50
+ messages: ModelMessage[];
51
+ }
52
+ export interface RunAgentLoopResult {
53
+ finishReason: AgentFinishReason;
54
+ iterations: number;
55
+ messages: ModelMessage[];
56
+ }
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,YAAY,EACZ,OAAO,EACR,MAAM,IAAI,CAAC;AAEZ,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AACtD,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1D,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAE3D,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,2BAA2B,CAAC,EAAE,iBAAiB,CAAC,6BAA6B,CAAC,CAAC;IAC/E,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,IAAI,EAAE,kBAAkB,GAAG,iBAAiB,CAAC;CACrD;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,eAAe,CAAC,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IACvD,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,eAAe,CAAC,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAC/C,UAAU,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAC3C,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,OAAO,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,EAAE,CACR,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,mBAAmB,KACzB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,UAAU,CAAC,EAAE,CACX,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,mBAAmB,KACzB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,cAAc,CAAC,EAAE,CACf,YAAY,EAAE,iBAAiB,EAC/B,OAAO,EAAE,mBAAmB,KACzB,OAAO,CAAC;CACd;AAED,MAAM,WAAW,mBAAoB,SAAQ,SAAS;IACpD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,iBAAiB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@ai-sdk-tool/harness",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "typecheck": "tsc --noEmit",
22
+ "test": "bun test"
23
+ },
24
+ "dependencies": {
25
+ "ai": "^6.0.101"
26
+ },
27
+ "peerDependencies": {
28
+ "typescript": "^5.0.0",
29
+ "zod": "^4.3.6"
30
+ },
31
+ "devDependencies": {
32
+ "typescript": "^5.9.3"
33
+ }
34
+ }