@assemblyline-agents/runtime 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/README.md +19 -0
- package/dist/agent-harness.d.ts +108 -0
- package/dist/agent-harness.d.ts.map +1 -0
- package/dist/agent-harness.js +2 -0
- package/dist/agent-harness.js.map +1 -0
- package/dist/attachments-legacy.d.ts +17 -0
- package/dist/attachments-legacy.d.ts.map +1 -0
- package/dist/attachments-legacy.js +273 -0
- package/dist/attachments-legacy.js.map +1 -0
- package/dist/attachments.d.ts +49 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +832 -0
- package/dist/attachments.js.map +1 -0
- package/dist/builtin-tool-executors.d.ts +96 -0
- package/dist/builtin-tool-executors.d.ts.map +1 -0
- package/dist/builtin-tool-executors.js +501 -0
- package/dist/builtin-tool-executors.js.map +1 -0
- package/dist/builtin-tools.d.ts +30 -0
- package/dist/builtin-tools.d.ts.map +1 -0
- package/dist/builtin-tools.js +690 -0
- package/dist/builtin-tools.js.map +1 -0
- package/dist/capability-catalog.d.ts +27 -0
- package/dist/capability-catalog.d.ts.map +1 -0
- package/dist/capability-catalog.js +193 -0
- package/dist/capability-catalog.js.map +1 -0
- package/dist/channel-http-util.d.ts +34 -0
- package/dist/channel-http-util.d.ts.map +1 -0
- package/dist/channel-http-util.js +93 -0
- package/dist/channel-http-util.js.map +1 -0
- package/dist/channel-ingress.d.ts +56 -0
- package/dist/channel-ingress.d.ts.map +1 -0
- package/dist/channel-ingress.js +273 -0
- package/dist/channel-ingress.js.map +1 -0
- package/dist/channel.d.ts +146 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +2 -0
- package/dist/channel.js.map +1 -0
- package/dist/checkpoints.d.ts +34 -0
- package/dist/checkpoints.d.ts.map +1 -0
- package/dist/checkpoints.js +86 -0
- package/dist/checkpoints.js.map +1 -0
- package/dist/code-mode.d.ts +20 -0
- package/dist/code-mode.d.ts.map +1 -0
- package/dist/code-mode.js +658 -0
- package/dist/code-mode.js.map +1 -0
- package/dist/computer-relay-protocol.d.ts +36 -0
- package/dist/computer-relay-protocol.d.ts.map +1 -0
- package/dist/computer-relay-protocol.js +127 -0
- package/dist/computer-relay-protocol.js.map +1 -0
- package/dist/concurrency.d.ts +68 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +193 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/connection-auth-util.d.ts +56 -0
- package/dist/connection-auth-util.d.ts.map +1 -0
- package/dist/connection-auth-util.js +154 -0
- package/dist/connection-auth-util.js.map +1 -0
- package/dist/connection-clients.d.ts +50 -0
- package/dist/connection-clients.d.ts.map +1 -0
- package/dist/connection-clients.js +402 -0
- package/dist/connection-clients.js.map +1 -0
- package/dist/connection-stores.d.ts +108 -0
- package/dist/connection-stores.d.ts.map +1 -0
- package/dist/connection-stores.js +127 -0
- package/dist/connection-stores.js.map +1 -0
- package/dist/connection-util.d.ts +27 -0
- package/dist/connection-util.d.ts.map +1 -0
- package/dist/connection-util.js +118 -0
- package/dist/connection-util.js.map +1 -0
- package/dist/connections.d.ts +152 -0
- package/dist/connections.d.ts.map +1 -0
- package/dist/connections.js +838 -0
- package/dist/connections.js.map +1 -0
- package/dist/content-capture.d.ts +32 -0
- package/dist/content-capture.d.ts.map +1 -0
- package/dist/content-capture.js +77 -0
- package/dist/content-capture.js.map +1 -0
- package/dist/context-policy-util.d.ts +45 -0
- package/dist/context-policy-util.d.ts.map +1 -0
- package/dist/context-policy-util.js +120 -0
- package/dist/context-policy-util.js.map +1 -0
- package/dist/conversation-context.d.ts +55 -0
- package/dist/conversation-context.d.ts.map +1 -0
- package/dist/conversation-context.js +179 -0
- package/dist/conversation-context.js.map +1 -0
- package/dist/conversation-transcript.d.ts +49 -0
- package/dist/conversation-transcript.d.ts.map +1 -0
- package/dist/conversation-transcript.js +77 -0
- package/dist/conversation-transcript.js.map +1 -0
- package/dist/conversation-turn-dispatch.d.ts +46 -0
- package/dist/conversation-turn-dispatch.d.ts.map +1 -0
- package/dist/conversation-turn-dispatch.js +201 -0
- package/dist/conversation-turn-dispatch.js.map +1 -0
- package/dist/delivery-queue.d.ts +89 -0
- package/dist/delivery-queue.d.ts.map +1 -0
- package/dist/delivery-queue.js +244 -0
- package/dist/delivery-queue.js.map +1 -0
- package/dist/delivery-send.d.ts +44 -0
- package/dist/delivery-send.d.ts.map +1 -0
- package/dist/delivery-send.js +494 -0
- package/dist/delivery-send.js.map +1 -0
- package/dist/env-config.d.ts +6 -0
- package/dist/env-config.d.ts.map +1 -0
- package/dist/env-config.js +27 -0
- package/dist/env-config.js.map +1 -0
- package/dist/eval-run-options.d.ts +37 -0
- package/dist/eval-run-options.d.ts.map +1 -0
- package/dist/eval-run-options.js +106 -0
- package/dist/eval-run-options.js.map +1 -0
- package/dist/harness-continuation.d.ts +54 -0
- package/dist/harness-continuation.d.ts.map +1 -0
- package/dist/harness-continuation.js +58 -0
- package/dist/harness-continuation.js.map +1 -0
- package/dist/harness-loop.d.ts +110 -0
- package/dist/harness-loop.d.ts.map +1 -0
- package/dist/harness-loop.js +575 -0
- package/dist/harness-loop.js.map +1 -0
- package/dist/hook-dispatch.d.ts +19 -0
- package/dist/hook-dispatch.d.ts.map +1 -0
- package/dist/hook-dispatch.js +37 -0
- package/dist/hook-dispatch.js.map +1 -0
- package/dist/http.d.ts +26 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +114 -0
- package/dist/http.js.map +1 -0
- package/dist/in-memory-conversation-turn-store.d.ts +29 -0
- package/dist/in-memory-conversation-turn-store.d.ts.map +1 -0
- package/dist/in-memory-conversation-turn-store.js +166 -0
- package/dist/in-memory-conversation-turn-store.js.map +1 -0
- package/dist/in-memory-run-store.d.ts +39 -0
- package/dist/in-memory-run-store.d.ts.map +1 -0
- package/dist/in-memory-run-store.js +332 -0
- package/dist/in-memory-run-store.js.map +1 -0
- package/dist/in-memory-sandbox-session-store.d.ts +33 -0
- package/dist/in-memory-sandbox-session-store.d.ts.map +1 -0
- package/dist/in-memory-sandbox-session-store.js +186 -0
- package/dist/in-memory-sandbox-session-store.js.map +1 -0
- package/dist/in-memory-small-stores.d.ts +117 -0
- package/dist/in-memory-small-stores.d.ts.map +1 -0
- package/dist/in-memory-small-stores.js +340 -0
- package/dist/in-memory-small-stores.js.map +1 -0
- package/dist/in-memory-usage-store.d.ts +15 -0
- package/dist/in-memory-usage-store.d.ts.map +1 -0
- package/dist/in-memory-usage-store.js +49 -0
- package/dist/in-memory-usage-store.js.map +1 -0
- package/dist/index.d.ts +467 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2046 -0
- package/dist/index.js.map +1 -0
- package/dist/json-util.d.ts +19 -0
- package/dist/json-util.d.ts.map +1 -0
- package/dist/json-util.js +59 -0
- package/dist/json-util.js.map +1 -0
- package/dist/local-sandbox.d.ts +16 -0
- package/dist/local-sandbox.d.ts.map +1 -0
- package/dist/local-sandbox.js +327 -0
- package/dist/local-sandbox.js.map +1 -0
- package/dist/logging.d.ts +16 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +41 -0
- package/dist/logging.js.map +1 -0
- package/dist/mcp-client.d.ts +27 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +169 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/model-harnesses.d.ts +4 -0
- package/dist/model-harnesses.d.ts.map +1 -0
- package/dist/model-harnesses.js +6 -0
- package/dist/model-harnesses.js.map +1 -0
- package/dist/model-media.d.ts +36 -0
- package/dist/model-media.d.ts.map +1 -0
- package/dist/model-media.js +234 -0
- package/dist/model-media.js.map +1 -0
- package/dist/operator-controls.d.ts +31 -0
- package/dist/operator-controls.d.ts.map +1 -0
- package/dist/operator-controls.js +71 -0
- package/dist/operator-controls.js.map +1 -0
- package/dist/pi-agent-harness.d.ts +40 -0
- package/dist/pi-agent-harness.d.ts.map +1 -0
- package/dist/pi-agent-harness.js +222 -0
- package/dist/pi-agent-harness.js.map +1 -0
- package/dist/pi-harness.d.ts +42 -0
- package/dist/pi-harness.d.ts.map +1 -0
- package/dist/pi-harness.js +142 -0
- package/dist/pi-harness.js.map +1 -0
- package/dist/relay-mcp-client.d.ts +17 -0
- package/dist/relay-mcp-client.d.ts.map +1 -0
- package/dist/relay-mcp-client.js +119 -0
- package/dist/relay-mcp-client.js.map +1 -0
- package/dist/replay-resume.d.ts +107 -0
- package/dist/replay-resume.d.ts.map +1 -0
- package/dist/replay-resume.js +495 -0
- package/dist/replay-resume.js.map +1 -0
- package/dist/resource-projection-util.d.ts +58 -0
- package/dist/resource-projection-util.d.ts.map +1 -0
- package/dist/resource-projection-util.js +298 -0
- package/dist/resource-projection-util.js.map +1 -0
- package/dist/resource-projection.d.ts +45 -0
- package/dist/resource-projection.d.ts.map +1 -0
- package/dist/resource-projection.js +481 -0
- package/dist/resource-projection.js.map +1 -0
- package/dist/run-heartbeat.d.ts +34 -0
- package/dist/run-heartbeat.d.ts.map +1 -0
- package/dist/run-heartbeat.js +62 -0
- package/dist/run-heartbeat.js.map +1 -0
- package/dist/run-outcome.d.ts +47 -0
- package/dist/run-outcome.d.ts.map +1 -0
- package/dist/run-outcome.js +92 -0
- package/dist/run-outcome.js.map +1 -0
- package/dist/run-recovery.d.ts +117 -0
- package/dist/run-recovery.d.ts.map +1 -0
- package/dist/run-recovery.js +466 -0
- package/dist/run-recovery.js.map +1 -0
- package/dist/run-resolver.d.ts +35 -0
- package/dist/run-resolver.d.ts.map +1 -0
- package/dist/run-resolver.js +84 -0
- package/dist/run-resolver.js.map +1 -0
- package/dist/run-stream.d.ts +37 -0
- package/dist/run-stream.d.ts.map +1 -0
- package/dist/run-stream.js +78 -0
- package/dist/run-stream.js.map +1 -0
- package/dist/runs-query.d.ts +29 -0
- package/dist/runs-query.d.ts.map +1 -0
- package/dist/runs-query.js +142 -0
- package/dist/runs-query.js.map +1 -0
- package/dist/runtime-bundle.d.ts +3 -0
- package/dist/runtime-bundle.d.ts.map +1 -0
- package/dist/runtime-bundle.js +18 -0
- package/dist/runtime-bundle.js.map +1 -0
- package/dist/runtime-types.d.ts +397 -0
- package/dist/runtime-types.d.ts.map +1 -0
- package/dist/runtime-types.js +2 -0
- package/dist/runtime-types.js.map +1 -0
- package/dist/runtime-util.d.ts +45 -0
- package/dist/runtime-util.d.ts.map +1 -0
- package/dist/runtime-util.js +116 -0
- package/dist/runtime-util.js.map +1 -0
- package/dist/sandbox-cli-client.d.ts +20 -0
- package/dist/sandbox-cli-client.d.ts.map +1 -0
- package/dist/sandbox-cli-client.js +97 -0
- package/dist/sandbox-cli-client.js.map +1 -0
- package/dist/sandbox-fs.d.ts +56 -0
- package/dist/sandbox-fs.d.ts.map +1 -0
- package/dist/sandbox-fs.js +276 -0
- package/dist/sandbox-fs.js.map +1 -0
- package/dist/sandbox-session-key.d.ts +8 -0
- package/dist/sandbox-session-key.d.ts.map +1 -0
- package/dist/sandbox-session-key.js +32 -0
- package/dist/sandbox-session-key.js.map +1 -0
- package/dist/sandbox-snapshot-policy.d.ts +27 -0
- package/dist/sandbox-snapshot-policy.d.ts.map +1 -0
- package/dist/sandbox-snapshot-policy.js +94 -0
- package/dist/sandbox-snapshot-policy.js.map +1 -0
- package/dist/sandbox-sync-worker.d.ts +63 -0
- package/dist/sandbox-sync-worker.d.ts.map +1 -0
- package/dist/sandbox-sync-worker.js +448 -0
- package/dist/sandbox-sync-worker.js.map +1 -0
- package/dist/schedule-execution.d.ts +59 -0
- package/dist/schedule-execution.d.ts.map +1 -0
- package/dist/schedule-execution.js +951 -0
- package/dist/schedule-execution.js.map +1 -0
- package/dist/scheduler.d.ts +19 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +38 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/security.d.ts +20 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +145 -0
- package/dist/security.js.map +1 -0
- package/dist/self-improvement.d.ts +245 -0
- package/dist/self-improvement.d.ts.map +1 -0
- package/dist/self-improvement.js +554 -0
- package/dist/self-improvement.js.map +1 -0
- package/dist/source-loader.d.ts +19 -0
- package/dist/source-loader.d.ts.map +1 -0
- package/dist/source-loader.js +160 -0
- package/dist/source-loader.js.map +1 -0
- package/dist/state-store-helpers.d.ts +28 -0
- package/dist/state-store-helpers.d.ts.map +1 -0
- package/dist/state-store-helpers.js +164 -0
- package/dist/state-store-helpers.js.map +1 -0
- package/dist/state-stores.d.ts +25 -0
- package/dist/state-stores.d.ts.map +1 -0
- package/dist/state-stores.js +157 -0
- package/dist/state-stores.js.map +1 -0
- package/dist/state.d.ts +736 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +46 -0
- package/dist/state.js.map +1 -0
- package/dist/storage.d.ts +188 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +752 -0
- package/dist/storage.js.map +1 -0
- package/dist/subagent-execution.d.ts +80 -0
- package/dist/subagent-execution.d.ts.map +1 -0
- package/dist/subagent-execution.js +135 -0
- package/dist/subagent-execution.js.map +1 -0
- package/dist/telemetry.d.ts +49 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +60 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tool-apis.d.ts +22 -0
- package/dist/tool-apis.d.ts.map +1 -0
- package/dist/tool-apis.js +344 -0
- package/dist/tool-apis.js.map +1 -0
- package/dist/tool-execution.d.ts +143 -0
- package/dist/tool-execution.d.ts.map +1 -0
- package/dist/tool-execution.js +573 -0
- package/dist/tool-execution.js.map +1 -0
- package/dist/trusted-attachments.d.ts +20 -0
- package/dist/trusted-attachments.d.ts.map +1 -0
- package/dist/trusted-attachments.js +276 -0
- package/dist/trusted-attachments.js.map +1 -0
- package/dist/usage-accounting.d.ts +37 -0
- package/dist/usage-accounting.d.ts.map +1 -0
- package/dist/usage-accounting.js +181 -0
- package/dist/usage-accounting.js.map +1 -0
- package/dist/usage-budget.d.ts +29 -0
- package/dist/usage-budget.d.ts.map +1 -0
- package/dist/usage-budget.js +145 -0
- package/dist/usage-budget.js.map +1 -0
- package/dist/usage-reconciliation.d.ts +76 -0
- package/dist/usage-reconciliation.d.ts.map +1 -0
- package/dist/usage-reconciliation.js +463 -0
- package/dist/usage-reconciliation.js.map +1 -0
- package/dist/usage-records.d.ts +24 -0
- package/dist/usage-records.d.ts.map +1 -0
- package/dist/usage-records.js +445 -0
- package/dist/usage-records.js.map +1 -0
- package/package.json +51 -0
package/dist/storage.js
ADDED
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { closeSync, existsSync, fsyncSync, mkdirSync, mkdtempSync, openSync, readFileSync, renameSync, writeFileSync, writeSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { dirname, join, resolve, sep } from "node:path";
|
|
5
|
+
import { normalizeDeliveryRecord } from "./delivery-queue.js";
|
|
6
|
+
import { InMemoryConversationStore, InMemoryConversationTurnStore, InMemoryFileIndexStore, InMemoryMemoryStateStore, InMemoryRunStore, InMemoryRuntimeSettingsStore, InMemorySandboxSessionStore, InMemoryScheduleStateStore, InMemoryUsageStore, memoryBodyText, memoryKey, memoryEmbeddingKey, memoryScopeMatches, memorySnippet, normalizeMemoryPath, positiveLimit } from "./state-stores.js";
|
|
7
|
+
import { normalizeStoredUsageRecord } from "./usage-records.js";
|
|
8
|
+
export { applySandboxSyncJobPatch, cosineSimilarity, createSandboxSyncJobRecord, isSandboxSyncJobDue, memoryBodyText, memoryEmbeddingKey, memoryKey, memoryScopeMatches, memorySnippet, normalizeMemoryPath, positiveLimit, sandboxSyncRetryDelayMs } from "./state-stores.js";
|
|
9
|
+
function timestamp() {
|
|
10
|
+
return new Date().toISOString();
|
|
11
|
+
}
|
|
12
|
+
function stringValue(value) {
|
|
13
|
+
return typeof value === "string" ? value.trim() : "";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Full in-memory `StateAdapter`, composed from the per-facet in-memory
|
|
17
|
+
* stores in `state-stores.ts`. Public name and behavior are unchanged; the
|
|
18
|
+
* facets share this adapter's `persist()` hook so `FileStateAdapter` keeps
|
|
19
|
+
* snapshotting everything on every write.
|
|
20
|
+
*/
|
|
21
|
+
export class InMemoryStateAdapter {
|
|
22
|
+
runStore = new InMemoryRunStore(() => this.persist());
|
|
23
|
+
conversationStore = new InMemoryConversationStore(() => this.persist());
|
|
24
|
+
conversationTurnStore = new InMemoryConversationTurnStore(() => this.persist());
|
|
25
|
+
scheduleStateStore = new InMemoryScheduleStateStore(() => this.persist());
|
|
26
|
+
fileIndexStore = new InMemoryFileIndexStore(() => this.persist());
|
|
27
|
+
usageStore = new InMemoryUsageStore(() => this.persist());
|
|
28
|
+
sandboxStore = new InMemorySandboxSessionStore(() => this.persist());
|
|
29
|
+
memoryStateStore = new InMemoryMemoryStateStore(() => this.persist());
|
|
30
|
+
runtimeSettingsStore = new InMemoryRuntimeSettingsStore(() => this.persist());
|
|
31
|
+
createRun(input) {
|
|
32
|
+
return this.runStore.createRun(input);
|
|
33
|
+
}
|
|
34
|
+
touchRun(id) {
|
|
35
|
+
return this.runStore.touchRun(id);
|
|
36
|
+
}
|
|
37
|
+
requestRunControl(id, intent) {
|
|
38
|
+
return this.runStore.requestRunControl(id, intent);
|
|
39
|
+
}
|
|
40
|
+
settleRunControl(id) {
|
|
41
|
+
return this.runStore.settleRunControl(id);
|
|
42
|
+
}
|
|
43
|
+
updateRun(id, patch) {
|
|
44
|
+
return this.runStore.updateRun(id, patch);
|
|
45
|
+
}
|
|
46
|
+
getRun(id) {
|
|
47
|
+
return this.runStore.getRun(id);
|
|
48
|
+
}
|
|
49
|
+
listRuns() {
|
|
50
|
+
return this.runStore.listRuns();
|
|
51
|
+
}
|
|
52
|
+
appendEvent(runId, type, data) {
|
|
53
|
+
return this.runStore.appendEvent(runId, type, data);
|
|
54
|
+
}
|
|
55
|
+
listEvents(runId) {
|
|
56
|
+
return this.runStore.listEvents(runId);
|
|
57
|
+
}
|
|
58
|
+
createToolCall(input) {
|
|
59
|
+
return this.runStore.createToolCall(input);
|
|
60
|
+
}
|
|
61
|
+
updateToolCall(id, patch) {
|
|
62
|
+
return this.runStore.updateToolCall(id, patch);
|
|
63
|
+
}
|
|
64
|
+
listToolCalls(runId) {
|
|
65
|
+
return this.runStore.listToolCalls(runId);
|
|
66
|
+
}
|
|
67
|
+
createCheckpoint(input) {
|
|
68
|
+
return this.runStore.createCheckpoint(input);
|
|
69
|
+
}
|
|
70
|
+
listCheckpoints(runId) {
|
|
71
|
+
return this.runStore.listCheckpoints(runId);
|
|
72
|
+
}
|
|
73
|
+
compactCheckpoints(options) {
|
|
74
|
+
return this.runStore.compactCheckpoints(options);
|
|
75
|
+
}
|
|
76
|
+
createDelivery(input) {
|
|
77
|
+
return this.runStore.createDelivery(input);
|
|
78
|
+
}
|
|
79
|
+
updateDelivery(id, patch) {
|
|
80
|
+
return this.runStore.updateDelivery(id, patch);
|
|
81
|
+
}
|
|
82
|
+
listDeliveries(runId) {
|
|
83
|
+
return this.runStore.listDeliveries(runId);
|
|
84
|
+
}
|
|
85
|
+
leaseDueDeliveries(options) {
|
|
86
|
+
return this.runStore.leaseDueDeliveries(options);
|
|
87
|
+
}
|
|
88
|
+
completeDeliverySend(id, leaseToken, patch) {
|
|
89
|
+
return this.runStore.completeDeliverySend(id, leaseToken, patch);
|
|
90
|
+
}
|
|
91
|
+
failDeliverySend(id, leaseToken, failure) {
|
|
92
|
+
return this.runStore.failDeliverySend(id, leaseToken, failure);
|
|
93
|
+
}
|
|
94
|
+
recoverExpiredDeliveries(now) {
|
|
95
|
+
return this.runStore.recoverExpiredDeliveries(now);
|
|
96
|
+
}
|
|
97
|
+
reserveIdempotencyKey(scope, key, ownerId) {
|
|
98
|
+
return this.runStore.reserveIdempotencyKey(scope, key, ownerId);
|
|
99
|
+
}
|
|
100
|
+
upsertConversation(input) {
|
|
101
|
+
return this.conversationStore.upsertConversation(input);
|
|
102
|
+
}
|
|
103
|
+
getConversation(id) {
|
|
104
|
+
return this.conversationStore.getConversation(id);
|
|
105
|
+
}
|
|
106
|
+
listConversations(input) {
|
|
107
|
+
return this.conversationStore.listConversations(input);
|
|
108
|
+
}
|
|
109
|
+
updateConversation(id, patch) {
|
|
110
|
+
return this.conversationStore.updateConversation(id, patch);
|
|
111
|
+
}
|
|
112
|
+
listRecentConversationsBySubject(input) {
|
|
113
|
+
return this.conversationStore.listRecentConversationsBySubject(input);
|
|
114
|
+
}
|
|
115
|
+
appendMessage(input) {
|
|
116
|
+
return this.conversationStore.appendMessage(input);
|
|
117
|
+
}
|
|
118
|
+
listRecentMessages(conversationId, limit) {
|
|
119
|
+
return this.conversationStore.listRecentMessages(conversationId, limit);
|
|
120
|
+
}
|
|
121
|
+
listMessages(input) {
|
|
122
|
+
return this.conversationStore.listMessages(input);
|
|
123
|
+
}
|
|
124
|
+
enqueueConversationTurn(input) {
|
|
125
|
+
return this.conversationTurnStore.enqueueConversationTurn(input);
|
|
126
|
+
}
|
|
127
|
+
leaseNextConversationTurn(options) {
|
|
128
|
+
return this.conversationTurnStore.leaseNextConversationTurn(options);
|
|
129
|
+
}
|
|
130
|
+
attachConversationTurnRun(id, leaseToken, runId) {
|
|
131
|
+
return this.conversationTurnStore.attachConversationTurnRun(id, leaseToken, runId);
|
|
132
|
+
}
|
|
133
|
+
settleConversationTurn(id, leaseToken, status, options) {
|
|
134
|
+
return this.conversationTurnStore.settleConversationTurn(id, leaseToken, status, options);
|
|
135
|
+
}
|
|
136
|
+
settleConversationTurnByRunId(runId, status, options) {
|
|
137
|
+
return this.conversationTurnStore.settleConversationTurnByRunId(runId, status, options);
|
|
138
|
+
}
|
|
139
|
+
retryConversationTurn(id, leaseToken, error) {
|
|
140
|
+
return this.conversationTurnStore.retryConversationTurn(id, leaseToken, error);
|
|
141
|
+
}
|
|
142
|
+
recoverExpiredConversationTurns(now) {
|
|
143
|
+
return this.conversationTurnStore.recoverExpiredConversationTurns(now);
|
|
144
|
+
}
|
|
145
|
+
listConversationTurns(options) {
|
|
146
|
+
return this.conversationTurnStore.listConversationTurns(options);
|
|
147
|
+
}
|
|
148
|
+
registerSchedule(input) {
|
|
149
|
+
return this.scheduleStateStore.registerSchedule(input);
|
|
150
|
+
}
|
|
151
|
+
recordScheduleRun(input) {
|
|
152
|
+
return this.scheduleStateStore.recordScheduleRun(input);
|
|
153
|
+
}
|
|
154
|
+
recordFileIndex(input) {
|
|
155
|
+
return this.fileIndexStore.recordFileIndex(input);
|
|
156
|
+
}
|
|
157
|
+
listFileIndexes(runId) {
|
|
158
|
+
return this.fileIndexStore.listFileIndexes(runId);
|
|
159
|
+
}
|
|
160
|
+
recordUsage(input) {
|
|
161
|
+
return this.usageStore.recordUsage(input);
|
|
162
|
+
}
|
|
163
|
+
listUsage(runId) {
|
|
164
|
+
return this.usageStore.listUsage(runId);
|
|
165
|
+
}
|
|
166
|
+
queryUsage(query) {
|
|
167
|
+
return this.usageStore.queryUsage(query);
|
|
168
|
+
}
|
|
169
|
+
summarizeUsage(query) {
|
|
170
|
+
return this.usageStore.summarizeUsage(query);
|
|
171
|
+
}
|
|
172
|
+
recordSandboxSnapshot(input) {
|
|
173
|
+
return this.sandboxStore.recordSandboxSnapshot(input);
|
|
174
|
+
}
|
|
175
|
+
upsertSandboxSession(input) {
|
|
176
|
+
return this.sandboxStore.upsertSandboxSession(input);
|
|
177
|
+
}
|
|
178
|
+
getSandboxSession(sessionKey) {
|
|
179
|
+
return this.sandboxStore.getSandboxSession(sessionKey);
|
|
180
|
+
}
|
|
181
|
+
listSandboxSessions(options) {
|
|
182
|
+
return this.sandboxStore.listSandboxSessions(options);
|
|
183
|
+
}
|
|
184
|
+
updateSandboxSession(sessionKey, patch) {
|
|
185
|
+
return this.sandboxStore.updateSandboxSession(sessionKey, patch);
|
|
186
|
+
}
|
|
187
|
+
createSandboxSyncJob(input) {
|
|
188
|
+
return this.sandboxStore.createSandboxSyncJob(input);
|
|
189
|
+
}
|
|
190
|
+
enqueueSandboxSyncJob(input) {
|
|
191
|
+
return this.sandboxStore.enqueueSandboxSyncJob(input);
|
|
192
|
+
}
|
|
193
|
+
updateSandboxSyncJob(id, patch) {
|
|
194
|
+
return this.sandboxStore.updateSandboxSyncJob(id, patch);
|
|
195
|
+
}
|
|
196
|
+
listSandboxSyncJobs(runId) {
|
|
197
|
+
return this.sandboxStore.listSandboxSyncJobs(runId);
|
|
198
|
+
}
|
|
199
|
+
leaseSandboxSyncJobs(options) {
|
|
200
|
+
return this.sandboxStore.leaseSandboxSyncJobs(options);
|
|
201
|
+
}
|
|
202
|
+
completeSandboxSyncJob(id, leaseToken, patch) {
|
|
203
|
+
return this.sandboxStore.completeSandboxSyncJob(id, leaseToken, patch);
|
|
204
|
+
}
|
|
205
|
+
failSandboxSyncJob(id, leaseToken, failure) {
|
|
206
|
+
return this.sandboxStore.failSandboxSyncJob(id, leaseToken, failure);
|
|
207
|
+
}
|
|
208
|
+
recoverExpiredSandboxSyncJobs(now) {
|
|
209
|
+
return this.sandboxStore.recoverExpiredSandboxSyncJobs(now);
|
|
210
|
+
}
|
|
211
|
+
listMemoryDocuments(scope, input) {
|
|
212
|
+
return this.memoryStateStore.listMemoryDocuments(scope, input);
|
|
213
|
+
}
|
|
214
|
+
supportsMemoryEmbeddings() {
|
|
215
|
+
return this.memoryStateStore.supportsMemoryEmbeddings();
|
|
216
|
+
}
|
|
217
|
+
getMemoryDocument(scope, path) {
|
|
218
|
+
return this.memoryStateStore.getMemoryDocument(scope, path);
|
|
219
|
+
}
|
|
220
|
+
upsertMemoryDocument(document) {
|
|
221
|
+
return this.memoryStateStore.upsertMemoryDocument(document);
|
|
222
|
+
}
|
|
223
|
+
deleteMemoryDocument(scope, path) {
|
|
224
|
+
return this.memoryStateStore.deleteMemoryDocument(scope, path);
|
|
225
|
+
}
|
|
226
|
+
listMemoryDocumentsNeedingEmbeddings(scope, options) {
|
|
227
|
+
return this.memoryStateStore.listMemoryDocumentsNeedingEmbeddings(scope, options);
|
|
228
|
+
}
|
|
229
|
+
upsertMemoryEmbedding(input) {
|
|
230
|
+
return this.memoryStateStore.upsertMemoryEmbedding(input);
|
|
231
|
+
}
|
|
232
|
+
searchMemoryEmbeddings(scope, input, embedding, options) {
|
|
233
|
+
return this.memoryStateStore.searchMemoryEmbeddings(scope, input, embedding, options);
|
|
234
|
+
}
|
|
235
|
+
markMemoryEmbeddingsStale(scope, path, currentSha256) {
|
|
236
|
+
return this.memoryStateStore.markMemoryEmbeddingsStale(scope, path, currentSha256);
|
|
237
|
+
}
|
|
238
|
+
getSetting(scope, key) {
|
|
239
|
+
return this.runtimeSettingsStore.getSetting(scope, key);
|
|
240
|
+
}
|
|
241
|
+
setSetting(scope, key, value) {
|
|
242
|
+
return this.runtimeSettingsStore.setSetting(scope, key, value);
|
|
243
|
+
}
|
|
244
|
+
appendRuntimeControlEvent(scope, type, data) {
|
|
245
|
+
return this.runtimeSettingsStore.appendRuntimeControlEvent(scope, type, data);
|
|
246
|
+
}
|
|
247
|
+
listRuntimeControlEvents(scope) {
|
|
248
|
+
return this.runtimeSettingsStore.listRuntimeControlEvents(scope);
|
|
249
|
+
}
|
|
250
|
+
async persist() {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/** Temp-file + fsync + atomic-rename write so a crash never tears the target file. */
|
|
255
|
+
function writeAtomic(path, tempPath, contents) {
|
|
256
|
+
const fd = openSync(tempPath, "w");
|
|
257
|
+
try {
|
|
258
|
+
writeSync(fd, contents);
|
|
259
|
+
fsyncSync(fd);
|
|
260
|
+
}
|
|
261
|
+
finally {
|
|
262
|
+
closeSync(fd);
|
|
263
|
+
}
|
|
264
|
+
renameSync(tempPath, path);
|
|
265
|
+
}
|
|
266
|
+
export class FileStateAdapter extends InMemoryStateAdapter {
|
|
267
|
+
path;
|
|
268
|
+
constructor(path) {
|
|
269
|
+
super();
|
|
270
|
+
this.path = path;
|
|
271
|
+
this.load();
|
|
272
|
+
}
|
|
273
|
+
async persist() {
|
|
274
|
+
mkdirSync(dirname(this.path), { recursive: true });
|
|
275
|
+
// Crash-safe write: serialize to a temp file, fsync, then atomically
|
|
276
|
+
// rename over the target so a crash mid-write can never leave a torn,
|
|
277
|
+
// unparseable state file behind.
|
|
278
|
+
const tempPath = `${this.path}.tmp-${process.pid}`;
|
|
279
|
+
writeAtomic(this.path, tempPath, JSON.stringify({
|
|
280
|
+
runs: [...this.runStore.runs.values()],
|
|
281
|
+
events: this.runStore.events,
|
|
282
|
+
toolCalls: [...this.runStore.toolCalls.values()],
|
|
283
|
+
checkpoints: this.runStore.checkpoints,
|
|
284
|
+
deliveries: [...this.runStore.deliveries.values()],
|
|
285
|
+
conversations: [...this.conversationStore.conversations.values()],
|
|
286
|
+
messages: this.conversationStore.messages,
|
|
287
|
+
conversationTurns: [...this.conversationTurnStore.turns.values()],
|
|
288
|
+
schedules: [...this.scheduleStateStore.schedules.values()],
|
|
289
|
+
scheduleRuns: this.scheduleStateStore.scheduleRuns,
|
|
290
|
+
fileIndexes: this.fileIndexStore.fileIndexes,
|
|
291
|
+
usageRecords: this.usageStore.usageRecords,
|
|
292
|
+
sandboxSnapshots: this.sandboxStore.sandboxSnapshots,
|
|
293
|
+
sandboxSessions: [...this.sandboxStore.sandboxSessions.values()],
|
|
294
|
+
sandboxSyncJobs: [...this.sandboxStore.sandboxSyncJobs.values()],
|
|
295
|
+
memoryDocuments: [...this.memoryStateStore.memoryDocuments.values()],
|
|
296
|
+
memoryEmbeddings: [...this.memoryStateStore.memoryEmbeddings.values()],
|
|
297
|
+
runtimeSettings: [...this.runtimeSettingsStore.settings.values()],
|
|
298
|
+
runtimeControlEvents: this.runtimeSettingsStore.controlEvents,
|
|
299
|
+
idempotency: [...this.runStore.idempotency.values()]
|
|
300
|
+
}, null, 2));
|
|
301
|
+
}
|
|
302
|
+
load() {
|
|
303
|
+
if (!existsSync(this.path))
|
|
304
|
+
return;
|
|
305
|
+
const raw = readFileSync(this.path, "utf8");
|
|
306
|
+
let data;
|
|
307
|
+
try {
|
|
308
|
+
data = JSON.parse(raw);
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
// A torn write from a pre-atomic-rename version of this adapter (or
|
|
312
|
+
// external corruption) must not brick the host: preserve the bytes for
|
|
313
|
+
// inspection and start from an empty state instead of throwing.
|
|
314
|
+
const backupPath = `${this.path}.corrupt-${Date.now()}`;
|
|
315
|
+
writeFileSync(backupPath, raw);
|
|
316
|
+
process.emitWarning(`OpenEve file state at ${this.path} was unreadable; backed up to ${backupPath} and starting fresh.`);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const parsed = data;
|
|
320
|
+
for (const run of parsed.runs ?? [])
|
|
321
|
+
this.runStore.runs.set(run.id, run);
|
|
322
|
+
this.runStore.events = parsed.events ?? [];
|
|
323
|
+
for (const toolCall of parsed.toolCalls ?? [])
|
|
324
|
+
this.runStore.toolCalls.set(toolCall.id, toolCall);
|
|
325
|
+
this.runStore.checkpoints = parsed.checkpoints ?? [];
|
|
326
|
+
for (const delivery of parsed.deliveries ?? []) {
|
|
327
|
+
const normalized = normalizeDeliveryRecord(delivery);
|
|
328
|
+
this.runStore.deliveries.set(normalized.id, normalized);
|
|
329
|
+
}
|
|
330
|
+
for (const conversation of parsed.conversations ?? [])
|
|
331
|
+
this.conversationStore.conversations.set(conversation.id, conversation);
|
|
332
|
+
this.conversationStore.messages = parsed.messages ?? [];
|
|
333
|
+
for (const turn of parsed.conversationTurns ?? []) {
|
|
334
|
+
this.conversationTurnStore.turns.set(turn.id, turn);
|
|
335
|
+
}
|
|
336
|
+
for (const schedule of parsed.schedules ?? [])
|
|
337
|
+
this.scheduleStateStore.schedules.set(schedule.id, schedule);
|
|
338
|
+
this.scheduleStateStore.scheduleRuns = parsed.scheduleRuns ?? [];
|
|
339
|
+
this.fileIndexStore.fileIndexes = parsed.fileIndexes ?? [];
|
|
340
|
+
this.usageStore.usageRecords = (parsed.usageRecords ?? [])
|
|
341
|
+
.map(normalizeStoredUsageRecord)
|
|
342
|
+
.filter((record) => record !== undefined);
|
|
343
|
+
this.sandboxStore.sandboxSnapshots = parsed.sandboxSnapshots ?? [];
|
|
344
|
+
for (const session of parsed.sandboxSessions ?? [])
|
|
345
|
+
this.sandboxStore.sandboxSessions.set(session.sessionKey, session);
|
|
346
|
+
for (const job of parsed.sandboxSyncJobs ?? []) {
|
|
347
|
+
const normalized = normalizeSandboxSyncJobRecord(job);
|
|
348
|
+
this.sandboxStore.sandboxSyncJobs.set(normalized.id, normalized);
|
|
349
|
+
}
|
|
350
|
+
for (const document of parsed.memoryDocuments ?? [])
|
|
351
|
+
this.memoryStateStore.memoryDocuments.set(memoryKey(document.scope, document.path), document);
|
|
352
|
+
for (const embedding of parsed.memoryEmbeddings ?? []) {
|
|
353
|
+
this.memoryStateStore.memoryEmbeddings.set(memoryEmbeddingKey(embedding.scope, embedding.path, embedding.model), embedding);
|
|
354
|
+
}
|
|
355
|
+
for (const setting of parsed.runtimeSettings ?? []) {
|
|
356
|
+
this.runtimeSettingsStore.settings.set(`${setting.scope}:${setting.key}`, setting);
|
|
357
|
+
}
|
|
358
|
+
this.runtimeSettingsStore.controlEvents = parsed.runtimeControlEvents ?? [];
|
|
359
|
+
this.runStore.idempotency = new Set(parsed.idempotency ?? []);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
export class LocalBlobAdapter {
|
|
363
|
+
root;
|
|
364
|
+
constructor(root = mkdtempSync(join(tmpdir(), "openeve-blob-"))) {
|
|
365
|
+
this.root = root;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Resolve a blob key to an absolute path that is guaranteed to stay inside the
|
|
369
|
+
* blob root. Stripping leading slashes alone leaves `..` segments intact, so a
|
|
370
|
+
* key like `../../etc/passwd` (e.g. a forged attachment `blobKey`) would
|
|
371
|
+
* otherwise escape the root for both reads and writes.
|
|
372
|
+
*/
|
|
373
|
+
resolveKey(key) {
|
|
374
|
+
const rootResolved = resolve(this.root);
|
|
375
|
+
const target = resolve(rootResolved, key.replace(/^\/+/, ""));
|
|
376
|
+
if (target !== rootResolved && !target.startsWith(rootResolved + sep)) {
|
|
377
|
+
throw new Error(`Blob key escapes the storage root: ${key}`);
|
|
378
|
+
}
|
|
379
|
+
return target;
|
|
380
|
+
}
|
|
381
|
+
async put(key, value, contentTypeOrOptions) {
|
|
382
|
+
const options = normalizeBlobPutOptions(contentTypeOrOptions);
|
|
383
|
+
const bytes = typeof value === "string" ? Buffer.from(value) : Buffer.from(value);
|
|
384
|
+
const safeKey = key.replace(/^\/+/, "");
|
|
385
|
+
const path = this.resolveKey(key);
|
|
386
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
387
|
+
writeFileSync(path, bytes);
|
|
388
|
+
const record = {
|
|
389
|
+
id: randomUUID(),
|
|
390
|
+
key: safeKey,
|
|
391
|
+
uri: path,
|
|
392
|
+
sha256: createHash("sha256").update(bytes).digest("hex"),
|
|
393
|
+
size: bytes.byteLength
|
|
394
|
+
};
|
|
395
|
+
if (options.contentType)
|
|
396
|
+
record.contentType = options.contentType;
|
|
397
|
+
if (options.visibility)
|
|
398
|
+
record.visibility = options.visibility;
|
|
399
|
+
return record;
|
|
400
|
+
}
|
|
401
|
+
async get(key) {
|
|
402
|
+
const path = this.resolveKey(key);
|
|
403
|
+
if (!existsSync(path))
|
|
404
|
+
return undefined;
|
|
405
|
+
return readFileSync(path);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function normalizeBlobPutOptions(contentTypeOrOptions) {
|
|
409
|
+
if (typeof contentTypeOrOptions === "string")
|
|
410
|
+
return { contentType: contentTypeOrOptions, visibility: "private" };
|
|
411
|
+
const options = { visibility: contentTypeOrOptions?.visibility ?? "private" };
|
|
412
|
+
if (contentTypeOrOptions?.contentType)
|
|
413
|
+
options.contentType = contentTypeOrOptions.contentType;
|
|
414
|
+
return options;
|
|
415
|
+
}
|
|
416
|
+
export class InMemoryMemoryStore {
|
|
417
|
+
documents = new Map();
|
|
418
|
+
async list(scope, input = {}) {
|
|
419
|
+
const prefix = normalizeMemoryPath(input.pathPrefix ?? "");
|
|
420
|
+
const limit = positiveLimit(input.limit, 50);
|
|
421
|
+
return [...this.documents.values()]
|
|
422
|
+
.filter((document) => memoryScopeMatches(scope, document.scope))
|
|
423
|
+
.filter((document) => !prefix || document.path.startsWith(prefix))
|
|
424
|
+
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))
|
|
425
|
+
.slice(0, limit);
|
|
426
|
+
}
|
|
427
|
+
async search(scope, input) {
|
|
428
|
+
const prefix = normalizeMemoryPath(input.pathPrefix ?? "");
|
|
429
|
+
const documents = [...this.documents.values()]
|
|
430
|
+
.filter((document) => memoryScopeMatches(scope, document.scope))
|
|
431
|
+
.filter((document) => !prefix || document.path.startsWith(prefix));
|
|
432
|
+
return rankMemoryDocuments(documents, input);
|
|
433
|
+
}
|
|
434
|
+
async read(scope, input) {
|
|
435
|
+
const document = this.documents.get(memoryKey(scope, normalizeMemoryPath(input.path)));
|
|
436
|
+
if (!document || !memoryScopeMatches(scope, document.scope))
|
|
437
|
+
return undefined;
|
|
438
|
+
if (input.expectedRevision && input.expectedRevision !== document.revision) {
|
|
439
|
+
throw new Error(`Memory revision mismatch for ${document.path}.`);
|
|
440
|
+
}
|
|
441
|
+
const sliced = sliceMemoryDocument(document, input);
|
|
442
|
+
return sliced;
|
|
443
|
+
}
|
|
444
|
+
async write(scope, input) {
|
|
445
|
+
const path = normalizeMemoryPath(input.path);
|
|
446
|
+
const key = memoryKey(scope, path);
|
|
447
|
+
const current = this.documents.get(key);
|
|
448
|
+
if (input.expectedRevision && current?.revision !== input.expectedRevision) {
|
|
449
|
+
throw new Error(`Memory revision mismatch for ${path}.`);
|
|
450
|
+
}
|
|
451
|
+
const document = createMemoryDocument(scope, path, current, input);
|
|
452
|
+
this.documents.set(key, document);
|
|
453
|
+
await this.persist();
|
|
454
|
+
return document;
|
|
455
|
+
}
|
|
456
|
+
async persist() {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
export class FileMemoryStore extends InMemoryMemoryStore {
|
|
461
|
+
path;
|
|
462
|
+
constructor(path) {
|
|
463
|
+
super();
|
|
464
|
+
this.path = path;
|
|
465
|
+
this.load();
|
|
466
|
+
}
|
|
467
|
+
async persist() {
|
|
468
|
+
mkdirSync(dirname(this.path), { recursive: true });
|
|
469
|
+
writeAtomic(this.path, `${this.path}.tmp-${process.pid}`, JSON.stringify({ documents: [...this.documents.values()] }, null, 2));
|
|
470
|
+
}
|
|
471
|
+
load() {
|
|
472
|
+
if (!existsSync(this.path))
|
|
473
|
+
return;
|
|
474
|
+
const raw = readFileSync(this.path, "utf8");
|
|
475
|
+
let parsed;
|
|
476
|
+
try {
|
|
477
|
+
parsed = JSON.parse(raw);
|
|
478
|
+
}
|
|
479
|
+
catch {
|
|
480
|
+
const backupPath = `${this.path}.corrupt-${Date.now()}`;
|
|
481
|
+
writeFileSync(backupPath, raw);
|
|
482
|
+
process.emitWarning(`OpenEve memory store at ${this.path} was unreadable; backed up to ${backupPath} and starting fresh.`);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
for (const document of parsed.documents ?? []) {
|
|
486
|
+
this.documents.set(memoryKey(document.scope, document.path), document);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
export class StateMemoryStore {
|
|
491
|
+
state;
|
|
492
|
+
embeddingProvider;
|
|
493
|
+
embeddingsEnabled;
|
|
494
|
+
constructor(state, embeddingProvider, embeddingsEnabled = false) {
|
|
495
|
+
this.state = state;
|
|
496
|
+
this.embeddingProvider = embeddingProvider;
|
|
497
|
+
this.embeddingsEnabled = embeddingsEnabled;
|
|
498
|
+
}
|
|
499
|
+
async list(scope, input = {}) {
|
|
500
|
+
const limit = input.limit === undefined ? 50 : input.limit;
|
|
501
|
+
return this.state.listMemoryDocuments(scope, { ...input, limit });
|
|
502
|
+
}
|
|
503
|
+
async search(scope, input) {
|
|
504
|
+
const wantsSemantic = input.mode === "semantic" || input.mode === "hybrid";
|
|
505
|
+
const lexicalMode = input.mode === "semantic" ? "keyword" : input.mode;
|
|
506
|
+
const lexicalInput = { ...input };
|
|
507
|
+
if (lexicalMode)
|
|
508
|
+
lexicalInput.mode = lexicalMode;
|
|
509
|
+
const lexical = input.mode === "semantic"
|
|
510
|
+
? []
|
|
511
|
+
: this.state.searchMemoryDocuments
|
|
512
|
+
? await this.state.searchMemoryDocuments(scope, lexicalInput)
|
|
513
|
+
: await this.portableSearch(scope, lexicalInput);
|
|
514
|
+
if (!wantsSemantic || !this.embeddingProvider || !this.embeddingsEnabled) {
|
|
515
|
+
return lexical.length > 0 ? lexical : input.mode === "semantic" ? await this.portableSearch(scope, lexicalInput) : lexical;
|
|
516
|
+
}
|
|
517
|
+
const queryEmbedding = await embedMemoryText(this.embeddingProvider, input.query, "query", {
|
|
518
|
+
searchMode: input.mode ?? "hybrid"
|
|
519
|
+
});
|
|
520
|
+
const semanticOptions = { model: queryEmbedding.model };
|
|
521
|
+
if (input.limit !== undefined)
|
|
522
|
+
semanticOptions.limit = input.limit;
|
|
523
|
+
const semantic = await this.state.searchMemoryEmbeddings(scope, input, queryEmbedding.embedding, semanticOptions);
|
|
524
|
+
if (input.mode === "semantic")
|
|
525
|
+
return semantic;
|
|
526
|
+
return mergeMemorySearchResults(semantic, lexical, input);
|
|
527
|
+
}
|
|
528
|
+
async portableSearch(scope, input) {
|
|
529
|
+
const listInput = {};
|
|
530
|
+
if (input.pathPrefix)
|
|
531
|
+
listInput.pathPrefix = input.pathPrefix;
|
|
532
|
+
const documents = await this.state.listMemoryDocuments(scope, listInput);
|
|
533
|
+
return rankMemoryDocuments(documents, input);
|
|
534
|
+
}
|
|
535
|
+
async read(scope, input) {
|
|
536
|
+
const document = await this.state.getMemoryDocument(scope, input.path);
|
|
537
|
+
if (!document)
|
|
538
|
+
return undefined;
|
|
539
|
+
if (input.expectedRevision && input.expectedRevision !== document.revision) {
|
|
540
|
+
throw new Error(`Memory revision mismatch for ${document.path}.`);
|
|
541
|
+
}
|
|
542
|
+
return sliceMemoryDocument(document, input);
|
|
543
|
+
}
|
|
544
|
+
async write(scope, input) {
|
|
545
|
+
const path = normalizeMemoryPath(input.path);
|
|
546
|
+
const current = await this.state.getMemoryDocument(scope, path);
|
|
547
|
+
if (input.expectedRevision && current?.revision !== input.expectedRevision) {
|
|
548
|
+
throw new Error(`Memory revision mismatch for ${path}.`);
|
|
549
|
+
}
|
|
550
|
+
const document = createMemoryDocument(scope, path, current, input);
|
|
551
|
+
const written = await this.state.upsertMemoryDocument(document);
|
|
552
|
+
if (this.embeddingsEnabled) {
|
|
553
|
+
await this.state.markMemoryEmbeddingsStale(scope, path, written.sha256);
|
|
554
|
+
}
|
|
555
|
+
return written;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
export function normalizeSandboxSyncJobRecord(job) {
|
|
559
|
+
const createdAt = job.createdAt ?? timestamp();
|
|
560
|
+
const record = {
|
|
561
|
+
...job,
|
|
562
|
+
status: job.status ?? "pending",
|
|
563
|
+
manifest: job.manifest ?? {},
|
|
564
|
+
attemptCount: typeof job.attemptCount === "number" ? job.attemptCount : 0,
|
|
565
|
+
maxAttempts: typeof job.maxAttempts === "number" ? job.maxAttempts : 5,
|
|
566
|
+
nextAttemptAt: job.nextAttemptAt ?? createdAt,
|
|
567
|
+
metadata: job.metadata ?? {},
|
|
568
|
+
createdAt,
|
|
569
|
+
updatedAt: job.updatedAt ?? createdAt
|
|
570
|
+
};
|
|
571
|
+
return record;
|
|
572
|
+
}
|
|
573
|
+
export function memoryEmbeddingDocumentText(document, maxTokens) {
|
|
574
|
+
const parts = [
|
|
575
|
+
document.path,
|
|
576
|
+
document.title ?? "",
|
|
577
|
+
document.summary ?? "",
|
|
578
|
+
document.tags.join(" "),
|
|
579
|
+
memoryBodyText(document)
|
|
580
|
+
].filter(Boolean);
|
|
581
|
+
const text = parts.join("\n");
|
|
582
|
+
const limit = positiveLimit(maxTokens, 2_000);
|
|
583
|
+
return text.slice(0, limit * 4);
|
|
584
|
+
}
|
|
585
|
+
export function sliceMemoryDocument(document, input) {
|
|
586
|
+
let body = memoryBodyText(document);
|
|
587
|
+
if (input.range) {
|
|
588
|
+
const lines = body.split(/\r?\n/u);
|
|
589
|
+
const start = Math.max(0, Math.floor(input.range.startLine) - 1);
|
|
590
|
+
const end = Math.max(start, Math.floor(input.range.endLine));
|
|
591
|
+
body = lines.slice(start, end).join("\n");
|
|
592
|
+
}
|
|
593
|
+
const maxTokens = positiveLimit(input.maxTokens, 0);
|
|
594
|
+
if (maxTokens > 0) {
|
|
595
|
+
const maxChars = maxTokens * 4;
|
|
596
|
+
body = body.length > maxChars ? `${body.slice(0, Math.max(0, maxChars - 3))}...` : body;
|
|
597
|
+
}
|
|
598
|
+
return {
|
|
599
|
+
...document,
|
|
600
|
+
body,
|
|
601
|
+
tokenEstimate: estimateTokens(body)
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
export function nextMemoryBody(previous, content, mode) {
|
|
605
|
+
if (mode === "replace")
|
|
606
|
+
return content;
|
|
607
|
+
if (mode === "append") {
|
|
608
|
+
if (!previous)
|
|
609
|
+
return content;
|
|
610
|
+
return `${previous.replace(/\s*$/u, "")}\n${content}`;
|
|
611
|
+
}
|
|
612
|
+
if (mode === "patch")
|
|
613
|
+
return content;
|
|
614
|
+
throw new Error(`Unsupported memory write mode: ${mode}`);
|
|
615
|
+
}
|
|
616
|
+
export function createMemoryDocument(scope, path, current, input) {
|
|
617
|
+
const previous = current ? memoryBodyText(current) : "";
|
|
618
|
+
const nextBody = nextMemoryBody(previous, input.content, input.mode);
|
|
619
|
+
const now = timestamp();
|
|
620
|
+
const metadata = input.metadata ?? {};
|
|
621
|
+
const bodyHash = createHash("sha256").update(nextBody).digest("hex");
|
|
622
|
+
const document = {
|
|
623
|
+
scope,
|
|
624
|
+
path,
|
|
625
|
+
body: nextBody,
|
|
626
|
+
contentType: "text/markdown",
|
|
627
|
+
tags: metadata.tags ?? current?.tags ?? [],
|
|
628
|
+
tokenEstimate: estimateTokens(nextBody),
|
|
629
|
+
sha256: bodyHash,
|
|
630
|
+
revision: `${bodyHash.slice(0, 16)}:${Date.parse(now) || Date.now()}`,
|
|
631
|
+
createdAt: current?.createdAt ?? now,
|
|
632
|
+
updatedAt: now
|
|
633
|
+
};
|
|
634
|
+
const title = metadata.title ?? current?.title;
|
|
635
|
+
const summary = metadata.summary ?? current?.summary;
|
|
636
|
+
const confidence = metadata.confidence ?? current?.confidence;
|
|
637
|
+
const sourceRefs = metadata.sourceRefs ?? current?.sourceRefs;
|
|
638
|
+
if (title)
|
|
639
|
+
document.title = title;
|
|
640
|
+
if (summary)
|
|
641
|
+
document.summary = summary;
|
|
642
|
+
if (confidence)
|
|
643
|
+
document.confidence = confidence;
|
|
644
|
+
if (sourceRefs)
|
|
645
|
+
document.sourceRefs = sourceRefs;
|
|
646
|
+
return document;
|
|
647
|
+
}
|
|
648
|
+
export function rankMemoryDocuments(documents, input) {
|
|
649
|
+
const query = stringValue(input.query).toLowerCase();
|
|
650
|
+
const normalizedQuery = normalizeMemoryPath(query).toLowerCase();
|
|
651
|
+
const limit = positiveLimit(input.limit, 8);
|
|
652
|
+
const ranked = documents
|
|
653
|
+
.map((document) => {
|
|
654
|
+
const body = memoryBodyText(document);
|
|
655
|
+
const tagText = document.tags.join(" ");
|
|
656
|
+
const haystack = `${document.path}\n${document.title ?? ""}\n${document.summary ?? ""}\n${tagText}\n${body}`.toLowerCase();
|
|
657
|
+
const pathExact = Boolean(query && (document.path.toLowerCase() === query || document.path.toLowerCase() === normalizedQuery));
|
|
658
|
+
const phraseMatch = Boolean(query && haystack.includes(query));
|
|
659
|
+
const terms = query.split(/\s+/u).filter(Boolean);
|
|
660
|
+
const tagMatch = terms.some((term) => document.tags.some((tag) => tag.toLowerCase().includes(term)));
|
|
661
|
+
const termMatches = terms.filter((term) => haystack.includes(term)).length;
|
|
662
|
+
const score = (pathExact ? 1000 : 0) + (phraseMatch ? 100 : 0) + (tagMatch ? 20 : 0) + termMatches;
|
|
663
|
+
return { document, body, score, pathExact, phraseMatch, tagMatch };
|
|
664
|
+
})
|
|
665
|
+
.filter((entry) => input.mode === "exact" && query ? entry.pathExact : query ? entry.score > 0 : true)
|
|
666
|
+
.sort((a, b) => b.score - a.score || b.document.updatedAt.localeCompare(a.document.updatedAt))
|
|
667
|
+
.slice(0, limit);
|
|
668
|
+
return ranked.map(({ document, body, pathExact, phraseMatch, tagMatch }) => ({
|
|
669
|
+
path: document.path,
|
|
670
|
+
...(document.title ? { title: document.title } : {}),
|
|
671
|
+
...(document.summary ? { summary: document.summary } : {}),
|
|
672
|
+
snippet: memorySnippet(body, query),
|
|
673
|
+
revision: document.revision,
|
|
674
|
+
tags: document.tags,
|
|
675
|
+
updatedAt: document.updatedAt,
|
|
676
|
+
rankReason: memoryRankReason({ pathExact, phraseMatch, tagMatch, keywordMatch: Boolean(query), recencyBoost: true })
|
|
677
|
+
}));
|
|
678
|
+
}
|
|
679
|
+
export function memoryRankReason(signals) {
|
|
680
|
+
const reasons = [];
|
|
681
|
+
if (signals.pathExact)
|
|
682
|
+
reasons.push("exact path match");
|
|
683
|
+
if (signals.phraseMatch && !signals.pathExact)
|
|
684
|
+
reasons.push("phrase match");
|
|
685
|
+
if (signals.tagMatch)
|
|
686
|
+
reasons.push("tag match");
|
|
687
|
+
if (typeof signals.fullTextRank === "number" && signals.fullTextRank > 0)
|
|
688
|
+
reasons.push(`full-text rank ${signals.fullTextRank.toFixed(3)}`);
|
|
689
|
+
if (signals.keywordMatch && reasons.length === 0)
|
|
690
|
+
reasons.push("keyword match");
|
|
691
|
+
if (signals.recencyBoost)
|
|
692
|
+
reasons.push("recency boost");
|
|
693
|
+
return reasons.join("; ") || "recency boost";
|
|
694
|
+
}
|
|
695
|
+
export async function embedMemoryText(provider, text, purpose, metadata = {}) {
|
|
696
|
+
const bounded = text.slice(0, positiveLimit(provider.maxInputTokens, 2_000) * 4);
|
|
697
|
+
const output = await provider.embed({ text: bounded, purpose, model: provider.model, metadata });
|
|
698
|
+
const embedding = output.embedding.filter((value) => Number.isFinite(value));
|
|
699
|
+
return {
|
|
700
|
+
embedding,
|
|
701
|
+
model: output.model ?? provider.model,
|
|
702
|
+
dimensions: output.dimensions ?? embedding.length
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
export function mergeMemorySearchResults(semantic, lexical, input) {
|
|
706
|
+
const limit = positiveLimit(input.limit, 8);
|
|
707
|
+
const byPath = new Map();
|
|
708
|
+
for (const result of semantic) {
|
|
709
|
+
byPath.set(result.path, result);
|
|
710
|
+
}
|
|
711
|
+
for (const result of lexical) {
|
|
712
|
+
const existing = byPath.get(result.path);
|
|
713
|
+
byPath.set(result.path, existing
|
|
714
|
+
? {
|
|
715
|
+
...existing,
|
|
716
|
+
snippet: existing.snippet || result.snippet,
|
|
717
|
+
rankReason: `${existing.rankReason}; ${result.rankReason}`
|
|
718
|
+
}
|
|
719
|
+
: result);
|
|
720
|
+
}
|
|
721
|
+
return [...byPath.values()].slice(0, limit);
|
|
722
|
+
}
|
|
723
|
+
export function estimateTokens(text) {
|
|
724
|
+
return Math.ceil(text.length / 4);
|
|
725
|
+
}
|
|
726
|
+
export function deliveryRetryDelayMs(attempt, minDelayMs, maxDelayMs) {
|
|
727
|
+
const cap = Math.max(minDelayMs, maxDelayMs);
|
|
728
|
+
const exponential = minDelayMs * 2 ** Math.max(0, attempt - 1);
|
|
729
|
+
return Math.min(cap, exponential);
|
|
730
|
+
}
|
|
731
|
+
export function sleepMs(ms) {
|
|
732
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
733
|
+
}
|
|
734
|
+
export function memoryDocumentSummary(document) {
|
|
735
|
+
return {
|
|
736
|
+
path: document.path,
|
|
737
|
+
title: document.title ?? null,
|
|
738
|
+
summary: document.summary ?? null,
|
|
739
|
+
tags: document.tags,
|
|
740
|
+
revision: document.revision,
|
|
741
|
+
tokenEstimate: document.tokenEstimate,
|
|
742
|
+
updatedAt: document.updatedAt
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
export function memoryDocumentForModel(document) {
|
|
746
|
+
return {
|
|
747
|
+
...memoryDocumentSummary(document),
|
|
748
|
+
contentType: document.contentType,
|
|
749
|
+
body: memoryBodyText(document)
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
//# sourceMappingURL=storage.js.map
|