@zaly/agent 0.1.1 → 0.3.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/dist/{agent-BRENvuvx.mjs → agent-GXRF7DUP.mjs} +102 -33
- package/dist/agent-GXRF7DUP.mjs.map +1 -0
- package/dist/{bash-DSy03sAj.mjs → bash-CB_VXpyd.mjs} +2 -2
- package/dist/{bash-DSy03sAj.mjs.map → bash-CB_VXpyd.mjs.map} +1 -1
- package/dist/{compactions-HFjEgrv3.mjs → compactions-92bMlcxJ.mjs} +25 -15
- package/dist/compactions-92bMlcxJ.mjs.map +1 -0
- package/dist/{edit-DT672zIy.mjs → edit-gkb6MCW-.mjs} +2 -2
- package/dist/{edit-DT672zIy.mjs.map → edit-gkb6MCW-.mjs.map} +1 -1
- package/dist/{fetch-BrtIqrid.mjs → fetch-D_GzL2yy.mjs} +4 -4
- package/dist/{fetch-BrtIqrid.mjs.map → fetch-D_GzL2yy.mjs.map} +1 -1
- package/dist/{find-B-vvdlHu.mjs → find-DlrYUTXT.mjs} +2 -2
- package/dist/{find-B-vvdlHu.mjs.map → find-DlrYUTXT.mjs.map} +1 -1
- package/dist/{grep-rvZ5S319.mjs → grep-BI8Rou2q.mjs} +2 -2
- package/dist/{grep-rvZ5S319.mjs.map → grep-BI8Rou2q.mjs.map} +1 -1
- package/dist/{html-VrAsoGBK.mjs → html-B-Lr-9W6.mjs} +9457 -4826
- package/dist/html-B-Lr-9W6.mjs.map +1 -0
- package/dist/{index-node-esm-BwaOzhXB.mjs → index-node-esm-75XSYyIw.mjs} +16 -13
- package/dist/index-node-esm-75XSYyIw.mjs.map +1 -0
- package/dist/index.d.mts +21 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{manager-1zEE5WiA.mjs → manager-CEociHy_.mjs} +2 -2
- package/dist/{manager-1zEE5WiA.mjs.map → manager-CEociHy_.mjs.map} +1 -1
- package/dist/{masker-DEgR_ntk.mjs → masker-DWuL2Fjs.mjs} +16 -5
- package/dist/{masker-DEgR_ntk.mjs.map → masker-DWuL2Fjs.mjs.map} +1 -1
- package/dist/{read-C5keKntU.mjs → read-DLtNq4XJ.mjs} +2 -2
- package/dist/{read-C5keKntU.mjs.map → read-DLtNq4XJ.mjs.map} +1 -1
- package/dist/{registry-CntkeXlo.mjs → registry-7mJQhyBA.mjs} +3 -3
- package/dist/{registry-CntkeXlo.mjs.map → registry-7mJQhyBA.mjs.map} +1 -1
- package/dist/{rolldown-runtime-DYf_mQCB.mjs → rolldown-runtime-BVN1G_yT.mjs} +4 -4
- package/dist/{session-C8zqqbPE.mjs → session-C5ra-Hi1.mjs} +80 -45
- package/dist/session-C5ra-Hi1.mjs.map +1 -0
- package/dist/{session-Cq52cam5.d.mts → session-WtXqtAaq.d.mts} +19 -10
- package/dist/session-WtXqtAaq.d.mts.map +1 -0
- package/dist/session.d.mts +1 -1
- package/dist/session.mjs +1 -1
- package/dist/{src-C04Qk9KE.mjs → src-Di-H3Oya.mjs} +71 -41
- package/dist/src-Di-H3Oya.mjs.map +1 -0
- package/dist/{subagent-BbcxLzgC.mjs → subagent-BOK4GFd4.mjs} +3 -3
- package/dist/{subagent-BbcxLzgC.mjs.map → subagent-BOK4GFd4.mjs.map} +1 -1
- package/dist/{tasks-Dgsiuh0Q.mjs → tasks-BUFqFoh6.mjs} +2 -2
- package/dist/{tasks-Dgsiuh0Q.mjs.map → tasks-BUFqFoh6.mjs.map} +1 -1
- package/dist/{tasks-D76WXWr2.mjs → tasks-CkDWJk_3.mjs} +4 -4
- package/dist/tasks-CkDWJk_3.mjs.map +1 -0
- package/dist/{tools-DmoUYORG.mjs → tools-Ca7VsMg3.mjs} +2 -2
- package/dist/{tools-DmoUYORG.mjs.map → tools-Ca7VsMg3.mjs.map} +1 -1
- package/dist/{write-BRQFfWAn.mjs → write-y93TC5ng.mjs} +2 -2
- package/dist/{write-BRQFfWAn.mjs.map → write-y93TC5ng.mjs.map} +1 -1
- package/package.json +11 -11
- package/dist/agent-BRENvuvx.mjs.map +0 -1
- package/dist/compactions-HFjEgrv3.mjs.map +0 -1
- package/dist/html-VrAsoGBK.mjs.map +0 -1
- package/dist/index-node-esm-BwaOzhXB.mjs.map +0 -1
- package/dist/session-C8zqqbPE.mjs.map +0 -1
- package/dist/session-Cq52cam5.d.mts.map +0 -1
- package/dist/src-C04Qk9KE.mjs.map +0 -1
- package/dist/tasks-D76WXWr2.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as __exportAll } from "./rolldown-runtime-
|
|
1
|
+
import { n as __exportAll } from "./rolldown-runtime-BVN1G_yT.mjs";
|
|
2
2
|
import { r as uuidv7 } from "./uuid-rfbQ9ad2.mjs";
|
|
3
3
|
import { n as JsonlStore } from "./jsonl-BGt7eqPK.mjs";
|
|
4
4
|
import { Emitter, normPath } from "@zaly/shared";
|
|
@@ -81,6 +81,7 @@ var Session = class Session extends Emitter {
|
|
|
81
81
|
#started = false;
|
|
82
82
|
#path;
|
|
83
83
|
#head;
|
|
84
|
+
#mutations;
|
|
84
85
|
constructor(opts) {
|
|
85
86
|
super();
|
|
86
87
|
this.#opts = opts;
|
|
@@ -154,28 +155,37 @@ var Session = class Session extends Emitter {
|
|
|
154
155
|
};
|
|
155
156
|
}
|
|
156
157
|
async update(settings, opts) {
|
|
157
|
-
return this.#commit({
|
|
158
|
+
return this.#mutate(() => this.#commit({
|
|
158
159
|
settings,
|
|
159
160
|
type: "session-settings"
|
|
160
|
-
}, opts);
|
|
161
|
+
}, opts));
|
|
161
162
|
}
|
|
162
163
|
/** Lazily emits `session-start` on a fresh session or `session-resume`
|
|
163
164
|
* on a hydrated one. Called from `#commit` before the first non-marker
|
|
164
165
|
* node lands so the start/resume marker always heads the chain. */
|
|
165
166
|
async #autostart() {
|
|
166
|
-
if (!this.#started) await this
|
|
167
|
+
if (!this.#started) await this.#start();
|
|
167
168
|
}
|
|
168
169
|
/** Explicitly mark the session as started — writes a `session-start`
|
|
169
170
|
* marker on a fresh session, `session-resume` on a hydrated one.
|
|
170
171
|
* Idempotent; subsequent calls are no-ops. Optional `meta` is
|
|
171
172
|
* applied via `update()` after the marker lands. */
|
|
172
173
|
async start(settings) {
|
|
173
|
-
|
|
174
|
+
return this.#mutate(() => this.#start(settings));
|
|
175
|
+
}
|
|
176
|
+
async #start(settings) {
|
|
177
|
+
if (this.#started) return settings ? this.#commit({
|
|
178
|
+
settings,
|
|
179
|
+
type: "session-settings"
|
|
180
|
+
}) : this.#store.root?.uuid;
|
|
174
181
|
this.#started = true;
|
|
175
182
|
const type = this.messages.length > 0 ? "session-resume" : "session-start";
|
|
176
183
|
await this.#commit({ type });
|
|
177
184
|
this.emit(type);
|
|
178
|
-
await this
|
|
185
|
+
await this.#commit({
|
|
186
|
+
settings: settings ?? {},
|
|
187
|
+
type: "session-settings"
|
|
188
|
+
});
|
|
179
189
|
return this.#store.root?.uuid;
|
|
180
190
|
}
|
|
181
191
|
/** Look up the decorated view for a node id — raw node plus the
|
|
@@ -218,46 +228,61 @@ var Session = class Session extends Emitter {
|
|
|
218
228
|
id: uuid,
|
|
219
229
|
ts
|
|
220
230
|
};
|
|
221
|
-
return this.#commit({
|
|
231
|
+
return this.#mutate(() => this.#commit({
|
|
222
232
|
message: m,
|
|
223
233
|
type: "message"
|
|
224
|
-
});
|
|
234
|
+
}));
|
|
225
235
|
}
|
|
226
|
-
/**
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
* meta anchor. */
|
|
236
|
+
/** Summarize an active prefix through a message ID, preserving everything
|
|
237
|
+
* appended after it. Boundary validation and tail calculation share the
|
|
238
|
+
* serialized commit with the new summary. Legacy tail-only calls remain
|
|
239
|
+
* supported. Original history stays in the store; a fresh settings anchor
|
|
240
|
+
* follows the compact node for reconstruction. */
|
|
232
241
|
async compact(opts) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
242
|
+
return this.#mutate(async () => {
|
|
243
|
+
opts.signal?.throwIfAborted();
|
|
244
|
+
let tail = opts.tail;
|
|
245
|
+
if (opts.to !== void 0) {
|
|
246
|
+
const index = this.messages.findIndex((m) => m.id === opts.to);
|
|
247
|
+
if (index === -1 || opts.from !== void 0 && this.messages[0]?.id !== opts.from) throw new Error("Compaction snapshot is no longer part of the active history");
|
|
248
|
+
tail = this.messages.length - index - 1;
|
|
249
|
+
}
|
|
250
|
+
if (tail === void 0 || !Number.isInteger(tail) || tail < 0) throw new Error("Compaction requires a message boundary or a non-negative integer tail");
|
|
251
|
+
const compactUuid = await this.#commit({
|
|
252
|
+
durationMs: opts.durationMs,
|
|
253
|
+
from: opts.from,
|
|
254
|
+
preTokens: opts.preTokens,
|
|
255
|
+
summary: opts.summary,
|
|
256
|
+
tail,
|
|
257
|
+
to: opts.to,
|
|
258
|
+
trigger: opts.trigger ?? "manual",
|
|
259
|
+
type: "compact"
|
|
260
|
+
});
|
|
261
|
+
await this.#commit({
|
|
262
|
+
settings: {},
|
|
263
|
+
type: "session-settings"
|
|
264
|
+
}, { force: true });
|
|
265
|
+
await this.#rebuild();
|
|
266
|
+
const node = this.#view.compact;
|
|
267
|
+
this.emit("compact", { node });
|
|
268
|
+
return compactUuid;
|
|
269
|
+
});
|
|
249
270
|
}
|
|
250
271
|
async addMaskCheckpoint(opts) {
|
|
251
|
-
this.#
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
272
|
+
return this.#mutate(async () => {
|
|
273
|
+
this.#view.maskCheckpoint = opts;
|
|
274
|
+
return this.#commit({
|
|
275
|
+
...opts,
|
|
276
|
+
type: "mask-checkpoint"
|
|
277
|
+
});
|
|
255
278
|
});
|
|
256
279
|
}
|
|
257
280
|
async checkout(uuid) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
281
|
+
return this.#mutate(async () => {
|
|
282
|
+
if (this.#closed) throw new Error("Session is closed");
|
|
283
|
+
this.#head = uuid;
|
|
284
|
+
await this.#rebuild();
|
|
285
|
+
});
|
|
261
286
|
}
|
|
262
287
|
/** Pre-active history of the current chain — messages from before
|
|
263
288
|
* the most recent compact (and earlier compacts), in chronological
|
|
@@ -274,9 +299,20 @@ var Session = class Session extends Emitter {
|
|
|
274
299
|
}
|
|
275
300
|
/** Flush + close the underlying store. Subsequent writes throw. */
|
|
276
301
|
async close() {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
302
|
+
return this.#mutate(async () => {
|
|
303
|
+
if (this.#closed) return;
|
|
304
|
+
this.#closed = true;
|
|
305
|
+
await this.#store.close?.();
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
#mutate(fn) {
|
|
309
|
+
const pending = this.#mutations ? this.#mutations.then(fn) : fn();
|
|
310
|
+
const settled = pending.then(() => {}, () => {});
|
|
311
|
+
this.#mutations = settled;
|
|
312
|
+
settled.then(() => {
|
|
313
|
+
if (this.#mutations === settled) this.#mutations = void 0;
|
|
314
|
+
});
|
|
315
|
+
return pending;
|
|
280
316
|
}
|
|
281
317
|
/** Atomically commit a node: register it in the store, update active
|
|
282
318
|
* messages, persist, and emit. Single chokepoint for all mutations. */
|
|
@@ -284,8 +320,8 @@ var Session = class Session extends Emitter {
|
|
|
284
320
|
let node = {
|
|
285
321
|
...n,
|
|
286
322
|
parentUuid: this.head,
|
|
287
|
-
ts: Date.now(),
|
|
288
|
-
uuid: uuidv7()
|
|
323
|
+
ts: n.type === "message" ? n.message.ts ?? Date.now() : Date.now(),
|
|
324
|
+
uuid: n.type === "message" ? n.message.id ?? uuidv7() : uuidv7()
|
|
289
325
|
};
|
|
290
326
|
if (!this.#started && node.type !== "session-start" && node.type !== "session-resume") await this.#autostart();
|
|
291
327
|
if (this.#closed) throw new Error("Session is closed");
|
|
@@ -363,8 +399,7 @@ var Session = class Session extends Emitter {
|
|
|
363
399
|
if (node.type === "mask-checkpoint" && !compact && !maskCheckpoint) maskCheckpoint = node;
|
|
364
400
|
if (node.type === "message") messageNodes.push(node);
|
|
365
401
|
if (node.type === "compact" && (opts.active ?? true)) {
|
|
366
|
-
|
|
367
|
-
compact = node;
|
|
402
|
+
compact ??= node;
|
|
368
403
|
limit = Math.min(limit, messageNodes.length + node.tail);
|
|
369
404
|
}
|
|
370
405
|
if (opts.stop?.(node)) break;
|
|
@@ -445,4 +480,4 @@ var Session = class Session extends Emitter {
|
|
|
445
480
|
};
|
|
446
481
|
export { session_exports as n, MemoryStore as r, Session as t };
|
|
447
482
|
|
|
448
|
-
//# sourceMappingURL=session-
|
|
483
|
+
//# sourceMappingURL=session-C5ra-Hi1.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-C5ra-Hi1.mjs","names":[],"sources":["../src/session/memory.ts","../src/session/session.ts"],"sourcesContent":["import type { SessionStore } from \"./store.ts\"\nimport type { SessionNode } from \"./types.ts\"\n\n/**\n * In-memory `SessionStore` — a `Map<uuid, SessionNode>` plus a `root`\n * pointer. No persistence. Construction takes optional initial nodes\n * for tests, replay tools, and the Claude session importer.\n */\nexport class MemoryStore implements SessionStore {\n readonly #nodes: Map<string, SessionNode>\n #root?: SessionNode\n\n constructor(nodes?: Iterable<SessionNode>) {\n this.#nodes = new Map()\n if (nodes) {\n for (const node of nodes) {\n this.#nodes.set(node.uuid, node)\n this.#root = node\n }\n }\n }\n\n get root(): SessionNode | undefined {\n return this.#root\n }\n\n async get(id: string): Promise<SessionNode | undefined> {\n return this.#nodes.get(id)\n }\n\n async write(node: SessionNode): Promise<void> {\n this.#nodes.set(node.uuid, node)\n this.#root = node\n }\n\n *all(): Iterable<SessionNode> {\n yield* this.#nodes.values()\n }\n}\n","import type { Message } from \"@zaly/ai\"\nimport type { SessionStore } from \"./store.ts\"\nimport type {\n MaskCheckpoint,\n PartialNode,\n SessionEvents,\n SessionInit,\n SessionMessage,\n SessionNode,\n SessionNodeView,\n SessionOptions,\n SessionSettings,\n SessionUpdate,\n SessionView,\n} from \"./types.ts\"\n\nimport { Emitter, normPath } from \"@zaly/shared\"\nimport { zalyPaths } from \"@zaly/shared/paths\"\nimport { isDeepStrictEqual } from \"node:util\"\nimport { join } from \"pathe\"\nimport { uuidv7 } from \"../utils/uuid.ts\"\nimport { JsonlStore } from \"./jsonl.ts\"\nimport { MemoryStore } from \"./memory.ts\"\n\nconst VERSION = 2\n\n/**\n * Conversation primitive. Owns a DAG of message + compaction + meta\n * nodes via a `SessionStore` backend; the *active* message list is\n * whatever you get by walking `parentUuid` backwards from the store's\n * root until you hit a `compact` node (or the start).\n *\n * **Meta is snapshot-based.** `session-meta` nodes carry the full\n * cumulative meta as of their commit time. Other node types (start,\n * resume, message, compact) don't carry meta — `Session` reconstructs\n * the cumulative meta at any point by finding the most recent\n * `session-meta` ancestor in a forward pass over the chain. Public\n * APIs return `SessionNodeView` (raw node + decorated `meta`).\n *\n * Designed so the loop, the persistor, the TUI, and any replay tool\n * all read from one source of truth and never mutate the DAG behind\n * each other's backs:\n *\n * - **Run loop** (`Agent`) calls `add()` on each new message and\n * `compact()` on overflow.\n * - **TUI** subscribes to the `node` event for streaming render.\n * - **Persistor** is the `SessionStore` — `MemoryStore` for ephemeral\n * sessions, `JsonlStore` for file-backed.\n *\n * Construction:\n * - Use `await Session.load(opts)` for the recommended path — picks\n * the right store (Memory if no path, JSONL if path).\n * - For tests / direct embedding, `new Session({ store })` works with\n * any pre-built store.\n */\nexport class Session<T extends SessionStore = SessionStore> extends Emitter<SessionEvents> {\n readonly #store: T\n #opts: SessionInit<T>\n #id: string\n #dir: string\n #settings: SessionSettings = {}\n #view: SessionView = { messages: [], nodes: new Map() }\n #closed = false\n #started = false\n #path?: string\n #head?: string\n #mutations?: Promise<void>\n\n protected constructor(opts: SessionInit<T>) {\n super()\n this.#opts = opts\n this.#path = opts.path\n this.#store = opts.store\n this.#id = opts.defaults?.sessionId ?? uuidv7()\n this.#dir = normPath(opts.dir ?? join(zalyPaths.env.tmp, \"sessions\", this.#id))\n }\n\n /** Recommended one-step path: pick the right store backend, hydrate\n * if applicable, return a ready-to-use session.\n *\n * - `path` provided → `JsonlStore` (file-backed, hydrates from disk\n * if the file exists, opens for append either way).\n * - No `path` → `MemoryStore` (ephemeral, no persistence). */\n static async load<T extends SessionStore = SessionStore>(\n opts: SessionOptions<T> & { store: T }\n ): Promise<Session<T>>\n static async load(opts: SessionOptions & { path: string }): Promise<Session<JsonlStore>>\n static async load(opts?: SessionOptions & {}): Promise<Session<MemoryStore>>\n static async load(opts: SessionOptions = {}): Promise<Session> {\n const session = await Session.create(opts)\n await session.#rebuild()\n return session\n }\n\n private static async create(opts: SessionOptions = {}): Promise<Session> {\n const path = opts.path ? normPath(opts.path) : undefined\n const store: SessionStore =\n opts.store ?? (path ? await JsonlStore.load(path) : new MemoryStore())\n const init: SessionInit = { ...opts, path, store }\n return new Session(init)\n }\n\n /** Efficiently fetch the most recent user message by walking backward until we hit\n * a user message, without reconstructing the full chain. Useful for a session picker. */\n static async lastMessage(opts: SessionOptions = {}): Promise<Message<\"user\"> | undefined> {\n const session = await Session.create(opts)\n let ret: Message<\"user\"> | undefined\n await session.#chain({\n stop: (node) => {\n if (node.type === \"message\" && node.message.role === \"user\") {\n ret = node.message\n return true\n }\n return false\n },\n })\n void session.close()\n return ret\n }\n\n async #rebuild(): Promise<void> {\n const chain = await this.#chain()\n this.#view = chain\n this.#settings = chain.settings\n this.#id = chain.settings.sessionId ?? this.#id\n }\n\n // ── Read ──────────────────────────────────────────────────────────────\n\n /** Active conversation — chain from current head back to the most\n * recent compact (exclusive), in chronological order. This is what\n * the agent sees on the next request. */\n get messages(): readonly Message[] {\n return this.#view.messages\n }\n\n get maskCheckpoint(): MaskCheckpoint | undefined {\n return this.#view.maskCheckpoint\n }\n\n get id(): string {\n return this.#id\n }\n\n get dir(): string {\n return this.#dir\n }\n\n get path(): string | undefined {\n return this.#path\n }\n\n get started(): boolean {\n return this.#started\n }\n\n /** Current session settings, merged with defaults. */\n get settings(): SessionSettings {\n return { ...this.#opts.defaults, ...this.#settings }\n }\n\n async update(settings: SessionUpdate, opts?: { force?: boolean }): Promise<string> {\n return this.#mutate(() => this.#commit({ settings, type: \"session-settings\" }, opts))\n }\n\n /** Lazily emits `session-start` on a fresh session or `session-resume`\n * on a hydrated one. Called from `#commit` before the first non-marker\n * node lands so the start/resume marker always heads the chain. */\n async #autostart(): Promise<void> {\n if (!this.#started) await this.#start()\n }\n\n /** Explicitly mark the session as started — writes a `session-start`\n * marker on a fresh session, `session-resume` on a hydrated one.\n * Idempotent; subsequent calls are no-ops. Optional `meta` is\n * applied via `update()` after the marker lands. */\n async start(settings?: SessionUpdate): Promise<string | undefined> {\n return this.#mutate(() => this.#start(settings))\n }\n\n async #start(settings?: SessionUpdate): Promise<string | undefined> {\n if (this.#started)\n return settings\n ? this.#commit({ settings, type: \"session-settings\" })\n : this.#store.root?.uuid\n this.#started = true\n const type = this.messages.length > 0 ? (\"session-resume\" as const) : (\"session-start\" as const)\n await this.#commit({ type })\n void this.emit(type)\n await this.#commit({ settings: settings ?? {}, type: \"session-settings\" })\n return this.#store.root?.uuid\n }\n\n /** Look up the decorated view for a node id — raw node plus the\n * cumulative meta as of that node's position. Returns the\n * message-typed view, or `undefined` if the id doesn't refer to a\n * message in this session. */\n async node(id?: string | Message): Promise<(SessionNodeView & { type: \"message\" }) | undefined> {\n const m = typeof id === \"string\" ? { id } : id\n if (!m?.id) return undefined\n const ret = this.#view.nodes.get(m.id)\n return ret?.type === \"message\" ? ret : undefined\n }\n\n /** Current head uuid — the root of the store, which is the most\n * recently appended node. */\n get head(): string | undefined {\n return this.#head ?? this.#store.root?.uuid\n }\n\n /** Full DAG iterator — backed by `store.all()`. Yields raw nodes\n * (no meta decoration). */\n nodes(): Iterable<SessionNode> | AsyncIterable<SessionNode> {\n return this.#store.all?.() ?? []\n }\n\n get root(): SessionNode | undefined {\n return this.#store.root\n }\n\n // ── Mutate ────────────────────────────────────────────────────────────\n\n /** Append a message. The new node is parented to the current head,\n * head advances, and a `node` event fires. Optional `meta` carries\n * usage / model / finish info — populate it for assistant turns\n * the agent commits after a step. Returns the assigned uuid.\n *\n * If `message.id` / `message.ts` are set (e.g. round-tripped from a\n * prior load), they're used as the node's uuid / timestamp; otherwise\n * fresh values are generated. The committed message always carries\n * both — `m.id === node.uuid` and `m.ts === node.ts`. */\n async add(message: Message): Promise<string> {\n const uuid = message.id ?? uuidv7()\n const ts = message.ts ?? Date.now()\n const m = { ...message, id: uuid, ts }\n return this.#mutate(() => this.#commit({ message: m, type: \"message\" }))\n }\n\n /** Summarize an active prefix through a message ID, preserving everything\n * appended after it. Boundary validation and tail calculation share the\n * serialized commit with the new summary. Legacy tail-only calls remain\n * supported. Original history stays in the store; a fresh settings anchor\n * follows the compact node for reconstruction. */\n async compact(opts: {\n trigger?: \"manual\" | \"auto\"\n preTokens?: number\n durationMs?: number\n /** Cancel a queued compaction before its commit begins. */\n signal?: AbortSignal\n /** Prefer an explicit boundary; tail-only calls remain supported. */\n to?: string\n /** Expected first message of the snapshot, including a prior summary if present. */\n from?: string\n tail?: number\n summary: Message<\"system\">\n }): Promise<string> {\n return this.#mutate(async () => {\n opts.signal?.throwIfAborted()\n let tail = opts.tail\n if (opts.to !== undefined) {\n const index = this.messages.findIndex((m) => m.id === opts.to)\n if (index === -1 || (opts.from !== undefined && this.messages[0]?.id !== opts.from)) {\n throw new Error(\"Compaction snapshot is no longer part of the active history\")\n }\n tail = this.messages.length - index - 1\n }\n if (tail === undefined || !Number.isInteger(tail) || tail < 0) {\n throw new Error(\"Compaction requires a message boundary or a non-negative integer tail\")\n }\n const compactUuid = await this.#commit({\n durationMs: opts.durationMs,\n from: opts.from,\n preTokens: opts.preTokens,\n summary: opts.summary,\n tail,\n to: opts.to,\n trigger: opts.trigger ?? \"manual\",\n type: \"compact\",\n })\n await this.#commit({ settings: {}, type: \"session-settings\" }, { force: true })\n await this.#rebuild()\n const node = this.#view.compact!\n void this.emit(\"compact\", { node })\n return compactUuid\n })\n }\n\n async addMaskCheckpoint(opts: MaskCheckpoint): Promise<string> {\n return this.#mutate(async () => {\n this.#view.maskCheckpoint = opts\n return this.#commit({ ...opts, type: \"mask-checkpoint\" })\n })\n }\n\n async checkout(uuid: string): Promise<void> {\n return this.#mutate(async () => {\n if (this.#closed) throw new Error(\"Session is closed\")\n this.#head = uuid\n await this.#rebuild()\n })\n }\n\n /** Pre-active history of the current chain — messages from before\n * the most recent compact (and earlier compacts), in chronological\n * order. Useful for TUI scrollback that wants to render context the\n * agent itself no longer sees.\n *\n * `limit` truncates from the front (oldest), so the most recent\n * history messages always make it through. */\n async history(limit?: number): Promise<readonly Message[]> {\n const chain = await this.#chain({ active: false, limit })\n return chain.messages\n }\n\n /** Flush + close the underlying store. Subsequent writes throw. */\n async close(): Promise<void> {\n return this.#mutate(async () => {\n if (this.#closed) return\n this.#closed = true\n await this.#store.close?.()\n })\n }\n\n // ── Internals ────────────────────────────────────────────────────────\n\n // Keep commits and view rebuilds together so appends cannot race a compaction.\n #mutate<R>(fn: () => Promise<R>): Promise<R> {\n const pending = this.#mutations ? this.#mutations.then(fn) : fn()\n const settled = pending.then(\n () => {},\n () => {}\n )\n this.#mutations = settled\n void settled.then(() => {\n if (this.#mutations === settled) this.#mutations = undefined\n })\n return pending\n }\n\n /** Atomically commit a node: register it in the store, update active\n * messages, persist, and emit. Single chokepoint for all mutations. */\n async #commit(n: PartialNode, opts: { force?: boolean } = {}): Promise<string> {\n let node: SessionNode = {\n ...n,\n parentUuid: this.head,\n ts: n.type === \"message\" ? (n.message.ts ?? Date.now()) : Date.now(),\n uuid: n.type === \"message\" ? (n.message.id ?? uuidv7()) : uuidv7(),\n }\n\n if (!this.#started && node.type !== \"session-start\" && node.type !== \"session-resume\") {\n await this.#autostart()\n }\n if (this.#closed) throw new Error(\"Session is closed\")\n\n const next: SessionSettings = {\n ...this.#opts.defaults,\n ...this.#settings,\n ...(node.type === \"session-settings\" ? node.settings : {}),\n sessionId: this.#id,\n version: VERSION,\n }\n if (next.cwd) next.cwd = normPath(next.cwd)\n if (next.workspace) next.workspace = normPath(next.workspace)\n\n if (node.type === \"session-settings\") {\n if (!opts.force && isDeepStrictEqual(this.#settings, next)) return this.#store.root!.uuid\n node = { ...node, settings: next }\n }\n\n node = { ...node, parentUuid: this.head }\n await this.#store.write(node)\n this.#head = undefined // invalidate head cache so it reflects the store's root on next read\n\n // Decorate the new node with cumulative meta and append to the\n // active chain view\n this.#view.nodes.set(node.uuid, { ...node, settings: next })\n if (node.type === \"message\") this.#view.messages.push(node.message)\n\n // cwd / meta event signaling\n if (node.type === \"session-settings\") {\n const prev = this.#settings\n this.#settings = next\n this.#emitChanges(prev)\n }\n\n void this.emit(\"node\", { node })\n return node.uuid\n }\n\n #emitChanges(prev: SessionSettings): void {\n const next = this.#settings\n if (next.cwd && next.cwd !== prev.cwd) void this.emit(\"cwd\", { cwd: next.cwd, prev: prev.cwd })\n if (next.modelId && next.modelId !== prev.modelId)\n void this.emit(\"model\", { model: next.modelId, prev: prev.modelId })\n if (next.reasoning && next.reasoning !== prev.reasoning)\n void this.emit(\"reasoning\", { effort: next.reasoning, prev: prev.reasoning })\n }\n\n /** Walk `parentUuid` from the given node back toward the root,\n * returning the chain as decorated views (each with cumulative meta).\n * The `active` flag controls what counts:\n * - `true` — only the active chain (stops at first compact /\n * session-start, with the kept tail spliced in via\n * the compact's `tail` field, summary substituted\n * in place of the compact node).\n * - `false` — includes everything back to the root\n * Returns chronological order. */\n async #chain(\n opts: {\n active?: boolean\n limit?: number\n uuid?: string\n stop?: (node: SessionNode) => boolean\n } = {}\n ): Promise<SessionView & { settings: SessionSettings }> {\n // Backward pass: collect raw nodes (new to old)\n const reverse: SessionNode[] = []\n let cursor = opts.uuid ?? this.head\n let limit = opts.limit ?? Infinity\n let compact: SessionNode<\"compact\"> | undefined\n const messageNodes: SessionNode<\"message\">[] = []\n let maskCheckpoint: SessionNode<\"mask-checkpoint\"> | undefined\n\n // Walk backward from the head until we hit a compact or the start, collecting nodes.\n while (cursor) {\n // eslint-disable-next-line no-await-in-loop\n const node = await this.#store.get(cursor)\n if (!node || (node.type === \"message\" && messageNodes.length + 1 > limit)) break\n cursor = node.parentUuid\n reverse.push(node)\n // Keep track if the last mask-checkpoint, until we hit a compaction.\n if (node.type === \"mask-checkpoint\" && !compact && !maskCheckpoint) maskCheckpoint = node\n if (node.type === \"message\") messageNodes.push(node)\n if (node.type === \"compact\" && (opts.active ?? true)) {\n compact ??= node\n // Earlier compactions may contain part of the kept tail. Walk through\n // their preserved messages, but never resurrect their summarized history.\n limit = Math.min(limit, messageNodes.length + node.tail)\n }\n if (opts.stop?.(node)) break\n }\n\n // Forward pass: decorate with cumulative meta. session-meta nodes\n // redefine the meta; everything else inherits the running snapshot.\n const nodes = new Map<string, SessionNodeView>()\n let settings: SessionSettings = {}\n for (const n of reverse.toReversed()) {\n if (n.type === \"session-settings\") settings = n.settings\n nodes.set(n.uuid, { ...n, settings })\n }\n\n this.#migrate(nodes)\n\n const messages: SessionMessage[] = []\n for (const n of messageNodes) {\n // add `id`, `ts` and `modelId` (if assistant turn) to the message\n const m = { ...n.message, id: n.uuid, ts: n.ts }\n if (m.role === \"assistant\") {\n // Add missing modelId to assistant messages if not present\n const s = nodes.get(n.uuid)?.settings ?? {}\n m.meta = { ...m.meta, modelId: m.meta?.modelId ?? s.modelId }\n }\n n.message = m\n messages.push(m)\n }\n\n // Add compaction summary as the first message\n if (compact) {\n messages.push({ ...compact.summary, id: compact.uuid, ts: compact.ts })\n nodes.set(compact.uuid, {\n message: compact.summary,\n parentUuid: compact.parentUuid,\n settings: nodes.get(compact.uuid)?.settings ?? {},\n ts: compact.ts,\n type: \"message\",\n uuid: compact.uuid,\n })\n }\n\n return {\n compact,\n maskCheckpoint,\n messages: messages.toReversed(),\n nodes,\n settings,\n }\n }\n\n #migrate(nodes: Map<string, SessionNodeView>) {\n for (const n of nodes.values()) {\n const version = n.settings.version ?? 0\n if (version === VERSION) continue\n n.settings = { ...n.settings, version: VERSION }\n\n if (n.type === \"compact\") {\n n.summary.meta = { kind: \"compaction-summary\", ...n.summary.meta }\n continue\n }\n\n if (n.type !== \"message\") continue\n const m = n.message\n\n if (\n m.role === \"system\" &&\n Array.isArray(m.content) &&\n m.content[0].type === \"meta\" &&\n m.content[0].tag === \"task\"\n ) {\n // Missing task meta data kind\n m.meta = { kind: \"task\", ...m.meta }\n }\n\n n.message = m\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Emitter } from "@zaly/shared";
|
|
2
1
|
import { Message, ReasoningEffort } from "@zaly/ai";
|
|
2
|
+
import { Emitter } from "@zaly/shared";
|
|
3
3
|
/** A single node in the session DAG. Same shape on disk (JSONL) as in
|
|
4
4
|
* memory — what we persist *is* what we navigate. Session settings live ONLY on
|
|
5
5
|
* `session-settings` nodes as a full snapshot of the cumulative session
|
|
@@ -35,7 +35,11 @@ type SessionN = {
|
|
|
35
35
|
preTokens?: number;
|
|
36
36
|
/** How long the compactor took, ms. */
|
|
37
37
|
durationMs?: number;
|
|
38
|
-
/**
|
|
38
|
+
/** Last active message covered by the summary. Absent on legacy entries. */
|
|
39
|
+
to?: string;
|
|
40
|
+
/** First active message in the summarized snapshot, used to reject stale summaries. */
|
|
41
|
+
from?: string;
|
|
42
|
+
/** Number of messages after the summary boundary at commit time. */
|
|
39
43
|
tail: number;
|
|
40
44
|
/** Frozen summary message that becomes the head of the active
|
|
41
45
|
* chain reconstruction. The full Message (not just text) so the
|
|
@@ -306,17 +310,22 @@ declare class Session<T extends SessionStore = SessionStore> extends Emitter<Ses
|
|
|
306
310
|
* fresh values are generated. The committed message always carries
|
|
307
311
|
* both — `m.id === node.uuid` and `m.ts === node.ts`. */
|
|
308
312
|
add(message: Message): Promise<string>;
|
|
309
|
-
/**
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
* meta anchor. */
|
|
313
|
+
/** Summarize an active prefix through a message ID, preserving everything
|
|
314
|
+
* appended after it. Boundary validation and tail calculation share the
|
|
315
|
+
* serialized commit with the new summary. Legacy tail-only calls remain
|
|
316
|
+
* supported. Original history stays in the store; a fresh settings anchor
|
|
317
|
+
* follows the compact node for reconstruction. */
|
|
315
318
|
compact(opts: {
|
|
316
319
|
trigger?: "manual" | "auto";
|
|
317
320
|
preTokens?: number;
|
|
318
321
|
durationMs?: number;
|
|
319
|
-
|
|
322
|
+
/** Cancel a queued compaction before its commit begins. */
|
|
323
|
+
signal?: AbortSignal;
|
|
324
|
+
/** Prefer an explicit boundary; tail-only calls remain supported. */
|
|
325
|
+
to?: string;
|
|
326
|
+
/** Expected first message of the snapshot, including a prior summary if present. */
|
|
327
|
+
from?: string;
|
|
328
|
+
tail?: number;
|
|
320
329
|
summary: Message<"system">;
|
|
321
330
|
}): Promise<string>;
|
|
322
331
|
addMaskCheckpoint(opts: MaskCheckpoint): Promise<string>;
|
|
@@ -333,4 +342,4 @@ declare class Session<T extends SessionStore = SessionStore> extends Emitter<Ses
|
|
|
333
342
|
close(): Promise<void>;
|
|
334
343
|
}
|
|
335
344
|
export { SessionStore as a, SessionEvents as c, SessionNode as d, SessionNodeView as f, SessionView as g, SessionUpdate as h, JsonlStore as i, SessionInit as l, SessionSettings as m, MemoryStore as n, MaskCheckpoint as o, SessionOptions as p, JsonlReader as r, PartialNode as s, Session as t, SessionMessage as u };
|
|
336
|
-
//# sourceMappingURL=session-
|
|
345
|
+
//# sourceMappingURL=session-WtXqtAaq.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-WtXqtAaq.d.mts","names":[],"sources":["../src/session/types.ts","../src/session/store.ts","../src/session/jsonl.ts","../src/session/memory.ts","../src/session/session.ts"],"mappings":";;;;;;;;;KAYK;EACH;;EAEA;;EAEA;;EAEI;;EACA;;EACA;EAA0B,UAAU;;EACpC;EAAiB,SAAS;;EAC1B;EAAyB;EAAmB;;EAE5C;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;;;EAKA,SAAS;;KAGV,kBAAkB;KAEX;EAAmB;EAAmB;;KAEtC,iBAAiB;EAAY;EAAY;;KAEzC,YAAY,UAAU,kBAAkB,mBAAmB,QACrE;EACE,MAAM;;;;;KAME,kBAAkB;EAAgB,UAAU;;KAE5C;EACV,UAAU;EACV,OAAO,YAAY;EACnB,UAAU;EACV,iBAAiB;;KAGP;EACV;EACA;EACA;EACA;EACA;EACA,YAAY;;KAGF,gBAAgB,KAAK;KAE5B,iBAAiB,GAAG,UAAU,eAAe,oBAAoB,KAAK,GAAG;KAElE,cAAc,iBAAiB;;;KAM/B;EACV;IAAQ,MAAM;;EACd;IAAY;IAA0B,mBAAmB;;EACzD;IAAW,MAAM;;EAEjB;IAAO;IAAa;;EACpB;IAAS;IAAe;;EACxB;IAAa,QAAQ;IAAiB,OAAO;;EAE7C;EACA;;KAKU,eAAe,UAAU,eAAe;EAClD,QAAQ;;;;;EAKR;;;;;EAKA;;;EAGA,WAAW,KAAK;;KAGN,YAAY,UAAU,eAAe,gBAAgB;;;EAG/D,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;UCjGQ;;;WAGN,MAAM;;EAGf,MAAM,eAAe,QAAQ;;;;EAK7B,QAAQ,MAAM,gBAAgB;;EAG9B,cAAc;;;;EAKd,YAAY,SAAS,eAAe,cAAc;;;;;;;;;;;;;;cCvBvC,sBAAsB;;WACxB;EAKT,YAAY;;;;SAQC,KAAK,eAAe,QAAQ;MAmBrC,QAAQ;EAIN,IAAI,aAAa,QAAQ;EAIzB,MAAM,MAAM,cAAc;EAS1B,SAAS;EAIR,OAAO,cAAc;;cAMjB,YAAY;;WAMF;EAArB,YAAqB;UAsBN;EAgCT,QAAQ,QAAQ;EAMhB,SAAK;;;;;;;cC3IA,uBAAuB;;EAIlC,YAAY,QAAQ,SAAS;MAUzB,QAAQ;EAIN,IAAI,aAAa,QAAQ;EAIzB,MAAM,MAAM,cAAc;EAK/B,OAAO,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCoBN,QAAQ,UAAU,eAAe,sBAAsB,QAAQ;;YAajE,YAAa,MAAM,YAAY;;;;;;;SAe3B,KAAK,UAAU,eAAe,cACzC,MAAM,eAAe;IAAO,OAAO;MAClC,QAAQ,QAAQ;SACN,KAAK,MAAM;IAAmB;MAAiB,QAAQ,QAAQ;SAC/D,KAAK,OAAO,sBAAsB,QAAQ,QAAQ;iBAO1C;;;SAUR,YAAY,OAAM,iBAAsB,QAAQ;;;;MA4BzD,qBAAqB;MAIrB,kBAAkB;MAIlB;MAIA;MAIA;MAIA;;MAKA,YAAY;EAIV,OAAO,UAAU,eAAe;IAAS;MAAoB;;;;;EAe7D,MAAM,WAAW,gBAAgB;;;;;EAqBjC,KAAK,cAAc,UAAU,SAAS;IAAoB;;;;MAS5D;;;EAMJ,SAAS,SAAS,eAAe,cAAc;MAI3C,QAAQ;;;;;;;;;;EAeN,IAAI,SAAS,UAAU;;;;;;EAYvB,QAAQ;IACZ;IACA;IACA;;IAEA,SAAS;;IAET;;IAEA;IACA;IACA,SAAS;MACP;EAgCE,kBAAkB,MAAM,iBAAiB;EAOzC,SAAS,eAAe;;;;;;;;EAexB,QAAQ,iBAAiB,iBAAiB;;EAM1C,SAAS"}
|
package/dist/session.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as SessionStore, c as SessionEvents, d as SessionNode, f as SessionNodeView, g as SessionView, h as SessionUpdate, i as JsonlStore, l as SessionInit, m as SessionSettings, n as MemoryStore, o as MaskCheckpoint, p as SessionOptions, r as JsonlReader, s as PartialNode, t as Session, u as SessionMessage } from "./session-
|
|
1
|
+
import { a as SessionStore, c as SessionEvents, d as SessionNode, f as SessionNodeView, g as SessionView, h as SessionUpdate, i as JsonlStore, l as SessionInit, m as SessionSettings, n as MemoryStore, o as MaskCheckpoint, p as SessionOptions, r as JsonlReader, s as PartialNode, t as Session, u as SessionMessage } from "./session-WtXqtAaq.mjs";
|
|
2
2
|
import { Stats } from "node:fs";
|
|
3
3
|
export type SessionInfo = {
|
|
4
4
|
/** uuidv7 session id. Absent for non-managed external paths until the
|
package/dist/session.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as isUuidv7Like, r as uuidv7 } from "./uuid-rfbQ9ad2.mjs";
|
|
2
|
+
import { r as MemoryStore, t as Session } from "./session-C5ra-Hi1.mjs";
|
|
2
3
|
import { n as JsonlStore, t as JsonlReader } from "./jsonl-BGt7eqPK.mjs";
|
|
3
|
-
import { r as MemoryStore, t as Session } from "./session-C8zqqbPE.mjs";
|
|
4
4
|
import { decodePath, encodePath, normPath, safeStatAsync } from "@zaly/shared";
|
|
5
5
|
import { basename, dirname, join, relative } from "pathe";
|
|
6
6
|
import { glob } from "@zaly/shared/glob";
|
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
import { n as __exportAll } from "./rolldown-runtime-
|
|
2
|
-
import
|
|
3
|
-
import "./
|
|
1
|
+
import { n as __exportAll } from "./rolldown-runtime-BVN1G_yT.mjs";
|
|
2
|
+
import "./registry-7mJQhyBA.mjs";
|
|
3
|
+
import { n as parseBash, t as TOOLS } from "./tools-Ca7VsMg3.mjs";
|
|
4
|
+
import { AiError, ContentTransform, attachmentToMeta, defineTool, errorToMeta, extractToolCalls, extractToolResults, metaToText, resolveReasoning, safeParseToolParams, sanitizeText, stringifyContent, toXml } from "@zaly/ai";
|
|
4
5
|
import { Emitter, formatDuration, isInstance, normPath, prettyPath, safeReadFile, safeStatAsync, safeStringify, toError } from "@zaly/shared";
|
|
5
6
|
import { LazyCache } from "@zaly/shared/cache";
|
|
6
7
|
import { BaseCollection } from "@zaly/shared/collection";
|
|
7
8
|
import { createRegistry } from "@zaly/shared/registry";
|
|
8
9
|
import { basename, dirname } from "pathe";
|
|
9
|
-
import { AiError, ContentTransform, attachmentToMeta, defineTool, errorToMeta, extractToolCalls, extractToolResults, metaToText, safeParseToolParams, sanitizeText, stringifyContent, toXml } from "@zaly/ai";
|
|
10
10
|
import { glob } from "@zaly/shared/glob";
|
|
11
11
|
import { readFile } from "node:fs/promises";
|
|
12
12
|
import { isDeepStrictEqual } from "node:util";
|
|
13
13
|
import { Type } from "typebox";
|
|
14
14
|
// src/ctx.ts
|
|
15
|
-
var ctx_exports = /* @__PURE__ */ __exportAll({
|
|
16
|
-
AgentContext: () => AgentContext,
|
|
17
|
-
createAgent: () => createAgent,
|
|
18
|
-
createAgentContext: () => createAgentContext
|
|
19
|
-
});
|
|
15
|
+
var ctx_exports = /* @__PURE__ */ __exportAll({ createAgent: () => createAgent });
|
|
20
16
|
var AgentContext = class extends Emitter {
|
|
21
17
|
#agent;
|
|
22
18
|
#opts;
|
|
@@ -32,7 +28,7 @@ var AgentContext = class extends Emitter {
|
|
|
32
28
|
super();
|
|
33
29
|
this.#opts = opts;
|
|
34
30
|
this.#cwd = normPath(opts.cwd);
|
|
35
|
-
this.#reasoning = opts.request?.reasoning
|
|
31
|
+
this.#reasoning = opts.request?.reasoning ?? "medium";
|
|
36
32
|
this.#session = opts.session;
|
|
37
33
|
this.#model = opts.model;
|
|
38
34
|
this.#skills = opts.skills;
|
|
@@ -98,14 +94,15 @@ var AgentContext = class extends Emitter {
|
|
|
98
94
|
return this.#agent;
|
|
99
95
|
}
|
|
100
96
|
get reasoning() {
|
|
101
|
-
return this.#reasoning;
|
|
97
|
+
return this.#model ? resolveReasoning(this.#model.spec, this.#reasoning) ?? "off" : this.#reasoning;
|
|
102
98
|
}
|
|
103
99
|
set reasoning(r) {
|
|
104
100
|
if (r === this.#reasoning) return;
|
|
105
|
-
const prev = this
|
|
101
|
+
const prev = this.reasoning;
|
|
106
102
|
this.#reasoning = r;
|
|
107
|
-
this.
|
|
108
|
-
|
|
103
|
+
const effort = this.reasoning;
|
|
104
|
+
if (effort !== prev) this.emit("reasoning", {
|
|
105
|
+
effort,
|
|
109
106
|
prev
|
|
110
107
|
});
|
|
111
108
|
}
|
|
@@ -141,11 +138,16 @@ var AgentContext = class extends Emitter {
|
|
|
141
138
|
set model(m) {
|
|
142
139
|
if (m === this.#model) return;
|
|
143
140
|
const prev = this.#model;
|
|
141
|
+
const reasoning = this.reasoning;
|
|
144
142
|
this.#model = m;
|
|
145
143
|
this.emit("model", {
|
|
146
144
|
model: m,
|
|
147
145
|
prev
|
|
148
146
|
});
|
|
147
|
+
if (this.reasoning !== reasoning) this.emit("reasoning", {
|
|
148
|
+
effort: this.reasoning,
|
|
149
|
+
prev: reasoning
|
|
150
|
+
});
|
|
149
151
|
}
|
|
150
152
|
set tools(tools) {
|
|
151
153
|
this.#tools = tools;
|
|
@@ -181,13 +183,13 @@ var AgentContext = class extends Emitter {
|
|
|
181
183
|
}
|
|
182
184
|
async masker() {
|
|
183
185
|
return this.#cache.want("masker", async (opts) => {
|
|
184
|
-
const { Masker } = await import("./masker-
|
|
186
|
+
const { Masker } = await import("./masker-DWuL2Fjs.mjs");
|
|
185
187
|
return new Masker(this.agent, opts);
|
|
186
188
|
}, this.#opts.mask);
|
|
187
189
|
}
|
|
188
190
|
async permissions() {
|
|
189
191
|
return this.#cache.need("permissions", async (opts) => {
|
|
190
|
-
const { PermissionManager } = await import("./manager-
|
|
192
|
+
const { PermissionManager } = await import("./manager-CEociHy_.mjs");
|
|
191
193
|
return new PermissionManager({
|
|
192
194
|
...opts,
|
|
193
195
|
cwd: this.cwd
|
|
@@ -198,7 +200,7 @@ var AgentContext = class extends Emitter {
|
|
|
198
200
|
async function loadSession(spec) {
|
|
199
201
|
if (isInstance(spec)) return spec;
|
|
200
202
|
else {
|
|
201
|
-
const { Session } = await import("./session-
|
|
203
|
+
const { Session } = await import("./session-C5ra-Hi1.mjs").then((n) => n.n);
|
|
202
204
|
return await Session.load({ ...spec });
|
|
203
205
|
}
|
|
204
206
|
}
|
|
@@ -210,7 +212,7 @@ async function createAgentContext(opts) {
|
|
|
210
212
|
});
|
|
211
213
|
}
|
|
212
214
|
async function createAgent(opts) {
|
|
213
|
-
const [{ Agent }, ctx] = await Promise.all([import("./agent-
|
|
215
|
+
const [{ Agent }, ctx] = await Promise.all([import("./agent-GXRF7DUP.mjs"), createAgentContext(opts)]);
|
|
214
216
|
return new Agent(ctx);
|
|
215
217
|
}
|
|
216
218
|
const promptRegistry = createRegistry("prompt").from({
|
|
@@ -257,19 +259,19 @@ async function promptCollection() {
|
|
|
257
259
|
const toolRegistry = createRegistry("tool").from({
|
|
258
260
|
agent_send: () => import("./swarm-D823Yumk.mjs").then((m) => m.agentSendTool),
|
|
259
261
|
agent_spawn: () => import("./swarm-D823Yumk.mjs").then((m) => m.agentSpawnTool),
|
|
260
|
-
bash: () => import("./bash-
|
|
261
|
-
edit: () => import("./edit-
|
|
262
|
-
fetch: () => import("./fetch-
|
|
263
|
-
find: () => import("./find-
|
|
264
|
-
grep: () => import("./grep-
|
|
265
|
-
read: () => import("./read-
|
|
262
|
+
bash: () => import("./bash-CB_VXpyd.mjs").then((m) => m.bashTool),
|
|
263
|
+
edit: () => import("./edit-gkb6MCW-.mjs").then((m) => m.editTool),
|
|
264
|
+
fetch: () => import("./fetch-D_GzL2yy.mjs").then((m) => m.fetchTool),
|
|
265
|
+
find: () => import("./find-DlrYUTXT.mjs").then((m) => m.findTool),
|
|
266
|
+
grep: () => import("./grep-BI8Rou2q.mjs").then((m) => m.grepTool),
|
|
267
|
+
read: () => import("./read-DLtNq4XJ.mjs").then((m) => m.readTool),
|
|
266
268
|
search: () => import("./search-B-89W3SM.mjs").then((m) => m.searchTool),
|
|
267
|
-
subagent: () => import("./subagent-
|
|
268
|
-
task_list: () => import("./tasks-
|
|
269
|
-
task_poll: () => import("./tasks-
|
|
270
|
-
task_stop: () => import("./tasks-
|
|
269
|
+
subagent: () => import("./subagent-BOK4GFd4.mjs").then((m) => m.subagentTool),
|
|
270
|
+
task_list: () => import("./tasks-BUFqFoh6.mjs").then((m) => m.taskListTool),
|
|
271
|
+
task_poll: () => import("./tasks-BUFqFoh6.mjs").then((m) => m.taskPollTool),
|
|
272
|
+
task_stop: () => import("./tasks-BUFqFoh6.mjs").then((m) => m.taskStopTool),
|
|
271
273
|
wakeup: () => import("./wakeup-CFr1nu_L.mjs").then((m) => m.wakeupTool),
|
|
272
|
-
write: () => import("./write-
|
|
274
|
+
write: () => import("./write-y93TC5ng.mjs").then((m) => m.writeTool)
|
|
273
275
|
});
|
|
274
276
|
var ToolCollection = class extends BaseCollection {
|
|
275
277
|
list() {
|
|
@@ -803,9 +805,34 @@ function fromText(text) {
|
|
|
803
805
|
function sumTokens(stats) {
|
|
804
806
|
return stats.reduce((sum, s) => sum + s.tokens, 0);
|
|
805
807
|
}
|
|
806
|
-
function
|
|
808
|
+
function estimateReasoning(part, ctx) {
|
|
809
|
+
let reasoning = ctx.reasoning;
|
|
810
|
+
if (ctx.model) {
|
|
811
|
+
let requested = "medium";
|
|
812
|
+
if (typeof reasoning === "string") requested = reasoning;
|
|
813
|
+
else if (reasoning === false) requested = "off";
|
|
814
|
+
reasoning = resolveReasoning(ctx.model, requested);
|
|
815
|
+
}
|
|
816
|
+
if (!(reasoning !== "off" && reasoning !== false && (!ctx.model || ctx.model.reasoning === true))) return 0;
|
|
817
|
+
if (ctx.message?.role === "assistant") {
|
|
818
|
+
if (ctx.model && ctx.message.meta?.modelId !== ctx.model.id) return 0;
|
|
819
|
+
const parts = Array.isArray(ctx.message.content) ? ctx.message.content.filter((p) => p.type === "reasoning") : [];
|
|
820
|
+
if (!parts.includes(part)) throw new Error("Reasoning part not found in message content");
|
|
821
|
+
const signed = parts.filter((p) => p.signature);
|
|
822
|
+
const reported = ctx.message.meta?.usage?.reasoning;
|
|
823
|
+
if (signed.length && reported !== void 0 && Number.isFinite(reported) && reported >= 0) {
|
|
824
|
+
if (part !== signed.at(0)) return 0;
|
|
825
|
+
return reported;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return fromText(part.text);
|
|
829
|
+
}
|
|
830
|
+
function estimatePart(p, ctx = {}) {
|
|
807
831
|
switch (p.type) {
|
|
808
|
-
case "reasoning":
|
|
832
|
+
case "reasoning": return {
|
|
833
|
+
tokens: estimateReasoning(p, ctx),
|
|
834
|
+
type: p.type
|
|
835
|
+
};
|
|
809
836
|
case "text": return {
|
|
810
837
|
tokens: fromText(p.text),
|
|
811
838
|
type: p.type
|
|
@@ -816,7 +843,7 @@ function estimatePart(p) {
|
|
|
816
843
|
type: p.type
|
|
817
844
|
};
|
|
818
845
|
case "tool-result": {
|
|
819
|
-
const children = estimateContent(p.content);
|
|
846
|
+
const children = estimateContent(p.content, ctx);
|
|
820
847
|
return {
|
|
821
848
|
children,
|
|
822
849
|
kind: p.name,
|
|
@@ -832,7 +859,7 @@ function estimatePart(p) {
|
|
|
832
859
|
type: p.type
|
|
833
860
|
};
|
|
834
861
|
case "meta": return {
|
|
835
|
-
children: p.content ? estimateContent(p.content) : void 0,
|
|
862
|
+
children: p.content ? estimateContent(p.content, ctx) : void 0,
|
|
836
863
|
kind: p.tag,
|
|
837
864
|
tokens: fromText(stringifyContent(p)),
|
|
838
865
|
type: p.type
|
|
@@ -844,7 +871,7 @@ function estimatePart(p) {
|
|
|
844
871
|
default: throw new Error(`Unknown part type: ${p.type}`);
|
|
845
872
|
}
|
|
846
873
|
}
|
|
847
|
-
function estimateContent(content) {
|
|
874
|
+
function estimateContent(content, ctx) {
|
|
848
875
|
if (typeof content === "string") return [{
|
|
849
876
|
tokens: fromText(content),
|
|
850
877
|
type: "text"
|
|
@@ -852,15 +879,18 @@ function estimateContent(content) {
|
|
|
852
879
|
let tokens = 0;
|
|
853
880
|
const children = [];
|
|
854
881
|
for (const p of content) {
|
|
855
|
-
const partStats = estimatePart(p);
|
|
882
|
+
const partStats = estimatePart(p, ctx);
|
|
856
883
|
tokens += partStats.tokens;
|
|
857
884
|
children.push(partStats);
|
|
858
885
|
}
|
|
859
886
|
return children;
|
|
860
887
|
}
|
|
861
|
-
function estimateMessage(m) {
|
|
888
|
+
function estimateMessage(m, ctx) {
|
|
862
889
|
const type = m.role;
|
|
863
|
-
const children = estimateContent(m.content
|
|
890
|
+
const children = estimateContent(m.content, {
|
|
891
|
+
...ctx,
|
|
892
|
+
message: m
|
|
893
|
+
});
|
|
864
894
|
return {
|
|
865
895
|
children,
|
|
866
896
|
kind: m.role === "system" ? m.meta?.kind : void 0,
|
|
@@ -876,7 +906,7 @@ function estimatePrompt(prompt, tools) {
|
|
|
876
906
|
}));
|
|
877
907
|
children.push(...tools?.map((t) => ({
|
|
878
908
|
kind: t.name,
|
|
879
|
-
tokens: fromText(t.name) + fromText(JSON.stringify(t.params ?? {})),
|
|
909
|
+
tokens: fromText(t.name) + fromText(t.desc ?? "") + fromText(JSON.stringify(t.params ?? {})),
|
|
880
910
|
type: "tool-schema"
|
|
881
911
|
})) ?? []);
|
|
882
912
|
return {
|
|
@@ -914,8 +944,8 @@ function tokenStats(msgs, opts = {}) {
|
|
|
914
944
|
tokens: 0
|
|
915
945
|
};
|
|
916
946
|
const counts = [];
|
|
917
|
-
if (opts.prompt) counts.push(estimatePrompt(opts.prompt, opts.tools));
|
|
918
|
-
counts.push(...msgs.map(estimateMessage));
|
|
947
|
+
if (opts.prompt || opts.tools) counts.push(estimatePrompt(opts.prompt ?? [], opts.tools));
|
|
948
|
+
counts.push(...msgs.map((message) => estimateMessage(message, opts)));
|
|
919
949
|
for (const stats of counts) {
|
|
920
950
|
root.tokens += stats.tokens;
|
|
921
951
|
root.count++;
|
|
@@ -946,4 +976,4 @@ function fmt(n) {
|
|
|
946
976
|
}
|
|
947
977
|
export { ctx_exports as _, extractConversation as a, formatFileUsage as c, Commands as d, toolCollection as f, createAgent as g, promptRegistry as h, extractBashUsage as i, messageTail as l, promptCollection as m, formatTokenStats as n, extractFileUsage as o, toolRegistry as p, tokenStats as r, formatBashUsage as s, estimatePart as t, Skills as u };
|
|
948
978
|
|
|
949
|
-
//# sourceMappingURL=src-
|
|
979
|
+
//# sourceMappingURL=src-Di-H3Oya.mjs.map
|