@artemiskit/core 0.5.3 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +12 -0
- package/dist/adapters/factory.d.ts +1 -1
- package/dist/adapters/index.d.ts +3 -3
- package/dist/adapters/registry.d.ts +1 -1
- package/dist/adapters/types.d.ts +7 -0
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/agent-evaluation/index.d.ts +2 -2
- package/dist/agent-evaluation/scorer.d.ts +1 -1
- package/dist/agent-workflow/catalog.d.ts +28 -0
- package/dist/agent-workflow/catalog.d.ts.map +1 -0
- package/dist/agent-workflow/environment.d.ts +47 -0
- package/dist/agent-workflow/environment.d.ts.map +1 -0
- package/dist/agent-workflow/index.d.ts +10 -0
- package/dist/agent-workflow/index.d.ts.map +1 -0
- package/dist/agent-workflow/parser.d.ts +7 -0
- package/dist/agent-workflow/parser.d.ts.map +1 -0
- package/dist/agent-workflow/sandbox-fixtures/qualify.d.ts +2 -0
- package/dist/agent-workflow/sandbox-fixtures/qualify.d.ts.map +1 -0
- package/dist/agent-workflow/sandbox.d.ts +12 -0
- package/dist/agent-workflow/sandbox.d.ts.map +1 -0
- package/dist/agent-workflow/schema.d.ts +774 -0
- package/dist/agent-workflow/schema.d.ts.map +1 -0
- package/dist/agent-workflow/session.d.ts +113 -0
- package/dist/agent-workflow/session.d.ts.map +1 -0
- package/dist/agent-workflow/simulated-tools.d.ts +35 -0
- package/dist/agent-workflow/simulated-tools.d.ts.map +1 -0
- package/dist/agent-workflow/target.d.ts +243 -0
- package/dist/agent-workflow/target.d.ts.map +1 -0
- package/dist/artifacts/index.d.ts +2 -2
- package/dist/artifacts/manifest.d.ts +1 -1
- package/dist/artifacts/types.d.ts +2 -2
- package/dist/comparison/eligibility.d.ts +1 -1
- package/dist/comparison/index.d.ts +1 -1
- package/dist/evaluators/combined.d.ts +2 -2
- package/dist/evaluators/contains.d.ts +2 -2
- package/dist/evaluators/exact.d.ts +2 -2
- package/dist/evaluators/fuzzy.d.ts +2 -2
- package/dist/evaluators/index.d.ts +13 -13
- package/dist/evaluators/inline.d.ts +2 -2
- package/dist/evaluators/json-schema.d.ts +2 -2
- package/dist/evaluators/llm-grader.d.ts +2 -2
- package/dist/evaluators/not-contains.d.ts +2 -2
- package/dist/evaluators/regex.d.ts +2 -2
- package/dist/evaluators/similarity.d.ts +2 -2
- package/dist/evaluators/tool-trace.d.ts +2 -2
- package/dist/evaluators/types.d.ts +3 -3
- package/dist/index.d.ts +15 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17827 -15174
- package/dist/provenance/execution-provenance.d.ts +1 -1
- package/dist/provenance/git.d.ts +1 -1
- package/dist/provenance/index.d.ts +4 -4
- package/dist/provenance/workload-identity.d.ts +2 -2
- package/dist/redaction/index.d.ts +2 -2
- package/dist/redaction/redactor.d.ts +1 -1
- package/dist/runner/executor.d.ts +3 -3
- package/dist/runner/index.d.ts +3 -3
- package/dist/runner/runner.d.ts +1 -1
- package/dist/runner/types.d.ts +5 -5
- package/dist/scenario/index.d.ts +4 -4
- package/dist/scenario/parser.d.ts +1 -1
- package/dist/scenario/variables.d.ts +1 -1
- package/dist/storage/factory.d.ts +1 -1
- package/dist/storage/index.d.ts +4 -4
- package/dist/storage/local.d.ts +2 -2
- package/dist/storage/supabase.d.ts +2 -2
- package/dist/storage/types.d.ts +2 -2
- package/dist/tools/fixture-executor.d.ts +2 -2
- package/dist/tools/index.d.ts +3 -3
- package/dist/tools/types.d.ts +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/validator/index.d.ts +2 -2
- package/dist/validator/validator.d.ts +1 -1
- package/package.json +4 -4
- package/src/adapters/types.ts +7 -0
- package/src/agent-workflow/catalog.ts +220 -0
- package/src/agent-workflow/environment.ts +207 -0
- package/src/agent-workflow/index.ts +10 -0
- package/src/agent-workflow/parser.ts +43 -0
- package/src/agent-workflow/sandbox-fixtures/qualify.ts +305 -0
- package/src/agent-workflow/sandbox.test.ts +117 -0
- package/src/agent-workflow/sandbox.ts +438 -0
- package/src/agent-workflow/schema.test.ts +218 -0
- package/src/agent-workflow/schema.ts +270 -0
- package/src/agent-workflow/session.test.ts +629 -0
- package/src/agent-workflow/session.ts +1119 -0
- package/src/agent-workflow/simulated-tools.test.ts +177 -0
- package/src/agent-workflow/simulated-tools.ts +230 -0
- package/src/agent-workflow/target.test.ts +280 -0
- package/src/agent-workflow/target.ts +357 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import Ajv from 'ajv';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import type { GenerateOptions, ModelClient, TokenUsage, ToolCall } from '../adapters/types';
|
|
5
|
+
import { getWorkflowTool } from './catalog';
|
|
6
|
+
|
|
7
|
+
const identifier = z.string().min(1).max(256);
|
|
8
|
+
const toolName = z.string().regex(/^[a-zA-Z_][a-zA-Z0-9_-]{0,63}$/);
|
|
9
|
+
const text = z.string().max(1_000_000);
|
|
10
|
+
const toolCallSchema = z
|
|
11
|
+
.object({
|
|
12
|
+
id: identifier,
|
|
13
|
+
type: z.literal('function'),
|
|
14
|
+
function: z.object({ name: toolName, arguments: text }).strict(),
|
|
15
|
+
})
|
|
16
|
+
.strict();
|
|
17
|
+
const messageSchema = z
|
|
18
|
+
.object({
|
|
19
|
+
role: z.enum(['system', 'user', 'assistant', 'tool']),
|
|
20
|
+
content: text,
|
|
21
|
+
toolCallId: identifier.optional(),
|
|
22
|
+
tool_calls: z.array(toolCallSchema).min(1).max(100).optional(),
|
|
23
|
+
})
|
|
24
|
+
.strict();
|
|
25
|
+
const timeoutSchema = z.number().int().min(1).max(2_147_483_647);
|
|
26
|
+
export const agentTurnRequestSchema = z
|
|
27
|
+
.object({
|
|
28
|
+
messages: z.array(messageSchema).min(1).max(1000),
|
|
29
|
+
tools: z
|
|
30
|
+
.array(
|
|
31
|
+
z
|
|
32
|
+
.object({
|
|
33
|
+
type: z.literal('function'),
|
|
34
|
+
function: z
|
|
35
|
+
.object({
|
|
36
|
+
name: toolName,
|
|
37
|
+
description: z.string().max(10_000).optional(),
|
|
38
|
+
parameters: z.record(z.unknown()),
|
|
39
|
+
})
|
|
40
|
+
.strict(),
|
|
41
|
+
})
|
|
42
|
+
.strict()
|
|
43
|
+
)
|
|
44
|
+
.max(100),
|
|
45
|
+
model: identifier.optional(),
|
|
46
|
+
generation: z
|
|
47
|
+
.object({
|
|
48
|
+
maxTokens: z.number().int().positive().max(1_000_000),
|
|
49
|
+
temperature: z.number().finite().min(0).max(2).optional(),
|
|
50
|
+
topP: z.number().finite().min(0).max(1).optional(),
|
|
51
|
+
seed: z.number().int().safe().optional(),
|
|
52
|
+
stop: z.array(z.string().min(1).max(1000)).max(16).optional(),
|
|
53
|
+
})
|
|
54
|
+
.strict(),
|
|
55
|
+
budgets: z
|
|
56
|
+
.object({
|
|
57
|
+
timeoutMs: timeoutSchema,
|
|
58
|
+
maxToolCalls: z.number().int().min(0).max(100),
|
|
59
|
+
})
|
|
60
|
+
.strict(),
|
|
61
|
+
})
|
|
62
|
+
.strict();
|
|
63
|
+
const resultSchema = z.object({
|
|
64
|
+
usageAvailable: z.boolean().optional(),
|
|
65
|
+
id: identifier,
|
|
66
|
+
model: identifier,
|
|
67
|
+
text,
|
|
68
|
+
tokens: z.object({
|
|
69
|
+
prompt: z.number().int().nonnegative().safe(),
|
|
70
|
+
completion: z.number().int().nonnegative().safe(),
|
|
71
|
+
total: z.number().int().nonnegative().safe(),
|
|
72
|
+
}),
|
|
73
|
+
latencyMs: z.number().finite().nonnegative(),
|
|
74
|
+
finishReason: z
|
|
75
|
+
.enum(['stop', 'length', 'function_call', 'tool_calls', 'content_filter'])
|
|
76
|
+
.optional(),
|
|
77
|
+
toolCalls: z.array(toolCallSchema).max(100).optional(),
|
|
78
|
+
functionCall: z.unknown().optional(),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export type AgentTurnRequest = z.infer<typeof agentTurnRequestSchema>;
|
|
82
|
+
export type AgentTargetFailure = {
|
|
83
|
+
rejectedCall?: {
|
|
84
|
+
requestedCallIdHash: string;
|
|
85
|
+
tool: string;
|
|
86
|
+
reason: 'undeclared_tool' | 'invalid_arguments' | 'duplicate_id';
|
|
87
|
+
};
|
|
88
|
+
tokens?: TokenUsage;
|
|
89
|
+
usageAvailable?: boolean;
|
|
90
|
+
status: 'unsupported' | 'invalid' | 'error';
|
|
91
|
+
code:
|
|
92
|
+
| 'invalid_request'
|
|
93
|
+
| 'tool_use_unsupported'
|
|
94
|
+
| 'invalid_response'
|
|
95
|
+
| 'target_error'
|
|
96
|
+
| 'timeout'
|
|
97
|
+
| 'aborted';
|
|
98
|
+
};
|
|
99
|
+
export type AgentTargetCapabilities = {
|
|
100
|
+
status: 'available';
|
|
101
|
+
toolUse: boolean;
|
|
102
|
+
transportCancellation: boolean;
|
|
103
|
+
};
|
|
104
|
+
export type AgentTurnResult =
|
|
105
|
+
| AgentTargetFailure
|
|
106
|
+
| {
|
|
107
|
+
status: 'completed';
|
|
108
|
+
id: string;
|
|
109
|
+
model: string;
|
|
110
|
+
message: { role: 'assistant'; content: string; tool_calls?: ToolCall[] };
|
|
111
|
+
/** Adapter-reported counts only; zero can mean unavailable in existing adapters. */
|
|
112
|
+
tokens: TokenUsage;
|
|
113
|
+
usageAvailable?: boolean;
|
|
114
|
+
latencyMs: number;
|
|
115
|
+
finishReason?: 'stop' | 'length' | 'tool_calls' | 'content_filter';
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** One bounded model turn. Tool execution, policy enforcement, and scoring belong to the harness. */
|
|
119
|
+
export interface AgentTarget {
|
|
120
|
+
readonly provider: string;
|
|
121
|
+
capabilities(
|
|
122
|
+
options: { timeoutMs: number },
|
|
123
|
+
signal?: AbortSignal
|
|
124
|
+
): Promise<AgentTargetCapabilities | AgentTargetFailure>;
|
|
125
|
+
turn(request: AgentTurnRequest, signal?: AbortSignal): Promise<AgentTurnResult>;
|
|
126
|
+
/** Wait for underlying callbacks hidden behind a bounded turn facade. */
|
|
127
|
+
drain?(options: { timeoutMs: number }): Promise<{ pendingOperations: number }>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const failure = (
|
|
131
|
+
status: AgentTargetFailure['status'],
|
|
132
|
+
code: AgentTargetFailure['code']
|
|
133
|
+
): AgentTargetFailure => ({ status, code });
|
|
134
|
+
|
|
135
|
+
/** Do not expose provider exception text, which can contain credentials or customer content. */
|
|
136
|
+
function bounded<T>(
|
|
137
|
+
run: () => Promise<T>,
|
|
138
|
+
timeoutMs: number,
|
|
139
|
+
signal?: AbortSignal
|
|
140
|
+
): Promise<T | AgentTargetFailure> {
|
|
141
|
+
if (signal?.aborted) return Promise.resolve(failure('error', 'aborted'));
|
|
142
|
+
return new Promise((resolve) => {
|
|
143
|
+
let finished = false;
|
|
144
|
+
const finish = (value: T | AgentTargetFailure) => {
|
|
145
|
+
if (finished) return;
|
|
146
|
+
finished = true;
|
|
147
|
+
clearTimeout(timer);
|
|
148
|
+
signal?.removeEventListener('abort', abort);
|
|
149
|
+
resolve(value);
|
|
150
|
+
};
|
|
151
|
+
const abort = () => finish(failure('error', 'aborted'));
|
|
152
|
+
const timer = setTimeout(() => finish(failure('error', 'timeout')), timeoutMs);
|
|
153
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
154
|
+
Promise.resolve()
|
|
155
|
+
.then<T | AgentTargetFailure>(() => (signal?.aborted ? failure('error', 'aborted') : run()))
|
|
156
|
+
.then(finish, () => finish(failure('error', 'target_error')));
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function validWorkflowTranscript(messages: AgentTurnRequest['messages']): boolean {
|
|
161
|
+
const seen = new Set<string>();
|
|
162
|
+
const pending = new Set<string>();
|
|
163
|
+
for (const message of messages) {
|
|
164
|
+
if (message.role === 'tool') {
|
|
165
|
+
if (!message.toolCallId || message.tool_calls || !pending.delete(message.toolCallId))
|
|
166
|
+
return false;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (message.toolCallId || pending.size || (message.tool_calls && message.role !== 'assistant'))
|
|
170
|
+
return false;
|
|
171
|
+
for (const call of message.tool_calls ?? []) {
|
|
172
|
+
if (seen.has(call.id)) return false;
|
|
173
|
+
try {
|
|
174
|
+
const args: unknown = JSON.parse(call.function.arguments);
|
|
175
|
+
if (!args || typeof args !== 'object' || Array.isArray(args)) return false;
|
|
176
|
+
} catch {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
seen.add(call.id);
|
|
180
|
+
pending.add(call.id);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return pending.size === 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Bridge existing adapters without provider-specific dispatch. Workflow calls disable supported
|
|
188
|
+
* transport retries and propagate abort only when the adapter declares transport cancellation.
|
|
189
|
+
* Returned text/tool arguments are working conversation data, not sanitized retained evidence.
|
|
190
|
+
*/
|
|
191
|
+
export function createModelClientTarget(client: ModelClient): AgentTarget {
|
|
192
|
+
if (
|
|
193
|
+
!client ||
|
|
194
|
+
!identifier.safeParse(client.provider).success ||
|
|
195
|
+
typeof client.generate !== 'function' ||
|
|
196
|
+
typeof client.capabilities !== 'function'
|
|
197
|
+
) {
|
|
198
|
+
throw new TypeError('Invalid ModelClient');
|
|
199
|
+
}
|
|
200
|
+
const pending = new Set<Promise<unknown>>();
|
|
201
|
+
const track = <T>(promise: Promise<T>): Promise<T> => {
|
|
202
|
+
pending.add(promise);
|
|
203
|
+
void promise.then(
|
|
204
|
+
() => pending.delete(promise),
|
|
205
|
+
() => pending.delete(promise)
|
|
206
|
+
);
|
|
207
|
+
return promise;
|
|
208
|
+
};
|
|
209
|
+
const readCapabilities = async (): Promise<AgentTargetCapabilities | AgentTargetFailure> => {
|
|
210
|
+
const value = await track(client.capabilities());
|
|
211
|
+
if (!value || typeof value.toolUse !== 'boolean') return failure('invalid', 'invalid_response');
|
|
212
|
+
return {
|
|
213
|
+
status: 'available',
|
|
214
|
+
toolUse: value.toolUse,
|
|
215
|
+
transportCancellation: value.transportCancellation === true,
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
return {
|
|
219
|
+
provider: client.provider,
|
|
220
|
+
async drain({ timeoutMs }) {
|
|
221
|
+
if (!timeoutSchema.safeParse(timeoutMs).success) return { pendingOperations: pending.size };
|
|
222
|
+
await bounded(() => Promise.allSettled([...pending]), timeoutMs);
|
|
223
|
+
return { pendingOperations: pending.size };
|
|
224
|
+
},
|
|
225
|
+
async capabilities(options, signal) {
|
|
226
|
+
if (!timeoutSchema.safeParse(options?.timeoutMs).success)
|
|
227
|
+
return failure('invalid', 'invalid_request');
|
|
228
|
+
return bounded(readCapabilities, options.timeoutMs, signal);
|
|
229
|
+
},
|
|
230
|
+
async turn(request, signal) {
|
|
231
|
+
let parsed: ReturnType<typeof agentTurnRequestSchema.safeParse>;
|
|
232
|
+
try {
|
|
233
|
+
parsed = agentTurnRequestSchema.safeParse(request);
|
|
234
|
+
} catch {
|
|
235
|
+
return failure('invalid', 'invalid_request');
|
|
236
|
+
}
|
|
237
|
+
if (!parsed.success || !validWorkflowTranscript(parsed.data.messages))
|
|
238
|
+
return failure('invalid', 'invalid_request');
|
|
239
|
+
const input = parsed.data;
|
|
240
|
+
const validators = new Map<string, ReturnType<Ajv['compile']>>();
|
|
241
|
+
try {
|
|
242
|
+
const ajv = new Ajv({ strict: false, allErrors: false, validateFormats: false });
|
|
243
|
+
for (const tool of input.tools) {
|
|
244
|
+
if (validators.has(tool.function.name)) return failure('invalid', 'invalid_request');
|
|
245
|
+
// Compile a detached JSON schema without remote loading or async validation.
|
|
246
|
+
const schema = JSON.parse(JSON.stringify(tool.function.parameters));
|
|
247
|
+
if (schema.$async) return failure('invalid', 'invalid_request');
|
|
248
|
+
const validate = ajv.compile(schema);
|
|
249
|
+
if ('$async' in validate && validate.$async) return failure('invalid', 'invalid_request');
|
|
250
|
+
validators.set(tool.function.name, validate);
|
|
251
|
+
}
|
|
252
|
+
} catch {
|
|
253
|
+
return failure('invalid', 'invalid_request');
|
|
254
|
+
}
|
|
255
|
+
const started = Date.now();
|
|
256
|
+
const controller = new AbortController();
|
|
257
|
+
const abort = () => controller.abort();
|
|
258
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
259
|
+
if (signal?.aborted) controller.abort();
|
|
260
|
+
const timer = setTimeout(abort, input.budgets.timeoutMs);
|
|
261
|
+
return bounded(
|
|
262
|
+
async (): Promise<AgentTurnResult> => {
|
|
263
|
+
const capabilities = await readCapabilities();
|
|
264
|
+
if (capabilities.status !== 'available') return capabilities;
|
|
265
|
+
if (input.tools.length && !capabilities.toolUse)
|
|
266
|
+
return failure('unsupported', 'tool_use_unsupported');
|
|
267
|
+
if (signal?.aborted) return failure('error', 'aborted');
|
|
268
|
+
if (Date.now() - started >= input.budgets.timeoutMs) return failure('error', 'timeout');
|
|
269
|
+
const options: GenerateOptions = {
|
|
270
|
+
maxRetries: 0,
|
|
271
|
+
prompt: input.messages,
|
|
272
|
+
tools: input.tools,
|
|
273
|
+
model: input.model,
|
|
274
|
+
...input.generation,
|
|
275
|
+
...(capabilities.transportCancellation ? { signal: controller.signal } : {}),
|
|
276
|
+
};
|
|
277
|
+
const generated = resultSchema.safeParse(await track(client.generate(options)));
|
|
278
|
+
if (!generated.success) return failure('invalid', 'invalid_response');
|
|
279
|
+
const result = generated.data;
|
|
280
|
+
const calls = result.toolCalls ?? [];
|
|
281
|
+
if (
|
|
282
|
+
result.functionCall !== undefined ||
|
|
283
|
+
result.finishReason === 'function_call' ||
|
|
284
|
+
(result.finishReason === 'tool_calls' && calls.length === 0) ||
|
|
285
|
+
calls.length > input.budgets.maxToolCalls ||
|
|
286
|
+
result.tokens.total !== result.tokens.prompt + result.tokens.completion
|
|
287
|
+
)
|
|
288
|
+
return failure('invalid', 'invalid_response');
|
|
289
|
+
const ids = new Set(
|
|
290
|
+
input.messages.flatMap((message) => message.tool_calls?.map((call) => call.id) ?? [])
|
|
291
|
+
);
|
|
292
|
+
const rejected = (
|
|
293
|
+
call: ToolCall,
|
|
294
|
+
reason: NonNullable<AgentTargetFailure['rejectedCall']>['reason']
|
|
295
|
+
): AgentTargetFailure => ({
|
|
296
|
+
...failure('invalid', 'invalid_response'),
|
|
297
|
+
tokens: result.tokens,
|
|
298
|
+
...(result.usageAvailable !== undefined
|
|
299
|
+
? { usageAvailable: result.usageAvailable }
|
|
300
|
+
: {}),
|
|
301
|
+
rejectedCall: {
|
|
302
|
+
requestedCallIdHash: createHash('sha256').update(call.id).digest('hex'),
|
|
303
|
+
tool: getWorkflowTool(call.function.name)?.id ?? 'unknown',
|
|
304
|
+
reason,
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
for (const call of calls) {
|
|
308
|
+
if (ids.has(call.id)) return rejected(call, 'duplicate_id');
|
|
309
|
+
ids.add(call.id);
|
|
310
|
+
const validate = validators.get(call.function.name);
|
|
311
|
+
if (!validate) return rejected(call, 'undeclared_tool');
|
|
312
|
+
try {
|
|
313
|
+
const args: unknown = JSON.parse(call.function.arguments);
|
|
314
|
+
if (
|
|
315
|
+
!args ||
|
|
316
|
+
typeof args !== 'object' ||
|
|
317
|
+
Array.isArray(args) ||
|
|
318
|
+
!validate ||
|
|
319
|
+
validate(args) !== true
|
|
320
|
+
)
|
|
321
|
+
return rejected(call, 'invalid_arguments');
|
|
322
|
+
} catch {
|
|
323
|
+
return rejected(call, 'invalid_arguments');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
status: 'completed',
|
|
328
|
+
id: result.id,
|
|
329
|
+
model: result.model,
|
|
330
|
+
message: {
|
|
331
|
+
role: 'assistant',
|
|
332
|
+
content: result.text,
|
|
333
|
+
...(calls.length ? { tool_calls: calls } : {}),
|
|
334
|
+
},
|
|
335
|
+
tokens: result.tokens,
|
|
336
|
+
...(result.usageAvailable !== undefined
|
|
337
|
+
? { usageAvailable: result.usageAvailable }
|
|
338
|
+
: {}),
|
|
339
|
+
latencyMs: result.latencyMs,
|
|
340
|
+
finishReason: result.finishReason,
|
|
341
|
+
};
|
|
342
|
+
},
|
|
343
|
+
input.budgets.timeoutMs,
|
|
344
|
+
signal
|
|
345
|
+
)
|
|
346
|
+
.then((result) =>
|
|
347
|
+
controller.signal.aborted
|
|
348
|
+
? failure('error', signal?.aborted ? 'aborted' : 'timeout')
|
|
349
|
+
: result
|
|
350
|
+
)
|
|
351
|
+
.finally(() => {
|
|
352
|
+
clearTimeout(timer);
|
|
353
|
+
signal?.removeEventListener('abort', abort);
|
|
354
|
+
});
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
}
|
package/src/index.ts
CHANGED