|
1 | | -import { analyzeResponse, defaultRepairPrompt } from "./rig.ts"; |
2 | | -import type { Agent, AgentAddon, AgentAddonContext } from "./rig.ts"; |
3 | | - |
4 | | -const DEFAULT_STEERING_WARNING = "You are running out of turns. This is your final attempt before reaching the turn limit. Please correct your output now."; |
5 | | - |
6 | | -export type SteeringOptions = { |
7 | | - /** Warning appended to the final retry prompt. */ |
8 | | - message?: string; |
9 | | -}; |
10 | | - |
11 | | -export type TimeoutOptions = { |
12 | | - timeout: number; |
13 | | -}; |
14 | | - |
15 | | -export type AgentRegistration = ( |
16 | | - agent: Agent, |
17 | | - context: AgentAddonContext, |
18 | | -) => void | Promise<void>; |
19 | | - |
20 | | -/** |
21 | | - * Appends a final-attempt warning to the retry prompt produced by an inner addon. |
22 | | - * |
23 | | - * Place this before `repair()`, for example |
24 | | - * `addons: [steering({ message: "Return valid JSON now." }), repair()]`. |
25 | | - */ |
26 | | -export function steering(options: SteeringOptions = {}): AgentAddon { |
27 | | - const message = options.message ?? DEFAULT_STEERING_WARNING; |
28 | | - return async (context, next) => { |
29 | | - await next(); |
30 | | - if (context.nextPrompt && context.turn + 1 === context.maxTurns) { |
31 | | - context.nextPrompt = `${context.nextPrompt}\n${message}`; |
32 | | - } |
33 | | - }; |
34 | | -} |
35 | | - |
36 | | -/** |
37 | | - * Parses and validates responses, retrying failures within the agent's turn budget. |
38 | | - * |
39 | | - * Configure `maxTurns` on the agent spec. |
40 | | - */ |
41 | | -export function repair(): AgentAddon { |
42 | | - return async (context, next) => { |
43 | | - await next(); |
44 | | - if (context.completed || context.error !== undefined || context.nextPrompt !== undefined) { |
45 | | - return; |
46 | | - } |
47 | | - if (context.response === undefined) { |
48 | | - return; |
49 | | - } |
50 | | - const analysis = analyzeResponse(context.response, context.outputSchema, context.spec.name, context.turn); |
51 | | - if (analysis.ok) { |
52 | | - context.completed = true; |
53 | | - context.output = analysis.output; |
54 | | - return; |
55 | | - } |
56 | | - if (context.turn >= context.maxTurns) { |
57 | | - context.error = analysis.error; |
58 | | - return; |
59 | | - } |
60 | | - context.nextPrompt = defaultRepairPrompt(context.spec, analysis.error); |
61 | | - }; |
62 | | -} |
63 | | - |
64 | | -export function timeout(options: TimeoutOptions): AgentAddon { |
65 | | - return async (context, next) => { |
66 | | - context.signal = timeoutSignal(context.signal, options.timeout); |
67 | | - await next(); |
68 | | - }; |
69 | | -} |
70 | | - |
71 | | -export function oncePerAgent(register: AgentRegistration): AgentAddon { |
72 | | - const seen = new WeakSet<Agent>(); |
73 | | - return async (context, next) => { |
74 | | - if (!seen.has(context.agent)) { |
75 | | - await register(context.agent, context); |
76 | | - seen.add(context.agent); |
77 | | - } |
78 | | - await next(); |
79 | | - }; |
80 | | -} |
81 | | - |
82 | | -function timeoutSignal(parent?: AbortSignal, timeoutMs?: number): AbortSignal | undefined { |
83 | | - if (!timeoutMs) { |
84 | | - return parent; |
85 | | - } |
86 | | - const controller = new AbortController(); |
87 | | - const onAbort = () => controller.abort(parent?.reason); |
88 | | - parent?.addEventListener("abort", onAbort, { once: true }); |
89 | | - const timer = setTimeout( |
90 | | - () => controller.abort(new Error(`Timed out after ${timeoutMs}ms`)), |
91 | | - timeoutMs, |
92 | | - ); |
93 | | - controller.signal.addEventListener("abort", () => clearTimeout(timer), { once: true }); |
94 | | - return controller.signal; |
95 | | -} |
96 | | - |
97 | | -export const addons = { |
98 | | - oncePerAgent, |
99 | | - timeout, |
100 | | - repair, |
101 | | - steering, |
102 | | -}; |
| 1 | +export { addons, oncePerAgent, repair, steering, timeout } from "./rig.ts"; |
| 2 | +export type { AgentRegistration, SteeringOptions, TimeoutOptions } from "./rig.ts"; |
0 commit comments