@botbotgo/agent-harness 0.0.155 → 0.0.157
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 +34 -6
- package/README.zh.md +34 -6
- package/dist/acp.d.ts +86 -0
- package/dist/acp.js +208 -0
- package/dist/api.d.ts +17 -2
- package/dist/api.js +19 -0
- package/dist/contracts/runtime.d.ts +79 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/persistence/file-store.d.ts +1 -0
- package/dist/persistence/file-store.js +10 -1
- package/dist/persistence/types.d.ts +2 -0
- package/dist/runtime/agent-runtime-adapter.d.ts +5 -1
- package/dist/runtime/agent-runtime-adapter.js +61 -24
- package/dist/runtime/harness/run/governance.d.ts +2 -0
- package/dist/runtime/harness/run/governance.js +76 -0
- package/dist/runtime/harness/run/inspection.js +4 -0
- package/dist/runtime/harness/system/policy-engine.d.ts +2 -1
- package/dist/runtime/harness/system/policy-engine.js +5 -1
- package/dist/runtime/harness/system/runtime-memory-records.d.ts +3 -0
- package/dist/runtime/harness/system/runtime-memory-records.js +48 -2
- package/dist/runtime/harness.d.ts +11 -1
- package/dist/runtime/harness.js +221 -2
- package/dist/workspace/agent-binding-compiler.js +7 -1
- package/dist/workspace/object-loader.js +9 -44
- package/dist/workspace/yaml-object-reader.d.ts +0 -4
- package/dist/workspace/yaml-object-reader.js +4 -32
- package/package.json +6 -1
|
@@ -96,6 +96,24 @@ export type RuntimeSnapshotTracing = {
|
|
|
96
96
|
tags?: string[];
|
|
97
97
|
metadata?: Record<string, unknown>;
|
|
98
98
|
};
|
|
99
|
+
export type RuntimeGovernanceRiskLevel = "low" | "medium" | "high";
|
|
100
|
+
export type RuntimeGovernanceToolPolicy = {
|
|
101
|
+
toolName: string;
|
|
102
|
+
toolId: string;
|
|
103
|
+
toolType: string;
|
|
104
|
+
category: "local" | "backend" | "mcp" | "provider-native";
|
|
105
|
+
risk: RuntimeGovernanceRiskLevel;
|
|
106
|
+
requiresApproval: boolean;
|
|
107
|
+
approvalPolicy: "explicit-hitl" | "runtime-default" | "none";
|
|
108
|
+
hasInputSchema: boolean;
|
|
109
|
+
inputRiskHints: string[];
|
|
110
|
+
};
|
|
111
|
+
export type RuntimeGovernanceBundle = {
|
|
112
|
+
bundleId: string;
|
|
113
|
+
title: string;
|
|
114
|
+
summary: string;
|
|
115
|
+
toolPolicies: RuntimeGovernanceToolPolicy[];
|
|
116
|
+
};
|
|
99
117
|
export type RuntimeSnapshot = {
|
|
100
118
|
agentId: string;
|
|
101
119
|
model?: RuntimeSnapshotModel;
|
|
@@ -103,6 +121,9 @@ export type RuntimeSnapshot = {
|
|
|
103
121
|
skills: RuntimeSnapshotSkill[];
|
|
104
122
|
memory: string[];
|
|
105
123
|
tracing?: RuntimeSnapshotTracing;
|
|
124
|
+
governance?: {
|
|
125
|
+
bundles: RuntimeGovernanceBundle[];
|
|
126
|
+
};
|
|
106
127
|
};
|
|
107
128
|
export type MemoryCandidate = {
|
|
108
129
|
content: string;
|
|
@@ -195,6 +216,37 @@ export type RecallInput = {
|
|
|
195
216
|
export type RecallResult = {
|
|
196
217
|
items: MemoryRecord[];
|
|
197
218
|
};
|
|
219
|
+
export type ListMemoriesInput = {
|
|
220
|
+
scopes?: MemoryScope[];
|
|
221
|
+
kinds?: MemoryKind[];
|
|
222
|
+
status?: MemoryRecordStatus[];
|
|
223
|
+
threadId?: string;
|
|
224
|
+
agentId?: string;
|
|
225
|
+
workspaceId?: string;
|
|
226
|
+
userId?: string;
|
|
227
|
+
projectId?: string;
|
|
228
|
+
limit?: number;
|
|
229
|
+
};
|
|
230
|
+
export type ListMemoriesResult = {
|
|
231
|
+
items: MemoryRecord[];
|
|
232
|
+
};
|
|
233
|
+
export type UpdateMemoryInput = {
|
|
234
|
+
memoryId: string;
|
|
235
|
+
content?: string;
|
|
236
|
+
summary?: string;
|
|
237
|
+
status?: MemoryRecordStatus;
|
|
238
|
+
confidence?: number;
|
|
239
|
+
expiresAt?: string | null;
|
|
240
|
+
sourceType?: string;
|
|
241
|
+
sourceRefs?: string[];
|
|
242
|
+
tags?: string[];
|
|
243
|
+
observedAt?: string;
|
|
244
|
+
lastConfirmedAt?: string;
|
|
245
|
+
provenance?: Record<string, unknown>;
|
|
246
|
+
};
|
|
247
|
+
export type RemoveMemoryInput = {
|
|
248
|
+
memoryId: string;
|
|
249
|
+
};
|
|
198
250
|
/**
|
|
199
251
|
* Operator-facing projection of tool execution policy already compiled into a binding.
|
|
200
252
|
* This summarizes existing timeout, retry, validation, and retry-safety hints without
|
|
@@ -508,6 +560,7 @@ export type SkillPackagingConvention = {
|
|
|
508
560
|
export type PolicyDecision = {
|
|
509
561
|
allowed: boolean;
|
|
510
562
|
reasons: string[];
|
|
563
|
+
bundles?: RuntimeGovernanceBundle[];
|
|
511
564
|
};
|
|
512
565
|
export type PolicyEvaluator = {
|
|
513
566
|
kind: string;
|
|
@@ -517,6 +570,32 @@ export type EventSubscriber = {
|
|
|
517
570
|
kind: string;
|
|
518
571
|
onEvent: HarnessEventListener;
|
|
519
572
|
};
|
|
573
|
+
export type RuntimeEvaluationExportInput = {
|
|
574
|
+
sessionId: string;
|
|
575
|
+
requestId: string;
|
|
576
|
+
includeArtifacts?: boolean;
|
|
577
|
+
includeArtifactContents?: boolean;
|
|
578
|
+
expectedOutput?: string;
|
|
579
|
+
rubric?: string[];
|
|
580
|
+
tags?: string[];
|
|
581
|
+
metadata?: Record<string, unknown>;
|
|
582
|
+
};
|
|
583
|
+
export type RuntimeEvaluationArtifact = ArtifactRecord & {
|
|
584
|
+
content?: unknown;
|
|
585
|
+
};
|
|
586
|
+
export type RuntimeEvaluationExport = {
|
|
587
|
+
session: SessionRecord | null;
|
|
588
|
+
request: RequestRecord | null;
|
|
589
|
+
approvals: ApprovalRecord[];
|
|
590
|
+
transcript: TranscriptMessage[];
|
|
591
|
+
events: HarnessEvent[];
|
|
592
|
+
artifacts: RuntimeEvaluationArtifact[];
|
|
593
|
+
runtimeHealth: RuntimeHealthSnapshot;
|
|
594
|
+
expectedOutput?: string;
|
|
595
|
+
rubric: string[];
|
|
596
|
+
tags: string[];
|
|
597
|
+
metadata?: Record<string, unknown>;
|
|
598
|
+
};
|
|
520
599
|
export type RuntimeInventoryContext = {
|
|
521
600
|
workspace: WorkspaceBundle;
|
|
522
601
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { AgentHarnessRuntime, cancelRun, createAgentHarness, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, getAgent, getApproval, getRequest, getHealth, getSession, listAgentSkills, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, resolveApproval, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
|
|
2
|
-
export type {
|
|
1
|
+
export { AgentHarnessAcpServer, AgentHarnessRuntime, cancelRun, createAgentHarness, createAcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, getArtifact, getAgent, getApproval, getRequest, getHealth, listMemories, getSession, listAgentSkills, listArtifacts, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, removeMemory, resolveApproval, run, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
|
|
2
|
+
export type { AcpApproval, AcpArtifact, AcpEventNotification, AcpJsonRpcError, AcpJsonRpcRequest, AcpJsonRpcResponse, AcpJsonRpcSuccess, AcpRequestRecord, AcpRunRequestParams, AcpServerCapabilities, AcpSessionRecord, } from "./acp.js";
|
|
3
|
+
export type { ListMemoriesInput, ListMemoriesResult, MemoryDecision, MemoryKind, MemoryRecord, MemoryScope, MemorizeInput, MemorizeResult, NormalizeUserChatInputOptions, RecallInput, RecallResult, RemoveMemoryInput, RuntimeEvaluationExport, RuntimeEvaluationExportInput, UpdateMemoryInput, UserChatInput, UserChatMessage, } from "./api.js";
|
|
3
4
|
export type { ToolMcpServerOptions } from "./mcp.js";
|
|
4
5
|
export { tool } from "./tools.js";
|
|
5
6
|
export type { UpstreamTimelineProjection, UpstreamTimelineReducer } from "./upstream-events.js";
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { AgentHarnessRuntime, cancelRun, createAgentHarness, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, getAgent, getApproval, getRequest, getHealth, getSession, listAgentSkills, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, resolveApproval, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
|
|
1
|
+
export { AgentHarnessAcpServer, AgentHarnessRuntime, cancelRun, createAgentHarness, createAcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, getArtifact, getAgent, getApproval, getRequest, getHealth, listMemories, getSession, listAgentSkills, listArtifacts, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, removeMemory, resolveApproval, run, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
|
|
2
2
|
export { tool } from "./tools.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.156";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.156";
|
|
@@ -69,6 +69,7 @@ export declare class FilePersistence implements RuntimePersistence {
|
|
|
69
69
|
resolveApproval(threadId: string, runId: string, approvalId: string, status: InternalApprovalRecord["status"]): Promise<InternalApprovalRecord>;
|
|
70
70
|
createArtifact(threadId: string, runId: string, artifact: ArtifactRecord, content: unknown): Promise<ArtifactRecord>;
|
|
71
71
|
listArtifacts(threadId: string, runId: string): Promise<ArtifactListing>;
|
|
72
|
+
readArtifact(threadId: string, runId: string, artifactPath: string): Promise<unknown>;
|
|
72
73
|
appendThreadMessage(threadId: string, message: TranscriptMessage): Promise<void>;
|
|
73
74
|
listThreadMessages(threadId: string, limit?: number): Promise<TranscriptMessage[]>;
|
|
74
75
|
saveRecoveryIntent(threadId: string, runId: string, intent: RecoveryIntent): Promise<void>;
|
|
@@ -328,7 +328,9 @@ export class FilePersistence {
|
|
|
328
328
|
if (!(await fileExists(eventsDir))) {
|
|
329
329
|
return [];
|
|
330
330
|
}
|
|
331
|
-
const entries = (await readdir(eventsDir))
|
|
331
|
+
const entries = (await readdir(eventsDir))
|
|
332
|
+
.filter((entry) => entry.endsWith(".json"))
|
|
333
|
+
.sort((left, right) => left.localeCompare(right));
|
|
332
334
|
return Promise.all(entries.map((entry) => readJson(path.join(eventsDir, entry))));
|
|
333
335
|
}
|
|
334
336
|
async listApprovals(filter = {}) {
|
|
@@ -460,6 +462,13 @@ export class FilePersistence {
|
|
|
460
462
|
async listArtifacts(threadId, runId) {
|
|
461
463
|
return readJson(path.join(this.runDir(threadId, runId), "artifacts.json"));
|
|
462
464
|
}
|
|
465
|
+
async readArtifact(threadId, runId, artifactPath) {
|
|
466
|
+
const filePath = path.join(this.runDir(threadId, runId), artifactPath);
|
|
467
|
+
if (!(await fileExists(filePath))) {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
return readJson(filePath);
|
|
471
|
+
}
|
|
463
472
|
async appendThreadMessage(threadId, message) {
|
|
464
473
|
const messagesPath = path.join(this.threadDir(threadId), "messages.json");
|
|
465
474
|
const current = (await fileExists(messagesPath))
|
|
@@ -120,6 +120,7 @@ export interface RuntimePersistence {
|
|
|
120
120
|
}): Promise<void>;
|
|
121
121
|
setRunState(threadId: string, runId: string, state: RunState, checkpointRef?: string | null): Promise<void>;
|
|
122
122
|
appendEvent(event: HarnessEvent): Promise<void>;
|
|
123
|
+
listRunEvents(threadId: string, runId: string): Promise<HarnessEvent[]>;
|
|
123
124
|
listSessions(filter?: ThreadSummaryFilter): Promise<ThreadSummary[]>;
|
|
124
125
|
listRuns(filter?: RunSummaryFilter): Promise<RunSummary[]>;
|
|
125
126
|
getRun(runId: string): Promise<RunSummary | null>;
|
|
@@ -147,6 +148,7 @@ export interface RuntimePersistence {
|
|
|
147
148
|
resolveApproval(threadId: string, runId: string, approvalId: string, status: InternalApprovalRecord["status"]): Promise<InternalApprovalRecord>;
|
|
148
149
|
createArtifact(threadId: string, runId: string, artifact: ArtifactRecord, content: unknown): Promise<ArtifactRecord>;
|
|
149
150
|
listArtifacts(threadId: string, runId: string): Promise<ArtifactListing>;
|
|
151
|
+
readArtifact(threadId: string, runId: string, artifactPath: string): Promise<unknown>;
|
|
150
152
|
appendThreadMessage(threadId: string, message: TranscriptMessage): Promise<void>;
|
|
151
153
|
listThreadMessages(threadId: string, limit?: number): Promise<TranscriptMessage[]>;
|
|
152
154
|
saveRecoveryIntent(threadId: string, runId: string, intent: RecoveryIntent): Promise<void>;
|
|
@@ -63,6 +63,7 @@ export declare class AgentRuntimeAdapter {
|
|
|
63
63
|
private resolveTools;
|
|
64
64
|
private getToolNameMapping;
|
|
65
65
|
private resolveFilesystemBackend;
|
|
66
|
+
private resolveFilesystemRootDir;
|
|
66
67
|
private resolveBuiltinMiddlewareBackend;
|
|
67
68
|
private createDeclaredMiddlewareResolverOptions;
|
|
68
69
|
private createAssemblyResolvers;
|
|
@@ -75,7 +76,10 @@ export declare class AgentRuntimeAdapter {
|
|
|
75
76
|
private createLangChainRunnable;
|
|
76
77
|
private createRunnable;
|
|
77
78
|
private createDeepAgentRunnable;
|
|
78
|
-
|
|
79
|
+
private buildRunnableCacheKey;
|
|
80
|
+
create(binding: CompiledAgentBinding, options?: {
|
|
81
|
+
threadId?: string;
|
|
82
|
+
}): Promise<RunnableLike>;
|
|
79
83
|
invoke(binding: CompiledAgentBinding, input: MessageContent, threadId: string, runId: string, resumePayload?: unknown, history?: TranscriptMessage[], options?: {
|
|
80
84
|
context?: Record<string, unknown>;
|
|
81
85
|
state?: Record<string, unknown>;
|
|
@@ -159,7 +159,7 @@ function shouldAttachMinimalDeepAgentBackend(binding) {
|
|
|
159
159
|
export class AgentRuntimeAdapter {
|
|
160
160
|
options;
|
|
161
161
|
modelCache = new Map();
|
|
162
|
-
runnableCache = new
|
|
162
|
+
runnableCache = new Map();
|
|
163
163
|
toolNameMappingCache = new WeakMap();
|
|
164
164
|
constructor(options = {}) {
|
|
165
165
|
this.options = options;
|
|
@@ -213,7 +213,12 @@ export class AgentRuntimeAdapter {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
invalidateBindingRuntimeCaches(binding) {
|
|
216
|
-
|
|
216
|
+
const prefix = `${binding.agent.sourcePath}::`;
|
|
217
|
+
for (const key of Array.from(this.runnableCache.keys())) {
|
|
218
|
+
if (key.startsWith(prefix)) {
|
|
219
|
+
this.runnableCache.delete(key);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
217
222
|
this.modelCache.clear();
|
|
218
223
|
}
|
|
219
224
|
resolveTools(tools, binding) {
|
|
@@ -232,15 +237,19 @@ export class AgentRuntimeAdapter {
|
|
|
232
237
|
this.toolNameMappingCache.set(binding, resolved);
|
|
233
238
|
return resolved;
|
|
234
239
|
}
|
|
235
|
-
resolveFilesystemBackend(binding) {
|
|
240
|
+
resolveFilesystemBackend(binding, options = {}) {
|
|
236
241
|
const filesystemConfig = getBindingFilesystemConfig(binding);
|
|
242
|
+
const sessionStorage = typeof filesystemConfig?.sessionStorage === "object" && filesystemConfig.sessionStorage
|
|
243
|
+
? filesystemConfig.sessionStorage
|
|
244
|
+
: undefined;
|
|
237
245
|
const configuredRootDir = typeof filesystemConfig?.rootDir === "string" && filesystemConfig.rootDir.trim().length > 0
|
|
238
246
|
? filesystemConfig.rootDir
|
|
239
247
|
: undefined;
|
|
240
248
|
const workspaceRoot = binding.harnessRuntime.workspaceRoot;
|
|
241
|
-
const
|
|
249
|
+
const baseRootDir = configuredRootDir
|
|
242
250
|
? (path.isAbsolute(configuredRootDir) ? configuredRootDir : path.resolve(workspaceRoot ?? process.cwd(), configuredRootDir))
|
|
243
251
|
: workspaceRoot ?? process.cwd();
|
|
252
|
+
const rootDir = this.resolveFilesystemRootDir(baseRootDir, binding, sessionStorage, options.threadId);
|
|
244
253
|
return new FilesystemBackend({
|
|
245
254
|
rootDir,
|
|
246
255
|
virtualMode: filesystemConfig?.virtualMode === true,
|
|
@@ -249,6 +258,25 @@ export class AgentRuntimeAdapter {
|
|
|
249
258
|
: 10,
|
|
250
259
|
});
|
|
251
260
|
}
|
|
261
|
+
resolveFilesystemRootDir(baseRootDir, binding, sessionStorage, threadId) {
|
|
262
|
+
const enabled = sessionStorage?.enabled === true;
|
|
263
|
+
if (!enabled || !threadId) {
|
|
264
|
+
return baseRootDir;
|
|
265
|
+
}
|
|
266
|
+
const workspaceRoot = binding.harnessRuntime.workspaceRoot ?? process.cwd();
|
|
267
|
+
const runRoot = binding.harnessRuntime.runRoot;
|
|
268
|
+
const configuredRootDir = typeof sessionStorage.rootDir === "string" && sessionStorage.rootDir.trim().length > 0
|
|
269
|
+
? sessionStorage.rootDir.trim()
|
|
270
|
+
: "{runRoot}/threads/{threadId}/filesystem";
|
|
271
|
+
const rendered = configuredRootDir
|
|
272
|
+
.replaceAll("{threadId}", threadId)
|
|
273
|
+
.replaceAll("{sessionId}", threadId)
|
|
274
|
+
.replaceAll("{agentId}", binding.agent.id)
|
|
275
|
+
.replaceAll("{runRoot}", runRoot)
|
|
276
|
+
.replaceAll("{workspaceRoot}", workspaceRoot)
|
|
277
|
+
.replaceAll("{baseRootDir}", baseRootDir);
|
|
278
|
+
return path.isAbsolute(rendered) ? rendered : path.resolve(workspaceRoot, rendered);
|
|
279
|
+
}
|
|
252
280
|
resolveBuiltinMiddlewareBackend(binding, options = {}) {
|
|
253
281
|
return resolveBuiltinMiddlewareBackendHelper({
|
|
254
282
|
binding,
|
|
@@ -257,7 +285,7 @@ export class AgentRuntimeAdapter {
|
|
|
257
285
|
options,
|
|
258
286
|
});
|
|
259
287
|
}
|
|
260
|
-
createDeclaredMiddlewareResolverOptions(binding) {
|
|
288
|
+
createDeclaredMiddlewareResolverOptions(binding, options = {}) {
|
|
261
289
|
return {
|
|
262
290
|
resolveModel: (model) => this.resolveModel(model),
|
|
263
291
|
resolveBackend: (resolvedBinding) => {
|
|
@@ -266,7 +294,7 @@ export class AgentRuntimeAdapter {
|
|
|
266
294
|
},
|
|
267
295
|
resolveFilesystemBackend: (resolvedBinding) => {
|
|
268
296
|
const targetBinding = resolvedBinding ?? binding;
|
|
269
|
-
return targetBinding ? this.resolveFilesystemBackend(targetBinding) : undefined;
|
|
297
|
+
return targetBinding ? this.resolveFilesystemBackend(targetBinding, { threadId: options.threadId }) : undefined;
|
|
270
298
|
},
|
|
271
299
|
resolveCustom: this.options.declaredMiddlewareResolver,
|
|
272
300
|
binding,
|
|
@@ -276,8 +304,8 @@ export class AgentRuntimeAdapter {
|
|
|
276
304
|
return {
|
|
277
305
|
resolveModel: (model) => this.resolveModel(model),
|
|
278
306
|
resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
|
|
279
|
-
resolveFilesystemBackend: (currentBinding) => this.resolveFilesystemBackend(currentBinding),
|
|
280
|
-
createDeclaredMiddlewareResolverOptions: (currentBinding) => this.createDeclaredMiddlewareResolverOptions(currentBinding),
|
|
307
|
+
resolveFilesystemBackend: (currentBinding) => this.resolveFilesystemBackend(currentBinding, { threadId: options.threadId }),
|
|
308
|
+
createDeclaredMiddlewareResolverOptions: (currentBinding) => this.createDeclaredMiddlewareResolverOptions(currentBinding, options),
|
|
281
309
|
resolveBuiltinMiddlewareBackend: (currentBinding, currentOptions = {}) => this.resolveBuiltinMiddlewareBackend(currentBinding, currentOptions),
|
|
282
310
|
resolveSubagents: (subagents, currentBinding) => this.resolveSubagents(subagents, currentBinding),
|
|
283
311
|
invokeBuiltinTaskTool: (currentBinding, toolInput, currentOptions = {}) => this.invokeBuiltinTaskTool(currentBinding, toolInput, currentOptions),
|
|
@@ -313,8 +341,8 @@ export class AgentRuntimeAdapter {
|
|
|
313
341
|
createDeclaredMiddlewareResolverOptions: assembly.createDeclaredMiddlewareResolverOptions,
|
|
314
342
|
});
|
|
315
343
|
}
|
|
316
|
-
async resolveLangChainRuntimeExtensionMiddleware(binding) {
|
|
317
|
-
const assembly = this.createAssemblyResolvers(binding);
|
|
344
|
+
async resolveLangChainRuntimeExtensionMiddleware(binding, options = {}) {
|
|
345
|
+
const assembly = this.createAssemblyResolvers(binding, options);
|
|
318
346
|
return resolveLangChainRuntimeExtensionMiddlewareHelper({
|
|
319
347
|
binding,
|
|
320
348
|
materializeAutomaticSummarizationMiddleware: (currentBinding) => this.materializeAutomaticSummarizationMiddleware(currentBinding),
|
|
@@ -324,14 +352,14 @@ export class AgentRuntimeAdapter {
|
|
|
324
352
|
resolveSubagents: assembly.resolveSubagents,
|
|
325
353
|
});
|
|
326
354
|
}
|
|
327
|
-
async resolveMiddleware(binding, interruptOn) {
|
|
328
|
-
const assembly = this.createAssemblyResolvers(binding);
|
|
355
|
+
async resolveMiddleware(binding, interruptOn, options = {}) {
|
|
356
|
+
const assembly = this.createAssemblyResolvers(binding, options);
|
|
329
357
|
return resolveMiddlewareHelper({
|
|
330
358
|
binding,
|
|
331
359
|
interruptOn,
|
|
332
360
|
runtimeAdapterOptions: this.options,
|
|
333
361
|
createDeclaredMiddlewareResolverOptions: assembly.createDeclaredMiddlewareResolverOptions,
|
|
334
|
-
resolveLangChainRuntimeExtensionMiddleware: (currentBinding) => this.resolveLangChainRuntimeExtensionMiddleware(currentBinding),
|
|
362
|
+
resolveLangChainRuntimeExtensionMiddleware: (currentBinding) => this.resolveLangChainRuntimeExtensionMiddleware(currentBinding, options),
|
|
335
363
|
});
|
|
336
364
|
}
|
|
337
365
|
async resolveSubagents(subagents, binding) {
|
|
@@ -354,7 +382,7 @@ export class AgentRuntimeAdapter {
|
|
|
354
382
|
const interruptOn = resolveRunnableInterruptOn(binding);
|
|
355
383
|
const resolvedModel = await this.resolveModel(primaryModel);
|
|
356
384
|
const resolvedTools = this.resolveTools(primaryTools, binding);
|
|
357
|
-
const resolvedMiddleware = await this.resolveMiddleware(binding, interruptOn);
|
|
385
|
+
const resolvedMiddleware = await this.resolveMiddleware(binding, interruptOn, { threadId: options.threadId });
|
|
358
386
|
const resolvedCheckpointer = resolveRunnableCheckpointer(this.options, binding);
|
|
359
387
|
const resolvedStore = this.options.storeResolver?.(binding);
|
|
360
388
|
const model = resolvedModel;
|
|
@@ -372,12 +400,12 @@ export class AgentRuntimeAdapter {
|
|
|
372
400
|
systemPromptOverride: options.systemPromptOverride,
|
|
373
401
|
}));
|
|
374
402
|
}
|
|
375
|
-
async createRunnable(binding) {
|
|
403
|
+
async createRunnable(binding, options = {}) {
|
|
376
404
|
if (getBindingAdapterKind(binding) === "langgraph") {
|
|
377
405
|
throw new Error(`Agent ${binding.agent.id} uses removed backend langgraph; use langchain-v1 or deepagent`);
|
|
378
406
|
}
|
|
379
407
|
if (isLangChainBinding(binding)) {
|
|
380
|
-
return this.createLangChainRunnable(binding);
|
|
408
|
+
return this.createLangChainRunnable(binding, { threadId: options.threadId });
|
|
381
409
|
}
|
|
382
410
|
return this.createDeepAgentRunnable(binding);
|
|
383
411
|
}
|
|
@@ -425,25 +453,34 @@ export class AgentRuntimeAdapter {
|
|
|
425
453
|
});
|
|
426
454
|
return createDeepAgent(deepAgentConfig);
|
|
427
455
|
}
|
|
428
|
-
|
|
429
|
-
const
|
|
456
|
+
buildRunnableCacheKey(binding, threadId) {
|
|
457
|
+
const filesystemConfig = getBindingFilesystemConfig(binding);
|
|
458
|
+
const sessionStorage = typeof filesystemConfig?.sessionStorage === "object" && filesystemConfig.sessionStorage
|
|
459
|
+
? filesystemConfig.sessionStorage
|
|
460
|
+
: undefined;
|
|
461
|
+
const sessionScoped = sessionStorage?.enabled === true;
|
|
462
|
+
return `${binding.agent.sourcePath}::${sessionScoped ? (threadId ?? "__default__") : "__binding__"}`;
|
|
463
|
+
}
|
|
464
|
+
async create(binding, options = {}) {
|
|
465
|
+
const cacheKey = this.buildRunnableCacheKey(binding, options.threadId);
|
|
466
|
+
const cached = this.runnableCache.get(cacheKey);
|
|
430
467
|
if (cached) {
|
|
431
468
|
return cached;
|
|
432
469
|
}
|
|
433
|
-
const pending = this.createRunnable(binding);
|
|
434
|
-
this.runnableCache.set(
|
|
470
|
+
const pending = this.createRunnable(binding, options);
|
|
471
|
+
this.runnableCache.set(cacheKey, pending);
|
|
435
472
|
try {
|
|
436
473
|
return await pending;
|
|
437
474
|
}
|
|
438
475
|
catch (error) {
|
|
439
|
-
this.runnableCache.delete(
|
|
476
|
+
this.runnableCache.delete(cacheKey);
|
|
440
477
|
throw error;
|
|
441
478
|
}
|
|
442
479
|
}
|
|
443
480
|
async invoke(binding, input, threadId, runId, resumePayload, history = [], options = {}) {
|
|
444
481
|
const callRuntime = async (activeBinding, activeRequest) => {
|
|
445
482
|
return this.invokeWithProviderRetry(activeBinding, async () => {
|
|
446
|
-
const runnable = await this.create(activeBinding);
|
|
483
|
+
const runnable = await this.create(activeBinding, { threadId });
|
|
447
484
|
return (await this.withTimeout(() => runnable.invoke(activeRequest, resolveLangChainInvocationConfig(activeBinding, {
|
|
448
485
|
threadId,
|
|
449
486
|
runId,
|
|
@@ -469,7 +506,7 @@ export class AgentRuntimeAdapter {
|
|
|
469
506
|
invokeOptions: options,
|
|
470
507
|
resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
|
|
471
508
|
getToolNameMapping: (currentBinding) => this.getToolNameMapping(currentBinding),
|
|
472
|
-
resolveBuiltinMiddlewareTools: (currentBinding, currentOptions) => this.resolveBuiltinMiddlewareTools(currentBinding, currentOptions),
|
|
509
|
+
resolveBuiltinMiddlewareTools: (currentBinding, currentOptions) => this.resolveBuiltinMiddlewareTools(currentBinding, { ...currentOptions, threadId }),
|
|
473
510
|
callRuntimeWithToolParseRecovery,
|
|
474
511
|
});
|
|
475
512
|
}
|
|
@@ -494,7 +531,7 @@ export class AgentRuntimeAdapter {
|
|
|
494
531
|
forceInvokeFallback,
|
|
495
532
|
canUseDirectModelStream,
|
|
496
533
|
langChainStreamModel,
|
|
497
|
-
createRunnable: () => this.create(binding),
|
|
534
|
+
createRunnable: () => this.create(binding, { threadId }),
|
|
498
535
|
withTimeout: (producer, timeoutMs, operation, stage) => this.withTimeout(producer, timeoutMs, operation, stage),
|
|
499
536
|
iterateWithTimeout: (iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs) => this.iterateWithTimeout(iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs),
|
|
500
537
|
invokeTimeoutMs: computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs),
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { getBindingPrimaryTools } from "../../support/compiled-binding.js";
|
|
2
|
+
import { toolRequiresRuntimeApproval } from "../../adapter/tool/tool-hitl.js";
|
|
3
|
+
const WRITE_LIKE_PATTERN = /\b(write|edit|delete|create|update|append|insert|push|commit|publish|send|post|apply|merge|sync|upload|save)\b/i;
|
|
4
|
+
function inputHints(binding, tool) {
|
|
5
|
+
const hints = new Set();
|
|
6
|
+
const target = `${tool.name} ${tool.description}`.toLowerCase();
|
|
7
|
+
if (/(path|file|dir|directory|folder|workspace|repo|repository)/.test(target)) {
|
|
8
|
+
hints.add("filesystem-scope");
|
|
9
|
+
}
|
|
10
|
+
if (/(memory|knowledge|store|recall)/.test(target)) {
|
|
11
|
+
hints.add("memory-scope");
|
|
12
|
+
}
|
|
13
|
+
if (tool.config?.mcp) {
|
|
14
|
+
hints.add("remote-mcp");
|
|
15
|
+
}
|
|
16
|
+
if (binding.agent.executionMode === "deepagent") {
|
|
17
|
+
hints.add("delegated-runtime");
|
|
18
|
+
}
|
|
19
|
+
return Array.from(hints);
|
|
20
|
+
}
|
|
21
|
+
function classifyRisk(policy) {
|
|
22
|
+
if (policy.requiresApproval) {
|
|
23
|
+
return "high";
|
|
24
|
+
}
|
|
25
|
+
const target = `${policy.toolName} ${policy.description}`;
|
|
26
|
+
if (policy.toolType === "mcp" && WRITE_LIKE_PATTERN.test(target)) {
|
|
27
|
+
return "high";
|
|
28
|
+
}
|
|
29
|
+
if (policy.toolType === "backend" || policy.toolType === "mcp") {
|
|
30
|
+
return "medium";
|
|
31
|
+
}
|
|
32
|
+
return "low";
|
|
33
|
+
}
|
|
34
|
+
function toCategory(toolType) {
|
|
35
|
+
if (toolType === "mcp") {
|
|
36
|
+
return "mcp";
|
|
37
|
+
}
|
|
38
|
+
if (toolType === "backend") {
|
|
39
|
+
return "backend";
|
|
40
|
+
}
|
|
41
|
+
if (toolType === "provider") {
|
|
42
|
+
return "provider-native";
|
|
43
|
+
}
|
|
44
|
+
return "local";
|
|
45
|
+
}
|
|
46
|
+
export function buildRuntimeGovernanceBundles(binding) {
|
|
47
|
+
const toolPolicies = getBindingPrimaryTools(binding).map((tool) => {
|
|
48
|
+
const requiresApproval = toolRequiresRuntimeApproval(tool);
|
|
49
|
+
return {
|
|
50
|
+
toolName: tool.name,
|
|
51
|
+
toolId: tool.id,
|
|
52
|
+
toolType: tool.type,
|
|
53
|
+
category: toCategory(tool.type),
|
|
54
|
+
risk: classifyRisk({
|
|
55
|
+
toolType: tool.type,
|
|
56
|
+
requiresApproval,
|
|
57
|
+
toolName: tool.name,
|
|
58
|
+
description: tool.description,
|
|
59
|
+
config: tool.config,
|
|
60
|
+
}),
|
|
61
|
+
requiresApproval,
|
|
62
|
+
approvalPolicy: tool.hitl?.enabled === true ? "explicit-hitl" : requiresApproval ? "runtime-default" : "none",
|
|
63
|
+
hasInputSchema: typeof tool.inputSchemaRef === "string" && tool.inputSchemaRef.trim().length > 0,
|
|
64
|
+
inputRiskHints: inputHints(binding, tool),
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
if (toolPolicies.length === 0) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
return [{
|
|
71
|
+
bundleId: `governance/${binding.agent.id}`,
|
|
72
|
+
title: "Runtime tool governance",
|
|
73
|
+
summary: `${toolPolicies.filter((tool) => tool.requiresApproval).length} of ${toolPolicies.length} tool(s) require approval`,
|
|
74
|
+
toolPolicies,
|
|
75
|
+
}];
|
|
76
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readSkillMetadata } from "../../support/skill-metadata.js";
|
|
2
2
|
import { getBindingMemorySources, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSkills, getBindingSubagents, } from "../../support/compiled-binding.js";
|
|
3
|
+
import { buildRuntimeGovernanceBundles } from "./governance.js";
|
|
3
4
|
function asObject(value) {
|
|
4
5
|
return typeof value === "object" && value !== null ? value : null;
|
|
5
6
|
}
|
|
@@ -67,6 +68,9 @@ export function buildRunRuntimeSnapshot(binding, options) {
|
|
|
67
68
|
};
|
|
68
69
|
}),
|
|
69
70
|
memory: getBindingMemorySources(binding),
|
|
71
|
+
governance: {
|
|
72
|
+
bundles: buildRuntimeGovernanceBundles(binding),
|
|
73
|
+
},
|
|
70
74
|
...(tracing ? { tracing } : {}),
|
|
71
75
|
};
|
|
72
76
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type { CompiledAgentBinding } from "../../../contracts/types.js";
|
|
1
|
+
import type { CompiledAgentBinding, RuntimeGovernanceBundle } from "../../../contracts/types.js";
|
|
2
2
|
export type PolicyEngineDecision = {
|
|
3
3
|
allowed: boolean;
|
|
4
4
|
reasons: string[];
|
|
5
|
+
bundles?: RuntimeGovernanceBundle[];
|
|
5
6
|
};
|
|
6
7
|
export declare class PolicyEngine {
|
|
7
8
|
/**
|
|
@@ -7,6 +7,7 @@ export class PolicyEngine {
|
|
|
7
7
|
*/
|
|
8
8
|
evaluate(binding) {
|
|
9
9
|
const reasons = [];
|
|
10
|
+
const bundles = [];
|
|
10
11
|
let allowed = true;
|
|
11
12
|
for (const evaluator of getPolicyEvaluators()) {
|
|
12
13
|
const decision = evaluator.evaluate(binding);
|
|
@@ -17,8 +18,11 @@ export class PolicyEngine {
|
|
|
17
18
|
allowed = false;
|
|
18
19
|
}
|
|
19
20
|
reasons.push(...decision.reasons);
|
|
21
|
+
if (Array.isArray(decision.bundles)) {
|
|
22
|
+
bundles.push(...decision.bundles);
|
|
23
|
+
}
|
|
20
24
|
}
|
|
21
|
-
return { allowed, reasons };
|
|
25
|
+
return bundles.length > 0 ? { allowed, reasons, bundles } : { allowed, reasons };
|
|
22
26
|
}
|
|
23
27
|
}
|
|
24
28
|
export { PolicyEngine as GovernanceEngine, };
|
|
@@ -15,6 +15,9 @@ export declare function renderMemoryRecordsMarkdown(title: string, records: Memo
|
|
|
15
15
|
export declare function rebuildStructuredMemoryProjections(store: StoreLike, namespace: string[], title: string, scope: MemoryScope, maxEntries: number): Promise<void>;
|
|
16
16
|
export declare function listMemoryRecordsForScopes(store: StoreLike, scopes: MemoryScope[]): Promise<MemoryRecord[]>;
|
|
17
17
|
export declare function getMemoryRecord(store: StoreLike, scope: MemoryScope, recordId: string): Promise<MemoryRecord | null>;
|
|
18
|
+
export declare function findMemoryRecordById(store: StoreLike, recordId: string): Promise<MemoryRecord | null>;
|
|
19
|
+
export declare function updateMemoryRecord(store: StoreLike, record: MemoryRecord, updatedAt: string): Promise<MemoryRecord>;
|
|
20
|
+
export declare function removeMemoryRecord(store: StoreLike, scope: MemoryScope, recordId: string): Promise<MemoryRecord | null>;
|
|
18
21
|
export declare function persistStructuredMemoryRecords(options: PersistMemoryRecordsOptions): Promise<{
|
|
19
22
|
records: MemoryRecord[];
|
|
20
23
|
decisions: MemoryDecision[];
|
|
@@ -34,6 +34,12 @@ function createCanonicalKey(candidate, kind, scope) {
|
|
|
34
34
|
function buildScopeNamespace(scope) {
|
|
35
35
|
return ["memories", "records", scope];
|
|
36
36
|
}
|
|
37
|
+
function buildCanonicalIndexNamespace(scope) {
|
|
38
|
+
return ["memories", "indexes", "canonical", scope];
|
|
39
|
+
}
|
|
40
|
+
function buildSourceRefIndexNamespace(scope) {
|
|
41
|
+
return ["memories", "indexes", "source-ref", scope];
|
|
42
|
+
}
|
|
37
43
|
function normalizeTextForCompare(value) {
|
|
38
44
|
return value.toLowerCase().replace(/\s+/g, " ").trim();
|
|
39
45
|
}
|
|
@@ -312,7 +318,7 @@ function evaluateDecision(existing, incoming, recordedAt) {
|
|
|
312
318
|
async function putRecordWithIndexes(store, record, updatedAt) {
|
|
313
319
|
const canonicalKeyId = createFingerprint(record.canonicalKey);
|
|
314
320
|
await store.put(buildScopeNamespace(record.scope), `${record.id}.json`, record);
|
|
315
|
-
await store.put(
|
|
321
|
+
await store.put(buildCanonicalIndexNamespace(record.scope), `${canonicalKeyId}-${record.id}.json`, {
|
|
316
322
|
canonicalKey: record.canonicalKey,
|
|
317
323
|
recordId: record.id,
|
|
318
324
|
scope: record.scope,
|
|
@@ -321,7 +327,7 @@ async function putRecordWithIndexes(store, record, updatedAt) {
|
|
|
321
327
|
});
|
|
322
328
|
await Promise.all(record.sourceRefs.map((sourceRef) => {
|
|
323
329
|
const sourceRefId = createFingerprint(sourceRef);
|
|
324
|
-
return store.put(
|
|
330
|
+
return store.put(buildSourceRefIndexNamespace(record.scope), `${sourceRefId}-${record.id}.json`, {
|
|
325
331
|
sourceRef,
|
|
326
332
|
recordId: record.id,
|
|
327
333
|
scope: record.scope,
|
|
@@ -384,6 +390,46 @@ export async function getMemoryRecord(store, scope, recordId) {
|
|
|
384
390
|
const candidate = record;
|
|
385
391
|
return typeof candidate.id === "string" && typeof candidate.content === "string" ? candidate : null;
|
|
386
392
|
}
|
|
393
|
+
export async function findMemoryRecordById(store, recordId) {
|
|
394
|
+
for (const scope of MEMORY_SCOPES) {
|
|
395
|
+
const record = await getMemoryRecord(store, scope, recordId);
|
|
396
|
+
if (record) {
|
|
397
|
+
return record;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
async function deleteRecordIndexes(store, record) {
|
|
403
|
+
const [canonicalEntries, sourceRefEntries] = await Promise.all([
|
|
404
|
+
store.search(buildCanonicalIndexNamespace(record.scope)),
|
|
405
|
+
store.search(buildSourceRefIndexNamespace(record.scope)),
|
|
406
|
+
]);
|
|
407
|
+
await Promise.all([
|
|
408
|
+
...canonicalEntries
|
|
409
|
+
.filter((entry) => entry.value?.recordId === record.id)
|
|
410
|
+
.map((entry) => store.delete(entry.namespace, entry.key)),
|
|
411
|
+
...sourceRefEntries
|
|
412
|
+
.filter((entry) => entry.value?.recordId === record.id)
|
|
413
|
+
.map((entry) => store.delete(entry.namespace, entry.key)),
|
|
414
|
+
]);
|
|
415
|
+
}
|
|
416
|
+
export async function updateMemoryRecord(store, record, updatedAt) {
|
|
417
|
+
const existing = await getMemoryRecord(store, record.scope, record.id);
|
|
418
|
+
if (existing) {
|
|
419
|
+
await deleteRecordIndexes(store, existing);
|
|
420
|
+
}
|
|
421
|
+
await putRecordWithIndexes(store, record, updatedAt);
|
|
422
|
+
return record;
|
|
423
|
+
}
|
|
424
|
+
export async function removeMemoryRecord(store, scope, recordId) {
|
|
425
|
+
const existing = await getMemoryRecord(store, scope, recordId);
|
|
426
|
+
if (!existing) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
await deleteRecordIndexes(store, existing);
|
|
430
|
+
await store.delete(buildScopeNamespace(scope), `${recordId}.json`);
|
|
431
|
+
return existing;
|
|
432
|
+
}
|
|
387
433
|
export async function persistStructuredMemoryRecords(options) {
|
|
388
434
|
const existingRecords = await listStoredRecords(options.store);
|
|
389
435
|
const persistedRecords = [];
|