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
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { appendFile, mkdir, readFile, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export const SESSION_FORMAT_VERSION = 1;
|
|
5
|
+
const SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
6
|
+
const SESSIONS_DIRECTORY = "sessions";
|
|
7
|
+
const DEFAULT_LIST_LIMIT = 20;
|
|
8
|
+
export function defaultSessionHome(environment = process.env) {
|
|
9
|
+
const configured = environment.CHIVGENT_HOME;
|
|
10
|
+
return configured !== undefined && configured.length > 0
|
|
11
|
+
? configured
|
|
12
|
+
: path.join(os.homedir(), ".chivgent");
|
|
13
|
+
}
|
|
14
|
+
export function createSessionId(now = new Date()) {
|
|
15
|
+
const stamp = now.toISOString().replaceAll(/[:.]/g, "-");
|
|
16
|
+
return `${stamp}-${Math.random().toString(36).slice(2, 8)}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Appends session records as JSON lines under `<home>/sessions/<id>.jsonl`.
|
|
20
|
+
* Writes are serialised per session so events keep their emission order.
|
|
21
|
+
*/
|
|
22
|
+
export class FileSessionStore {
|
|
23
|
+
directory;
|
|
24
|
+
pendingWrites = Promise.resolve();
|
|
25
|
+
constructor(home = defaultSessionHome()) {
|
|
26
|
+
this.directory = path.join(home, SESSIONS_DIRECTORY);
|
|
27
|
+
}
|
|
28
|
+
location(id) {
|
|
29
|
+
return path.join(this.directory, `${assertSessionId(id)}.jsonl`);
|
|
30
|
+
}
|
|
31
|
+
append(id, record) {
|
|
32
|
+
const file = this.location(id);
|
|
33
|
+
const line = `${JSON.stringify(record)}\n`;
|
|
34
|
+
const write = this.pendingWrites.then(async () => {
|
|
35
|
+
await mkdir(this.directory, { recursive: true });
|
|
36
|
+
await appendFile(file, line, "utf8");
|
|
37
|
+
});
|
|
38
|
+
// Keep the queue usable after an individual write fails. The caller still
|
|
39
|
+
// receives `write` and can observe that failure, while later appends are
|
|
40
|
+
// chained from a recovered promise instead of a permanently rejected one.
|
|
41
|
+
this.pendingWrites = write.catch(() => undefined);
|
|
42
|
+
return write;
|
|
43
|
+
}
|
|
44
|
+
async flush() {
|
|
45
|
+
await this.pendingWrites;
|
|
46
|
+
}
|
|
47
|
+
async read(id) {
|
|
48
|
+
let contents;
|
|
49
|
+
try {
|
|
50
|
+
contents = await readFile(this.location(id), "utf8");
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (isNotFound(error)) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
return parseTranscript(contents);
|
|
59
|
+
}
|
|
60
|
+
async list(options = {}) {
|
|
61
|
+
let files;
|
|
62
|
+
try {
|
|
63
|
+
files = await readdir(this.directory);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (isNotFound(error)) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
const summaries = [];
|
|
72
|
+
for (const file of files) {
|
|
73
|
+
if (!file.endsWith(".jsonl")) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const summary = await this.summarise(path.join(this.directory, file));
|
|
77
|
+
if (summary === undefined) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (options.cwd !== undefined && summary.cwd !== options.cwd) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
summaries.push(summary);
|
|
84
|
+
}
|
|
85
|
+
return summaries
|
|
86
|
+
.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt))
|
|
87
|
+
.slice(0, options.limit ?? DEFAULT_LIST_LIMIT);
|
|
88
|
+
}
|
|
89
|
+
async summarise(file) {
|
|
90
|
+
let transcript;
|
|
91
|
+
let updatedAt;
|
|
92
|
+
try {
|
|
93
|
+
transcript = parseTranscript(await readFile(file, "utf8"));
|
|
94
|
+
updatedAt = (await stat(file)).mtime.toISOString();
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (isNotFound(error)) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
if (transcript === undefined) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
const lastPrompt = transcript.prompts.at(-1);
|
|
106
|
+
return {
|
|
107
|
+
id: transcript.header.id,
|
|
108
|
+
cwd: transcript.header.cwd,
|
|
109
|
+
timestamp: transcript.header.timestamp,
|
|
110
|
+
updatedAt,
|
|
111
|
+
promptCount: transcript.prompts.length,
|
|
112
|
+
...(lastPrompt === undefined ? {} : { lastPrompt }),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Rebuilds a transcript from a session file. The authoritative message list is
|
|
118
|
+
* the one carried by the last `agent_end`, so a partially written file degrades
|
|
119
|
+
* to the last completed run instead of failing to load.
|
|
120
|
+
*/
|
|
121
|
+
export function parseTranscript(contents) {
|
|
122
|
+
let header;
|
|
123
|
+
let messages = [];
|
|
124
|
+
const prompts = [];
|
|
125
|
+
for (const line of contents.split("\n")) {
|
|
126
|
+
if (line.trim().length === 0) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
let record;
|
|
130
|
+
try {
|
|
131
|
+
record = JSON.parse(line);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
continue; // A truncated final line must not discard the session.
|
|
135
|
+
}
|
|
136
|
+
if (typeof record !== "object" || record === null || !("type" in record)) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (record.type === "session") {
|
|
140
|
+
header = toHeader(record);
|
|
141
|
+
}
|
|
142
|
+
else if (record.type === "agent_start" && "prompt" in record) {
|
|
143
|
+
if (typeof record.prompt === "string") {
|
|
144
|
+
prompts.push(record.prompt);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else if (record.type === "agent_end" && "messages" in record) {
|
|
148
|
+
if (Array.isArray(record.messages)) {
|
|
149
|
+
messages = record.messages;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return header === undefined ? undefined : { header, messages, prompts };
|
|
154
|
+
}
|
|
155
|
+
function toHeader(record) {
|
|
156
|
+
const candidate = record;
|
|
157
|
+
if (typeof candidate.id !== "string" ||
|
|
158
|
+
typeof candidate.cwd !== "string" ||
|
|
159
|
+
typeof candidate.timestamp !== "string" ||
|
|
160
|
+
typeof candidate.version !== "number") {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
type: "session",
|
|
165
|
+
version: candidate.version,
|
|
166
|
+
id: candidate.id,
|
|
167
|
+
timestamp: candidate.timestamp,
|
|
168
|
+
cwd: candidate.cwd,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function assertSessionId(id) {
|
|
172
|
+
if (!SESSION_ID_PATTERN.test(id)) {
|
|
173
|
+
throw new TypeError(`Invalid session id: ${id}`);
|
|
174
|
+
}
|
|
175
|
+
return id;
|
|
176
|
+
}
|
|
177
|
+
function isNotFound(error) {
|
|
178
|
+
return (typeof error === "object" &&
|
|
179
|
+
error !== null &&
|
|
180
|
+
"code" in error &&
|
|
181
|
+
(error.code === "ENOENT" || error.code === "ENOTDIR"));
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type AgentOptions, type AgentRunResult } from "./agent.js";
|
|
2
|
+
import type { AgentEventListener } from "./events.js";
|
|
3
|
+
import type { Message } from "./messages.js";
|
|
4
|
+
import { type SessionHeader, type SessionStore } from "./session-store.js";
|
|
5
|
+
export interface AgentSessionOptions {
|
|
6
|
+
/** Agent configuration. The session owns event delivery, so `onEvent` is not part of it. */
|
|
7
|
+
readonly agent: Omit<AgentOptions, "onEvent">;
|
|
8
|
+
readonly id?: string;
|
|
9
|
+
readonly cwd?: string;
|
|
10
|
+
readonly store?: SessionStore;
|
|
11
|
+
/** Messages restored from an earlier session. */
|
|
12
|
+
readonly messages?: readonly Message[];
|
|
13
|
+
/** True when the session log already has a header line. */
|
|
14
|
+
readonly resumed?: boolean;
|
|
15
|
+
readonly now?: () => Date;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Owns one conversation: the transcript that survives across prompts, the
|
|
19
|
+
* listeners that watch it, and the optional durable log. The Agent stays
|
|
20
|
+
* stateless between runs; the session is what makes a chivgent conversation
|
|
21
|
+
* multi-turn.
|
|
22
|
+
*/
|
|
23
|
+
export declare class AgentSession {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly cwd: string;
|
|
26
|
+
private readonly agent;
|
|
27
|
+
private readonly listeners;
|
|
28
|
+
private readonly store;
|
|
29
|
+
private readonly now;
|
|
30
|
+
private transcript;
|
|
31
|
+
private headerWritten;
|
|
32
|
+
private promptCount;
|
|
33
|
+
constructor(options: AgentSessionOptions);
|
|
34
|
+
get messages(): readonly Message[];
|
|
35
|
+
get turns(): number;
|
|
36
|
+
get toolNames(): readonly string[];
|
|
37
|
+
subscribe(listener: AgentEventListener): () => void;
|
|
38
|
+
/** Drops the transcript but keeps the session id and its log. */
|
|
39
|
+
clear(): void;
|
|
40
|
+
prompt(text: string, options?: {
|
|
41
|
+
readonly signal?: AbortSignal;
|
|
42
|
+
}): Promise<AgentRunResult>;
|
|
43
|
+
header(): SessionHeader;
|
|
44
|
+
private dispatch;
|
|
45
|
+
private record;
|
|
46
|
+
private writeHeader;
|
|
47
|
+
private flush;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,KAAK,EAAc,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,mBAAmB;IAClC,4FAA4F;IAC5F,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IACvC,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;IAC3D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IACjD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,WAAW,CAAK;IAExB,YAAY,OAAO,EAAE,mBAAmB,EAavC;IAED,IAAI,QAAQ,IAAI,SAAS,OAAO,EAAE,CAEjC;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,SAAS,IAAI,SAAS,MAAM,EAAE,CAEjC;IAED,SAAS,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAKlD;IAED,iEAAiE;IACjE,KAAK,IAAI,IAAI,CAEZ;IAEK,MAAM,CACV,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GAC9C,OAAO,CAAC,cAAc,CAAC,CAWzB;IAED,MAAM,IAAI,aAAa,CAQtB;IAED,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,MAAM;YAcA,WAAW;YAYX,KAAK;CAOpB"}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Agent } from "./agent.js";
|
|
2
|
+
import { createSessionId, SESSION_FORMAT_VERSION, } from "./session-store.js";
|
|
3
|
+
/**
|
|
4
|
+
* Owns one conversation: the transcript that survives across prompts, the
|
|
5
|
+
* listeners that watch it, and the optional durable log. The Agent stays
|
|
6
|
+
* stateless between runs; the session is what makes a chivgent conversation
|
|
7
|
+
* multi-turn.
|
|
8
|
+
*/
|
|
9
|
+
export class AgentSession {
|
|
10
|
+
id;
|
|
11
|
+
cwd;
|
|
12
|
+
agent;
|
|
13
|
+
listeners = new Set();
|
|
14
|
+
store;
|
|
15
|
+
now;
|
|
16
|
+
transcript;
|
|
17
|
+
headerWritten;
|
|
18
|
+
promptCount = 0;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.id = options.id ?? createSessionId();
|
|
21
|
+
this.cwd = options.cwd ?? process.cwd();
|
|
22
|
+
this.store = options.store;
|
|
23
|
+
this.now = options.now ?? (() => new Date());
|
|
24
|
+
this.transcript = structuredClone(options.messages ?? []);
|
|
25
|
+
this.headerWritten = options.resumed ?? false;
|
|
26
|
+
this.agent = new Agent({
|
|
27
|
+
...options.agent,
|
|
28
|
+
onEvent: (event) => {
|
|
29
|
+
this.dispatch(event);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
get messages() {
|
|
34
|
+
return this.transcript;
|
|
35
|
+
}
|
|
36
|
+
get turns() {
|
|
37
|
+
return this.promptCount;
|
|
38
|
+
}
|
|
39
|
+
get toolNames() {
|
|
40
|
+
return this.agent.toolNames;
|
|
41
|
+
}
|
|
42
|
+
subscribe(listener) {
|
|
43
|
+
this.listeners.add(listener);
|
|
44
|
+
return () => {
|
|
45
|
+
this.listeners.delete(listener);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** Drops the transcript but keeps the session id and its log. */
|
|
49
|
+
clear() {
|
|
50
|
+
this.transcript = [];
|
|
51
|
+
}
|
|
52
|
+
async prompt(text, options = {}) {
|
|
53
|
+
await this.writeHeader();
|
|
54
|
+
this.promptCount += 1;
|
|
55
|
+
const result = await this.agent.run(text, {
|
|
56
|
+
history: this.transcript,
|
|
57
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
58
|
+
});
|
|
59
|
+
this.transcript = result.messages;
|
|
60
|
+
await this.flush();
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
header() {
|
|
64
|
+
return {
|
|
65
|
+
type: "session",
|
|
66
|
+
version: SESSION_FORMAT_VERSION,
|
|
67
|
+
id: this.id,
|
|
68
|
+
timestamp: this.now().toISOString(),
|
|
69
|
+
cwd: this.cwd,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
dispatch(event) {
|
|
73
|
+
for (const listener of this.listeners) {
|
|
74
|
+
try {
|
|
75
|
+
listener(event);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// A failing subscriber must not change the outcome of the run.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
this.record(event);
|
|
82
|
+
}
|
|
83
|
+
record(event) {
|
|
84
|
+
if (this.store === undefined ||
|
|
85
|
+
!this.headerWritten ||
|
|
86
|
+
event.type === "message_update") {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
// Events are emitted synchronously; the store serialises the writes.
|
|
90
|
+
void this.store.append(this.id, event).catch(() => {
|
|
91
|
+
// A session log is a convenience, never a reason to fail a run.
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async writeHeader() {
|
|
95
|
+
if (this.store === undefined || this.headerWritten) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
await this.store.append(this.id, this.header());
|
|
100
|
+
this.headerWritten = true;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Skip persistence for this run. A later prompt can retry the header.
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async flush() {
|
|
107
|
+
try {
|
|
108
|
+
await this.store?.flush?.();
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// Persistence is best-effort and must not change the Agent result.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Tool, ToolContext, ToolOutput } from "./tool.js";
|
|
2
|
+
export declare class ListFilesTool implements Tool {
|
|
3
|
+
readonly name = "list_files";
|
|
4
|
+
readonly description = "List project files and directories in deterministic order. Ignored, generated, and sensitive paths are excluded.";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly path: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly description: 'Directory relative to the workspace root. Use "." for the root.';
|
|
11
|
+
};
|
|
12
|
+
readonly max_depth: {
|
|
13
|
+
readonly type: "integer";
|
|
14
|
+
readonly minimum: 1;
|
|
15
|
+
readonly maximum: 8;
|
|
16
|
+
readonly description: "Maximum directory depth to include. Usually use 4.";
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
readonly required: readonly ["path", "max_depth"];
|
|
20
|
+
readonly additionalProperties: false;
|
|
21
|
+
};
|
|
22
|
+
execute(argumentsValue: unknown, context: ToolContext): Promise<ToolOutput>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=list-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-files.d.ts","sourceRoot":"","sources":["../../src/tools/list-files.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AA+B/D,qBAAa,aAAc,YAAW,IAAI;IACxC,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,QAAQ,CAAC,WAAW,sHACiG;IACrH,QAAQ,CAAC,WAAW;uBA3Bd,QAAQ;;qBAEZ,IAAI;yBACF,IAAI,EAAE,QAAQ;yBACd,WAAW,EACT,iEAAiE;;qBAErE,SAAS;yBACP,IAAI,EAAE,SAAS;yBACf,OAAO,EAAE,CAAC;yBACV,OAAO;yBACP,WAAW,EAAE,oDAAoD;;;qCAG1D,MAAM,EAAE,WAAW;;MAaK;IAE7B,OAAO,CACX,cAAc,EAAE,OAAO,EACvB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAiCrB;CACF"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { WorkspaceError } from "../workspace.js";
|
|
2
|
+
import { formatBoundedLineOutput } from "./output.js";
|
|
3
|
+
const DEFAULT_PATH = ".";
|
|
4
|
+
const DEFAULT_MAX_DEPTH = 4;
|
|
5
|
+
const MAX_DEPTH = 8;
|
|
6
|
+
const inputSchema = {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
path: {
|
|
10
|
+
type: "string",
|
|
11
|
+
description: 'Directory relative to the workspace root. Use "." for the root.',
|
|
12
|
+
},
|
|
13
|
+
max_depth: {
|
|
14
|
+
type: "integer",
|
|
15
|
+
minimum: 1,
|
|
16
|
+
maximum: MAX_DEPTH,
|
|
17
|
+
description: "Maximum directory depth to include. Usually use 4.",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
required: ["path", "max_depth"],
|
|
21
|
+
additionalProperties: false,
|
|
22
|
+
};
|
|
23
|
+
export class ListFilesTool {
|
|
24
|
+
name = "list_files";
|
|
25
|
+
description = "List project files and directories in deterministic order. Ignored, generated, and sensitive paths are excluded.";
|
|
26
|
+
inputSchema = inputSchema;
|
|
27
|
+
async execute(argumentsValue, context) {
|
|
28
|
+
const argumentsObject = parseArguments(argumentsValue);
|
|
29
|
+
if (argumentsObject === undefined) {
|
|
30
|
+
return {
|
|
31
|
+
content: 'Invalid arguments. Expected {"path":".","max_depth":4}; max_depth must be an integer from 1 to 8.',
|
|
32
|
+
isError: true,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const result = await context.workspace.listFiles({
|
|
37
|
+
path: argumentsObject.path,
|
|
38
|
+
maxDepth: argumentsObject.maxDepth,
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
content: formatBoundedLineOutput(result.entries.map((entry) => entry.path), {
|
|
42
|
+
emptyMessage: "No discoverable files found.",
|
|
43
|
+
truncated: result.truncated,
|
|
44
|
+
truncationMessage: "[truncated: narrow path or reduce max_depth to inspect a smaller subtree]",
|
|
45
|
+
}),
|
|
46
|
+
isError: false,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (error instanceof WorkspaceError || error instanceof TypeError) {
|
|
51
|
+
return { content: error.message, isError: true };
|
|
52
|
+
}
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function parseArguments(value) {
|
|
58
|
+
if (!isRecord(value)) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const keys = Object.keys(value);
|
|
62
|
+
if (keys.some((key) => key !== "path" && key !== "max_depth")) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const path = value.path ?? DEFAULT_PATH;
|
|
66
|
+
const maxDepth = value.max_depth ?? DEFAULT_MAX_DEPTH;
|
|
67
|
+
if (typeof path !== "string" ||
|
|
68
|
+
path.length === 0 ||
|
|
69
|
+
typeof maxDepth !== "number" ||
|
|
70
|
+
!Number.isSafeInteger(maxDepth) ||
|
|
71
|
+
maxDepth < 1 ||
|
|
72
|
+
maxDepth > MAX_DEPTH) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
return { path, maxDepth };
|
|
76
|
+
}
|
|
77
|
+
function isRecord(value) {
|
|
78
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=list-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-files.js","sourceRoot":"","sources":["../../src/tools/list-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const MAX_TOOL_OUTPUT_BYTES: number;
|
|
2
|
+
export interface BoundedLineOutputOptions {
|
|
3
|
+
readonly emptyMessage: string;
|
|
4
|
+
readonly metadata?: string;
|
|
5
|
+
readonly truncated: boolean;
|
|
6
|
+
readonly truncationMessage: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function formatBoundedLineOutput(lines: readonly string[], options: BoundedLineOutputOptions): string;
|
|
9
|
+
export declare function truncateUtf8(value: string, maxBytes: number): string;
|
|
10
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/tools/output.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,QAAY,CAAC;AAE/C,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,wBAAwB,GAChC,MAAM,CA8BR;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAepE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const MAX_TOOL_OUTPUT_BYTES = 64 * 1024;
|
|
2
|
+
export function formatBoundedLineOutput(lines, options) {
|
|
3
|
+
const mainLines = lines.length === 0 ? [options.emptyMessage] : lines;
|
|
4
|
+
const reservedSuffix = [options.truncationMessage, options.metadata]
|
|
5
|
+
.filter((value) => value !== undefined)
|
|
6
|
+
.join("\n");
|
|
7
|
+
const mainBudget = Math.max(0, MAX_TOOL_OUTPUT_BYTES - Buffer.byteLength(reservedSuffix, "utf8") - 1);
|
|
8
|
+
const accepted = [];
|
|
9
|
+
let usedBytes = 0;
|
|
10
|
+
let truncated = options.truncated;
|
|
11
|
+
for (const line of mainLines) {
|
|
12
|
+
const separatorBytes = accepted.length === 0 ? 0 : 1;
|
|
13
|
+
const lineBytes = Buffer.byteLength(line, "utf8");
|
|
14
|
+
if (usedBytes + separatorBytes + lineBytes > mainBudget) {
|
|
15
|
+
truncated = true;
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
accepted.push(line);
|
|
19
|
+
usedBytes += separatorBytes + lineBytes;
|
|
20
|
+
}
|
|
21
|
+
const outputLines = [
|
|
22
|
+
...accepted,
|
|
23
|
+
...(truncated ? [options.truncationMessage] : []),
|
|
24
|
+
...(options.metadata === undefined ? [] : [options.metadata]),
|
|
25
|
+
];
|
|
26
|
+
return truncateUtf8(outputLines.join("\n"), MAX_TOOL_OUTPUT_BYTES);
|
|
27
|
+
}
|
|
28
|
+
export function truncateUtf8(value, maxBytes) {
|
|
29
|
+
const encoded = Buffer.from(value, "utf8");
|
|
30
|
+
if (encoded.byteLength <= maxBytes) {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
34
|
+
for (let end = maxBytes; end >= Math.max(0, maxBytes - 4); end -= 1) {
|
|
35
|
+
try {
|
|
36
|
+
return decoder.decode(encoded.subarray(0, end));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Try the previous byte until the UTF-8 prefix is complete.
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return "";
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/tools/output.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,CAAC;AAS/C,MAAM,UAAU,uBAAuB,CACrC,KAAwB,EACxB,OAAiC;IAEjC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACtE,MAAM,cAAc,GAAG,CAAC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,QAAQ,CAAC;SACjE,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC;SACvD,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CACzB,CAAC,EACD,qBAAqB,GAAG,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,CACtE,CAAC;IACF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAClD,IAAI,SAAS,GAAG,cAAc,GAAG,SAAS,GAAG,UAAU,EAAE,CAAC;YACxD,SAAS,GAAG,IAAI,CAAC;YACjB,MAAM;QACR,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,SAAS,IAAI,cAAc,GAAG,SAAS,CAAC;IAC1C,CAAC;IAED,MAAM,WAAW,GAAG;QAClB,GAAG,QAAQ;QACX,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;KAC9D,CAAC;IACF,OAAO,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,qBAAqB,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,QAAgB;IAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,UAAU,IAAI,QAAQ,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,KAAK,IAAI,GAAG,GAAG,QAAQ,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC;YACH,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,4DAA4D;QAC9D,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Tool, ToolContext, ToolOutput } from "./tool.js";
|
|
2
|
+
export declare class ReadFileTool implements Tool {
|
|
3
|
+
readonly name = "read_file";
|
|
4
|
+
readonly description = "Read a bounded range from a UTF-8 text file inside the workspace. Use list_files or search_text first when the path is unknown.";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly path: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly description: "Path relative to the workspace root.";
|
|
11
|
+
};
|
|
12
|
+
readonly start_line: {
|
|
13
|
+
readonly type: "integer";
|
|
14
|
+
readonly minimum: 1;
|
|
15
|
+
readonly description: "First one-based line to read. Usually start with 1.";
|
|
16
|
+
};
|
|
17
|
+
readonly line_count: {
|
|
18
|
+
readonly type: "integer";
|
|
19
|
+
readonly minimum: 1;
|
|
20
|
+
readonly maximum: 500;
|
|
21
|
+
readonly description: "Number of lines to read. Usually use 200.";
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
readonly required: readonly ["path", "start_line", "line_count"];
|
|
25
|
+
readonly additionalProperties: false;
|
|
26
|
+
};
|
|
27
|
+
execute(argumentsValue: unknown, context: ToolContext): Promise<ToolOutput>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=read-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-file.d.ts","sourceRoot":"","sources":["../../src/tools/read-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAsC/D,qBAAa,YAAa,YAAW,IAAI;IACvC,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,WAAW,qIACgH;IACpI,QAAQ,CAAC,WAAW;uBAhCd,QAAQ;;qBAEZ,IAAI;yBACF,IAAI,EAAE,QAAQ;yBACd,WAAW,EAAE,sCAAsC;;qBAErD,UAAU;yBACR,IAAI,EAAE,SAAS;yBACf,OAAO,EAAE,CAAC;yBACV,WAAW,EAAE,qDAAqD;;qBAEpE,UAAU;yBACR,IAAI,EAAE,SAAS;yBACf,OAAO,EAAE,CAAC;yBACV,OAAO;yBACP,WAAW,EAAE,2CAA2C;;;qCAGjD,MAAM,EAAE,YAAY,EAAE,YAAY;;MAcV;IAE7B,OAAO,CACX,cAAc,EAAE,OAAO,EACvB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CA6BrB;CACF"}
|