@chengchenccc/oh-my-agent 0.1.1-rc.1
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/README.md +79 -0
- package/dist/cli/args.d.ts +24 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +120 -0
- package/dist/cli/initial-input.d.ts +32 -0
- package/dist/cli/initial-input.d.ts.map +1 -0
- package/dist/cli/initial-input.js +131 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3 -0
- package/dist/core/__fixtures__/echo-model.d.ts +6 -0
- package/dist/core/__fixtures__/echo-model.d.ts.map +1 -0
- package/dist/core/__fixtures__/echo-model.js +10 -0
- package/dist/core/__fixtures__/mcp-echo-server.d.ts +2 -0
- package/dist/core/__fixtures__/mcp-echo-server.d.ts.map +1 -0
- package/dist/core/__fixtures__/mcp-echo-server.js +54 -0
- package/dist/core/agent-runtime.d.ts +21 -0
- package/dist/core/agent-runtime.d.ts.map +1 -0
- package/dist/core/agent-runtime.js +14 -0
- package/dist/core/memory/autonomous-memory.d.ts +21 -0
- package/dist/core/memory/autonomous-memory.d.ts.map +1 -0
- package/dist/core/memory/autonomous-memory.js +202 -0
- package/dist/core/persistence/in-memory-session-store.d.ts +3 -0
- package/dist/core/persistence/in-memory-session-store.d.ts.map +1 -0
- package/dist/core/persistence/in-memory-session-store.js +109 -0
- package/dist/core/persistence/session-store.contract.d.ts +5 -0
- package/dist/core/persistence/session-store.contract.d.ts.map +1 -0
- package/dist/core/persistence/session-store.contract.js +183 -0
- package/dist/core/persistence/session-store.d.ts +33 -0
- package/dist/core/persistence/session-store.d.ts.map +1 -0
- package/dist/core/persistence/session-store.js +22 -0
- package/dist/core/persistence/session-tree.d.ts +49 -0
- package/dist/core/persistence/session-tree.d.ts.map +1 -0
- package/dist/core/persistence/session-tree.js +1 -0
- package/dist/core/plugins/plugin-code.d.ts +13 -0
- package/dist/core/plugins/plugin-code.d.ts.map +1 -0
- package/dist/core/plugins/plugin-code.js +62 -0
- package/dist/core/plugins/plugin-marketplace.d.ts +72 -0
- package/dist/core/plugins/plugin-marketplace.d.ts.map +1 -0
- package/dist/core/plugins/plugin-marketplace.js +340 -0
- package/dist/core/plugins/plugin-resolve.d.ts +32 -0
- package/dist/core/plugins/plugin-resolve.d.ts.map +1 -0
- package/dist/core/plugins/plugin-resolve.js +101 -0
- package/dist/core/plugins/plugin-trust.d.ts +24 -0
- package/dist/core/plugins/plugin-trust.d.ts.map +1 -0
- package/dist/core/plugins/plugin-trust.js +89 -0
- package/dist/core/runtime/agent-event.d.ts +98 -0
- package/dist/core/runtime/agent-event.d.ts.map +1 -0
- package/dist/core/runtime/agent-event.js +1 -0
- package/dist/core/runtime/agent-loop.d.ts +142 -0
- package/dist/core/runtime/agent-loop.d.ts.map +1 -0
- package/dist/core/runtime/agent-loop.js +1008 -0
- package/dist/core/runtime/approval.d.ts +23 -0
- package/dist/core/runtime/approval.d.ts.map +1 -0
- package/dist/core/runtime/approval.js +25 -0
- package/dist/core/runtime/compaction.d.ts +22 -0
- package/dist/core/runtime/compaction.d.ts.map +1 -0
- package/dist/core/runtime/compaction.js +90 -0
- package/dist/core/runtime/context-estimate.d.ts +42 -0
- package/dist/core/runtime/context-estimate.d.ts.map +1 -0
- package/dist/core/runtime/context-estimate.js +34 -0
- package/dist/core/runtime/create-runtime.d.ts +81 -0
- package/dist/core/runtime/create-runtime.d.ts.map +1 -0
- package/dist/core/runtime/create-runtime.js +250 -0
- package/dist/core/runtime/fake-provider.d.ts +3 -0
- package/dist/core/runtime/fake-provider.d.ts.map +1 -0
- package/dist/core/runtime/fake-provider.js +87 -0
- package/dist/core/runtime/logger.d.ts +13 -0
- package/dist/core/runtime/logger.d.ts.map +1 -0
- package/dist/core/runtime/logger.js +38 -0
- package/dist/core/runtime/loop-input.d.ts +39 -0
- package/dist/core/runtime/loop-input.d.ts.map +1 -0
- package/dist/core/runtime/loop-input.js +38 -0
- package/dist/core/runtime/message-cache.d.ts +16 -0
- package/dist/core/runtime/message-cache.d.ts.map +1 -0
- package/dist/core/runtime/message-cache.js +23 -0
- package/dist/core/runtime/model-catalog.d.ts +10 -0
- package/dist/core/runtime/model-catalog.d.ts.map +1 -0
- package/dist/core/runtime/model-catalog.js +14 -0
- package/dist/core/runtime/plugin-runtime.d.ts +41 -0
- package/dist/core/runtime/plugin-runtime.d.ts.map +1 -0
- package/dist/core/runtime/plugin-runtime.js +1 -0
- package/dist/core/runtime/plugin.d.ts +86 -0
- package/dist/core/runtime/plugin.d.ts.map +1 -0
- package/dist/core/runtime/plugin.js +23 -0
- package/dist/core/runtime/process-tree.d.ts +12 -0
- package/dist/core/runtime/process-tree.d.ts.map +1 -0
- package/dist/core/runtime/process-tree.js +40 -0
- package/dist/core/runtime/prompt.d.ts +23 -0
- package/dist/core/runtime/prompt.d.ts.map +1 -0
- package/dist/core/runtime/prompt.js +29 -0
- package/dist/core/runtime/prompts.d.ts +16 -0
- package/dist/core/runtime/prompts.d.ts.map +1 -0
- package/dist/core/runtime/prompts.js +36 -0
- package/dist/core/runtime/retry.d.ts +20 -0
- package/dist/core/runtime/retry.d.ts.map +1 -0
- package/dist/core/runtime/retry.js +60 -0
- package/dist/core/runtime/run-runtime.d.ts +93 -0
- package/dist/core/runtime/run-runtime.d.ts.map +1 -0
- package/dist/core/runtime/run-runtime.js +664 -0
- package/dist/core/runtime/runtime-catalog.d.ts +12 -0
- package/dist/core/runtime/runtime-catalog.d.ts.map +1 -0
- package/dist/core/runtime/runtime-catalog.js +89 -0
- package/dist/core/runtime/stream-rules.d.ts +9 -0
- package/dist/core/runtime/stream-rules.d.ts.map +1 -0
- package/dist/core/runtime/stream-rules.js +44 -0
- package/dist/core/runtime/title.d.ts +7 -0
- package/dist/core/runtime/title.d.ts.map +1 -0
- package/dist/core/runtime/title.js +114 -0
- package/dist/core/runtime/todo.d.ts +16 -0
- package/dist/core/runtime/todo.d.ts.map +1 -0
- package/dist/core/runtime/todo.js +40 -0
- package/dist/core/runtime/tool-filter.d.ts +12 -0
- package/dist/core/runtime/tool-filter.d.ts.map +1 -0
- package/dist/core/runtime/tool-filter.js +23 -0
- package/dist/core/runtime/tool-pruning.d.ts +29 -0
- package/dist/core/runtime/tool-pruning.d.ts.map +1 -0
- package/dist/core/runtime/tool-pruning.js +105 -0
- package/dist/core/session/input-history.d.ts +8 -0
- package/dist/core/session/input-history.d.ts.map +1 -0
- package/dist/core/session/input-history.js +41 -0
- package/dist/core/session/session-file.d.ts +84 -0
- package/dist/core/session/session-file.d.ts.map +1 -0
- package/dist/core/session/session-file.js +392 -0
- package/dist/core/session/session-loop.d.ts +33 -0
- package/dist/core/session/session-loop.d.ts.map +1 -0
- package/dist/core/session/session-loop.js +30 -0
- package/dist/core/settings/project-settings.d.ts +46 -0
- package/dist/core/settings/project-settings.d.ts.map +1 -0
- package/dist/core/settings/project-settings.js +85 -0
- package/dist/core/settings/workspace-context.d.ts +10 -0
- package/dist/core/settings/workspace-context.d.ts.map +1 -0
- package/dist/core/settings/workspace-context.js +48 -0
- package/dist/core/tools/agent-fs-like.d.ts +15 -0
- package/dist/core/tools/agent-fs-like.d.ts.map +1 -0
- package/dist/core/tools/agent-fs-like.js +4 -0
- package/dist/core/tools/ask-question.d.ts +5 -0
- package/dist/core/tools/ask-question.d.ts.map +1 -0
- package/dist/core/tools/ask-question.js +51 -0
- package/dist/core/tools/bash.d.ts +5 -0
- package/dist/core/tools/bash.d.ts.map +1 -0
- package/dist/core/tools/bash.js +109 -0
- package/dist/core/tools/eval.d.ts +10 -0
- package/dist/core/tools/eval.d.ts.map +1 -0
- package/dist/core/tools/eval.js +83 -0
- package/dist/core/tools/file-tools.d.ts +18 -0
- package/dist/core/tools/file-tools.d.ts.map +1 -0
- package/dist/core/tools/file-tools.js +249 -0
- package/dist/core/tools/glob.d.ts +5 -0
- package/dist/core/tools/glob.d.ts.map +1 -0
- package/dist/core/tools/glob.js +54 -0
- package/dist/core/tools/grep.d.ts +5 -0
- package/dist/core/tools/grep.d.ts.map +1 -0
- package/dist/core/tools/grep.js +61 -0
- package/dist/core/tools/index.d.ts +14 -0
- package/dist/core/tools/index.d.ts.map +1 -0
- package/dist/core/tools/index.js +14 -0
- package/dist/core/tools/ls-tree.d.ts +10 -0
- package/dist/core/tools/ls-tree.d.ts.map +1 -0
- package/dist/core/tools/ls-tree.js +177 -0
- package/dist/core/tools/mcp-mount.d.ts +63 -0
- package/dist/core/tools/mcp-mount.d.ts.map +1 -0
- package/dist/core/tools/mcp-mount.js +287 -0
- package/dist/core/tools/read-image.d.ts +6 -0
- package/dist/core/tools/read-image.d.ts.map +1 -0
- package/dist/core/tools/read-image.js +98 -0
- package/dist/core/tools/skill.d.ts +11 -0
- package/dist/core/tools/skill.d.ts.map +1 -0
- package/dist/core/tools/skill.js +65 -0
- package/dist/core/tools/skills.d.ts +10 -0
- package/dist/core/tools/skills.d.ts.map +1 -0
- package/dist/core/tools/skills.js +116 -0
- package/dist/core/tools/todo-store.d.ts +8 -0
- package/dist/core/tools/todo-store.d.ts.map +1 -0
- package/dist/core/tools/todo-store.js +100 -0
- package/dist/core/tools/todo.d.ts +8 -0
- package/dist/core/tools/todo.d.ts.map +1 -0
- package/dist/core/tools/todo.js +91 -0
- package/dist/core/tools/url-guard.d.ts +12 -0
- package/dist/core/tools/url-guard.d.ts.map +1 -0
- package/dist/core/tools/url-guard.js +58 -0
- package/dist/core/tools/web-ports-std.d.ts +6 -0
- package/dist/core/tools/web-ports-std.d.ts.map +1 -0
- package/dist/core/tools/web-ports-std.js +145 -0
- package/dist/core/tools/web-ports.d.ts +56 -0
- package/dist/core/tools/web-ports.d.ts.map +1 -0
- package/dist/core/tools/web-ports.js +62 -0
- package/dist/core/tools/workspace-sandbox.d.ts +20 -0
- package/dist/core/tools/workspace-sandbox.d.ts.map +1 -0
- package/dist/core/tools/workspace-sandbox.js +84 -0
- package/dist/core/workflow/subagent-registry.d.ts +40 -0
- package/dist/core/workflow/subagent-registry.d.ts.map +1 -0
- package/dist/core/workflow/subagent-registry.js +118 -0
- package/dist/core/workflow/workflow-evaluator.d.ts +23 -0
- package/dist/core/workflow/workflow-evaluator.d.ts.map +1 -0
- package/dist/core/workflow/workflow-evaluator.js +21 -0
- package/dist/core/workflow/workflow-executor.d.ts +108 -0
- package/dist/core/workflow/workflow-executor.d.ts.map +1 -0
- package/dist/core/workflow/workflow-executor.js +549 -0
- package/dist/core/workflow/workflow-tools.d.ts +50 -0
- package/dist/core/workflow/workflow-tools.d.ts.map +1 -0
- package/dist/core/workflow/workflow-tools.js +217 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/main.d.ts +9 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +97 -0
- package/dist/modes/json-mode.d.ts +5 -0
- package/dist/modes/json-mode.d.ts.map +1 -0
- package/dist/modes/json-mode.js +46 -0
- package/dist/modes/print-mode.d.ts +20 -0
- package/dist/modes/print-mode.d.ts.map +1 -0
- package/dist/modes/print-mode.js +82 -0
- package/dist/modes/rpc/jsonl.d.ts +23 -0
- package/dist/modes/rpc/jsonl.d.ts.map +1 -0
- package/dist/modes/rpc/jsonl.js +88 -0
- package/dist/modes/rpc/rpc-mode.d.ts +18 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-mode.js +326 -0
- package/dist/modes/tui/settings-overlay.d.ts +23 -0
- package/dist/modes/tui/settings-overlay.d.ts.map +1 -0
- package/dist/modes/tui/settings-overlay.js +136 -0
- package/dist/modes/tui/tui-commands-session.d.ts +3 -0
- package/dist/modes/tui/tui-commands-session.d.ts.map +1 -0
- package/dist/modes/tui/tui-commands-session.js +191 -0
- package/dist/modes/tui/tui-commands.d.ts +52 -0
- package/dist/modes/tui/tui-commands.d.ts.map +1 -0
- package/dist/modes/tui/tui-commands.js +373 -0
- package/dist/modes/tui/tui-components.d.ts +81 -0
- package/dist/modes/tui/tui-components.d.ts.map +1 -0
- package/dist/modes/tui/tui-components.js +248 -0
- package/dist/modes/tui/tui-format.d.ts +65 -0
- package/dist/modes/tui/tui-format.d.ts.map +1 -0
- package/dist/modes/tui/tui-format.js +246 -0
- package/dist/modes/tui/tui-frame-provider.d.ts +16 -0
- package/dist/modes/tui/tui-frame-provider.d.ts.map +1 -0
- package/dist/modes/tui/tui-frame-provider.js +31 -0
- package/dist/modes/tui/tui-interactive.d.ts +16 -0
- package/dist/modes/tui/tui-interactive.d.ts.map +1 -0
- package/dist/modes/tui/tui-interactive.js +123 -0
- package/dist/modes/tui/tui-io.d.ts +12 -0
- package/dist/modes/tui/tui-io.d.ts.map +1 -0
- package/dist/modes/tui/tui-io.js +620 -0
- package/dist/modes/tui/tui-mode.d.ts +120 -0
- package/dist/modes/tui/tui-mode.d.ts.map +1 -0
- package/dist/modes/tui/tui-mode.js +391 -0
- package/dist/modes/tui/tui-render.d.ts +54 -0
- package/dist/modes/tui/tui-render.d.ts.map +1 -0
- package/dist/modes/tui/tui-render.js +399 -0
- package/dist/modes/tui/tui-slash.d.ts +12 -0
- package/dist/modes/tui/tui-slash.d.ts.map +1 -0
- package/dist/modes/tui/tui-slash.js +64 -0
- package/dist/modes/tui/tui-tool-render.d.ts +6 -0
- package/dist/modes/tui/tui-tool-render.d.ts.map +1 -0
- package/dist/modes/tui/tui-tool-render.js +79 -0
- package/dist/modes/tui/tui-transcript-reconciler.d.ts +25 -0
- package/dist/modes/tui/tui-transcript-reconciler.d.ts.map +1 -0
- package/dist/modes/tui/tui-transcript-reconciler.js +97 -0
- package/dist/modes/tui/view-state.d.ts +67 -0
- package/dist/modes/tui/view-state.d.ts.map +1 -0
- package/dist/modes/tui/view-state.js +353 -0
- package/dist/prompts/agents/subagent.md +26 -0
- package/dist/prompts/system/base.md +20 -0
- package/dist/prompts/system/memory.md +23 -0
- package/dist/prompts/system/safety.md +12 -0
- package/dist/protocol/index.d.ts +5 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +2 -0
- package/dist/protocol/mapping.d.ts +25 -0
- package/dist/protocol/mapping.d.ts.map +1 -0
- package/dist/protocol/mapping.js +115 -0
- package/dist/protocol/transport.d.ts +1396 -0
- package/dist/protocol/transport.d.ts.map +1 -0
- package/dist/protocol/transport.js +170 -0
- package/package.json +49 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** HITL approval (spec: 2026-08-26-plugin-trust-model-design.md): one handler
|
|
2
|
+
* type, three resolution pipelines (tui overlay / print+json fail-closed /
|
|
3
|
+
* rpc wire with deadline). */
|
|
4
|
+
export interface ApprovalRequest {
|
|
5
|
+
readonly callId: string;
|
|
6
|
+
readonly toolName: string;
|
|
7
|
+
readonly input: unknown;
|
|
8
|
+
/** Who asked: "permission" (ask-mode gate) or "tool" (options.request). */
|
|
9
|
+
readonly source: "permission" | "tool";
|
|
10
|
+
readonly reason?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ApprovalDecision {
|
|
13
|
+
readonly decision: "allow" | "deny";
|
|
14
|
+
readonly reason?: string;
|
|
15
|
+
}
|
|
16
|
+
export type ApprovalHandler = (req: ApprovalRequest) => Promise<ApprovalDecision>;
|
|
17
|
+
export declare const DEFAULT_APPROVAL_TIMEOUT_MS = 120000;
|
|
18
|
+
export declare function approvalTimeoutMs(): number;
|
|
19
|
+
/** Resolve with a deadline; a silent human fails closed (deny). 0 = wait. */
|
|
20
|
+
export declare function withApprovalDeadline(p: Promise<ApprovalDecision>, timeoutMs: number): Promise<ApprovalDecision>;
|
|
21
|
+
/** The fail-closed handler for headless one-shot modes (print/json). */
|
|
22
|
+
export declare function denyAllApprovals(req: ApprovalRequest): Promise<ApprovalDecision>;
|
|
23
|
+
//# sourceMappingURL=approval.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/approval.ts"],"names":[],"mappings":"AAAA;;+BAE+B;AAE/B,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAElF,eAAO,MAAM,2BAA2B,SAAU,CAAC;AAEnD,wBAAgB,iBAAiB,IAAI,MAAM,CAI1C;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAClC,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAC5B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAW3B;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAKhF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** HITL approval (spec: 2026-08-26-plugin-trust-model-design.md): one handler
|
|
2
|
+
* type, three resolution pipelines (tui overlay / print+json fail-closed /
|
|
3
|
+
* rpc wire with deadline). */
|
|
4
|
+
export const DEFAULT_APPROVAL_TIMEOUT_MS = 120_000;
|
|
5
|
+
export function approvalTimeoutMs() {
|
|
6
|
+
const raw = process.env.OMA_APPROVAL_TIMEOUT_MS;
|
|
7
|
+
const n = raw === undefined ? DEFAULT_APPROVAL_TIMEOUT_MS : Number(raw);
|
|
8
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_APPROVAL_TIMEOUT_MS;
|
|
9
|
+
}
|
|
10
|
+
/** Resolve with a deadline; a silent human fails closed (deny). 0 = wait. */
|
|
11
|
+
export function withApprovalDeadline(p, timeoutMs) {
|
|
12
|
+
if (timeoutMs === 0)
|
|
13
|
+
return p;
|
|
14
|
+
return Promise.race([
|
|
15
|
+
p,
|
|
16
|
+
new Promise((resolve) => setTimeout(() => resolve({ decision: "deny", reason: "approval deadline exceeded" }), timeoutMs)),
|
|
17
|
+
]);
|
|
18
|
+
}
|
|
19
|
+
/** The fail-closed handler for headless one-shot modes (print/json). */
|
|
20
|
+
export function denyAllApprovals(req) {
|
|
21
|
+
return Promise.resolve({
|
|
22
|
+
decision: "deny",
|
|
23
|
+
reason: `${req.toolName}: approval requested in non-interactive mode (fail-closed)`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Message } from "@chengchenccc/message";
|
|
2
|
+
import type { SessionStore } from "../persistence/session-store.js";
|
|
3
|
+
export interface CompactionResult {
|
|
4
|
+
readonly entryId: string;
|
|
5
|
+
readonly coveredIds: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
/** Token budget used for compaction cut points. `estimate` is a per-message
|
|
8
|
+
* token cost; `limit` is the target ceiling for the retained context. */
|
|
9
|
+
export interface CompactionBudget {
|
|
10
|
+
estimate(message: Message): number;
|
|
11
|
+
limit: number;
|
|
12
|
+
}
|
|
13
|
+
/** Compact a session branch: summarize oldest entries, append CompactionEntry,
|
|
14
|
+
* leave tail entries intact. Shared by threshold/manual/overflow triggers.
|
|
15
|
+
*
|
|
16
|
+
* The summarizer receives full Message objects (including tool_use/tool_result
|
|
17
|
+
* blocks) so tool semantics survive compaction. The AbortSignal lets stop()
|
|
18
|
+
* cancel an in-flight summarizer; an aborted compaction writes nothing.
|
|
19
|
+
* No-op when the context is already under budget (no summarizer call, no
|
|
20
|
+
* CompactionEntry), and never writes an entry with empty coversEntryIds. */
|
|
21
|
+
export declare function compactSession(store: SessionStore, sessionId: string, summarizer: (messages: readonly Message[], signal?: AbortSignal) => Promise<string>, signal?: AbortSignal, budget?: CompactionBudget): Promise<CompactionResult>;
|
|
22
|
+
//# sourceMappingURL=compaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/compaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAGpE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED;0EAC0E;AAC1E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AA6DD;;;;;;;6EAO6E;AAC7E,wBAAsB,cAAc,CAClC,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,EACnF,MAAM,CAAC,EAAE,WAAW,EACpB,MAAM,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,gBAAgB,CAAC,CAsC3B"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/** If the cut lands between an assistant tool_use and its tool_result,
|
|
2
|
+
* move the cut before the assistant so the pair stays intact. */
|
|
3
|
+
function adjustCutForToolPairs(messages, cutIdx) {
|
|
4
|
+
let cut = cutIdx;
|
|
5
|
+
while (cut < messages.length && messages[cut]?.type === "message") {
|
|
6
|
+
const first = messages[cut];
|
|
7
|
+
if (first.role !== "tool")
|
|
8
|
+
break;
|
|
9
|
+
const toolUseId = first.message?.blocks?.find((b) => b.type === "tool_result")?.tool_use_id;
|
|
10
|
+
if (!toolUseId)
|
|
11
|
+
break;
|
|
12
|
+
let assocIdx = -1;
|
|
13
|
+
for (let i = 0; i < cut; i++) {
|
|
14
|
+
const m = messages[i];
|
|
15
|
+
if (m.role === "assistant" &&
|
|
16
|
+
m.message?.blocks?.some((b) => b.type === "tool_use" && b.id === toolUseId)) {
|
|
17
|
+
assocIdx = i;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (assocIdx === -1)
|
|
21
|
+
break;
|
|
22
|
+
cut = assocIdx;
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
return cut;
|
|
26
|
+
}
|
|
27
|
+
/** Compute the compaction cut point. Always returns a value: without a budget
|
|
28
|
+
* it uses a message-count heuristic; with a budget it accumulates tokens from
|
|
29
|
+
* the oldest messages until the retained tail fits under the limit. When the
|
|
30
|
+
* context is already under the limit, cutIdx is 0 (no compaction needed). */
|
|
31
|
+
function findCut(messages, budget) {
|
|
32
|
+
if (!budget) {
|
|
33
|
+
return { cutIdx: Math.floor(messages.length * 0.6) };
|
|
34
|
+
}
|
|
35
|
+
const tokens = messages.map((m) => budget.estimate(m.message));
|
|
36
|
+
const tokensBefore = tokens.reduce((sum, t) => sum + t, 0);
|
|
37
|
+
if (tokensBefore <= budget.limit) {
|
|
38
|
+
return { cutIdx: 0, tokensBefore };
|
|
39
|
+
}
|
|
40
|
+
let remaining = tokensBefore;
|
|
41
|
+
let cutIdx = 0;
|
|
42
|
+
while (cutIdx < messages.length && remaining > budget.limit) {
|
|
43
|
+
remaining -= tokens[cutIdx];
|
|
44
|
+
cutIdx++;
|
|
45
|
+
}
|
|
46
|
+
return { cutIdx, tokensBefore };
|
|
47
|
+
}
|
|
48
|
+
/** Compact a session branch: summarize oldest entries, append CompactionEntry,
|
|
49
|
+
* leave tail entries intact. Shared by threshold/manual/overflow triggers.
|
|
50
|
+
*
|
|
51
|
+
* The summarizer receives full Message objects (including tool_use/tool_result
|
|
52
|
+
* blocks) so tool semantics survive compaction. The AbortSignal lets stop()
|
|
53
|
+
* cancel an in-flight summarizer; an aborted compaction writes nothing.
|
|
54
|
+
* No-op when the context is already under budget (no summarizer call, no
|
|
55
|
+
* CompactionEntry), and never writes an entry with empty coversEntryIds. */
|
|
56
|
+
export async function compactSession(store, sessionId, summarizer, signal, budget) {
|
|
57
|
+
const branch = await store.readBranch(sessionId);
|
|
58
|
+
const messages = branch.filter((e) => e.type === "message");
|
|
59
|
+
if (messages.length < 4)
|
|
60
|
+
return { entryId: "", coveredIds: [] };
|
|
61
|
+
const { cutIdx: rawCutIdx, tokensBefore } = findCut(messages, budget);
|
|
62
|
+
let cutIdx = rawCutIdx;
|
|
63
|
+
cutIdx = adjustCutForToolPairs(messages, cutIdx);
|
|
64
|
+
// No compaction needed: nothing to cover (under budget or cut collapsed).
|
|
65
|
+
if (cutIdx <= 0)
|
|
66
|
+
return { entryId: "", coveredIds: [] };
|
|
67
|
+
const coveredEntries = messages.slice(0, cutIdx);
|
|
68
|
+
const coveredIds = coveredEntries.map((m) => m.entryId);
|
|
69
|
+
const retainedIds = messages.slice(cutIdx).map((m) => m.entryId);
|
|
70
|
+
const coveredMessages = coveredEntries.map((m) => m.message);
|
|
71
|
+
const summary = await summarizer(coveredMessages, signal);
|
|
72
|
+
// If aborted during summarization, do not write a CompactionEntry.
|
|
73
|
+
if (signal?.aborted)
|
|
74
|
+
return { entryId: "", coveredIds: [] };
|
|
75
|
+
const result = await store.appendBatch(sessionId, {
|
|
76
|
+
entries: [
|
|
77
|
+
{
|
|
78
|
+
type: "compaction",
|
|
79
|
+
summary,
|
|
80
|
+
coversEntryIds: coveredIds,
|
|
81
|
+
...(budget ? { tokensBefore, retainedEntryIds: retainedIds } : {}),
|
|
82
|
+
createdAt: Date.now(),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
});
|
|
86
|
+
return {
|
|
87
|
+
entryId: result.appendedIds[0] ?? "",
|
|
88
|
+
coveredIds: coveredIds,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Context-token estimation helpers absorbed from oh-my-pi
|
|
2
|
+
* (packages/agent/src/harness/compaction/compaction.ts):
|
|
3
|
+
* usage-anchored estimation + silent-overflow detection. */
|
|
4
|
+
/** Per-turn usage quartet (concrete, unlike the all-optional run Usage). */
|
|
5
|
+
export interface TurnUsage {
|
|
6
|
+
readonly inputTokens: number;
|
|
7
|
+
readonly outputTokens: number;
|
|
8
|
+
readonly cacheReadTokens: number;
|
|
9
|
+
readonly cacheWriteTokens: number;
|
|
10
|
+
}
|
|
11
|
+
/** A real-usage anchor: `tokens` is a completed model call's own total
|
|
12
|
+
* (input + output + cache legs) and is authoritative for every entry
|
|
13
|
+
* persisted before `afterEntryId`; only entries AFTER it fall back to
|
|
14
|
+
* per-message estimation (chars/4). Falls back wholesale when the anchor
|
|
15
|
+
* entry no longer exists (post-compaction branch, resumed runs).
|
|
16
|
+
*
|
|
17
|
+
* ponytail: the anchor is in-memory per Run — pi persists usage on
|
|
18
|
+
* assistant messages and re-anchors after resume. Persist it onto the
|
|
19
|
+
* session file if follow-up Runs ever drift badly. */
|
|
20
|
+
export interface UsageAnchor {
|
|
21
|
+
readonly afterEntryId: string | null;
|
|
22
|
+
readonly tokens: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function usageTotalTokens(usage: TurnUsage): number;
|
|
25
|
+
/** Context size estimate anchored on the last real usage: anchor tokens +
|
|
26
|
+
* per-entry estimates for entries persisted after the anchor boundary.
|
|
27
|
+
* Without an anchor (or when the boundary entry is gone) every entry is
|
|
28
|
+
* estimated — the pre-anchor behavior. */
|
|
29
|
+
export declare function estimateContextTokens<T extends {
|
|
30
|
+
entryId: string;
|
|
31
|
+
}>(entries: readonly T[], anchor: UsageAnchor | null, estimateEntry: (entry: T) => number): number;
|
|
32
|
+
/** Silent context overflow (oh-my-pi isContextOverflow): some providers
|
|
33
|
+
* accept an oversized request instead of erroring.
|
|
34
|
+
* - zai-style: the input side exceeds the model window — never legitimate.
|
|
35
|
+
* - Xiaomi-style: input truncated to exactly fill the window, leaving zero
|
|
36
|
+
* room to generate (length-stop with zero output). */
|
|
37
|
+
export declare function isSilentContextOverflow(usage: {
|
|
38
|
+
inputTokens?: number;
|
|
39
|
+
outputTokens?: number;
|
|
40
|
+
cacheReadTokens?: number;
|
|
41
|
+
} | undefined, stopReason: string | undefined, contextLimit: number): boolean;
|
|
42
|
+
//# sourceMappingURL=context-estimate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-estimate.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/context-estimate.ts"],"names":[],"mappings":"AAAA;;4DAE4D;AAE5D,4EAA4E;AAC5E,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;sDAQsD;AACtD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAEzD;AAED;;;0CAG0C;AAC1C,wBAAgB,qBAAqB,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EACjE,OAAO,EAAE,SAAS,CAAC,EAAE,EACrB,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,aAAa,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,GAClC,MAAM,CAOR;AAED;;;;wDAIwD;AACxD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EAC5F,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,YAAY,EAAE,MAAM,GACnB,OAAO,CAQT"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Context-token estimation helpers absorbed from oh-my-pi
|
|
2
|
+
* (packages/agent/src/harness/compaction/compaction.ts):
|
|
3
|
+
* usage-anchored estimation + silent-overflow detection. */
|
|
4
|
+
export function usageTotalTokens(usage) {
|
|
5
|
+
return usage.inputTokens + usage.outputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
|
|
6
|
+
}
|
|
7
|
+
/** Context size estimate anchored on the last real usage: anchor tokens +
|
|
8
|
+
* per-entry estimates for entries persisted after the anchor boundary.
|
|
9
|
+
* Without an anchor (or when the boundary entry is gone) every entry is
|
|
10
|
+
* estimated — the pre-anchor behavior. */
|
|
11
|
+
export function estimateContextTokens(entries, anchor, estimateEntry) {
|
|
12
|
+
const fallback = () => entries.reduce((sum, e) => sum + estimateEntry(e), 0);
|
|
13
|
+
if (!anchor)
|
|
14
|
+
return fallback();
|
|
15
|
+
const idx = anchor.afterEntryId === null ? -1 : entries.findIndex((e) => e.entryId === anchor.afterEntryId);
|
|
16
|
+
if (anchor.afterEntryId !== null && idx === -1)
|
|
17
|
+
return fallback();
|
|
18
|
+
return anchor.tokens + entries.slice(idx + 1).reduce((sum, e) => sum + estimateEntry(e), 0);
|
|
19
|
+
}
|
|
20
|
+
/** Silent context overflow (oh-my-pi isContextOverflow): some providers
|
|
21
|
+
* accept an oversized request instead of erroring.
|
|
22
|
+
* - zai-style: the input side exceeds the model window — never legitimate.
|
|
23
|
+
* - Xiaomi-style: input truncated to exactly fill the window, leaving zero
|
|
24
|
+
* room to generate (length-stop with zero output). */
|
|
25
|
+
export function isSilentContextOverflow(usage, stopReason, contextLimit) {
|
|
26
|
+
if (!usage || contextLimit <= 0)
|
|
27
|
+
return false;
|
|
28
|
+
const input = (usage.inputTokens ?? 0) + (usage.cacheReadTokens ?? 0);
|
|
29
|
+
if (input <= 0)
|
|
30
|
+
return false;
|
|
31
|
+
if (input > contextLimit)
|
|
32
|
+
return true;
|
|
33
|
+
return (stopReason === "max_tokens" && (usage.outputTokens ?? 0) === 0 && input >= contextLimit * 0.99);
|
|
34
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { BackendInputMessage, BackendRunInput, BackendRunSegment, ProjectedHistoryItem } from "@chengchenccc/agent-contract";
|
|
2
|
+
import type { ModelRuntime } from "@chengchenccc/ai";
|
|
3
|
+
import type { Message } from "@chengchenccc/message";
|
|
4
|
+
import type { RunEventEnvelope } from "../../protocol/index.js";
|
|
5
|
+
import { type MemoryLearnResult } from "../memory/autonomous-memory.js";
|
|
6
|
+
import type { PluginMcpConfig } from "../plugins/plugin-resolve.js";
|
|
7
|
+
import type { ApprovalHandler } from "./approval.js";
|
|
8
|
+
import type { Plugin } from "./plugin.js";
|
|
9
|
+
import type { ToolFilter } from "./tool-filter.js";
|
|
10
|
+
/** The single Runtime assembly entry point for the Oma product.
|
|
11
|
+
* Every mode (print / json / rpc / future TUI) builds the SAME runtime from
|
|
12
|
+
* these options: fresh in-memory SessionStore per Runtime, no state shared
|
|
13
|
+
* across Runtimes except the process-level Provider/ModelRuntime. */
|
|
14
|
+
export interface CreateOmaRuntimeOptions {
|
|
15
|
+
runId: string;
|
|
16
|
+
/** Canonical `<provider>/<model>` id of the Run's model: the context
|
|
17
|
+
* budget and summarizer bind to it. */
|
|
18
|
+
modelId: string;
|
|
19
|
+
workspaceRoot: string;
|
|
20
|
+
workspaceAccess: "read_only" | "read_write";
|
|
21
|
+
modelRuntime: ModelRuntime;
|
|
22
|
+
skillRoots: readonly string[];
|
|
23
|
+
/** The resumed CLI session transcript (ADR 0003 decision 6), validated
|
|
24
|
+
* messages from the session file. Seeds the loop's store in place of the
|
|
25
|
+
* retired wire `history` projection. Absent = fresh session. */
|
|
26
|
+
sessionTranscript?: readonly ProjectedHistoryItem[];
|
|
27
|
+
/** Called for every runtime event as a wire envelope (id/type/data), after
|
|
28
|
+
* the in-process segment stream. Used by RPC mode to forward events to
|
|
29
|
+
* stdout; print/json modes leave it unset. */
|
|
30
|
+
onEvent?: (envelope: RunEventEnvelope) => void;
|
|
31
|
+
/** Real-time session-file persistence: fired after every conversational
|
|
32
|
+
* persist (pi appendMessage). When set, the caller owns writing these
|
|
33
|
+
* messages to its session file as they happen. */
|
|
34
|
+
onPersistMessages?: (messages: readonly Message[]) => void;
|
|
35
|
+
/** --tools filter (CLI): applied to the final tool table. */
|
|
36
|
+
toolFilter?: ToolFilter;
|
|
37
|
+
/** Assembled plugin code components (from assemblePluginRuntime, mode
|
|
38
|
+
* layer). The runtime mounts them; it never reads the registry. */
|
|
39
|
+
pluginComponents?: {
|
|
40
|
+
plugins: readonly Plugin[];
|
|
41
|
+
mcpServers?: readonly PluginMcpConfig[];
|
|
42
|
+
};
|
|
43
|
+
/** Frozen Run permissionMode; "deny" drops plugin code components. */
|
|
44
|
+
permissionMode?: "ask" | "auto" | "deny";
|
|
45
|
+
/** Standalone modes: gate the repo-controlled workspace .mcp.json behind
|
|
46
|
+
* the trust record (spec follow-up #3). */
|
|
47
|
+
gateWorkspaceMcp?: boolean;
|
|
48
|
+
/** HITL approval pipeline; absent + ask = fail-closed. */
|
|
49
|
+
approvalHandler?: ApprovalHandler;
|
|
50
|
+
}
|
|
51
|
+
/** One Runtime = one Run. The loop runs directly in-process; steer injects
|
|
52
|
+
* into the live loop; stop aborts it; close tears down MCP clients and the
|
|
53
|
+
* SessionStore. */
|
|
54
|
+
export interface OmaRuntime {
|
|
55
|
+
/** Start the Run's loop. Returns the segment whose outcome is the Run's
|
|
56
|
+
* ONLY terminal result. A Runtime accepts exactly one run(). */
|
|
57
|
+
run(input: BackendRunInput<"oma">): Promise<BackendRunSegment<"oma">>;
|
|
58
|
+
/** Inject a steer input into the live loop. Throws when no loop is live. */
|
|
59
|
+
steer(input: BackendInputMessage): Promise<void>;
|
|
60
|
+
/** Request cancellation of the live loop. The segment's outcome still
|
|
61
|
+
* resolves (aborted). Safe to call before run() starts the loop. */
|
|
62
|
+
stop(): Promise<void>;
|
|
63
|
+
/** Close MCP clients and the in-memory Store. Call after the run settles. */
|
|
64
|
+
close(): Promise<void>;
|
|
65
|
+
/** Compaction summaries from this run's loop; read before close(). */
|
|
66
|
+
compactions(): Promise<string[]>;
|
|
67
|
+
/** Estimated context footprint of the run's branch under the run model's
|
|
68
|
+
* window — the same estimate/limit pair the compactor decides on. Read
|
|
69
|
+
* before close(). */
|
|
70
|
+
contextUsage(): Promise<{
|
|
71
|
+
estimatedTokens: number;
|
|
72
|
+
limit: number;
|
|
73
|
+
} | undefined>;
|
|
74
|
+
/** The run's background memory-learn pass (omp AutoLearn analog).
|
|
75
|
+
* Present once the run completed; never rejects; resolves after close()
|
|
76
|
+
* too (inputs are captured up front). Surfaces use it for the "learn"
|
|
77
|
+
* indicator. */
|
|
78
|
+
memoryLearning(): Promise<MemoryLearnResult> | undefined;
|
|
79
|
+
}
|
|
80
|
+
export declare function createOmaRuntime(options: CreateOmaRuntimeOptions): Promise<OmaRuntime>;
|
|
81
|
+
//# sourceMappingURL=create-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-runtime.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/create-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EAEf,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EAA2B,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;sEAGsE;AACtE,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd;4CACwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,WAAW,GAAG,YAAY,CAAC;IAC5C,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B;;qEAEiE;IACjE,iBAAiB,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACpD;;mDAE+C;IAC/C,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC/C;;uDAEmD;IACnD,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,KAAK,IAAI,CAAC;IAC3D,6DAA6D;IAC7D,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;wEACoE;IACpE,gBAAgB,CAAC,EAAE;QACjB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,UAAU,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;KACzC,CAAC;IACF,sEAAsE;IACtE,cAAc,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACzC;gDAC4C;IAC5C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0DAA0D;IAC1D,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED;;oBAEoB;AACpB,MAAM,WAAW,UAAU;IACzB;qEACiE;IACjE,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,4EAA4E;IAC5E,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD;yEACqE;IACrE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,6EAA6E;IAC7E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,sEAAsE;IACtE,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC;;0BAEsB;IACtB,YAAY,IAAI,OAAO,CAAC;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAAC;IAChF;;;oBAGgB;IAChB,cAAc,IAAI,OAAO,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;CAC1D;AAuDD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,UAAU,CAAC,CAiN5F"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { mapRunEvent } from "../../protocol/index.js";
|
|
2
|
+
import { extractAutonomousMemory } from "../memory/autonomous-memory.js";
|
|
3
|
+
import { assembleRunRuntime } from "./run-runtime.js";
|
|
4
|
+
/** Add workflow (subagent) usage into a run's terminal usage. Missing
|
|
5
|
+
* fields default to 0; an all-zero workflow side leaves the base alone. */
|
|
6
|
+
function mergeWorkflowUsage(base, wf) {
|
|
7
|
+
const zero = (v) => v ?? 0;
|
|
8
|
+
const total = zero(wf?.inputTokens) +
|
|
9
|
+
zero(wf?.outputTokens) +
|
|
10
|
+
zero(wf?.cacheReadTokens) +
|
|
11
|
+
zero(wf?.cacheWriteTokens);
|
|
12
|
+
if (total === 0)
|
|
13
|
+
return base;
|
|
14
|
+
return {
|
|
15
|
+
inputTokens: zero(base?.inputTokens) + zero(wf?.inputTokens),
|
|
16
|
+
outputTokens: zero(base?.outputTokens) + zero(wf?.outputTokens),
|
|
17
|
+
cacheReadTokens: zero(base?.cacheReadTokens) + zero(wf?.cacheReadTokens),
|
|
18
|
+
cacheWriteTokens: zero(base?.cacheWriteTokens) + zero(wf?.cacheWriteTokens),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Attach the persisted message trail when present. A failed/aborted run
|
|
22
|
+
* still surfaces what it did so the caller can persist it for the next
|
|
23
|
+
* turn ("continue" resumes the context). */
|
|
24
|
+
function withMessages(outcome, messages) {
|
|
25
|
+
return messages && messages.length > 0 ? { ...outcome, messages } : outcome;
|
|
26
|
+
}
|
|
27
|
+
function mapLoopResult(result) {
|
|
28
|
+
if (result.status === "completed") {
|
|
29
|
+
// No fabricated output: when the loop persisted no canonical messages,
|
|
30
|
+
// omit them rather than inventing an empty sequence.
|
|
31
|
+
return withMessages({
|
|
32
|
+
status: "completed",
|
|
33
|
+
...(result.usage ? { usage: result.usage } : {}),
|
|
34
|
+
...(result.title ? { title: result.title } : {}),
|
|
35
|
+
}, result.messages);
|
|
36
|
+
}
|
|
37
|
+
if (result.status === "stopped") {
|
|
38
|
+
return withMessages({ status: "aborted", error: result.error ?? "stopped by user" }, result.messages);
|
|
39
|
+
}
|
|
40
|
+
return withMessages({ status: "failed", error: result.error ?? "loop failed" }, result.messages);
|
|
41
|
+
}
|
|
42
|
+
export async function createOmaRuntime(options) {
|
|
43
|
+
const rt = await assembleRunRuntime({
|
|
44
|
+
workspaceRoot: options.workspaceRoot,
|
|
45
|
+
workspaceAccess: options.workspaceAccess,
|
|
46
|
+
runId: options.runId,
|
|
47
|
+
modelRuntime: options.modelRuntime,
|
|
48
|
+
modelId: options.modelId,
|
|
49
|
+
skillRoots: options.skillRoots,
|
|
50
|
+
...(options.onPersistMessages ? { onPersistMessages: options.onPersistMessages } : {}),
|
|
51
|
+
...(options.pluginComponents?.plugins.length
|
|
52
|
+
? { codePlugins: options.pluginComponents.plugins }
|
|
53
|
+
: {}),
|
|
54
|
+
...(options.gateWorkspaceMcp ? { gateWorkspaceMcp: true } : {}),
|
|
55
|
+
...(options.approvalHandler ? { approvalHandler: options.approvalHandler } : {}),
|
|
56
|
+
...(options.pluginComponents?.mcpServers?.length
|
|
57
|
+
? { pluginMcpServers: options.pluginComponents.mcpServers }
|
|
58
|
+
: {}),
|
|
59
|
+
...(options.permissionMode ? { permissionMode: options.permissionMode } : {}),
|
|
60
|
+
...(options.toolFilter ? { toolFilter: options.toolFilter } : {}),
|
|
61
|
+
});
|
|
62
|
+
let stopRequested = false;
|
|
63
|
+
let started = false;
|
|
64
|
+
let memoryLearning;
|
|
65
|
+
return {
|
|
66
|
+
async run(input) {
|
|
67
|
+
if (started) {
|
|
68
|
+
throw new Error(`runtime ${options.runId} already ran once (one Runtime = one Run)`);
|
|
69
|
+
}
|
|
70
|
+
started = true;
|
|
71
|
+
// run() resolves only when the loop is at a SAFE steer boundary
|
|
72
|
+
// (message_start fires after acceptingSteer=true) or settled without
|
|
73
|
+
// starting - acceptance therefore implies steer/abort are routable,
|
|
74
|
+
// with no timing window.
|
|
75
|
+
let liveResolve = null;
|
|
76
|
+
const live = new Promise((resolve) => {
|
|
77
|
+
liveResolve = resolve;
|
|
78
|
+
});
|
|
79
|
+
let liveSettled = false;
|
|
80
|
+
const settleLive = () => {
|
|
81
|
+
if (liveSettled)
|
|
82
|
+
return;
|
|
83
|
+
liveSettled = true;
|
|
84
|
+
liveResolve?.();
|
|
85
|
+
};
|
|
86
|
+
// Stop landing before the loop starts settles aborted without running.
|
|
87
|
+
if (stopRequested) {
|
|
88
|
+
settleLive();
|
|
89
|
+
const outcome = { status: "aborted", error: "stopped before start" };
|
|
90
|
+
return {
|
|
91
|
+
events: (async function* () { })(),
|
|
92
|
+
outcome: Promise.resolve(outcome),
|
|
93
|
+
stop: async () => { },
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Push-based event fan-out: onEvent envelopes feed both the RPC stdout
|
|
97
|
+
// writer and the in-process segment stream.
|
|
98
|
+
const queue = [];
|
|
99
|
+
const waiters = [];
|
|
100
|
+
let closed = false;
|
|
101
|
+
let seq = 0;
|
|
102
|
+
const unsubscribe = rt.session.onEvent((event) => {
|
|
103
|
+
if (event.type === "message_start" || event.type === "agent_end")
|
|
104
|
+
settleLive();
|
|
105
|
+
const envelope = { id: seq++, type: event.type, data: event };
|
|
106
|
+
queue.push(envelope);
|
|
107
|
+
options.onEvent?.(envelope);
|
|
108
|
+
for (const w of waiters.splice(0))
|
|
109
|
+
w();
|
|
110
|
+
});
|
|
111
|
+
// The Run's store is seeded with the full Product history + the current
|
|
112
|
+
// input by the loop itself (buildLoopInput appends history + meta +
|
|
113
|
+
// input atomically). Create the session root first.
|
|
114
|
+
await rt.store.create({
|
|
115
|
+
sessionId: options.runId,
|
|
116
|
+
backendKind: "oma",
|
|
117
|
+
workspaceRoot: options.workspaceRoot,
|
|
118
|
+
leafEntryId: null,
|
|
119
|
+
createdAt: Date.now(),
|
|
120
|
+
updatedAt: Date.now(),
|
|
121
|
+
});
|
|
122
|
+
rt.setActiveRun(input.run);
|
|
123
|
+
const outcomePromise = (async () => {
|
|
124
|
+
try {
|
|
125
|
+
// Workflow mode: the input IS a script to execute (Loop items).
|
|
126
|
+
// No interactive loop, no messages — the script's return value is
|
|
127
|
+
// the run's product (outcome.workflow.value).
|
|
128
|
+
if (input.workflow) {
|
|
129
|
+
const result = await rt.executeWorkflow(input.workflow);
|
|
130
|
+
// Top-level usage so product accounting (usage totals, Loop
|
|
131
|
+
// budget) sees the subagent spend; workflow.usage mirrors it.
|
|
132
|
+
const usage = { inputTokens: 0, outputTokens: result.totalTokens };
|
|
133
|
+
return {
|
|
134
|
+
status: "completed",
|
|
135
|
+
usage,
|
|
136
|
+
workflow: { ok: result.ok, value: result.value, usage },
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const result = await rt.session.startLoop({
|
|
140
|
+
history: options.sessionTranscript ?? [],
|
|
141
|
+
input: input.input,
|
|
142
|
+
run: input.run,
|
|
143
|
+
workspace: input.workspace,
|
|
144
|
+
metadata: input.metadata,
|
|
145
|
+
});
|
|
146
|
+
if (result.status === "completed") {
|
|
147
|
+
// Autonomous memory: extract durable facts from this Run's
|
|
148
|
+
// transcript + compaction summaries, persist to the workspace.
|
|
149
|
+
// Best-effort — never affects the outcome.
|
|
150
|
+
const branch = await rt.store.readBranch(options.runId);
|
|
151
|
+
const compactions = [];
|
|
152
|
+
for (const entry of branch) {
|
|
153
|
+
if (entry.type === "compaction" && entry.summary)
|
|
154
|
+
compactions.push(entry.summary);
|
|
155
|
+
}
|
|
156
|
+
// FIRE-AND-FORGET: awaiting here blocks the outcome (and the
|
|
157
|
+
// TUI busy state) on a second model call the user cannot abort.
|
|
158
|
+
memoryLearning = extractAutonomousMemory({
|
|
159
|
+
modelRuntime: options.modelRuntime,
|
|
160
|
+
modelId: options.modelId,
|
|
161
|
+
workspaceRoot: options.workspaceRoot,
|
|
162
|
+
runId: options.runId,
|
|
163
|
+
messages: result.messages ?? [],
|
|
164
|
+
compactions,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const outcome = mapLoopResult(result);
|
|
168
|
+
if (outcome.status === "completed") {
|
|
169
|
+
// Fan-out spend (run_workflow / workflow_run subagents) merges
|
|
170
|
+
// into the run's terminal usage (B6).
|
|
171
|
+
return { ...outcome, usage: mergeWorkflowUsage(outcome.usage, rt.workflowUsage()) };
|
|
172
|
+
}
|
|
173
|
+
return outcome;
|
|
174
|
+
}
|
|
175
|
+
catch (caught) {
|
|
176
|
+
const errObj = caught instanceof Error ? caught : new Error(String(caught));
|
|
177
|
+
return { status: "failed", error: errObj.message };
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
settleLive(); // loop settled without starting: live is still resolved
|
|
181
|
+
unsubscribe();
|
|
182
|
+
closed = true;
|
|
183
|
+
for (const w of waiters.splice(0))
|
|
184
|
+
w();
|
|
185
|
+
}
|
|
186
|
+
})();
|
|
187
|
+
const segment = {
|
|
188
|
+
events: (async function* () {
|
|
189
|
+
while (!closed || queue.length > 0) {
|
|
190
|
+
if (queue.length > 0) {
|
|
191
|
+
yield mapRunEvent(queue.shift());
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (closed)
|
|
195
|
+
return;
|
|
196
|
+
await new Promise((resolve) => waiters.push(resolve));
|
|
197
|
+
}
|
|
198
|
+
})(),
|
|
199
|
+
outcome: outcomePromise,
|
|
200
|
+
stop: async () => {
|
|
201
|
+
rt.session.stop();
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
// Acceptance = live: run() resolves once steer/abort are routable.
|
|
205
|
+
await live;
|
|
206
|
+
return segment;
|
|
207
|
+
},
|
|
208
|
+
async steer(input) {
|
|
209
|
+
rt.session.steer(input);
|
|
210
|
+
},
|
|
211
|
+
async stop() {
|
|
212
|
+
stopRequested = true;
|
|
213
|
+
rt.session.stop();
|
|
214
|
+
},
|
|
215
|
+
async close() {
|
|
216
|
+
await rt.close();
|
|
217
|
+
},
|
|
218
|
+
/** Compaction summaries produced by this run's loop (empty when the
|
|
219
|
+
* run never compacted). Read the store BEFORE close(). */
|
|
220
|
+
async compactions() {
|
|
221
|
+
const branch = await rt.store.readBranch(options.runId);
|
|
222
|
+
const summaries = [];
|
|
223
|
+
for (const entry of branch) {
|
|
224
|
+
if (entry.type === "compaction" && entry.summary)
|
|
225
|
+
summaries.push(entry.summary);
|
|
226
|
+
}
|
|
227
|
+
return summaries;
|
|
228
|
+
},
|
|
229
|
+
/** Estimated context footprint under the run model's window (the same
|
|
230
|
+
* estimate/limit the compactor uses). Read before close(). */
|
|
231
|
+
async contextUsage() {
|
|
232
|
+
const budget = rt.contextBudget;
|
|
233
|
+
if (!budget)
|
|
234
|
+
return undefined;
|
|
235
|
+
const branch = await rt.store.readBranch(options.runId);
|
|
236
|
+
let estimatedTokens = 0;
|
|
237
|
+
for (const entry of branch) {
|
|
238
|
+
if (entry.type !== "message")
|
|
239
|
+
continue;
|
|
240
|
+
estimatedTokens += budget.estimate(entry.message);
|
|
241
|
+
}
|
|
242
|
+
return { estimatedTokens, limit: budget.limit };
|
|
243
|
+
},
|
|
244
|
+
/** Background memory-learn pass for the completed run (undefined while
|
|
245
|
+
* the run has not completed). */
|
|
246
|
+
memoryLearning() {
|
|
247
|
+
return memoryLearning;
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-provider.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/fake-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAmCxD,wBAAgB,YAAY,CAC1B,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAC9D,QAAQ,CA4DV"}
|