@botbotgo/agent-harness 0.0.283 → 0.0.285
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 +2 -2
- package/README.zh.md +2 -2
- package/dist/config/agents/direct.yaml +2 -5
- package/dist/config/agents/orchestra.yaml +2 -5
- package/dist/config/catalogs/stores.yaml +3 -3
- package/dist/config/catalogs/vector-stores.yaml +1 -1
- package/dist/config/runtime/workspace.yaml +16 -9
- package/dist/contracts/workspace.d.ts +6 -0
- package/dist/init-project.js +3 -1
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/persistence/sqlite-store.js +5 -2
- package/dist/runtime/harness/run/resources.js +2 -2
- package/dist/runtime/harness/system/mem0-ingestion-sync.js +1 -1
- package/dist/runtime/harness/system/runtime-memory-manager.js +1 -1
- package/dist/runtime/maintenance/checkpoint-maintenance.js +41 -3
- package/dist/runtime/maintenance/index.d.ts +1 -0
- package/dist/runtime/maintenance/index.js +1 -0
- package/dist/runtime/maintenance/sqlite-checkpoint-saver.d.ts +28 -0
- package/dist/runtime/maintenance/sqlite-checkpoint-saver.js +177 -0
- package/dist/runtime/support/llamaindex.d.ts +1 -1
- package/dist/runtime/support/llamaindex.js +2 -2
- package/dist/runtime/support/runtime-factories.js +8 -3
- package/dist/runtime/support/runtime-layout.d.ts +7 -6
- package/dist/runtime/support/runtime-layout.js +15 -12
- package/dist/runtime/support/vector-stores.js +4 -3
- package/dist/workspace/agent-binding-compiler.js +8 -6
- package/dist/workspace/compile.js +6 -1
- package/dist/workspace/object-loader.js +3 -0
- package/dist/workspace/support/workspace-ref-utils.d.ts +6 -0
- package/dist/workspace/support/workspace-ref-utils.js +25 -0
- package/dist/workspace/validate.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -859,8 +859,8 @@ spec:
|
|
|
859
859
|
path: store.sqlite
|
|
860
860
|
- kind: Checkpointer
|
|
861
861
|
name: default
|
|
862
|
-
checkpointerKind:
|
|
863
|
-
path: checkpoints.
|
|
862
|
+
checkpointerKind: SqliteSaver
|
|
863
|
+
path: runtime/checkpoints.sqlite
|
|
864
864
|
```
|
|
865
865
|
|
|
866
866
|
### `config/runtime/runtime-memory.yaml`
|
package/README.zh.md
CHANGED
|
@@ -818,8 +818,8 @@ spec:
|
|
|
818
818
|
path: store.sqlite
|
|
819
819
|
- kind: Checkpointer
|
|
820
820
|
name: default
|
|
821
|
-
checkpointerKind:
|
|
822
|
-
path: checkpoints.
|
|
821
|
+
checkpointerKind: SqliteSaver
|
|
822
|
+
path: runtime/checkpoints.sqlite
|
|
823
823
|
```
|
|
824
824
|
|
|
825
825
|
### `config/runtime/runtime-memory.yaml`
|
|
@@ -10,9 +10,6 @@ metadata:
|
|
|
10
10
|
description: Manual low-latency host for direct answers and lightweight inventory lookup. Do not use it as the default executor for tool-heavy or delegation-heavy tasks.
|
|
11
11
|
spec:
|
|
12
12
|
runtime:
|
|
13
|
-
# agent-harness feature: host-level run data placement override.
|
|
14
|
-
# This matches the workspace default and keeps the default config shape explicit.
|
|
15
|
-
runRoot: ./.agent
|
|
16
13
|
# agent-harness feature: workspace-level durable long-term memory defaults for this host profile.
|
|
17
14
|
runtimeMemory: default
|
|
18
15
|
# =====================
|
|
@@ -36,8 +33,8 @@ spec:
|
|
|
36
33
|
mcpServers: []
|
|
37
34
|
# Runtime execution feature: checkpointer config passed into the selected backend adapter.
|
|
38
35
|
# Even the lightweight direct path can benefit from resumable state during interactive use.
|
|
39
|
-
# Available `kind` options in this harness: `FileCheckpointer`, `MemorySaver`.
|
|
40
|
-
# The repository default uses the
|
|
36
|
+
# Available `kind` options in this harness: `SqliteSaver`, `FileCheckpointer`, `MemorySaver`.
|
|
37
|
+
# The repository default uses the sqlite-backed preset so durable checkpoint state stays inside `runtime/checkpoints.sqlite`.
|
|
41
38
|
checkpointer: default
|
|
42
39
|
# Upstream execution feature: LangGraph store available to middleware and runtime context hooks.
|
|
43
40
|
# The default direct host keeps this enabled so middleware can use the same durable store surface as other hosts.
|
|
@@ -10,9 +10,6 @@ metadata:
|
|
|
10
10
|
description: Default execution host. Answer directly when possible, use local tools and skills first, and delegate only when a subagent is a better fit. Not a reflex delegation-only orchestrator.
|
|
11
11
|
spec:
|
|
12
12
|
runtime:
|
|
13
|
-
# agent-harness feature: host-level run data placement override.
|
|
14
|
-
# This matches the workspace default and keeps the default config shape explicit.
|
|
15
|
-
runRoot: ./.agent
|
|
16
13
|
# agent-harness feature: workspace-level durable long-term memory defaults for this host profile.
|
|
17
14
|
runtimeMemory: default
|
|
18
15
|
# =====================
|
|
@@ -43,8 +40,8 @@ spec:
|
|
|
43
40
|
mcpServers: []
|
|
44
41
|
# Runtime execution feature: checkpointer config passed into the selected backend adapter.
|
|
45
42
|
# This persists resumable graph state for this agent.
|
|
46
|
-
# Available `kind` options in this harness: `FileCheckpointer`, `MemorySaver`.
|
|
47
|
-
# The repository default uses the
|
|
43
|
+
# Available `kind` options in this harness: `SqliteSaver`, `FileCheckpointer`, `MemorySaver`.
|
|
44
|
+
# The repository default uses the sqlite-backed preset so durable checkpoint state stays inside `runtime/checkpoints.sqlite`.
|
|
48
45
|
checkpointer: default
|
|
49
46
|
# Upstream execution feature: store config passed into the selected backend adapter.
|
|
50
47
|
# In the default deepagent adapter this is the LangGraph store used by `StoreBackend` routes.
|
|
@@ -13,6 +13,6 @@ spec:
|
|
|
13
13
|
# agent-harness feature: reusable checkpointer preset for resumable execution state.
|
|
14
14
|
- kind: Checkpointer
|
|
15
15
|
name: default
|
|
16
|
-
description: Default
|
|
17
|
-
checkpointerKind:
|
|
18
|
-
path: checkpoints.
|
|
16
|
+
description: Default sqlite-backed checkpointer preset for durable local graph state under the runtime data root.
|
|
17
|
+
checkpointerKind: SqliteSaver
|
|
18
|
+
path: runtime/checkpoints.sqlite
|
|
@@ -13,7 +13,7 @@ spec:
|
|
|
13
13
|
storeKind: LibSQLVectorStore
|
|
14
14
|
# LangChain aligned feature: libSQL connection URL.
|
|
15
15
|
# Local SQLite files use the `file:` prefix.
|
|
16
|
-
url: file
|
|
16
|
+
url: file:knowledge/vectors.sqlite
|
|
17
17
|
# LangChain aligned feature: target table and embedding column.
|
|
18
18
|
table: rag_chunks
|
|
19
19
|
column: embedding
|
|
@@ -12,15 +12,22 @@ spec:
|
|
|
12
12
|
# ======================
|
|
13
13
|
# agent-harness Features
|
|
14
14
|
# ======================
|
|
15
|
-
# agent-harness feature:
|
|
16
|
-
# This
|
|
17
|
-
# -
|
|
18
|
-
# -
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
|
|
15
|
+
# agent-harness feature: read-only application folder that contains the shared workspace assembly.
|
|
16
|
+
# This is where the runtime loads config catalogs and packaged resources such as:
|
|
17
|
+
# - config/
|
|
18
|
+
# - resources/
|
|
19
|
+
# Downstream applications can point multiple runtime profiles at the same application folder.
|
|
20
|
+
applicationRoot: .
|
|
21
|
+
|
|
22
|
+
# agent-harness feature: writable data folder for one runtime profile.
|
|
23
|
+
# Runtime-owned persistence stays under this root, split by function:
|
|
24
|
+
# - runtime/ for requests, approvals, checkpoints, and artifacts
|
|
25
|
+
# - knowledge/ for durable knowledge and vector indexes
|
|
26
|
+
# Different runtime profiles can use different data folders while sharing the same application folder.
|
|
27
|
+
dataRoot: ./.agent
|
|
28
|
+
|
|
29
|
+
# agent-harness feature: stable runtime profile identifier for this data folder.
|
|
30
|
+
profile: default
|
|
24
31
|
|
|
25
32
|
# agent-harness feature: runtime-level task queue and maximum number of concurrent runs.
|
|
26
33
|
# Additional runs wait in the harness queue until a slot becomes available.
|
|
@@ -7,6 +7,9 @@ export type ParsedAgentObject = {
|
|
|
7
7
|
description: string;
|
|
8
8
|
modelRef: string;
|
|
9
9
|
runRoot?: string;
|
|
10
|
+
applicationRoot?: string;
|
|
11
|
+
dataRoot?: string;
|
|
12
|
+
runtimeProfile?: string;
|
|
10
13
|
toolRefs: string[];
|
|
11
14
|
toolBindings?: ParsedAgentToolBinding[];
|
|
12
15
|
inlineTools?: ParsedToolObject[];
|
|
@@ -260,6 +263,9 @@ export type CompiledAgentBinding = {
|
|
|
260
263
|
*/
|
|
261
264
|
deepAgentParams?: LegacyDeepAgentParams;
|
|
262
265
|
harnessRuntime: {
|
|
266
|
+
applicationRoot?: string;
|
|
267
|
+
dataRoot?: string;
|
|
268
|
+
runtimeProfile?: string;
|
|
263
269
|
runRoot: string;
|
|
264
270
|
workspaceRoot?: string;
|
|
265
271
|
capabilities?: RuntimeCapabilities;
|
package/dist/init-project.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.284";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.284";
|
|
@@ -2,6 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import { mkdir, rm } from "node:fs/promises";
|
|
3
3
|
import { createClient } from "@libsql/client";
|
|
4
4
|
import { fileExists, readJson, writeJson } from "../utils/fs.js";
|
|
5
|
+
import { resolveRuntimeRoot, resolveRuntimeSqlitePath } from "../runtime/support/runtime-layout.js";
|
|
5
6
|
import { SqliteRunContextStore } from "./sqlite-run-context-store.js";
|
|
6
7
|
import { SqliteRunQueueStore } from "./sqlite-run-queue-store.js";
|
|
7
8
|
const RUNTIME_SQLITE_SCHEMA_VERSION = 6;
|
|
@@ -97,7 +98,9 @@ export class SqlitePersistence {
|
|
|
97
98
|
initialization = null;
|
|
98
99
|
constructor(runRoot, dbFile = "runtime.sqlite") {
|
|
99
100
|
this.runRoot = runRoot;
|
|
100
|
-
this.dbPath =
|
|
101
|
+
this.dbPath = dbFile === "runtime.sqlite"
|
|
102
|
+
? resolveRuntimeSqlitePath(runRoot)
|
|
103
|
+
: path.join(resolveRuntimeRoot(runRoot), dbFile);
|
|
101
104
|
this.runContextStore = new SqliteRunContextStore({
|
|
102
105
|
execute: (sql, args) => this.execute(sql, args),
|
|
103
106
|
selectOne: (sql, args) => this.selectOne(sql, args),
|
|
@@ -148,7 +151,7 @@ export class SqlitePersistence {
|
|
|
148
151
|
return;
|
|
149
152
|
}
|
|
150
153
|
this.initialization = (async () => {
|
|
151
|
-
await mkdir(this.runRoot, { recursive: true });
|
|
154
|
+
await mkdir(resolveRuntimeRoot(this.runRoot), { recursive: true });
|
|
152
155
|
await this.getClient();
|
|
153
156
|
await this.rawExecute("PRAGMA journal_mode=WAL");
|
|
154
157
|
await this.rawExecute("PRAGMA foreign_keys=ON");
|
|
@@ -43,13 +43,13 @@ export async function resolveVectorStore(workspace, vectorStores, vectorStoreRef
|
|
|
43
43
|
return resolved;
|
|
44
44
|
}
|
|
45
45
|
export function resolveCheckpointer(checkpointers, binding) {
|
|
46
|
-
const key = `${binding.harnessRuntime.runRoot}:${JSON.stringify(binding.harnessRuntime.checkpointer ?? { kind: "
|
|
46
|
+
const key = `${binding.harnessRuntime.runRoot}:${JSON.stringify(binding.harnessRuntime.checkpointer ?? { kind: "SqliteSaver", path: resolveRuntimeCheckpointerPath(binding.harnessRuntime.runRoot, "checkpoints.sqlite") })}`;
|
|
47
47
|
const existing = checkpointers.get(key);
|
|
48
48
|
if (existing) {
|
|
49
49
|
return existing;
|
|
50
50
|
}
|
|
51
51
|
const resolvedConfig = binding.harnessRuntime.checkpointer ??
|
|
52
|
-
{ kind: "
|
|
52
|
+
{ kind: "SqliteSaver", path: resolveRuntimeCheckpointerPath(binding.harnessRuntime.runRoot, "checkpoints.sqlite") };
|
|
53
53
|
if (typeof resolvedConfig === "boolean") {
|
|
54
54
|
checkpointers.set(key, resolvedConfig);
|
|
55
55
|
return resolvedConfig;
|
|
@@ -62,7 +62,7 @@ export function readMem0RuntimeConfig(runtimeMemory, workspaceRoot) {
|
|
|
62
62
|
projectId: asNonEmptyString(mem0.projectId),
|
|
63
63
|
appId: asNonEmptyString(mem0.appId) ?? workspaceBaseName,
|
|
64
64
|
userIdPrefix: asNonEmptyString(mem0.userIdPrefix),
|
|
65
|
-
stateStorePath: asNonEmptyString(mem0.stateStorePath) ?? "mem0-sync-state.json",
|
|
65
|
+
stateStorePath: asNonEmptyString(mem0.stateStorePath) ?? "knowledge/mem0-sync-state.json",
|
|
66
66
|
maxMessagesPerRun: asPositiveInteger(mem0.maxMessagesPerRun) ?? 200,
|
|
67
67
|
writeOnApprovalResolution: asBoolean(mem0.writeOnApprovalResolution) ?? asBoolean(ingestion?.writeOnApprovalResolution) ?? true,
|
|
68
68
|
writeOnRunCompletion: asBoolean(mem0.writeOnRunCompletion) ?? asBoolean(ingestion?.writeOnRunCompletion) ?? true,
|
|
@@ -57,7 +57,7 @@ export function readRuntimeMemoryFormationConfig(runtimeMemory, workspaceRoot) {
|
|
|
57
57
|
enabled: asBoolean(background?.enabled) ?? true,
|
|
58
58
|
maxMessagesPerRun: asPositiveInteger(background?.maxMessagesPerRun) ?? asPositiveInteger(ingestion?.maxMessagesPerRun) ?? 40,
|
|
59
59
|
scopes: normalizeScopeList(asMemoryScopes(background?.scopes) ?? ["thread"]),
|
|
60
|
-
stateStorePath: asNonEmptyString(background?.stateStorePath) ??
|
|
60
|
+
stateStorePath: asNonEmptyString(background?.stateStorePath) ?? `knowledge/${workspaceBaseName}-memory-formation-state.json`,
|
|
61
61
|
writeOnApprovalResolution: asBoolean(background?.writeOnApprovalResolution) ?? asBoolean(ingestion?.writeOnApprovalResolution) ?? true,
|
|
62
62
|
writeOnRunCompletion: asBoolean(background?.writeOnRunCompletion) ?? asBoolean(ingestion?.writeOnRunCompletion) ?? true,
|
|
63
63
|
},
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { stat } from "node:fs/promises";
|
|
3
|
+
import { createClient } from "@libsql/client";
|
|
2
4
|
import { fileExists } from "../../utils/fs.js";
|
|
3
5
|
import { resolveRuntimeCheckpointerPath } from "../support/runtime-layout.js";
|
|
4
6
|
import { getRuntimeDefaults } from "../../workspace/support/workspace-ref-utils.js";
|
|
@@ -73,13 +75,49 @@ export function discoverCheckpointMaintenanceTargets(workspace) {
|
|
|
73
75
|
export function maintainSqliteCheckpoints(dbPath, config, nowMs = Date.now()) {
|
|
74
76
|
return maintainSqliteCheckpointsInternal(dbPath, config, nowMs);
|
|
75
77
|
}
|
|
76
|
-
async function maintainSqliteCheckpointsInternal(dbPath, config,
|
|
78
|
+
async function maintainSqliteCheckpointsInternal(dbPath, config, nowMs) {
|
|
77
79
|
if (!(await fileExists(dbPath))) {
|
|
78
80
|
return { deletedCount: 0 };
|
|
79
81
|
}
|
|
80
|
-
|
|
82
|
+
const client = createClient({ url: `file:${dbPath}` });
|
|
83
|
+
await client.execute("PRAGMA journal_mode=WAL");
|
|
84
|
+
await client.execute("PRAGMA foreign_keys=ON");
|
|
85
|
+
await client.execute("PRAGMA busy_timeout=5000");
|
|
86
|
+
await client.execute(`
|
|
87
|
+
CREATE TABLE IF NOT EXISTS checkpoint_state (
|
|
88
|
+
state_key TEXT PRIMARY KEY,
|
|
89
|
+
state_json TEXT NOT NULL,
|
|
90
|
+
updated_at TEXT NOT NULL
|
|
91
|
+
)
|
|
92
|
+
`);
|
|
93
|
+
const result = await client.execute("SELECT state_key, updated_at FROM checkpoint_state");
|
|
94
|
+
if (result.rows.length === 0) {
|
|
95
|
+
return { deletedCount: 0 };
|
|
96
|
+
}
|
|
97
|
+
const stats = await stat(dbPath).catch(() => null);
|
|
98
|
+
const maxAgeMs = config.policies.maxAgeSeconds ? config.policies.maxAgeSeconds * 1000 : null;
|
|
99
|
+
const maxBytes = config.policies.maxBytes ?? null;
|
|
100
|
+
const sweepBatchSize = Math.max(1, config.sqlite.sweepBatchSize);
|
|
101
|
+
let deletedCount = 0;
|
|
102
|
+
for (const row of result.rows.slice(0, sweepBatchSize)) {
|
|
103
|
+
const stateKey = typeof row.state_key === "string" ? row.state_key : "";
|
|
104
|
+
const updatedAtMs = typeof row.updated_at === "string" ? Date.parse(row.updated_at) : NaN;
|
|
105
|
+
const exceededAge = maxAgeMs !== null && Number.isFinite(updatedAtMs) && nowMs - updatedAtMs > maxAgeMs;
|
|
106
|
+
const exceededBytes = maxBytes !== null && stats !== null && stats.size > maxBytes;
|
|
107
|
+
if (!exceededAge && !exceededBytes) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
await client.execute({
|
|
111
|
+
sql: "DELETE FROM checkpoint_state WHERE state_key = ?",
|
|
112
|
+
args: [stateKey],
|
|
113
|
+
});
|
|
114
|
+
deletedCount += 1;
|
|
115
|
+
}
|
|
116
|
+
if (deletedCount > 0 && config.sqlite.vacuum) {
|
|
117
|
+
await client.execute("VACUUM");
|
|
118
|
+
}
|
|
81
119
|
void path.dirname(dbPath);
|
|
82
|
-
|
|
120
|
+
return { deletedCount };
|
|
83
121
|
}
|
|
84
122
|
export class CheckpointMaintenanceLoop {
|
|
85
123
|
targets;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MemorySaver } from "@langchain/langgraph";
|
|
2
|
+
type MemorySaverConfig = Parameters<MemorySaver["getTuple"]>[0];
|
|
3
|
+
type MemorySaverListOptions = Parameters<MemorySaver["list"]>[1];
|
|
4
|
+
type MemorySaverPutCheckpoint = Parameters<MemorySaver["put"]>[1];
|
|
5
|
+
type MemorySaverPutMetadata = Parameters<MemorySaver["put"]>[2];
|
|
6
|
+
type MemorySaverPutWrites = Parameters<MemorySaver["putWrites"]>[1];
|
|
7
|
+
type MemorySaverPutResult = ReturnType<MemorySaver["put"]>;
|
|
8
|
+
export declare class SqliteCheckpointSaver extends MemorySaver {
|
|
9
|
+
readonly filePath: string;
|
|
10
|
+
private client;
|
|
11
|
+
private loaded;
|
|
12
|
+
private initialized;
|
|
13
|
+
private initialization;
|
|
14
|
+
private operationChain;
|
|
15
|
+
constructor(filePath: string);
|
|
16
|
+
private runSerialized;
|
|
17
|
+
private getClient;
|
|
18
|
+
private ensureInitialized;
|
|
19
|
+
private loadStateRow;
|
|
20
|
+
private ensureLoaded;
|
|
21
|
+
private persist;
|
|
22
|
+
getTuple(config: MemorySaverConfig): Promise<import("@langchain/langgraph").CheckpointTuple | undefined>;
|
|
23
|
+
list(config: MemorySaverConfig, options?: MemorySaverListOptions): AsyncGenerator<import("@langchain/langgraph").CheckpointTuple, void, unknown>;
|
|
24
|
+
put(config: MemorySaverConfig, checkpoint: MemorySaverPutCheckpoint, metadata: MemorySaverPutMetadata): MemorySaverPutResult;
|
|
25
|
+
putWrites(config: MemorySaverConfig, writes: MemorySaverPutWrites, taskId: string): Promise<void>;
|
|
26
|
+
deleteThread(threadId: string): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export { SqliteCheckpointSaver as SqliteSaver };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { MemorySaver } from "@langchain/langgraph";
|
|
4
|
+
import { createClient } from "@libsql/client";
|
|
5
|
+
const CHECKPOINT_TABLE = "checkpoint_state";
|
|
6
|
+
const DEFAULT_STATE_KEY = "default";
|
|
7
|
+
function encodeBinary(value) {
|
|
8
|
+
if (value instanceof Uint8Array) {
|
|
9
|
+
return {
|
|
10
|
+
__type: "Uint8Array",
|
|
11
|
+
data: Array.from(value),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return value.map((item) => encodeBinary(item));
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === "object" && value) {
|
|
18
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, encodeBinary(entry)]));
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function decodeBinary(value) {
|
|
23
|
+
if (Array.isArray(value)) {
|
|
24
|
+
return value.map((item) => decodeBinary(item));
|
|
25
|
+
}
|
|
26
|
+
if (typeof value === "object" && value) {
|
|
27
|
+
const typed = value;
|
|
28
|
+
if (typed.__type === "Uint8Array" && Array.isArray(typed.data)) {
|
|
29
|
+
return new Uint8Array(typed.data.map((item) => Number(item)));
|
|
30
|
+
}
|
|
31
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, decodeBinary(entry)]));
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function pruneThreadEntries(record, threadId) {
|
|
36
|
+
for (const key of Object.keys(record)) {
|
|
37
|
+
if (key.includes(threadId)) {
|
|
38
|
+
delete record[key];
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const value = record[key];
|
|
42
|
+
if (typeof value === "object" && value && !Array.isArray(value)) {
|
|
43
|
+
pruneThreadEntries(value, threadId);
|
|
44
|
+
if (Object.keys(value).length === 0) {
|
|
45
|
+
delete record[key];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export class SqliteCheckpointSaver extends MemorySaver {
|
|
51
|
+
filePath;
|
|
52
|
+
client = null;
|
|
53
|
+
loaded = false;
|
|
54
|
+
initialized = false;
|
|
55
|
+
initialization = null;
|
|
56
|
+
operationChain = Promise.resolve();
|
|
57
|
+
constructor(filePath) {
|
|
58
|
+
super();
|
|
59
|
+
this.filePath = filePath;
|
|
60
|
+
mkdirSync(path.dirname(filePath), { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
async runSerialized(operation) {
|
|
63
|
+
const pending = this.operationChain.then(operation, operation);
|
|
64
|
+
this.operationChain = pending.then(() => undefined, () => undefined);
|
|
65
|
+
return pending;
|
|
66
|
+
}
|
|
67
|
+
async getClient() {
|
|
68
|
+
if (!this.client) {
|
|
69
|
+
this.client = createClient({ url: `file:${this.filePath}` });
|
|
70
|
+
}
|
|
71
|
+
return this.client;
|
|
72
|
+
}
|
|
73
|
+
async ensureInitialized() {
|
|
74
|
+
if (this.initialized) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (this.initialization) {
|
|
78
|
+
await this.initialization;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.initialization = (async () => {
|
|
82
|
+
const client = await this.getClient();
|
|
83
|
+
await client.execute("PRAGMA journal_mode=WAL");
|
|
84
|
+
await client.execute("PRAGMA foreign_keys=ON");
|
|
85
|
+
await client.execute("PRAGMA busy_timeout=5000");
|
|
86
|
+
await client.execute(`
|
|
87
|
+
CREATE TABLE IF NOT EXISTS ${CHECKPOINT_TABLE} (
|
|
88
|
+
state_key TEXT PRIMARY KEY,
|
|
89
|
+
state_json TEXT NOT NULL,
|
|
90
|
+
updated_at TEXT NOT NULL
|
|
91
|
+
)
|
|
92
|
+
`);
|
|
93
|
+
this.initialized = true;
|
|
94
|
+
this.initialization = null;
|
|
95
|
+
})();
|
|
96
|
+
await this.initialization;
|
|
97
|
+
}
|
|
98
|
+
async loadStateRow() {
|
|
99
|
+
await this.ensureInitialized();
|
|
100
|
+
const client = await this.getClient();
|
|
101
|
+
const result = await client.execute({
|
|
102
|
+
sql: `SELECT state_json, updated_at FROM ${CHECKPOINT_TABLE} WHERE state_key = ?`,
|
|
103
|
+
args: [DEFAULT_STATE_KEY],
|
|
104
|
+
});
|
|
105
|
+
return result.rows[0] ?? null;
|
|
106
|
+
}
|
|
107
|
+
async ensureLoaded() {
|
|
108
|
+
if (this.loaded) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const row = await this.loadStateRow();
|
|
112
|
+
if (row) {
|
|
113
|
+
const parsed = JSON.parse(row.state_json);
|
|
114
|
+
this.storage = decodeBinary(parsed.storage ?? {});
|
|
115
|
+
this.writes = decodeBinary(parsed.writes ?? {});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
this.storage = {};
|
|
119
|
+
this.writes = {};
|
|
120
|
+
}
|
|
121
|
+
this.loaded = true;
|
|
122
|
+
}
|
|
123
|
+
async persist() {
|
|
124
|
+
await this.ensureInitialized();
|
|
125
|
+
const client = await this.getClient();
|
|
126
|
+
const now = new Date().toISOString();
|
|
127
|
+
const payload = JSON.stringify({
|
|
128
|
+
storage: this.storage,
|
|
129
|
+
writes: this.writes,
|
|
130
|
+
}, (_key, value) => encodeBinary(value));
|
|
131
|
+
await client.execute({
|
|
132
|
+
sql: `INSERT INTO ${CHECKPOINT_TABLE} (state_key, state_json, updated_at)
|
|
133
|
+
VALUES (?, ?, ?)
|
|
134
|
+
ON CONFLICT(state_key) DO UPDATE SET
|
|
135
|
+
state_json = excluded.state_json,
|
|
136
|
+
updated_at = excluded.updated_at`,
|
|
137
|
+
args: [DEFAULT_STATE_KEY, payload, now],
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async getTuple(config) {
|
|
141
|
+
return this.runSerialized(async () => {
|
|
142
|
+
await this.ensureLoaded();
|
|
143
|
+
return super.getTuple(config);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async *list(config, options) {
|
|
147
|
+
await this.ensureLoaded();
|
|
148
|
+
for await (const item of super.list(config, options)) {
|
|
149
|
+
yield item;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async put(config, checkpoint, metadata) {
|
|
153
|
+
return this.runSerialized(async () => {
|
|
154
|
+
await this.ensureLoaded();
|
|
155
|
+
const result = await super.put(config, checkpoint, metadata);
|
|
156
|
+
await this.persist();
|
|
157
|
+
return result;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
async putWrites(config, writes, taskId) {
|
|
161
|
+
return this.runSerialized(async () => {
|
|
162
|
+
await this.ensureLoaded();
|
|
163
|
+
const result = await super.putWrites(config, writes, taskId);
|
|
164
|
+
await this.persist();
|
|
165
|
+
return result;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async deleteThread(threadId) {
|
|
169
|
+
return this.runSerialized(async () => {
|
|
170
|
+
await this.ensureLoaded();
|
|
171
|
+
pruneThreadEntries(this.storage, threadId);
|
|
172
|
+
pruneThreadEntries(this.writes, threadId);
|
|
173
|
+
await this.persist();
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
export { SqliteCheckpointSaver as SqliteSaver };
|
|
@@ -21,4 +21,4 @@ export type VectorStoreRuntimeLike = {
|
|
|
21
21
|
}) => Promise<void>;
|
|
22
22
|
};
|
|
23
23
|
export declare function createLlamaIndexEmbeddingModel(embeddingModel: CompiledEmbeddingModel): EmbeddingRuntimeLike;
|
|
24
|
-
export declare function createLlamaIndexVectorStore(
|
|
24
|
+
export declare function createLlamaIndexVectorStore(dataRoot: string, vectorStore: CompiledVectorStore, embeddings: EmbeddingRuntimeLike): Promise<VectorStoreRuntimeLike>;
|
|
@@ -41,8 +41,8 @@ export function createLlamaIndexEmbeddingModel(embeddingModel) {
|
|
|
41
41
|
},
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
export async function createLlamaIndexVectorStore(
|
|
45
|
-
const persistPath = resolveFilePath(vectorStore.url ?? "
|
|
44
|
+
export async function createLlamaIndexVectorStore(dataRoot, vectorStore, embeddings) {
|
|
45
|
+
const persistPath = resolveFilePath(vectorStore.url ?? "knowledge/vectors.json", dataRoot);
|
|
46
46
|
await mkdir(path.dirname(persistPath), { recursive: true });
|
|
47
47
|
const emptyStore = () => SimpleVectorStore.fromDict({
|
|
48
48
|
embeddingDict: {},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { MemorySaver } from "@langchain/langgraph";
|
|
3
3
|
import { FileCheckpointSaver } from "../maintenance/file-checkpoint-saver.js";
|
|
4
|
+
import { SqliteCheckpointSaver } from "../maintenance/sqlite-checkpoint-saver.js";
|
|
4
5
|
import { createInMemoryStore, FileBackedStore, SqliteBackedStore } from "../harness/system/store.js";
|
|
5
6
|
import { resolveKnowledgeFileStorePath, resolveKnowledgeStorePath, resolveRuntimeCheckpointerPath, } from "./runtime-layout.js";
|
|
6
7
|
export function createStoreForConfig(storeConfig, runRoot) {
|
|
@@ -28,12 +29,16 @@ export function createCheckpointerForConfig(checkpointerConfig, runRoot) {
|
|
|
28
29
|
if (typeof checkpointerConfig === "boolean") {
|
|
29
30
|
return checkpointerConfig;
|
|
30
31
|
}
|
|
31
|
-
const kind = typeof checkpointerConfig.kind === "string" ? checkpointerConfig.kind : "
|
|
32
|
+
const kind = typeof checkpointerConfig.kind === "string" ? checkpointerConfig.kind : "SqliteSaver";
|
|
32
33
|
switch (kind) {
|
|
33
34
|
case "MemorySaver":
|
|
34
35
|
return new MemorySaver();
|
|
35
|
-
case "SqliteSaver":
|
|
36
|
-
|
|
36
|
+
case "SqliteSaver": {
|
|
37
|
+
const configuredPath = typeof checkpointerConfig.path === "string"
|
|
38
|
+
? String(checkpointerConfig.path)
|
|
39
|
+
: resolveRuntimeCheckpointerPath(runRoot, "checkpoints.sqlite");
|
|
40
|
+
return new SqliteCheckpointSaver(path.isAbsolute(configuredPath) ? configuredPath : path.join(runRoot, configuredPath));
|
|
41
|
+
}
|
|
37
42
|
case "FileCheckpointer": {
|
|
38
43
|
const configuredPath = typeof checkpointerConfig.path === "string"
|
|
39
44
|
? String(checkpointerConfig.path)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export declare function
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function
|
|
4
|
-
export declare function
|
|
5
|
-
export declare function
|
|
6
|
-
export declare function
|
|
1
|
+
export declare function resolveRuntimeRoot(dataRoot: string): string;
|
|
2
|
+
export declare function resolveRuntimeArtifactsRoot(dataRoot: string): string;
|
|
3
|
+
export declare function resolveRuntimeSqlitePath(dataRoot: string): string;
|
|
4
|
+
export declare function resolveRuntimeCheckpointerPath(dataRoot: string, fileName?: string): string;
|
|
5
|
+
export declare function resolveKnowledgeRoot(dataRoot: string): string;
|
|
6
|
+
export declare function resolveKnowledgeStorePath(dataRoot: string, fileName?: string): string;
|
|
7
|
+
export declare function resolveKnowledgeFileStorePath(dataRoot: string, fileName?: string): string;
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
export function
|
|
3
|
-
return path.join(
|
|
2
|
+
export function resolveRuntimeRoot(dataRoot) {
|
|
3
|
+
return path.join(dataRoot, "runtime");
|
|
4
4
|
}
|
|
5
|
-
export function
|
|
6
|
-
return path.join(
|
|
5
|
+
export function resolveRuntimeArtifactsRoot(dataRoot) {
|
|
6
|
+
return path.join(resolveRuntimeRoot(dataRoot), "artifacts");
|
|
7
7
|
}
|
|
8
|
-
export function
|
|
9
|
-
return path.join(
|
|
8
|
+
export function resolveRuntimeSqlitePath(dataRoot) {
|
|
9
|
+
return path.join(resolveRuntimeRoot(dataRoot), "runtime.sqlite");
|
|
10
10
|
}
|
|
11
|
-
export function
|
|
12
|
-
return path.join(
|
|
11
|
+
export function resolveRuntimeCheckpointerPath(dataRoot, fileName = "checkpoints.json") {
|
|
12
|
+
return path.join(resolveRuntimeRoot(dataRoot), fileName);
|
|
13
13
|
}
|
|
14
|
-
export function
|
|
15
|
-
return path.join(
|
|
14
|
+
export function resolveKnowledgeRoot(dataRoot) {
|
|
15
|
+
return path.join(dataRoot, "knowledge");
|
|
16
16
|
}
|
|
17
|
-
export function
|
|
18
|
-
return path.join(resolveKnowledgeRoot(
|
|
17
|
+
export function resolveKnowledgeStorePath(dataRoot, fileName = "records.sqlite") {
|
|
18
|
+
return path.join(resolveKnowledgeRoot(dataRoot), fileName);
|
|
19
|
+
}
|
|
20
|
+
export function resolveKnowledgeFileStorePath(dataRoot, fileName = "records.json") {
|
|
21
|
+
return path.join(resolveKnowledgeRoot(dataRoot), fileName);
|
|
19
22
|
}
|
|
@@ -5,7 +5,7 @@ import { createClient } from "@libsql/client";
|
|
|
5
5
|
import { LibSQLVectorStore } from "@langchain/community/vectorstores/libsql";
|
|
6
6
|
import { QdrantClient } from "@qdrant/js-client-rest";
|
|
7
7
|
import { compileVectorStore } from "../../workspace/resource-compilers.js";
|
|
8
|
-
import { resolveRefId } from "../../workspace/support/workspace-ref-utils.js";
|
|
8
|
+
import { getRuntimeStorageRoots, resolveRefId } from "../../workspace/support/workspace-ref-utils.js";
|
|
9
9
|
import { resolveCompiledEmbeddingModel, resolveCompiledEmbeddingModelRef } from "./embedding-models.js";
|
|
10
10
|
import { createLlamaIndexVectorStore } from "./llamaindex.js";
|
|
11
11
|
function resolveFileUrl(rawUrl, workspaceRoot) {
|
|
@@ -92,10 +92,11 @@ export async function resolveCompiledVectorStore(workspace, vectorStore, options
|
|
|
92
92
|
if (options.vectorStoreResolver) {
|
|
93
93
|
return options.vectorStoreResolver(vectorStore.id);
|
|
94
94
|
}
|
|
95
|
+
const { dataRoot } = getRuntimeStorageRoots(workspace.refs, workspace.workspaceRoot);
|
|
95
96
|
if (vectorStore.kind === "LlamaIndexSimpleVectorStore") {
|
|
96
97
|
const embeddingModel = resolveCompiledEmbeddingModelRef(workspace, vectorStore.embeddingModelRef);
|
|
97
98
|
const embeddings = await resolveCompiledEmbeddingModel(embeddingModel, options.embeddingModelResolver);
|
|
98
|
-
return createLlamaIndexVectorStore(
|
|
99
|
+
return createLlamaIndexVectorStore(dataRoot, vectorStore, embeddings);
|
|
99
100
|
}
|
|
100
101
|
if (vectorStore.kind === "QdrantVectorStore") {
|
|
101
102
|
const embeddingModel = resolveCompiledEmbeddingModelRef(workspace, vectorStore.embeddingModelRef);
|
|
@@ -178,7 +179,7 @@ export async function resolveCompiledVectorStore(workspace, vectorStore, options
|
|
|
178
179
|
const embeddingModel = resolveCompiledEmbeddingModelRef(workspace, vectorStore.embeddingModelRef);
|
|
179
180
|
const embeddings = await resolveCompiledEmbeddingModel(embeddingModel, options.embeddingModelResolver);
|
|
180
181
|
const db = createClient({
|
|
181
|
-
url: await ensureFileUrlDirectory(vectorStore.url ?? "",
|
|
182
|
+
url: await ensureFileUrlDirectory(vectorStore.url ?? "", dataRoot),
|
|
182
183
|
...(vectorStore.authToken ? { authToken: vectorStore.authToken } : {}),
|
|
183
184
|
});
|
|
184
185
|
const table = vectorStore.table ?? "vectors";
|
|
@@ -5,7 +5,7 @@ import { compileModel, compileTool } from "./resource-compilers.js";
|
|
|
5
5
|
import { inferAgentCapabilities } from "./support/agent-capabilities.js";
|
|
6
6
|
import { getAgentExecutionConfigValue, getAgentExecutionObject, getAgentExecutionString } from "./support/agent-execution-config.js";
|
|
7
7
|
import { discoverSkillPaths } from "./support/discovery.js";
|
|
8
|
-
import { compileAgentMemories, getResilienceConfig, getRuntimeDefaults, getRuntimeMemoryDefaults, getWorkspaceObject, resolvePromptValue, resolveRefId } from "./support/workspace-ref-utils.js";
|
|
8
|
+
import { compileAgentMemories, getResilienceConfig, getRuntimeDefaults, getRuntimeMemoryDefaults, getRuntimeStorageRoots, getWorkspaceObject, resolvePromptValue, resolveRefId, } from "./support/workspace-ref-utils.js";
|
|
9
9
|
const WORKSPACE_BOUNDARY_GUIDANCE = "Keep repository and file exploration bounded to the current workspace root unless the user explicitly asks for broader host or filesystem access. " +
|
|
10
10
|
"Do not inspect absolute paths outside the workspace, system directories, or unrelated repos by default. " +
|
|
11
11
|
"Prefer workspace-local tools, relative paths, and the current repository checkout when analyzing code.";
|
|
@@ -339,6 +339,7 @@ function resolveRuntimeMemoryConfig(agent, refs) {
|
|
|
339
339
|
export function compileBinding(workspaceRoot, agent, agents, referencedSubagentIds, refs, models, tools) {
|
|
340
340
|
const internalSubagent = referencedSubagentIds.has(agent.id);
|
|
341
341
|
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
342
|
+
const runtimeStorage = getRuntimeStorageRoots(refs, workspaceRoot);
|
|
342
343
|
const resilience = getResilienceConfig(refs);
|
|
343
344
|
const compiledAgentSkills = compileAgentSkills(workspaceRoot, agent);
|
|
344
345
|
const compiledAgentMemory = compileAgentMemories(workspaceRoot, agent.memorySources);
|
|
@@ -361,15 +362,16 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
361
362
|
? mergeConfigObjects(runtimeFilesystemDefaults, getAgentExecutionObject(agent, "filesystem", { executionMode: "langchain-v1" }))
|
|
362
363
|
: undefined;
|
|
363
364
|
const runRoot = typeof agent.runRoot === "string" && agent.runRoot.trim().length > 0
|
|
364
|
-
? path.resolve(
|
|
365
|
-
:
|
|
366
|
-
? path.resolve(workspaceRoot, runtimeDefaults.runRoot)
|
|
367
|
-
: path.join(workspaceRoot, "run-data");
|
|
365
|
+
? (path.isAbsolute(agent.runRoot) ? agent.runRoot : path.resolve(runtimeStorage.dataRoot, agent.runRoot))
|
|
366
|
+
: runtimeStorage.dataRoot;
|
|
368
367
|
const base = {
|
|
369
368
|
agent,
|
|
370
369
|
harnessRuntime: {
|
|
370
|
+
applicationRoot: runtimeStorage.applicationRoot,
|
|
371
|
+
dataRoot: runtimeStorage.dataRoot,
|
|
372
|
+
runtimeProfile: runtimeStorage.runtimeProfile,
|
|
371
373
|
runRoot,
|
|
372
|
-
workspaceRoot,
|
|
374
|
+
workspaceRoot: runtimeStorage.applicationRoot,
|
|
373
375
|
capabilities: inferAgentCapabilities(agent),
|
|
374
376
|
resilience,
|
|
375
377
|
...(runtimeGovernanceDefaults ? { governance: runtimeGovernanceDefaults } : {}),
|
|
@@ -10,7 +10,7 @@ import { validateAgent, validateTopology } from "./validate.js";
|
|
|
10
10
|
import { compileBinding } from "./agent-binding-compiler.js";
|
|
11
11
|
import { discoverSubagents, ensureDiscoverySources } from "./support/discovery.js";
|
|
12
12
|
import { collectAgentDiscoverySourceRefs, collectToolSourceRefs } from "./support/source-collectors.js";
|
|
13
|
-
import { getRoutingDefaultAgentId, getRuntimeResources, getToolModuleDiscoveryConfig, getRoutingRules, resolveRefId, } from "./support/workspace-ref-utils.js";
|
|
13
|
+
import { getRoutingDefaultAgentId, getRuntimeResources, getRuntimeStorageRoots, getToolModuleDiscoveryConfig, getRoutingRules, resolveRefId, } from "./support/workspace-ref-utils.js";
|
|
14
14
|
import { hydrateAgentMcpTools, hydrateResourceAndExternalTools } from "./tool-hydration.js";
|
|
15
15
|
import { traceStartupStage } from "../runtime/startup-tracing.js";
|
|
16
16
|
import { shouldSkipScanDirectory } from "../utils/fs.js";
|
|
@@ -209,6 +209,11 @@ export async function loadWorkspace(workspaceRoot, options = {}) {
|
|
|
209
209
|
const loaded = await traceStartupStage("workspace.load.objects", () => loadWorkspaceObjects(workspaceRoot, options), {
|
|
210
210
|
workspaceRoot,
|
|
211
211
|
});
|
|
212
|
+
const runtimeStorage = getRuntimeStorageRoots(loaded.refs, workspaceRoot);
|
|
213
|
+
if (path.resolve(runtimeStorage.applicationRoot) !== path.resolve(workspaceRoot)) {
|
|
214
|
+
throw new Error(`Runtime applicationRoot ${runtimeStorage.applicationRoot} must resolve to the loaded workspace root ${workspaceRoot}. ` +
|
|
215
|
+
"Load the shared application folder as the workspace root and use Runtime.dataRoot for writable profile data.");
|
|
216
|
+
}
|
|
212
217
|
loaded.agents = await traceStartupStage("workspace.discover.subagents", () => discoverSubagents(loaded.agents, workspaceRoot), {
|
|
213
218
|
workspaceRoot,
|
|
214
219
|
});
|
|
@@ -516,6 +516,9 @@ export function parseAgentItem(item, sourcePath) {
|
|
|
516
516
|
description: String(normalizedItem.description ?? ""),
|
|
517
517
|
modelRef: readExecutionValue(normalizedItem, "modelRef", readSingleRef) ?? "",
|
|
518
518
|
runRoot: typeof runtime?.runRoot === "string" ? runtime.runRoot : undefined,
|
|
519
|
+
applicationRoot: typeof runtime?.applicationRoot === "string" ? runtime.applicationRoot : undefined,
|
|
520
|
+
dataRoot: typeof runtime?.dataRoot === "string" ? runtime.dataRoot : undefined,
|
|
521
|
+
runtimeProfile: typeof runtime?.profile === "string" ? runtime.profile : undefined,
|
|
519
522
|
toolRefs: toolBindings.map((binding) => binding.ref),
|
|
520
523
|
toolBindings,
|
|
521
524
|
inlineTools: undefined,
|
|
@@ -37,6 +37,12 @@ export type ToolModuleDiscoveryConfig = {
|
|
|
37
37
|
};
|
|
38
38
|
export declare function getWorkspaceObject(refs: Map<string, WorkspaceObject | ParsedAgentObject>, ref: string | undefined): WorkspaceObject | undefined;
|
|
39
39
|
export declare function getRuntimeDefaults(refs: Map<string, WorkspaceObject | ParsedAgentObject>): Record<string, unknown> | undefined;
|
|
40
|
+
export type RuntimeStorageRoots = {
|
|
41
|
+
applicationRoot: string;
|
|
42
|
+
dataRoot: string;
|
|
43
|
+
runtimeProfile: string;
|
|
44
|
+
};
|
|
45
|
+
export declare function getRuntimeStorageRoots(refs: Map<string, WorkspaceObject | ParsedAgentObject>, workspaceRoot: string): RuntimeStorageRoots;
|
|
40
46
|
export declare function getRuntimeResources(refs: Map<string, WorkspaceObject | ParsedAgentObject>): string[];
|
|
41
47
|
export declare function getToolModuleDiscoveryConfig(refs: Map<string, WorkspaceObject | ParsedAgentObject>): ToolModuleDiscoveryConfig;
|
|
42
48
|
export declare function getRuntimeMemoryDefaults(refs: Map<string, WorkspaceObject | ParsedAgentObject>): Record<string, unknown> | undefined;
|
|
@@ -26,6 +26,31 @@ export function getRuntimeDefaults(refs) {
|
|
|
26
26
|
}
|
|
27
27
|
return runtimes[0].value;
|
|
28
28
|
}
|
|
29
|
+
function asNonEmptyString(value) {
|
|
30
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
31
|
+
}
|
|
32
|
+
export function getRuntimeStorageRoots(refs, workspaceRoot) {
|
|
33
|
+
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
34
|
+
const configuredApplicationRoot = asNonEmptyString(runtimeDefaults?.applicationRoot);
|
|
35
|
+
const configuredDataRoot = asNonEmptyString(runtimeDefaults?.dataRoot);
|
|
36
|
+
const configuredProfile = asNonEmptyString(runtimeDefaults?.profile);
|
|
37
|
+
const applicationRoot = configuredApplicationRoot
|
|
38
|
+
? (path.isAbsolute(configuredApplicationRoot)
|
|
39
|
+
? configuredApplicationRoot
|
|
40
|
+
: path.resolve(workspaceRoot, configuredApplicationRoot))
|
|
41
|
+
: workspaceRoot;
|
|
42
|
+
const dataRoot = configuredDataRoot
|
|
43
|
+
? (path.isAbsolute(configuredDataRoot)
|
|
44
|
+
? configuredDataRoot
|
|
45
|
+
: path.resolve(applicationRoot, configuredDataRoot))
|
|
46
|
+
: path.join(applicationRoot, ".agent");
|
|
47
|
+
const runtimeProfile = configuredProfile ?? "default";
|
|
48
|
+
return {
|
|
49
|
+
applicationRoot,
|
|
50
|
+
dataRoot,
|
|
51
|
+
runtimeProfile,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
29
54
|
export function getRuntimeResources(refs) {
|
|
30
55
|
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
31
56
|
if (!Array.isArray(runtimeDefaults?.resources)) {
|
|
@@ -10,7 +10,7 @@ function validateCheckpointerConfig(agent) {
|
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
12
|
const typedCheckpointer = checkpointer;
|
|
13
|
-
const kind = typeof typedCheckpointer.kind === "string" ? typedCheckpointer.kind : "
|
|
13
|
+
const kind = typeof typedCheckpointer.kind === "string" ? typedCheckpointer.kind : "SqliteSaver";
|
|
14
14
|
const hasPath = typeof typedCheckpointer.path === "string" && typedCheckpointer.path.trim().length > 0;
|
|
15
15
|
if (kind === "MemorySaver" && hasPath) {
|
|
16
16
|
throw new Error(`Agent ${agent.id} checkpointer.path is not supported for kind MemorySaver`);
|