maestro-agent-sdk 0.1.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/NOTICE +24 -0
- package/README.md +133 -0
- package/dist/agents/contracts.d.ts +49 -0
- package/dist/agents/contracts.d.ts.map +1 -0
- package/dist/agents/contracts.js +2 -0
- package/dist/agents/contracts.js.map +1 -0
- package/dist/agents/rollout/shared.d.ts +24 -0
- package/dist/agents/rollout/shared.d.ts.map +1 -0
- package/dist/agents/rollout/shared.js +105 -0
- package/dist/agents/rollout/shared.js.map +1 -0
- package/dist/core/agent.d.ts +71 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +22 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/loop.d.ts +26 -0
- package/dist/core/loop.d.ts.map +1 -0
- package/dist/core/loop.js +317 -0
- package/dist/core/loop.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +79 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +176 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/pool-cache.d.ts +103 -0
- package/dist/mcp/pool-cache.d.ts.map +1 -0
- package/dist/mcp/pool-cache.js +249 -0
- package/dist/mcp/pool-cache.js.map +1 -0
- package/dist/mcp/pool.d.ts +65 -0
- package/dist/mcp/pool.d.ts.map +1 -0
- package/dist/mcp/pool.js +86 -0
- package/dist/mcp/pool.js.map +1 -0
- package/dist/media/file-events.d.ts +8 -0
- package/dist/media/file-events.d.ts.map +1 -0
- package/dist/media/file-events.js +15 -0
- package/dist/media/file-events.js.map +1 -0
- package/dist/memory/active-task-template.d.ts +34 -0
- package/dist/memory/active-task-template.d.ts.map +1 -0
- package/dist/memory/active-task-template.js +63 -0
- package/dist/memory/active-task-template.js.map +1 -0
- package/dist/memory/compressor.d.ts +87 -0
- package/dist/memory/compressor.d.ts.map +1 -0
- package/dist/memory/compressor.js +164 -0
- package/dist/memory/compressor.js.map +1 -0
- package/dist/memory/hash.d.ts +17 -0
- package/dist/memory/hash.d.ts.map +1 -0
- package/dist/memory/hash.js +20 -0
- package/dist/memory/hash.js.map +1 -0
- package/dist/memory/prune.d.ts +117 -0
- package/dist/memory/prune.d.ts.map +1 -0
- package/dist/memory/prune.js +416 -0
- package/dist/memory/prune.js.map +1 -0
- package/dist/memory/reminder.d.ts +57 -0
- package/dist/memory/reminder.d.ts.map +1 -0
- package/dist/memory/reminder.js +57 -0
- package/dist/memory/reminder.js.map +1 -0
- package/dist/memory/scrubber.d.ts +28 -0
- package/dist/memory/scrubber.d.ts.map +1 -0
- package/dist/memory/scrubber.js +147 -0
- package/dist/memory/scrubber.js.map +1 -0
- package/dist/memory/token-estimate.d.ts +10 -0
- package/dist/memory/token-estimate.d.ts.map +1 -0
- package/dist/memory/token-estimate.js +69 -0
- package/dist/memory/token-estimate.js.map +1 -0
- package/dist/platform/config.d.ts +12 -0
- package/dist/platform/config.d.ts.map +1 -0
- package/dist/platform/config.js +54 -0
- package/dist/platform/config.js.map +1 -0
- package/dist/platform/jsonl.d.ts +15 -0
- package/dist/platform/jsonl.d.ts.map +1 -0
- package/dist/platform/jsonl.js +80 -0
- package/dist/platform/jsonl.js.map +1 -0
- package/dist/platform/lifecycle.d.ts +22 -0
- package/dist/platform/lifecycle.d.ts.map +1 -0
- package/dist/platform/lifecycle.js +60 -0
- package/dist/platform/lifecycle.js.map +1 -0
- package/dist/platform/logger.d.ts +26 -0
- package/dist/platform/logger.d.ts.map +1 -0
- package/dist/platform/logger.js +41 -0
- package/dist/platform/logger.js.map +1 -0
- package/dist/platform/mcp-config.d.ts +15 -0
- package/dist/platform/mcp-config.d.ts.map +1 -0
- package/dist/platform/mcp-config.js +8 -0
- package/dist/platform/mcp-config.js.map +1 -0
- package/dist/provider.d.ts +81 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +444 -0
- package/dist/provider.js.map +1 -0
- package/dist/providers/anthropic.d.ts +132 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +518 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/base.d.ts +140 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +2 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/deepseek.d.ts +118 -0
- package/dist/providers/deepseek.d.ts.map +1 -0
- package/dist/providers/deepseek.js +467 -0
- package/dist/providers/deepseek.js.map +1 -0
- package/dist/registry.d.ts +3 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +94 -0
- package/dist/registry.js.map +1 -0
- package/dist/session-store.d.ts +133 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +277 -0
- package/dist/session-store.js.map +1 -0
- package/dist/skills/curator.d.ts +104 -0
- package/dist/skills/curator.d.ts.map +1 -0
- package/dist/skills/curator.js +162 -0
- package/dist/skills/curator.js.map +1 -0
- package/dist/skills/index-builder.d.ts +42 -0
- package/dist/skills/index-builder.d.ts.map +1 -0
- package/dist/skills/index-builder.js +94 -0
- package/dist/skills/index-builder.js.map +1 -0
- package/dist/skills/loader.d.ts +107 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +286 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/preprocess.d.ts +45 -0
- package/dist/skills/preprocess.d.ts.map +1 -0
- package/dist/skills/preprocess.js +126 -0
- package/dist/skills/preprocess.js.map +1 -0
- package/dist/skills/usage.d.ts +75 -0
- package/dist/skills/usage.d.ts.map +1 -0
- package/dist/skills/usage.js +147 -0
- package/dist/skills/usage.js.map +1 -0
- package/dist/state/todos.d.ts +95 -0
- package/dist/state/todos.d.ts.map +1 -0
- package/dist/state/todos.js +198 -0
- package/dist/state/todos.js.map +1 -0
- package/dist/storage/conversations.d.ts +28 -0
- package/dist/storage/conversations.d.ts.map +1 -0
- package/dist/storage/conversations.js +8 -0
- package/dist/storage/conversations.js.map +1 -0
- package/dist/sub-agent/runner.d.ts +78 -0
- package/dist/sub-agent/runner.d.ts.map +1 -0
- package/dist/sub-agent/runner.js +215 -0
- package/dist/sub-agent/runner.js.map +1 -0
- package/dist/tools/builtin/agent.d.ts +33 -0
- package/dist/tools/builtin/agent.d.ts.map +1 -0
- package/dist/tools/builtin/agent.js +76 -0
- package/dist/tools/builtin/agent.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +11 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -0
- package/dist/tools/builtin/bash.js +91 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/edit.d.ts +21 -0
- package/dist/tools/builtin/edit.d.ts.map +1 -0
- package/dist/tools/builtin/edit.js +238 -0
- package/dist/tools/builtin/edit.js.map +1 -0
- package/dist/tools/builtin/read.d.ts +17 -0
- package/dist/tools/builtin/read.d.ts.map +1 -0
- package/dist/tools/builtin/read.js +139 -0
- package/dist/tools/builtin/read.js.map +1 -0
- package/dist/tools/builtin/sandbox.d.ts +16 -0
- package/dist/tools/builtin/sandbox.d.ts.map +1 -0
- package/dist/tools/builtin/sandbox.js +58 -0
- package/dist/tools/builtin/sandbox.js.map +1 -0
- package/dist/tools/builtin/skill_view.d.ts +37 -0
- package/dist/tools/builtin/skill_view.d.ts.map +1 -0
- package/dist/tools/builtin/skill_view.js +82 -0
- package/dist/tools/builtin/skill_view.js.map +1 -0
- package/dist/tools/builtin/todo_write.d.ts +29 -0
- package/dist/tools/builtin/todo_write.d.ts.map +1 -0
- package/dist/tools/builtin/todo_write.js +96 -0
- package/dist/tools/builtin/todo_write.js.map +1 -0
- package/dist/tools/builtin/web_fetch.d.ts +10 -0
- package/dist/tools/builtin/web_fetch.d.ts.map +1 -0
- package/dist/tools/builtin/web_fetch.js +150 -0
- package/dist/tools/builtin/web_fetch.js.map +1 -0
- package/dist/tools/builtin/write.d.ts +35 -0
- package/dist/tools/builtin/write.d.ts.map +1 -0
- package/dist/tools/builtin/write.js +70 -0
- package/dist/tools/builtin/write.js.map +1 -0
- package/dist/tools/file-state.d.ts +99 -0
- package/dist/tools/file-state.d.ts.map +1 -0
- package/dist/tools/file-state.js +133 -0
- package/dist/tools/file-state.js.map +1 -0
- package/dist/tools/hooks/sandbox-fs.d.ts +25 -0
- package/dist/tools/hooks/sandbox-fs.d.ts.map +1 -0
- package/dist/tools/hooks/sandbox-fs.js +48 -0
- package/dist/tools/hooks/sandbox-fs.js.map +1 -0
- package/dist/tools/registry.d.ts +102 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +93 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/types.d.ts +109 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isSandboxEnabled } from "../tools/builtin/sandbox.js";
|
|
2
|
+
import { WORKSPACE_DIR } from "../platform/config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Build the `<system-reminder>` block. Returns a self-contained string that
|
|
5
|
+
* callers attach verbatim as a `text` content block on a user message.
|
|
6
|
+
*
|
|
7
|
+
* Empty extras + sandbox-enabled (default) state renders to ~3 lines so
|
|
8
|
+
* the per-turn token cost is bounded; the catalog of facts only grows as
|
|
9
|
+
* later phases add semantic state (Phase 3.2 task list, etc.).
|
|
10
|
+
*/
|
|
11
|
+
export function buildSystemReminder(ctx) {
|
|
12
|
+
const lines = ["<system-reminder>"];
|
|
13
|
+
// Sandbox state — the model needs to know whether file paths outside
|
|
14
|
+
// WORKSPACE_DIR will be rejected, so it can either prefix paths correctly
|
|
15
|
+
// or pre-emptively flag the limitation when the user asks for an
|
|
16
|
+
// out-of-workspace operation. Default is unsandboxed (parity with
|
|
17
|
+
// claude/codex providers); the operator opts in by exporting
|
|
18
|
+
// `MAESTRO_FS_SANDBOX_ENABLED=1`.
|
|
19
|
+
if (isSandboxEnabled()) {
|
|
20
|
+
lines.push(`Filesystem sandbox: enabled. Allowed root: ${WORKSPACE_DIR}`);
|
|
21
|
+
lines.push(" Paths outside this root will be rejected by Read/Write/Edit. " +
|
|
22
|
+
"Prefer relative-to-workspace paths.");
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
lines.push("Filesystem sandbox: disabled (any absolute path may be read/written).");
|
|
26
|
+
}
|
|
27
|
+
// Session id — emitted so cross-session tools (ask_session, tell_session,
|
|
28
|
+
// fork helpers) have a stable handle to reference without round-tripping.
|
|
29
|
+
lines.push(`Session: ${ctx.sessionId}`);
|
|
30
|
+
// TodoWrite read-side: render the current list (if any) so the model
|
|
31
|
+
// doesn't need a `todo_list` tool. Compact one-line-per-entry format
|
|
32
|
+
// tracks `[✓/→/ ] task-N content` — matches the tool result preview
|
|
33
|
+
// so the model sees the same shape it wrote.
|
|
34
|
+
if (ctx.todos && ctx.todos.length > 0) {
|
|
35
|
+
lines.push(`Task list (${todoSummaryCount(ctx.todos)}):`);
|
|
36
|
+
for (const t of ctx.todos) {
|
|
37
|
+
const mark = t.status === "completed" ? "✓" : t.status === "in_progress" ? "→" : " ";
|
|
38
|
+
lines.push(` [${mark}] ${t.id} ${t.content}`);
|
|
39
|
+
}
|
|
40
|
+
lines.push("Update this list with `todo_write` whenever you start a step, finish one, " +
|
|
41
|
+
"or change the plan. Only ONE item may be in_progress at a time.");
|
|
42
|
+
}
|
|
43
|
+
// Caller-supplied tail. Each extra is one line — caller owns formatting.
|
|
44
|
+
for (const e of ctx.extras ?? []) {
|
|
45
|
+
if (e.length > 0)
|
|
46
|
+
lines.push(e);
|
|
47
|
+
}
|
|
48
|
+
lines.push("</system-reminder>");
|
|
49
|
+
return lines.join("\n");
|
|
50
|
+
}
|
|
51
|
+
/** Compact "3/5" style summary — completed over total. Used in the list
|
|
52
|
+
* header so the model gets progress at a glance without re-counting. */
|
|
53
|
+
function todoSummaryCount(todos) {
|
|
54
|
+
const done = todos.filter((t) => t.status === "completed").length;
|
|
55
|
+
return `${done}/${todos.length}`;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=reminder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reminder.js","sourceRoot":"","sources":["../../src/memory/reminder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAkDlD;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAA0B;IAC5D,MAAM,KAAK,GAAa,CAAC,mBAAmB,CAAC,CAAC;IAE9C,qEAAqE;IACrE,0EAA0E;IAC1E,iEAAiE;IACjE,kEAAkE;IAClE,6DAA6D;IAC7D,kCAAkC;IAClC,IAAI,gBAAgB,EAAE,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,8CAA8C,aAAa,EAAE,CAAC,CAAC;QAC1E,KAAK,CAAC,IAAI,CACR,iEAAiE;YAC/D,qCAAqC,CACxC,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;IACtF,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;IAExC,qEAAqE;IACrE,qEAAqE;IACrE,qEAAqE;IACrE,6CAA6C;IAC7C,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,cAAc,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1D,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YACrF,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAClD,CAAC;QACD,KAAK,CAAC,IAAI,CACR,4EAA4E;YAC1E,iEAAiE,CACpE,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;yEACyE;AACzE,SAAS,gBAAgB,CAAC,KAA2B;IACnD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM,CAAC;IAClE,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare class StreamingContextScrubber {
|
|
2
|
+
private state;
|
|
3
|
+
private readonly bufferCap;
|
|
4
|
+
/**
|
|
5
|
+
* Push a chunk of streamed text. Returns the bytes that should be
|
|
6
|
+
* emitted downstream (the unscrubbed part). Internal state advances so
|
|
7
|
+
* subsequent calls pick up where the last one left off.
|
|
8
|
+
*
|
|
9
|
+
* Safe on empty chunks (returns empty string).
|
|
10
|
+
*/
|
|
11
|
+
feed(chunk: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Stream ended. Flush any safe-to-emit pending bytes. If we're still
|
|
14
|
+
* matching-open (the model said `<comp` and stopped), flush the buffered
|
|
15
|
+
* candidate (it wasn't a real marker after all). If we're inside a fence
|
|
16
|
+
* that never closed, drop the rest silently — better than leaking
|
|
17
|
+
* partial summary text.
|
|
18
|
+
*/
|
|
19
|
+
finish(): string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* One-shot helper for non-streaming cases: scrub an entire string by
|
|
23
|
+
* feeding it through a scrubber and finishing. Used by the
|
|
24
|
+
* `text` (consolidated) UnifiedEvent emit at end-of-turn so non-streaming
|
|
25
|
+
* consumers (recorders, logs) also see the cleaned text.
|
|
26
|
+
*/
|
|
27
|
+
export declare function scrubString(input: string): string;
|
|
28
|
+
//# sourceMappingURL=scrubber.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrubber.d.ts","sourceRoot":"","sources":["../../src/memory/scrubber.ts"],"names":[],"mappings":"AAgFA,qBAAa,wBAAwB;IACnC,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAE5C;;;;;;OAMG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAqE3B;;;;;;OAMG;IACH,MAAM,IAAI,MAAM;CAUjB;AAmBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { COMPACTED_MARKER_CLOSE, COMPACTED_MARKER_OPEN, } from "../memory/active-task-template.js";
|
|
2
|
+
/** Anthropic models occasionally surface their chain-of-thought as
|
|
3
|
+
* literal `<thinking>...</thinking>` text in the assistant message body
|
|
4
|
+
* (a pretrained pattern, separate from extended-thinking blocks which we
|
|
5
|
+
* already keep server-side via the `thinking` content type). On telegram
|
|
6
|
+
* this leaks raw reasoning the user explicitly asked to hide. Treat the
|
|
7
|
+
* fence identically to compacted-history: drop entire block including
|
|
8
|
+
* the markers. */
|
|
9
|
+
const THINKING_MARKER_OPEN = "<thinking>";
|
|
10
|
+
const THINKING_MARKER_CLOSE = "</thinking>";
|
|
11
|
+
const MARKERS = [
|
|
12
|
+
{ open: COMPACTED_MARKER_OPEN, close: COMPACTED_MARKER_CLOSE },
|
|
13
|
+
{ open: THINKING_MARKER_OPEN, close: THINKING_MARKER_CLOSE },
|
|
14
|
+
];
|
|
15
|
+
/** Longest prefix of any open/close marker we might still be matching.
|
|
16
|
+
* Tracked so we know how many trailing bytes to buffer (waiting for the
|
|
17
|
+
* next chunk) vs. flush. */
|
|
18
|
+
function maxMarkerLen() {
|
|
19
|
+
let m = 0;
|
|
20
|
+
for (const p of MARKERS) {
|
|
21
|
+
if (p.open.length > m)
|
|
22
|
+
m = p.open.length;
|
|
23
|
+
if (p.close.length > m)
|
|
24
|
+
m = p.close.length;
|
|
25
|
+
}
|
|
26
|
+
return m;
|
|
27
|
+
}
|
|
28
|
+
export class StreamingContextScrubber {
|
|
29
|
+
state = { kind: "outside" };
|
|
30
|
+
bufferCap = maxMarkerLen();
|
|
31
|
+
/**
|
|
32
|
+
* Push a chunk of streamed text. Returns the bytes that should be
|
|
33
|
+
* emitted downstream (the unscrubbed part). Internal state advances so
|
|
34
|
+
* subsequent calls pick up where the last one left off.
|
|
35
|
+
*
|
|
36
|
+
* Safe on empty chunks (returns empty string).
|
|
37
|
+
*/
|
|
38
|
+
feed(chunk) {
|
|
39
|
+
if (!chunk)
|
|
40
|
+
return "";
|
|
41
|
+
let i = 0;
|
|
42
|
+
let out = "";
|
|
43
|
+
while (i < chunk.length) {
|
|
44
|
+
const remaining = chunk.slice(i);
|
|
45
|
+
if (this.state.kind === "outside") {
|
|
46
|
+
// Look for the earliest start-of-marker candidate in `remaining`.
|
|
47
|
+
const startIdx = findPossibleMarkerStart(remaining);
|
|
48
|
+
if (startIdx < 0) {
|
|
49
|
+
// No partial marker — entire remaining is safe to emit.
|
|
50
|
+
out += remaining;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
// Emit everything before the candidate position.
|
|
54
|
+
out += remaining.slice(0, startIdx);
|
|
55
|
+
this.state = { kind: "matching-open", buffer: "" };
|
|
56
|
+
i += startIdx;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (this.state.kind === "matching-open") {
|
|
60
|
+
this.state.buffer += remaining[0];
|
|
61
|
+
i++;
|
|
62
|
+
// Did we complete an open marker?
|
|
63
|
+
const match = MARKERS.find((m) => this.state.kind === "matching-open" && this.state.buffer === m.open);
|
|
64
|
+
if (match) {
|
|
65
|
+
this.state = { kind: "inside", pending: match, buffer: "" };
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
// Still a viable prefix of any open marker?
|
|
69
|
+
const isViable = MARKERS.some((m) => this.state.kind === "matching-open" && m.open.startsWith(this.state.buffer));
|
|
70
|
+
if (!isViable) {
|
|
71
|
+
// False alarm — flush the buffered candidate and resume outside.
|
|
72
|
+
out += this.state.buffer;
|
|
73
|
+
this.state = { kind: "outside" };
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (this.state.buffer.length >= this.bufferCap) {
|
|
77
|
+
// Saturated without matching — flush and resume.
|
|
78
|
+
out += this.state.buffer;
|
|
79
|
+
this.state = { kind: "outside" };
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// state.kind === "inside" — drop bytes until close marker found.
|
|
84
|
+
this.state.buffer += remaining[0];
|
|
85
|
+
i++;
|
|
86
|
+
const closeIdx = this.state.buffer.indexOf(this.state.pending.close);
|
|
87
|
+
if (closeIdx >= 0) {
|
|
88
|
+
// Consumed (and dropped) up to and including the close marker.
|
|
89
|
+
this.state = { kind: "outside" };
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// Cap the inside buffer so a runaway (unclosed) fence doesn't grow
|
|
93
|
+
// forever — keep only the last `bufferCap` bytes (enough to detect
|
|
94
|
+
// the close marker spanning into the next chunk).
|
|
95
|
+
if (this.state.buffer.length > this.bufferCap) {
|
|
96
|
+
this.state.buffer = this.state.buffer.slice(-this.bufferCap);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Stream ended. Flush any safe-to-emit pending bytes. If we're still
|
|
103
|
+
* matching-open (the model said `<comp` and stopped), flush the buffered
|
|
104
|
+
* candidate (it wasn't a real marker after all). If we're inside a fence
|
|
105
|
+
* that never closed, drop the rest silently — better than leaking
|
|
106
|
+
* partial summary text.
|
|
107
|
+
*/
|
|
108
|
+
finish() {
|
|
109
|
+
if (this.state.kind === "matching-open") {
|
|
110
|
+
const tail = this.state.buffer;
|
|
111
|
+
this.state = { kind: "outside" };
|
|
112
|
+
return tail;
|
|
113
|
+
}
|
|
114
|
+
// outside → nothing to flush. inside → drop.
|
|
115
|
+
this.state = { kind: "outside" };
|
|
116
|
+
return "";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Index of the earliest position in `text` where a marker open sequence
|
|
121
|
+
* COULD begin. Looks for the first character of any open marker. Returns
|
|
122
|
+
* -1 when none found. Cheap pre-filter so the scrubber only enters
|
|
123
|
+
* matching-open state when it has a real candidate.
|
|
124
|
+
*/
|
|
125
|
+
function findPossibleMarkerStart(text) {
|
|
126
|
+
// All current markers start with `<`. If new marker types are added with
|
|
127
|
+
// a different leading char, extend this set.
|
|
128
|
+
const candidates = new Set();
|
|
129
|
+
for (const m of MARKERS)
|
|
130
|
+
candidates.add(m.open[0]);
|
|
131
|
+
for (let i = 0; i < text.length; i++) {
|
|
132
|
+
if (candidates.has(text[i]))
|
|
133
|
+
return i;
|
|
134
|
+
}
|
|
135
|
+
return -1;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* One-shot helper for non-streaming cases: scrub an entire string by
|
|
139
|
+
* feeding it through a scrubber and finishing. Used by the
|
|
140
|
+
* `text` (consolidated) UnifiedEvent emit at end-of-turn so non-streaming
|
|
141
|
+
* consumers (recorders, logs) also see the cleaned text.
|
|
142
|
+
*/
|
|
143
|
+
export function scrubString(input) {
|
|
144
|
+
const s = new StreamingContextScrubber();
|
|
145
|
+
return s.feed(input) + s.finish();
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=scrubber.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrubber.js","sourceRoot":"","sources":["../../src/memory/scrubber.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ProviderContentBlock, ProviderMessage } from "../providers/base.js";
|
|
2
|
+
/** Estimate tokens for a single content block. Unknown block types fall back
|
|
3
|
+
* to the text rate since their wire encoding is JSON-ish. */
|
|
4
|
+
export declare function estimateBlockTokens(block: ProviderContentBlock): number;
|
|
5
|
+
/** Estimate tokens for one message. Includes a small overhead per message
|
|
6
|
+
* for the role marker + JSON framing the API adds on the wire. */
|
|
7
|
+
export declare function estimateMessageTokens(msg: ProviderMessage): number;
|
|
8
|
+
/** Estimate total tokens for a message array. */
|
|
9
|
+
export declare function estimateTokens(messages: readonly ProviderMessage[]): number;
|
|
10
|
+
//# sourceMappingURL=token-estimate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-estimate.d.ts","sourceRoot":"","sources":["../../src/memory/token-estimate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AA4B9E;8DAC8D;AAC9D,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAuBvE;AAED;mEACmE;AACnE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAQlE;AAED,iDAAiD;AACjD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,CAI3E"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cheap token estimator for the maestro compaction trigger.
|
|
3
|
+
*
|
|
4
|
+
* We don't want a tokenizer dependency on the per-turn hot path — running a
|
|
5
|
+
* BPE encoder over every message before each provider call would cost more
|
|
6
|
+
* than the cache hit it saves. Instead we approximate token count by
|
|
7
|
+
* character length divided by a per-content-type factor, calibrated against
|
|
8
|
+
* Claude Sonnet 4 BPE empirics on representative dialogue:
|
|
9
|
+
*
|
|
10
|
+
* plain text: chars / 3.5 (English-leaning; CJK runs lower)
|
|
11
|
+
* tool_use input: chars / 4.0 (JSON literals compress further)
|
|
12
|
+
* tool_result: chars / 3.8 (mix of text + JSON)
|
|
13
|
+
*
|
|
14
|
+
* The estimator is intentionally biased **high** — over-counting triggers
|
|
15
|
+
* compaction slightly earlier than necessary, which is the safer failure
|
|
16
|
+
* mode (compacting a turn early is mildly wasteful; missing a compact and
|
|
17
|
+
* blowing past the context window is a hard 400 error).
|
|
18
|
+
*
|
|
19
|
+
* Upstream reference: `/Users/maestrobot/__KEEP_MAESTRO_AGENT__/agent/context_compressor.py`
|
|
20
|
+
* uses a similar char-based approximation when no tokenizer is plugged in.
|
|
21
|
+
*/
|
|
22
|
+
const CHARS_PER_TEXT_TOKEN = 3.5;
|
|
23
|
+
const CHARS_PER_TOOL_USE_TOKEN = 4.0;
|
|
24
|
+
const CHARS_PER_TOOL_RESULT_TOKEN = 3.8;
|
|
25
|
+
/** Estimate tokens for a single content block. Unknown block types fall back
|
|
26
|
+
* to the text rate since their wire encoding is JSON-ish. */
|
|
27
|
+
export function estimateBlockTokens(block) {
|
|
28
|
+
switch (block.type) {
|
|
29
|
+
case "text":
|
|
30
|
+
return Math.ceil(block.text.length / CHARS_PER_TEXT_TOKEN);
|
|
31
|
+
case "tool_use": {
|
|
32
|
+
// name + JSON-stringified input. Don't pretty-print — the wire format
|
|
33
|
+
// is compact and that's what the API actually counts against the cap.
|
|
34
|
+
const len = block.name.length + JSON.stringify(block.input).length;
|
|
35
|
+
return Math.ceil(len / CHARS_PER_TOOL_USE_TOKEN);
|
|
36
|
+
}
|
|
37
|
+
case "tool_result": {
|
|
38
|
+
const content = typeof block.content === "string" ? block.content : JSON.stringify(block.content);
|
|
39
|
+
return Math.ceil(content.length / CHARS_PER_TOOL_RESULT_TOKEN);
|
|
40
|
+
}
|
|
41
|
+
default: {
|
|
42
|
+
// Defensive: unknown future block shapes (e.g. image). JSON-encode and
|
|
43
|
+
// charge the text rate. Better to over-count than to silently zero out
|
|
44
|
+
// a block we don't recognize.
|
|
45
|
+
const json = JSON.stringify(block);
|
|
46
|
+
return Math.ceil(json.length / CHARS_PER_TEXT_TOKEN);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Estimate tokens for one message. Includes a small overhead per message
|
|
51
|
+
* for the role marker + JSON framing the API adds on the wire. */
|
|
52
|
+
export function estimateMessageTokens(msg) {
|
|
53
|
+
const overhead = 4; // role + framing
|
|
54
|
+
if (typeof msg.content === "string") {
|
|
55
|
+
return overhead + Math.ceil(msg.content.length / CHARS_PER_TEXT_TOKEN);
|
|
56
|
+
}
|
|
57
|
+
let sum = overhead;
|
|
58
|
+
for (const block of msg.content)
|
|
59
|
+
sum += estimateBlockTokens(block);
|
|
60
|
+
return sum;
|
|
61
|
+
}
|
|
62
|
+
/** Estimate total tokens for a message array. */
|
|
63
|
+
export function estimateTokens(messages) {
|
|
64
|
+
let sum = 0;
|
|
65
|
+
for (const msg of messages)
|
|
66
|
+
sum += estimateMessageTokens(msg);
|
|
67
|
+
return sum;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=token-estimate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-estimate.js","sourceRoot":"","sources":["../../src/memory/token-estimate.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AACrC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAExC;8DAC8D;AAC9D,MAAM,UAAU,mBAAmB,CAAC,KAA2B;IAC7D,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM;YACT,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,oBAAoB,CAAC,CAAC;QAC7D,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,sEAAsE;YACtE,sEAAsE;YACtE,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;YACnE,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,wBAAwB,CAAC,CAAC;QACnD,CAAC;QACD,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,OAAO,GACX,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpF,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,2BAA2B,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,CAAC,CAAC,CAAC;YACR,uEAAuE;YACvE,uEAAuE;YACvE,8BAA8B;YAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACnC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,oBAAoB,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;AACH,CAAC;AAED;mEACmE;AACnE,MAAM,UAAU,qBAAqB,CAAC,GAAoB;IACxD,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,iBAAiB;IACrC,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,oBAAoB,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO;QAAE,GAAG,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACnE,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,cAAc,CAAC,QAAoC;IACjE,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,GAAG,IAAI,QAAQ;QAAE,GAAG,IAAI,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC9D,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const DATA_DIR: string;
|
|
2
|
+
export declare const WORKSPACE_DIR: string;
|
|
3
|
+
export declare const MODEL_HAIKU: string;
|
|
4
|
+
export declare const MODEL_SONNET: string;
|
|
5
|
+
export declare const MODEL_OPUS: string;
|
|
6
|
+
export declare const MODEL_DEEPSEEK_V4_PRO: string;
|
|
7
|
+
export declare const MODEL_DEEPSEEK_V4_FLASH: string;
|
|
8
|
+
export declare const FILE_TAG_REGEX: RegExp;
|
|
9
|
+
/** Returns `process.env` without `CLAUDECODE` so spawned subprocesses don't
|
|
10
|
+
* inherit a nested-claude-code detection flag from a parent harness. */
|
|
11
|
+
export declare function getCleanEnv(): NodeJS.ProcessEnv;
|
|
12
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/platform/config.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,QAAQ,EAAE,MAEY,CAAC;AAEpC,eAAO,MAAM,aAAa,EAAE,MAEU,CAAC;AAEvC,eAAO,MAAM,WAAW,EAAE,MAC4C,CAAC;AAKvE,eAAO,MAAM,YAAY,EAAE,MAA4B,CAAC;AACxD,eAAO,MAAM,UAAU,EAAE,MAA0B,CAAC;AAGpD,eAAO,MAAM,qBAAqB,EAAE,MAA0B,CAAC;AAC/D,eAAO,MAAM,uBAAuB,EAAE,MAA4B,CAAC;AAEnE,eAAO,MAAM,cAAc,EAAE,MAAgC,CAAC;AAgB9D;yEACyE;AACzE,wBAAgB,WAAW,IAAI,MAAM,CAAC,UAAU,CAI/C"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* SDK runtime configuration — replaces clawgram's bespoke `platform/config`.
|
|
6
|
+
*
|
|
7
|
+
* Values are resolved once at module load. Hosts that need non-default paths
|
|
8
|
+
* must set the corresponding env var (`MAESTRO_DATA_DIR`, `MAESTRO_WORKSPACE_DIR`,
|
|
9
|
+
* `MAESTRO_COMPRESSION_MODEL`) **before** importing any SDK module that
|
|
10
|
+
* depends on them.
|
|
11
|
+
*
|
|
12
|
+
* For per-call overrides, prefer `AgentQueryOptions.cwd` (filesystem root)
|
|
13
|
+
* and `AIAgentConfig.model` (compression model is wired through there too).
|
|
14
|
+
*/
|
|
15
|
+
const HOME = homedir();
|
|
16
|
+
export const DATA_DIR = process.env.MAESTRO_DATA_DIR
|
|
17
|
+
? resolve(process.env.MAESTRO_DATA_DIR)
|
|
18
|
+
: resolve(HOME, ".maestro-agent");
|
|
19
|
+
export const WORKSPACE_DIR = process.env.MAESTRO_WORKSPACE_DIR
|
|
20
|
+
? resolve(process.env.MAESTRO_WORKSPACE_DIR)
|
|
21
|
+
: resolve(HOME, "maestro-workspace");
|
|
22
|
+
export const MODEL_HAIKU = process.env.MAESTRO_COMPRESSION_MODEL ?? "claude-haiku-4-5-20251001";
|
|
23
|
+
// Canonical model IDs used by the SDK's maestro registry. Hosts can pick a
|
|
24
|
+
// different default per-query via `AgentQueryOptions.model`, so these are
|
|
25
|
+
// just baseline references.
|
|
26
|
+
export const MODEL_SONNET = "claude-sonnet-4-6";
|
|
27
|
+
export const MODEL_OPUS = "claude-opus-4-7";
|
|
28
|
+
// DeepSeek V4 (released 2026-04-24). OpenAI-compatible chat-completions API.
|
|
29
|
+
export const MODEL_DEEPSEEK_V4_PRO = "deepseek-v4-pro";
|
|
30
|
+
export const MODEL_DEEPSEEK_V4_FLASH = "deepseek-v4-flash";
|
|
31
|
+
export const FILE_TAG_REGEX = /\[FILE:(\/[^\]]+)\]/gi;
|
|
32
|
+
// Make sure DATA_DIR and WORKSPACE_DIR exist before any tool/skill code tries
|
|
33
|
+
// to mkdtemp/readdir into them. Idempotent and best-effort — hosts that point
|
|
34
|
+
// these at read-only mount points should override before importing the SDK.
|
|
35
|
+
try {
|
|
36
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// ignore — host may have pre-created with stricter perms
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
mkdirSync(WORKSPACE_DIR, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// ignore — host may have pre-created with stricter perms
|
|
46
|
+
}
|
|
47
|
+
/** Returns `process.env` without `CLAUDECODE` so spawned subprocesses don't
|
|
48
|
+
* inherit a nested-claude-code detection flag from a parent harness. */
|
|
49
|
+
export function getCleanEnv() {
|
|
50
|
+
const env = { ...process.env };
|
|
51
|
+
delete env.CLAUDECODE;
|
|
52
|
+
return env;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/platform/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;;;;;GAUG;AAEH,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;AAEvB,MAAM,CAAC,MAAM,QAAQ,GAAW,OAAO,CAAC,GAAG,CAAC,gBAAgB;IAC1D,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACvC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;AAEpC,MAAM,CAAC,MAAM,aAAa,GAAW,OAAO,CAAC,GAAG,CAAC,qBAAqB;IACpE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IAC5C,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;AAEvC,MAAM,CAAC,MAAM,WAAW,GACtB,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,2BAA2B,CAAC;AAEvE,2EAA2E;AAC3E,0EAA0E;AAC1E,4BAA4B;AAC5B,MAAM,CAAC,MAAM,YAAY,GAAW,mBAAmB,CAAC;AACxD,MAAM,CAAC,MAAM,UAAU,GAAW,iBAAiB,CAAC;AAEpD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,qBAAqB,GAAW,iBAAiB,CAAC;AAC/D,MAAM,CAAC,MAAM,uBAAuB,GAAW,mBAAmB,CAAC;AAEnE,MAAM,CAAC,MAAM,cAAc,GAAW,uBAAuB,CAAC;AAE9D,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,IAAI,CAAC;IACH,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3C,CAAC;AAAC,MAAM,CAAC;IACP,yDAAyD;AAC3D,CAAC;AACD,IAAI,CAAC;IACH,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC;AAAC,MAAM,CAAC;IACP,yDAAyD;AAC3D,CAAC;AAED;yEACyE;AACzE,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC/B,OAAO,GAAG,CAAC,UAAU,CAAC;IACtB,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrowed JSONL helpers for the SDK.
|
|
3
|
+
*
|
|
4
|
+
* Upstream clawgram exposes cross-process append locks via a sidecar
|
|
5
|
+
* `.lock` file and `Bun.sleepSync`. The SDK only ships single-process
|
|
6
|
+
* read/write helpers — the agent loop and session-store never share a
|
|
7
|
+
* JSONL file with another process — so the lock complexity (and Bun
|
|
8
|
+
* dependency) is dropped here.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readJsonlLines(filePath: string): string[];
|
|
11
|
+
export declare function parseJsonlText<T = unknown>(raw: string): T[];
|
|
12
|
+
export declare function readJsonFile<T = unknown>(filePath: string): T | null;
|
|
13
|
+
/** Overwrite a JSONL file atomically (write to temp, fsync, rename). */
|
|
14
|
+
export declare function writeJsonlFile(filePath: string, entries: readonly unknown[]): void;
|
|
15
|
+
//# sourceMappingURL=jsonl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../src/platform/jsonl.ts"],"names":[],"mappings":"AAYA;;;;;;;;GAQG;AAEH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAEzD;AAED,wBAAgB,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,CAM5D;AAED,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAMpE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CA2BlF"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { closeSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Narrowed JSONL helpers for the SDK.
|
|
5
|
+
*
|
|
6
|
+
* Upstream clawgram exposes cross-process append locks via a sidecar
|
|
7
|
+
* `.lock` file and `Bun.sleepSync`. The SDK only ships single-process
|
|
8
|
+
* read/write helpers — the agent loop and session-store never share a
|
|
9
|
+
* JSONL file with another process — so the lock complexity (and Bun
|
|
10
|
+
* dependency) is dropped here.
|
|
11
|
+
*/
|
|
12
|
+
export function readJsonlLines(filePath) {
|
|
13
|
+
return readFileSync(filePath, "utf-8").trim().split("\n").filter(Boolean);
|
|
14
|
+
}
|
|
15
|
+
export function parseJsonlText(raw) {
|
|
16
|
+
return raw
|
|
17
|
+
.trim()
|
|
18
|
+
.split("\n")
|
|
19
|
+
.filter(Boolean)
|
|
20
|
+
.map((line) => JSON.parse(line));
|
|
21
|
+
}
|
|
22
|
+
export function readJsonFile(filePath) {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Overwrite a JSONL file atomically (write to temp, fsync, rename). */
|
|
31
|
+
export function writeJsonlFile(filePath, entries) {
|
|
32
|
+
const dir = dirname(filePath);
|
|
33
|
+
mkdirSync(dir, { recursive: true });
|
|
34
|
+
const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}-${Math.random()
|
|
35
|
+
.toString(16)
|
|
36
|
+
.slice(2)}`;
|
|
37
|
+
const payload = `${entries.map((e) => JSON.stringify(e)).join("\n")}\n`;
|
|
38
|
+
let fd = null;
|
|
39
|
+
try {
|
|
40
|
+
fd = openSync(tmpPath, "w");
|
|
41
|
+
writeFileSync(fd, payload);
|
|
42
|
+
fsyncSync(fd);
|
|
43
|
+
closeSync(fd);
|
|
44
|
+
fd = null;
|
|
45
|
+
renameSync(tmpPath, filePath);
|
|
46
|
+
fsyncDirectoryBestEffort(dir);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (fd !== null) {
|
|
50
|
+
try {
|
|
51
|
+
closeSync(fd);
|
|
52
|
+
}
|
|
53
|
+
catch { }
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
unlinkSync(tmpPath);
|
|
57
|
+
}
|
|
58
|
+
catch { }
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function fsyncDirectoryBestEffort(dir) {
|
|
63
|
+
let fd = null;
|
|
64
|
+
try {
|
|
65
|
+
fd = openSync(dir, "r");
|
|
66
|
+
fsyncSync(fd);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Directory fsync is not portable across every runtime/filesystem.
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
if (fd !== null) {
|
|
73
|
+
try {
|
|
74
|
+
closeSync(fd);
|
|
75
|
+
}
|
|
76
|
+
catch { }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=jsonl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../../src/platform/jsonl.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared process-shutdown registry for SDK subsystems (MCP pool, sub-agents).
|
|
3
|
+
*
|
|
4
|
+
* Ported verbatim from clawgram. Modules call `onShutdown(name, priority, fn)`;
|
|
5
|
+
* the first SIGINT/SIGTERM/beforeExit drains them in descending priority order
|
|
6
|
+
* with a per-handler timeout and a hard exit ceiling.
|
|
7
|
+
*
|
|
8
|
+
* Priority convention (rough):
|
|
9
|
+
* - 100+: stateful network/connection resources (MCP pool, DB conns).
|
|
10
|
+
* - 50: subsystems that kill external processes (subprocess pools).
|
|
11
|
+
* - 10: final reporting / metrics flushing.
|
|
12
|
+
*/
|
|
13
|
+
export interface ShutdownHandler {
|
|
14
|
+
name: string;
|
|
15
|
+
priority: number;
|
|
16
|
+
fn: () => Promise<void> | void;
|
|
17
|
+
}
|
|
18
|
+
export type SignalReason = "beforeExit" | "SIGINT" | "SIGTERM" | "test";
|
|
19
|
+
export declare function onShutdown(name: string, priority: number, fn: () => Promise<void> | void): void;
|
|
20
|
+
export declare function runShutdown(reason: SignalReason): Promise<void>;
|
|
21
|
+
export declare function __resetForTests(): void;
|
|
22
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/platform/lifecycle.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAChC;AASD,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAExE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAG/F;AAgBD,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCrE;AAED,wBAAgB,eAAe,IAAI,IAAI,CAItC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { logger } from "../platform/logger.js";
|
|
2
|
+
const handlers = [];
|
|
3
|
+
let signalHooksInstalled = false;
|
|
4
|
+
let triggered = false;
|
|
5
|
+
const HANDLER_TIMEOUT_MS = 5_000;
|
|
6
|
+
const HARD_EXIT_TIMEOUT_MS = 15_000;
|
|
7
|
+
export function onShutdown(name, priority, fn) {
|
|
8
|
+
handlers.push({ name, priority, fn });
|
|
9
|
+
ensureSignalHooks();
|
|
10
|
+
}
|
|
11
|
+
function ensureSignalHooks() {
|
|
12
|
+
if (signalHooksInstalled)
|
|
13
|
+
return;
|
|
14
|
+
signalHooksInstalled = true;
|
|
15
|
+
process.once("beforeExit", () => {
|
|
16
|
+
void runShutdown("beforeExit");
|
|
17
|
+
});
|
|
18
|
+
process.once("SIGINT", () => {
|
|
19
|
+
void runShutdown("SIGINT");
|
|
20
|
+
});
|
|
21
|
+
process.once("SIGTERM", () => {
|
|
22
|
+
void runShutdown("SIGTERM");
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export async function runShutdown(reason) {
|
|
26
|
+
if (triggered)
|
|
27
|
+
return;
|
|
28
|
+
triggered = true;
|
|
29
|
+
logger.info({ reason, handlerCount: handlers.length }, "lifecycle: shutdown sequence starting");
|
|
30
|
+
const ordered = handlers
|
|
31
|
+
.map((h, i) => ({ h, i }))
|
|
32
|
+
.sort((a, b) => b.h.priority - a.h.priority || a.i - b.i)
|
|
33
|
+
.map(({ h }) => h);
|
|
34
|
+
const hardExit = setTimeout(() => {
|
|
35
|
+
logger.error({ reason }, "lifecycle: hard-exit ceiling reached, forcing process.exit");
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}, HARD_EXIT_TIMEOUT_MS);
|
|
38
|
+
hardExit.unref?.();
|
|
39
|
+
for (const h of ordered) {
|
|
40
|
+
const start = Date.now();
|
|
41
|
+
try {
|
|
42
|
+
await Promise.race([
|
|
43
|
+
Promise.resolve(h.fn()),
|
|
44
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("handler timeout")), HANDLER_TIMEOUT_MS)),
|
|
45
|
+
]);
|
|
46
|
+
logger.info({ handler: h.name, priority: h.priority, ms: Date.now() - start }, "lifecycle: shutdown handler completed");
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
logger.warn({ err, handler: h.name, priority: h.priority, ms: Date.now() - start }, "lifecycle: shutdown handler failed or timed out (continuing)");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
clearTimeout(hardExit);
|
|
53
|
+
logger.info({ reason }, "lifecycle: shutdown sequence complete");
|
|
54
|
+
}
|
|
55
|
+
export function __resetForTests() {
|
|
56
|
+
handlers.length = 0;
|
|
57
|
+
triggered = false;
|
|
58
|
+
signalHooksInstalled = false;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/platform/lifecycle.ts"],"names":[],"mappings":"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"}
|