chivgent 0.6.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 +21 -0
- package/README.md +359 -0
- package/README.zh-CN.md +345 -0
- package/dist/agent.d.ts +58 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +281 -0
- package/dist/agent.js.map +1 -0
- package/dist/cli-options.d.ts +33 -0
- package/dist/cli-options.d.ts.map +1 -0
- package/dist/cli-options.js +151 -0
- package/dist/cli-options.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +233 -0
- package/dist/cli.js.map +1 -0
- package/dist/events.d.ts +79 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +12 -0
- package/dist/events.js.map +1 -0
- package/dist/llm.d.ts +38 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +17 -0
- package/dist/llm.js.map +1 -0
- package/dist/messages.d.ts +23 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +2 -0
- package/dist/messages.js.map +1 -0
- package/dist/providers/deepseek.d.ts +12 -0
- package/dist/providers/deepseek.d.ts.map +1 -0
- package/dist/providers/deepseek.js +15 -0
- package/dist/providers/deepseek.js.map +1 -0
- package/dist/providers/openai-compatible-chat.d.ts +25 -0
- package/dist/providers/openai-compatible-chat.d.ts.map +1 -0
- package/dist/providers/openai-compatible-chat.js +293 -0
- package/dist/providers/openai-compatible-chat.js.map +1 -0
- package/dist/providers/openai.d.ts +16 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +183 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/render.d.ts +26 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +95 -0
- package/dist/render.js.map +1 -0
- package/dist/repl.d.ts +29 -0
- package/dist/repl.d.ts.map +1 -0
- package/dist/repl.js +119 -0
- package/dist/repl.js.map +1 -0
- package/dist/retry.d.ts +42 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +186 -0
- package/dist/retry.js.map +1 -0
- package/dist/session-store.d.ts +66 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +183 -0
- package/dist/session-store.js.map +1 -0
- package/dist/session.d.ts +49 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +115 -0
- package/dist/session.js.map +1 -0
- package/dist/tools/list-files.d.ts +24 -0
- package/dist/tools/list-files.d.ts.map +1 -0
- package/dist/tools/list-files.js +80 -0
- package/dist/tools/list-files.js.map +1 -0
- package/dist/tools/output.d.ts +10 -0
- package/dist/tools/output.d.ts.map +1 -0
- package/dist/tools/output.js +44 -0
- package/dist/tools/output.js.map +1 -0
- package/dist/tools/read-file.d.ts +29 -0
- package/dist/tools/read-file.d.ts.map +1 -0
- package/dist/tools/read-file.js +150 -0
- package/dist/tools/read-file.js.map +1 -0
- package/dist/tools/search-text.d.ts +28 -0
- package/dist/tools/search-text.d.ts.map +1 -0
- package/dist/tools/search-text.js +94 -0
- package/dist/tools/search-text.js.map +1 -0
- package/dist/tools/tool.d.ts +22 -0
- package/dist/tools/tool.d.ts.map +1 -0
- package/dist/tools/tool.js +2 -0
- package/dist/tools/tool.js.map +1 -0
- package/dist/workspace.d.ts +72 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +504 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +55 -0
package/dist/render.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const MAX_ARGUMENT_CHARACTERS = 120;
|
|
2
|
+
const MAX_RESULT_CHARACTERS = 100;
|
|
3
|
+
const DIM = "\u001B[2m";
|
|
4
|
+
const RED = "\u001B[31m";
|
|
5
|
+
const RESET = "\u001B[0m";
|
|
6
|
+
/**
|
|
7
|
+
* Renders runtime events for a terminal. The answer goes to stdout so it stays
|
|
8
|
+
* pipeable; tool activity and run status go to stderr.
|
|
9
|
+
*/
|
|
10
|
+
export function createEventRenderer(streams, options = {}) {
|
|
11
|
+
const stream = options.stream ?? true;
|
|
12
|
+
const showToolActivity = options.showToolActivity ?? true;
|
|
13
|
+
const color = options.color ?? false;
|
|
14
|
+
const paint = (value, code) => color ? `${code}${value}${RESET}` : value;
|
|
15
|
+
let lineOpen = false;
|
|
16
|
+
const endLine = () => {
|
|
17
|
+
if (lineOpen) {
|
|
18
|
+
streams.stdout.write("\n");
|
|
19
|
+
lineOpen = false;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
return (event) => {
|
|
23
|
+
switch (event.type) {
|
|
24
|
+
case "message_update":
|
|
25
|
+
if (stream && event.delta.length > 0) {
|
|
26
|
+
streams.stdout.write(event.delta);
|
|
27
|
+
lineOpen = !event.delta.endsWith("\n");
|
|
28
|
+
}
|
|
29
|
+
return;
|
|
30
|
+
case "message_end":
|
|
31
|
+
if (!stream && event.message.content.length > 0) {
|
|
32
|
+
streams.stdout.write(`${event.message.content}\n`);
|
|
33
|
+
}
|
|
34
|
+
endLine();
|
|
35
|
+
return;
|
|
36
|
+
case "tool_execution_start":
|
|
37
|
+
if (showToolActivity) {
|
|
38
|
+
streams.stderr.write(paint(`· ${event.toolName} ${summariseArguments(event.arguments)}\n`, DIM));
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
case "tool_execution_end":
|
|
42
|
+
if (showToolActivity) {
|
|
43
|
+
const summary = ` ↳ ${summariseResult(event.content, event.isError)}\n`;
|
|
44
|
+
streams.stderr.write(paint(summary, event.isError ? RED : DIM));
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
case "agent_end":
|
|
48
|
+
endLine();
|
|
49
|
+
if (event.status === "max_turns") {
|
|
50
|
+
streams.stderr.write(`Stopped after ${event.turnCount} turns without a final answer.\n`);
|
|
51
|
+
}
|
|
52
|
+
else if (event.status === "aborted") {
|
|
53
|
+
streams.stderr.write("Interrupted.\n");
|
|
54
|
+
}
|
|
55
|
+
// A failed run is reported by whoever awaited it, with the real error.
|
|
56
|
+
return;
|
|
57
|
+
default:
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Writes one JSON object per line: the session header first, then every event.
|
|
64
|
+
* This is the machine-readable counterpart of the terminal renderer.
|
|
65
|
+
*/
|
|
66
|
+
export function createJsonEventWriter(output, header) {
|
|
67
|
+
if (header !== undefined) {
|
|
68
|
+
output.write(`${JSON.stringify(header)}\n`);
|
|
69
|
+
}
|
|
70
|
+
return (event) => {
|
|
71
|
+
output.write(`${JSON.stringify(event)}\n`);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function summariseArguments(value) {
|
|
75
|
+
let text;
|
|
76
|
+
try {
|
|
77
|
+
text = typeof value === "string" ? value : (JSON.stringify(value) ?? "");
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
text = "[unserialisable arguments]";
|
|
81
|
+
}
|
|
82
|
+
return truncate(text.replaceAll(/\s+/g, " "), MAX_ARGUMENT_CHARACTERS);
|
|
83
|
+
}
|
|
84
|
+
function summariseResult(content, isError) {
|
|
85
|
+
const firstLine = content.split("\n", 1)[0] ?? "";
|
|
86
|
+
const lineCount = content.length === 0 ? 0 : content.split("\n").length;
|
|
87
|
+
const suffix = lineCount > 1 ? ` (${lineCount} lines)` : "";
|
|
88
|
+
return `${isError ? "error: " : ""}${truncate(firstLine, MAX_RESULT_CHARACTERS)}${suffix}`;
|
|
89
|
+
}
|
|
90
|
+
function truncate(value, maxCharacters) {
|
|
91
|
+
return value.length <= maxCharacters
|
|
92
|
+
? value
|
|
93
|
+
: `${value.slice(0, maxCharacters - 1)}…`;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/dist/repl.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AgentSession } from "./session.js";
|
|
2
|
+
import type { OutputStream } from "./render.js";
|
|
3
|
+
export declare const REPL_PROMPT = "\u203A ";
|
|
4
|
+
export type SlashCommandOutcome = "handled" | "exit" | "not-a-command";
|
|
5
|
+
export interface SlashCommandContext {
|
|
6
|
+
readonly session: AgentSession;
|
|
7
|
+
readonly write: (text: string) => void;
|
|
8
|
+
readonly sessionFile?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Interprets one line of REPL input. Returns `not-a-command` when the line is
|
|
12
|
+
* an ordinary prompt for the model.
|
|
13
|
+
*/
|
|
14
|
+
export declare function handleSlashCommand(line: string, context: SlashCommandContext): SlashCommandOutcome;
|
|
15
|
+
export interface ReplOptions {
|
|
16
|
+
readonly session: AgentSession;
|
|
17
|
+
readonly input: NodeJS.ReadableStream;
|
|
18
|
+
readonly output: NodeJS.WritableStream;
|
|
19
|
+
readonly stderr: OutputStream;
|
|
20
|
+
readonly banner?: string;
|
|
21
|
+
readonly sessionFile?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Reads prompts until the user leaves. One run at a time: Ctrl+C cancels the
|
|
25
|
+
* answer in progress instead of killing the process, so the transcript and the
|
|
26
|
+
* session log survive an interrupt.
|
|
27
|
+
*/
|
|
28
|
+
export declare function runRepl(options: ReplOptions): Promise<number>;
|
|
29
|
+
//# sourceMappingURL=repl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,WAAW,YAAO,CAAC;AAEhC,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,MAAM,GAAG,eAAe,CAAC;AAEvE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAYD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,mBAAmB,GAC3B,mBAAmB,CAmCrB;AAeD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA6DnE"}
|
package/dist/repl.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
export const REPL_PROMPT = "› ";
|
|
3
|
+
const HELP = `Commands:
|
|
4
|
+
/help Show this help
|
|
5
|
+
/session Show the current session id, workspace, and size
|
|
6
|
+
/tools List the tools available to the model
|
|
7
|
+
/clear Start a new transcript in the same session
|
|
8
|
+
/exit Leave chivgent (Ctrl+D also works)
|
|
9
|
+
|
|
10
|
+
Anything else is sent to the model. Ctrl+C stops the answer in progress.
|
|
11
|
+
`;
|
|
12
|
+
/**
|
|
13
|
+
* Interprets one line of REPL input. Returns `not-a-command` when the line is
|
|
14
|
+
* an ordinary prompt for the model.
|
|
15
|
+
*/
|
|
16
|
+
export function handleSlashCommand(line, context) {
|
|
17
|
+
const trimmed = line.trim();
|
|
18
|
+
if (!trimmed.startsWith("/")) {
|
|
19
|
+
return "not-a-command";
|
|
20
|
+
}
|
|
21
|
+
switch (trimmed.split(/\s+/, 1)[0]) {
|
|
22
|
+
case "/help":
|
|
23
|
+
case "/?":
|
|
24
|
+
context.write(HELP);
|
|
25
|
+
return "handled";
|
|
26
|
+
case "/session":
|
|
27
|
+
context.write(describeSession(context));
|
|
28
|
+
return "handled";
|
|
29
|
+
case "/tools":
|
|
30
|
+
context.write(`${context.session.toolNames.map((name) => ` ${name}`).join("\n")}\n`);
|
|
31
|
+
return "handled";
|
|
32
|
+
case "/clear":
|
|
33
|
+
context.session.clear();
|
|
34
|
+
context.write("Transcript cleared.\n");
|
|
35
|
+
return "handled";
|
|
36
|
+
case "/exit":
|
|
37
|
+
case "/quit":
|
|
38
|
+
return "exit";
|
|
39
|
+
default:
|
|
40
|
+
context.write(`Unknown command: ${trimmed}. Try /help.\n`);
|
|
41
|
+
return "handled";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function describeSession(context) {
|
|
45
|
+
const lines = [
|
|
46
|
+
`id: ${context.session.id}`,
|
|
47
|
+
`workspace: ${context.session.cwd}`,
|
|
48
|
+
`prompts: ${context.session.turns}`,
|
|
49
|
+
`messages: ${context.session.messages.length}`,
|
|
50
|
+
];
|
|
51
|
+
if (context.sessionFile !== undefined) {
|
|
52
|
+
lines.push(`log: ${context.sessionFile}`);
|
|
53
|
+
}
|
|
54
|
+
return `${lines.join("\n")}\n`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Reads prompts until the user leaves. One run at a time: Ctrl+C cancels the
|
|
58
|
+
* answer in progress instead of killing the process, so the transcript and the
|
|
59
|
+
* session log survive an interrupt.
|
|
60
|
+
*/
|
|
61
|
+
export async function runRepl(options) {
|
|
62
|
+
const write = (text) => {
|
|
63
|
+
options.stderr.write(text);
|
|
64
|
+
};
|
|
65
|
+
const readline = createInterface({
|
|
66
|
+
input: options.input,
|
|
67
|
+
output: options.output,
|
|
68
|
+
terminal: true,
|
|
69
|
+
prompt: REPL_PROMPT,
|
|
70
|
+
});
|
|
71
|
+
let controller;
|
|
72
|
+
readline.on("SIGINT", () => {
|
|
73
|
+
if (controller === undefined) {
|
|
74
|
+
write("Press Ctrl+D or /exit to leave.\n");
|
|
75
|
+
readline.prompt();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
controller.abort();
|
|
79
|
+
});
|
|
80
|
+
if (options.banner !== undefined) {
|
|
81
|
+
write(options.banner);
|
|
82
|
+
}
|
|
83
|
+
readline.prompt();
|
|
84
|
+
for await (const line of readline) {
|
|
85
|
+
if (line.trim().length === 0) {
|
|
86
|
+
readline.prompt();
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const outcome = handleSlashCommand(line, {
|
|
90
|
+
session: options.session,
|
|
91
|
+
write,
|
|
92
|
+
...(options.sessionFile === undefined
|
|
93
|
+
? {}
|
|
94
|
+
: { sessionFile: options.sessionFile }),
|
|
95
|
+
});
|
|
96
|
+
if (outcome === "exit") {
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
if (outcome === "handled") {
|
|
100
|
+
readline.prompt();
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
controller = new AbortController();
|
|
104
|
+
try {
|
|
105
|
+
await options.session.prompt(line, { signal: controller.signal });
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
109
|
+
write(`Agent failed: ${message}\n`);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
controller = undefined;
|
|
113
|
+
}
|
|
114
|
+
readline.prompt();
|
|
115
|
+
}
|
|
116
|
+
readline.close();
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=repl.js.map
|
package/dist/repl.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repl.js","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"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"}
|
package/dist/retry.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type LLMClient, type LLMRequest, type LLMResponse, type LLMStreamHandlers } from "./llm.js";
|
|
2
|
+
export declare class LLMTimeoutError extends Error {
|
|
3
|
+
constructor(timeoutMs: number);
|
|
4
|
+
}
|
|
5
|
+
export interface RetryOptions {
|
|
6
|
+
/** Total attempts, including the first one. Defaults to 3. */
|
|
7
|
+
readonly maxAttempts?: number;
|
|
8
|
+
readonly initialDelayMs?: number;
|
|
9
|
+
readonly maxDelayMs?: number;
|
|
10
|
+
/** Per-attempt deadline. Use 0 to disable. Defaults to 120000. */
|
|
11
|
+
readonly requestTimeoutMs?: number;
|
|
12
|
+
/** Injected so tests do not depend on wall-clock time. */
|
|
13
|
+
readonly sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
14
|
+
readonly onRetry?: (info: RetryAttempt) => void;
|
|
15
|
+
}
|
|
16
|
+
export interface RetryAttempt {
|
|
17
|
+
readonly attempt: number;
|
|
18
|
+
readonly delayMs: number;
|
|
19
|
+
readonly reason: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Wraps a Provider with per-attempt timeouts and bounded exponential backoff.
|
|
23
|
+
* Retries stay invisible to the Agent Loop: it still sees one call that either
|
|
24
|
+
* resolves with an assistant message or fails.
|
|
25
|
+
*/
|
|
26
|
+
export declare class RetryingLLMClient implements LLMClient {
|
|
27
|
+
readonly stream?: (request: LLMRequest, handlers: LLMStreamHandlers) => Promise<LLMResponse>;
|
|
28
|
+
private readonly inner;
|
|
29
|
+
private readonly maxAttempts;
|
|
30
|
+
private readonly initialDelayMs;
|
|
31
|
+
private readonly maxDelayMs;
|
|
32
|
+
private readonly requestTimeoutMs;
|
|
33
|
+
private readonly sleep;
|
|
34
|
+
private readonly onRetry;
|
|
35
|
+
constructor(inner: LLMClient, options?: RetryOptions);
|
|
36
|
+
complete(request: LLMRequest): Promise<LLMResponse>;
|
|
37
|
+
private runStream;
|
|
38
|
+
private withRetries;
|
|
39
|
+
private backoffDelay;
|
|
40
|
+
private createDeadline;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,UAAU,CAAC;AAkBlB,qBAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,SAAS,EAAE,MAAM,EAG5B;CACF;AAED,MAAM,WAAW,YAAY;IAC3B,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,SAAS;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,CAChB,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,iBAAiB,KACxB,OAAO,CAAC,WAAW,CAAC,CAAC;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsD;IAC5E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6C;IAErE,YAAY,KAAK,EAAE,SAAS,EAAE,OAAO,GAAE,YAAiB,EAgBvD;IAEK,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAIxD;YAEa,SAAS;YAoBT,WAAW;IA0CzB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,cAAc;CAqCvB"}
|
package/dist/retry.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { isAbortError, LLMAbortError, } from "./llm.js";
|
|
2
|
+
const DEFAULT_MAX_ATTEMPTS = 3;
|
|
3
|
+
const DEFAULT_INITIAL_DELAY_MS = 500;
|
|
4
|
+
const DEFAULT_MAX_DELAY_MS = 8_000;
|
|
5
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 120_000;
|
|
6
|
+
const RETRYABLE_STATUS_CODES = new Set([408, 409, 425, 429]);
|
|
7
|
+
const RETRYABLE_ERROR_CODES = new Set([
|
|
8
|
+
"ECONNRESET",
|
|
9
|
+
"ECONNREFUSED",
|
|
10
|
+
"EPIPE",
|
|
11
|
+
"ETIMEDOUT",
|
|
12
|
+
"EAI_AGAIN",
|
|
13
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
14
|
+
"UND_ERR_SOCKET",
|
|
15
|
+
]);
|
|
16
|
+
export class LLMTimeoutError extends Error {
|
|
17
|
+
constructor(timeoutMs) {
|
|
18
|
+
super(`The Provider call exceeded ${timeoutMs}ms.`);
|
|
19
|
+
this.name = "LLMTimeoutError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Wraps a Provider with per-attempt timeouts and bounded exponential backoff.
|
|
24
|
+
* Retries stay invisible to the Agent Loop: it still sees one call that either
|
|
25
|
+
* resolves with an assistant message or fails.
|
|
26
|
+
*/
|
|
27
|
+
export class RetryingLLMClient {
|
|
28
|
+
stream;
|
|
29
|
+
inner;
|
|
30
|
+
maxAttempts;
|
|
31
|
+
initialDelayMs;
|
|
32
|
+
maxDelayMs;
|
|
33
|
+
requestTimeoutMs;
|
|
34
|
+
sleep;
|
|
35
|
+
onRetry;
|
|
36
|
+
constructor(inner, options = {}) {
|
|
37
|
+
this.inner = inner;
|
|
38
|
+
this.maxAttempts = positiveInteger(options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS, "maxAttempts");
|
|
39
|
+
this.initialDelayMs = options.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
|
|
40
|
+
this.maxDelayMs = options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
|
|
41
|
+
this.requestTimeoutMs =
|
|
42
|
+
options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
43
|
+
this.sleep = options.sleep ?? defaultSleep;
|
|
44
|
+
this.onRetry = options.onRetry;
|
|
45
|
+
if (inner.stream !== undefined) {
|
|
46
|
+
this.stream = (request, handlers) => this.runStream(request, handlers);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async complete(request) {
|
|
50
|
+
return this.withRetries(request, (attemptRequest) => this.inner.complete(attemptRequest));
|
|
51
|
+
}
|
|
52
|
+
async runStream(request, handlers) {
|
|
53
|
+
const stream = this.inner.stream;
|
|
54
|
+
if (stream === undefined) {
|
|
55
|
+
throw new TypeError("The wrapped Provider does not support streaming.");
|
|
56
|
+
}
|
|
57
|
+
return this.withRetries(request, async (attemptRequest, markCommitted) => stream.call(this.inner, attemptRequest, {
|
|
58
|
+
onTextDelta: (delta) => {
|
|
59
|
+
// Text already shown to the user cannot be replayed by a retry.
|
|
60
|
+
markCommitted();
|
|
61
|
+
handlers.onTextDelta(delta);
|
|
62
|
+
},
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
async withRetries(request, call) {
|
|
66
|
+
let lastError;
|
|
67
|
+
for (let attempt = 1; attempt <= this.maxAttempts; attempt += 1) {
|
|
68
|
+
throwIfAborted(request.signal);
|
|
69
|
+
const deadline = this.createDeadline(request.signal);
|
|
70
|
+
let committed = false;
|
|
71
|
+
try {
|
|
72
|
+
return await call({ ...request, signal: deadline.signal }, () => {
|
|
73
|
+
committed = true;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
lastError = deadline.timedOut ? new LLMTimeoutError(this.requestTimeoutMs) : error;
|
|
78
|
+
throwIfAborted(request.signal);
|
|
79
|
+
if (isAbortError(error) && !deadline.timedOut) {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
if (committed || attempt === this.maxAttempts || !isRetryable(lastError)) {
|
|
83
|
+
throw lastError;
|
|
84
|
+
}
|
|
85
|
+
const delayMs = this.backoffDelay(attempt);
|
|
86
|
+
this.onRetry?.({
|
|
87
|
+
attempt,
|
|
88
|
+
delayMs,
|
|
89
|
+
reason: describeError(lastError),
|
|
90
|
+
});
|
|
91
|
+
await this.sleep(delayMs, request.signal);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
deadline.dispose();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
throw lastError ?? new Error("The Provider call failed.");
|
|
98
|
+
}
|
|
99
|
+
backoffDelay(attempt) {
|
|
100
|
+
const exponential = this.initialDelayMs * 2 ** (attempt - 1);
|
|
101
|
+
return Math.min(this.maxDelayMs, exponential);
|
|
102
|
+
}
|
|
103
|
+
createDeadline(signal) {
|
|
104
|
+
const controller = new AbortController();
|
|
105
|
+
const state = { timedOut: false };
|
|
106
|
+
const forward = () => {
|
|
107
|
+
controller.abort(signal?.reason);
|
|
108
|
+
};
|
|
109
|
+
if (signal !== undefined) {
|
|
110
|
+
if (signal.aborted) {
|
|
111
|
+
forward();
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
signal.addEventListener("abort", forward, { once: true });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const timer = this.requestTimeoutMs > 0
|
|
118
|
+
? setTimeout(() => {
|
|
119
|
+
state.timedOut = true;
|
|
120
|
+
controller.abort(new LLMTimeoutError(this.requestTimeoutMs));
|
|
121
|
+
}, this.requestTimeoutMs)
|
|
122
|
+
: undefined;
|
|
123
|
+
timer?.unref?.();
|
|
124
|
+
return {
|
|
125
|
+
signal: controller.signal,
|
|
126
|
+
get timedOut() {
|
|
127
|
+
return state.timedOut;
|
|
128
|
+
},
|
|
129
|
+
dispose() {
|
|
130
|
+
if (timer !== undefined) {
|
|
131
|
+
clearTimeout(timer);
|
|
132
|
+
}
|
|
133
|
+
signal?.removeEventListener("abort", forward);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function isRetryable(error) {
|
|
139
|
+
if (error instanceof LLMTimeoutError) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
if (typeof error !== "object" || error === null) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
if ("status" in error && typeof error.status === "number") {
|
|
146
|
+
return (RETRYABLE_STATUS_CODES.has(error.status) ||
|
|
147
|
+
(error.status >= 500 && error.status <= 599));
|
|
148
|
+
}
|
|
149
|
+
if ("code" in error && typeof error.code === "string") {
|
|
150
|
+
return RETRYABLE_ERROR_CODES.has(error.code);
|
|
151
|
+
}
|
|
152
|
+
return ("name" in error &&
|
|
153
|
+
(error.name === "APIConnectionError" ||
|
|
154
|
+
error.name === "APIConnectionTimeoutError"));
|
|
155
|
+
}
|
|
156
|
+
function describeError(error) {
|
|
157
|
+
if (error instanceof Error) {
|
|
158
|
+
return `${error.name}: ${error.message}`;
|
|
159
|
+
}
|
|
160
|
+
return "Unknown Provider error";
|
|
161
|
+
}
|
|
162
|
+
function throwIfAborted(signal) {
|
|
163
|
+
if (signal !== undefined && signal.aborted) {
|
|
164
|
+
throw new LLMAbortError();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function positiveInteger(value, name) {
|
|
168
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
169
|
+
throw new TypeError(`${name} must be a positive safe integer.`);
|
|
170
|
+
}
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
function defaultSleep(ms, signal) {
|
|
174
|
+
return new Promise((resolve, reject) => {
|
|
175
|
+
const timer = setTimeout(() => {
|
|
176
|
+
signal?.removeEventListener("abort", onAbort);
|
|
177
|
+
resolve();
|
|
178
|
+
}, ms);
|
|
179
|
+
const onAbort = () => {
|
|
180
|
+
clearTimeout(timer);
|
|
181
|
+
reject(new LLMAbortError());
|
|
182
|
+
};
|
|
183
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { AgentEvent } from "./events.js";
|
|
2
|
+
import type { Message } from "./messages.js";
|
|
3
|
+
export declare const SESSION_FORMAT_VERSION = 1;
|
|
4
|
+
export interface SessionHeader {
|
|
5
|
+
readonly type: "session";
|
|
6
|
+
readonly version: number;
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly timestamp: string;
|
|
9
|
+
readonly cwd: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One JSONL line. The header comes first, then the run events. `message_update`
|
|
13
|
+
* deltas are not persisted: they are reconstructible from `message_end`, and
|
|
14
|
+
* keeping them would make a session file grow with every token.
|
|
15
|
+
*/
|
|
16
|
+
export type SessionRecord = SessionHeader | AgentEvent;
|
|
17
|
+
export interface SessionTranscript {
|
|
18
|
+
readonly header: SessionHeader;
|
|
19
|
+
readonly messages: readonly Message[];
|
|
20
|
+
readonly prompts: readonly string[];
|
|
21
|
+
}
|
|
22
|
+
export interface SessionSummary {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly cwd: string;
|
|
25
|
+
readonly timestamp: string;
|
|
26
|
+
readonly updatedAt: string;
|
|
27
|
+
readonly promptCount: number;
|
|
28
|
+
readonly lastPrompt?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface SessionListOptions {
|
|
31
|
+
/** Keep only sessions recorded for this workspace. */
|
|
32
|
+
readonly cwd?: string;
|
|
33
|
+
readonly limit?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface SessionStore {
|
|
36
|
+
append(id: string, record: SessionRecord): Promise<void>;
|
|
37
|
+
read(id: string): Promise<SessionTranscript | undefined>;
|
|
38
|
+
list(options?: SessionListOptions): Promise<readonly SessionSummary[]>;
|
|
39
|
+
location(id: string): string;
|
|
40
|
+
/** Resolves once every queued append has settled. */
|
|
41
|
+
flush?(): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
export declare function defaultSessionHome(environment?: NodeJS.ProcessEnv): string;
|
|
44
|
+
export declare function createSessionId(now?: Date): string;
|
|
45
|
+
/**
|
|
46
|
+
* Appends session records as JSON lines under `<home>/sessions/<id>.jsonl`.
|
|
47
|
+
* Writes are serialised per session so events keep their emission order.
|
|
48
|
+
*/
|
|
49
|
+
export declare class FileSessionStore implements SessionStore {
|
|
50
|
+
private readonly directory;
|
|
51
|
+
private pendingWrites;
|
|
52
|
+
constructor(home?: string);
|
|
53
|
+
location(id: string): string;
|
|
54
|
+
append(id: string, record: SessionRecord): Promise<void>;
|
|
55
|
+
flush(): Promise<void>;
|
|
56
|
+
read(id: string): Promise<SessionTranscript | undefined>;
|
|
57
|
+
list(options?: SessionListOptions): Promise<readonly SessionSummary[]>;
|
|
58
|
+
private summarise;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Rebuilds a transcript from a session file. The authoritative message list is
|
|
62
|
+
* the one carried by the last `agent_end`, so a partially written file degrades
|
|
63
|
+
* to the last completed run instead of failing to load.
|
|
64
|
+
*/
|
|
65
|
+
export declare function parseTranscript(contents: string): SessionTranscript | undefined;
|
|
66
|
+
//# sourceMappingURL=session-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAMxC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,UAAU,CAAC;AAEvD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAAC;IACzD,IAAI,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAC;IACvE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,qDAAqD;IACrD,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,wBAAgB,kBAAkB,CAChC,WAAW,GAAE,MAAM,CAAC,UAAwB,GAC3C,MAAM,CAKR;AAED,wBAAgB,eAAe,CAAC,GAAG,GAAE,IAAiB,GAAG,MAAM,CAG9D;AAED;;;GAGG;AACH,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,aAAa,CAAoC;IAEzD,YAAY,IAAI,GAAE,MAA6B,EAE9C;IAED,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE3B;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAavD;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAEK,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAW7D;IAEK,IAAI,CACR,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CA6BpC;YAEa,SAAS;CA0BxB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,GACf,iBAAiB,GAAG,SAAS,CAiC/B"}
|