@botbotgo/agent-harness 0.0.55 → 0.0.57
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 +131 -56
- package/dist/api.d.ts +7 -0
- package/dist/api.js +6 -0
- package/dist/config/agents/direct.yaml +18 -0
- package/dist/config/agents/orchestra.yaml +10 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/resource/resource-impl.js +41 -9
- package/dist/runtime/agent-runtime-adapter.d.ts +8 -0
- package/dist/runtime/agent-runtime-adapter.js +126 -8
- package/dist/runtime/declared-middleware.d.ts +5 -0
- package/dist/runtime/declared-middleware.js +38 -2
- package/dist/runtime/harness.d.ts +7 -0
- package/dist/runtime/harness.js +7 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/inventory.d.ts +10 -5
- package/dist/runtime/inventory.js +50 -12
- package/dist/runtime/skill-requirements.d.ts +27 -0
- package/dist/runtime/skill-requirements.js +112 -0
- package/dist/runtime/support/runtime-env.d.ts +2 -0
- package/dist/runtime/support/runtime-env.js +57 -0
- package/dist/runtime/support/skill-metadata.d.ts +14 -1
- package/dist/runtime/support/skill-metadata.js +59 -7
- package/dist/workspace/validate.js +3 -0
- package/package.json +2 -2
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { existsSync, statSync } from "node:fs";
|
|
3
|
+
import { cp, mkdir, rm } from "node:fs/promises";
|
|
2
4
|
import { Command, MemorySaver } from "@langchain/langgraph";
|
|
3
5
|
import { tool as createLangChainTool } from "@langchain/core/tools";
|
|
4
6
|
import { createDeepAgent, createMemoryMiddleware, createSkillsMiddleware, createSubAgentMiddleware, FilesystemBackend, } from "deepagents";
|
|
@@ -16,6 +18,7 @@ import { wrapToolForExecution } from "./tool-hitl.js";
|
|
|
16
18
|
import { resolveDeclaredMiddleware } from "./declared-middleware.js";
|
|
17
19
|
import { extractMessageText, normalizeMessageContent } from "../utils/message-content.js";
|
|
18
20
|
import { getBindingDeepAgentParams, getBindingInterruptCompatibilityRules, getBindingLangChainParams, getBindingMiddlewareConfigs, getBindingModelInit, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSystemPrompt, isDeepAgentBinding, isLangChainBinding, } from "./support/compiled-binding.js";
|
|
21
|
+
import { readSkillMetadata } from "./support/skill-metadata.js";
|
|
19
22
|
function countConfiguredTools(binding) {
|
|
20
23
|
return getBindingPrimaryTools(binding).length;
|
|
21
24
|
}
|
|
@@ -52,6 +55,65 @@ function computeRemainingTimeoutMs(deadlineAt, fallbackTimeoutMs) {
|
|
|
52
55
|
function isPlaceholderApiKey(value) {
|
|
53
56
|
return typeof value === "string" && value.trim().toLowerCase() === "dummy";
|
|
54
57
|
}
|
|
58
|
+
export function relativizeDeepAgentSkillSourcePaths(workspaceRoot, skillPaths) {
|
|
59
|
+
if (!workspaceRoot || !skillPaths) {
|
|
60
|
+
return skillPaths;
|
|
61
|
+
}
|
|
62
|
+
return skillPaths.map((skillPath) => {
|
|
63
|
+
if (!path.isAbsolute(skillPath)) {
|
|
64
|
+
return skillPath;
|
|
65
|
+
}
|
|
66
|
+
const relative = path.relative(workspaceRoot, skillPath);
|
|
67
|
+
if (!relative || relative.startsWith("..")) {
|
|
68
|
+
return skillPath;
|
|
69
|
+
}
|
|
70
|
+
return relative.split(path.sep).join("/");
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function isDeepAgentSkillDirectory(sourcePath) {
|
|
74
|
+
return existsSync(sourcePath) && statSync(sourcePath).isDirectory() && existsSync(path.join(sourcePath, "SKILL.md"));
|
|
75
|
+
}
|
|
76
|
+
function toWorkspaceRelativePath(workspaceRoot, targetPath) {
|
|
77
|
+
if (!workspaceRoot) {
|
|
78
|
+
return targetPath;
|
|
79
|
+
}
|
|
80
|
+
const relative = path.relative(workspaceRoot, targetPath);
|
|
81
|
+
if (!relative || relative.startsWith("..")) {
|
|
82
|
+
return targetPath;
|
|
83
|
+
}
|
|
84
|
+
return relative.split(path.sep).join("/");
|
|
85
|
+
}
|
|
86
|
+
export async function materializeDeepAgentSkillSourcePaths(options) {
|
|
87
|
+
const { workspaceRoot, runRoot, ownerId, skillPaths } = options;
|
|
88
|
+
if (!skillPaths) {
|
|
89
|
+
return skillPaths;
|
|
90
|
+
}
|
|
91
|
+
const materialized = relativizeDeepAgentSkillSourcePaths(workspaceRoot, skillPaths) ?? skillPaths;
|
|
92
|
+
if (!workspaceRoot || !runRoot) {
|
|
93
|
+
return materialized;
|
|
94
|
+
}
|
|
95
|
+
const sourceRoot = path.join(runRoot, "deepagent-skill-sources", ownerId);
|
|
96
|
+
let wroteSyntheticSource = false;
|
|
97
|
+
const resolvedSources = [];
|
|
98
|
+
for (const [index, sourcePath] of materialized.entries()) {
|
|
99
|
+
const absolutePath = path.isAbsolute(sourcePath) ? sourcePath : path.resolve(workspaceRoot, sourcePath);
|
|
100
|
+
if (!isDeepAgentSkillDirectory(absolutePath)) {
|
|
101
|
+
resolvedSources.push(sourcePath);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (!wroteSyntheticSource) {
|
|
105
|
+
await rm(sourceRoot, { recursive: true, force: true });
|
|
106
|
+
await mkdir(sourceRoot, { recursive: true });
|
|
107
|
+
wroteSyntheticSource = true;
|
|
108
|
+
}
|
|
109
|
+
const skillDirectoryName = path.basename(absolutePath);
|
|
110
|
+
const syntheticSourcePath = path.join(sourceRoot, `${String(index + 1).padStart(3, "0")}-${skillDirectoryName}`);
|
|
111
|
+
await mkdir(syntheticSourcePath, { recursive: true });
|
|
112
|
+
await cp(absolutePath, path.join(syntheticSourcePath, skillDirectoryName), { recursive: true });
|
|
113
|
+
resolvedSources.push(toWorkspaceRelativePath(workspaceRoot, syntheticSourcePath));
|
|
114
|
+
}
|
|
115
|
+
return resolvedSources;
|
|
116
|
+
}
|
|
55
117
|
function buildAuthOmittingFetch(baseFetch = fetch) {
|
|
56
118
|
return async (input, init) => {
|
|
57
119
|
const sanitizedHeaders = new Headers(input instanceof Request ? input.headers : undefined);
|
|
@@ -399,11 +461,42 @@ export class AgentRuntimeAdapter {
|
|
|
399
461
|
{ role: "user", content: normalizeMessageContent(input) },
|
|
400
462
|
];
|
|
401
463
|
}
|
|
402
|
-
|
|
464
|
+
buildSlashCommandSkillInstruction(binding, input) {
|
|
465
|
+
const inputText = extractMessageText(input).trim();
|
|
466
|
+
const match = inputText.match(/^\/([a-z0-9]+(?:-[a-z0-9]+)*)(?:\s+([\s\S]*))?$/i);
|
|
467
|
+
if (!match) {
|
|
468
|
+
return undefined;
|
|
469
|
+
}
|
|
470
|
+
const invokedName = match[1].toLowerCase();
|
|
471
|
+
const argumentText = match[2]?.trim() ?? "";
|
|
472
|
+
const skillPaths = binding.deepAgentParams?.skills ?? binding.langchainAgentParams?.skills ?? [];
|
|
473
|
+
const matchedSkillPath = skillPaths.find((skillPath) => readSkillMetadata(skillPath).name.toLowerCase() === invokedName);
|
|
474
|
+
if (!matchedSkillPath) {
|
|
475
|
+
return undefined;
|
|
476
|
+
}
|
|
477
|
+
const metadata = readSkillMetadata(matchedSkillPath);
|
|
478
|
+
const skillQualifier = metadata.userInvocable === true ? "user-invocable skill" : "skill";
|
|
479
|
+
const dryRunHint = /\s--dry-run(?:\s|$)/.test(` ${argumentText} `)
|
|
480
|
+
? "This invocation includes `--dry-run`. Perform the real fetch or inspection steps needed for dry-run output. Do not return hypothetical or mock results."
|
|
481
|
+
: undefined;
|
|
482
|
+
return [
|
|
483
|
+
`This user message is an explicit command-style invocation of the ${skillQualifier} \`${metadata.name}\`.`,
|
|
484
|
+
`Read the skill file for \`${metadata.name}\` before taking action, then follow its documented phases and constraints exactly.`,
|
|
485
|
+
`You must use the \`${metadata.name}\` skill for this request and follow its documented workflow.`,
|
|
486
|
+
`Treat everything after \`/${metadata.name}\` as the skill argument string: ${argumentText ? JSON.stringify(argumentText) : '""'}.`,
|
|
487
|
+
"Do not answer with a generic explanation of what the skill would do. Execute the skill workflow using the available tools unless the skill instructions explicitly require confirmation before acting.",
|
|
488
|
+
dryRunHint,
|
|
489
|
+
].filter((line) => typeof line === "string" && line.length > 0).join("\n");
|
|
490
|
+
}
|
|
491
|
+
buildInvocationRequest(binding, history, input, options = {}) {
|
|
492
|
+
const userInvocableInstruction = this.buildSlashCommandSkillInstruction(binding, input);
|
|
493
|
+
const messages = this.buildAgentMessages(history, input);
|
|
403
494
|
return {
|
|
404
495
|
...(options.state ?? {}),
|
|
405
496
|
...(options.files ? { files: options.files } : {}),
|
|
406
|
-
messages:
|
|
497
|
+
messages: userInvocableInstruction
|
|
498
|
+
? [{ role: "system", content: userInvocableInstruction }, ...messages]
|
|
499
|
+
: messages,
|
|
407
500
|
};
|
|
408
501
|
}
|
|
409
502
|
buildStateSnapshot(result) {
|
|
@@ -414,11 +507,15 @@ export class AgentRuntimeAdapter {
|
|
|
414
507
|
delete snapshot.files;
|
|
415
508
|
return Object.keys(snapshot).length > 0 ? snapshot : undefined;
|
|
416
509
|
}
|
|
417
|
-
buildRawModelMessages(systemPrompt, history, input) {
|
|
510
|
+
buildRawModelMessages(binding, systemPrompt, history, input) {
|
|
418
511
|
const messages = [];
|
|
419
512
|
if (systemPrompt) {
|
|
420
513
|
messages.push({ role: "system", content: systemPrompt });
|
|
421
514
|
}
|
|
515
|
+
const userInvocableInstruction = this.buildSlashCommandSkillInstruction(binding, input);
|
|
516
|
+
if (userInvocableInstruction) {
|
|
517
|
+
messages.push({ role: "system", content: userInvocableInstruction });
|
|
518
|
+
}
|
|
422
519
|
messages.push(...this.buildAgentMessages(history, input));
|
|
423
520
|
return messages;
|
|
424
521
|
}
|
|
@@ -525,6 +622,8 @@ export class AgentRuntimeAdapter {
|
|
|
525
622
|
async resolveMiddleware(binding, interruptOn) {
|
|
526
623
|
const declarativeMiddleware = await resolveDeclaredMiddleware(getBindingMiddlewareConfigs(binding), {
|
|
527
624
|
resolveModel: (model) => this.resolveModel(model),
|
|
625
|
+
resolveBackend: (resolvedBinding) => this.options.backendResolver?.(resolvedBinding ?? binding),
|
|
626
|
+
resolveFilesystemBackend: (resolvedBinding) => this.resolveFilesystemBackend(resolvedBinding ?? binding),
|
|
528
627
|
resolveCustom: this.options.declaredMiddlewareResolver,
|
|
529
628
|
binding,
|
|
530
629
|
});
|
|
@@ -570,11 +669,25 @@ export class AgentRuntimeAdapter {
|
|
|
570
669
|
...(subagent.passthrough ?? {}),
|
|
571
670
|
model: subagent.model ? (await this.resolveModel(subagent.model)) : undefined,
|
|
572
671
|
tools: subagent.tools ? this.resolveTools(subagent.tools) : undefined,
|
|
672
|
+
skills: await materializeDeepAgentSkillSourcePaths({
|
|
673
|
+
workspaceRoot: binding?.harnessRuntime.workspaceRoot,
|
|
674
|
+
runRoot: binding?.harnessRuntime.runRoot,
|
|
675
|
+
ownerId: `${binding?.agent.id ?? "agent"}-${subagent.name}`,
|
|
676
|
+
skillPaths: subagent.skills,
|
|
677
|
+
}),
|
|
573
678
|
interruptOn: this.compileInterruptOn(subagent.tools ?? [], subagent.interruptOn),
|
|
574
679
|
responseFormat: subagent.responseFormat,
|
|
575
680
|
contextSchema: subagent.contextSchema,
|
|
576
681
|
middleware: (await resolveDeclaredMiddleware(subagent.middleware, {
|
|
577
682
|
resolveModel: (model) => this.resolveModel(model),
|
|
683
|
+
resolveBackend: (resolvedBinding) => {
|
|
684
|
+
const targetBinding = resolvedBinding ?? binding;
|
|
685
|
+
return targetBinding ? this.options.backendResolver?.(targetBinding) : undefined;
|
|
686
|
+
},
|
|
687
|
+
resolveFilesystemBackend: (resolvedBinding) => {
|
|
688
|
+
const targetBinding = resolvedBinding ?? binding;
|
|
689
|
+
return targetBinding ? this.resolveFilesystemBackend(targetBinding) : undefined;
|
|
690
|
+
},
|
|
578
691
|
resolveCustom: this.options.declaredMiddlewareResolver,
|
|
579
692
|
binding,
|
|
580
693
|
})),
|
|
@@ -625,7 +738,12 @@ export class AgentRuntimeAdapter {
|
|
|
625
738
|
interruptOn: this.resolveInterruptOn(binding),
|
|
626
739
|
name: params.name,
|
|
627
740
|
memory: params.memory,
|
|
628
|
-
skills:
|
|
741
|
+
skills: await materializeDeepAgentSkillSourcePaths({
|
|
742
|
+
workspaceRoot: binding.harnessRuntime.workspaceRoot,
|
|
743
|
+
runRoot: binding.harnessRuntime.runRoot,
|
|
744
|
+
ownerId: binding.agent.id,
|
|
745
|
+
skillPaths: params.skills,
|
|
746
|
+
}),
|
|
629
747
|
generalPurposeAgent: params.generalPurposeAgent,
|
|
630
748
|
taskDescription: params.taskDescription,
|
|
631
749
|
};
|
|
@@ -660,7 +778,7 @@ export class AgentRuntimeAdapter {
|
|
|
660
778
|
}
|
|
661
779
|
async invoke(binding, input, threadId, runId, resumePayload, history = [], options = {}) {
|
|
662
780
|
const request = resumePayload === undefined
|
|
663
|
-
? this.buildInvocationRequest(history, input, options)
|
|
781
|
+
? this.buildInvocationRequest(binding, history, input, options)
|
|
664
782
|
: new Command({ resume: resumePayload });
|
|
665
783
|
let result;
|
|
666
784
|
try {
|
|
@@ -673,7 +791,7 @@ export class AgentRuntimeAdapter {
|
|
|
673
791
|
}
|
|
674
792
|
const retriedBinding = this.applyStrictToolJsonInstruction(binding);
|
|
675
793
|
const runnable = await this.create(retriedBinding);
|
|
676
|
-
result = (await this.withTimeout(() => runnable.invoke(this.buildInvocationRequest(history, input, options), { configurable: { thread_id: threadId }, ...(options.context ? { context: options.context } : {}) }), this.resolveBindingTimeout(retriedBinding), "agent invoke", "invoke"));
|
|
794
|
+
result = (await this.withTimeout(() => runnable.invoke(this.buildInvocationRequest(retriedBinding, history, input, options), { configurable: { thread_id: threadId }, ...(options.context ? { context: options.context } : {}) }), this.resolveBindingTimeout(retriedBinding), "agent invoke", "invoke"));
|
|
677
795
|
}
|
|
678
796
|
const interruptContent = Array.isArray(result.__interrupt__) && result.__interrupt__.length > 0 ? JSON.stringify(result.__interrupt__) : undefined;
|
|
679
797
|
const extractedOutput = extractVisibleOutput(result);
|
|
@@ -729,7 +847,7 @@ export class AgentRuntimeAdapter {
|
|
|
729
847
|
// agent loop and only adds an extra model round-trip before the runnable path.
|
|
730
848
|
if (canUseDirectModelStream && typeof model.stream === "function") {
|
|
731
849
|
let emitted = false;
|
|
732
|
-
const stream = await this.withTimeout(() => model.stream(this.buildRawModelMessages(getBindingSystemPrompt(binding), history, input)), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "model stream start", "stream");
|
|
850
|
+
const stream = await this.withTimeout(() => model.stream(this.buildRawModelMessages(binding, getBindingSystemPrompt(binding), history, input)), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "model stream start", "stream");
|
|
733
851
|
for await (const chunk of this.iterateWithTimeout(stream, streamIdleTimeoutMs, "model stream", streamDeadlineAt, invokeTimeoutMs)) {
|
|
734
852
|
const delta = readStreamDelta(chunk);
|
|
735
853
|
if (delta) {
|
|
@@ -748,7 +866,7 @@ export class AgentRuntimeAdapter {
|
|
|
748
866
|
}
|
|
749
867
|
}
|
|
750
868
|
const runnable = await this.create(binding);
|
|
751
|
-
const request = this.buildInvocationRequest(history, input, options);
|
|
869
|
+
const request = this.buildInvocationRequest(binding, history, input, options);
|
|
752
870
|
if (typeof runnable.streamEvents === "function") {
|
|
753
871
|
const events = await this.withTimeout(() => runnable.streamEvents(request, { configurable: { thread_id: threadId }, version: "v2", ...(options.context ? { context: options.context } : {}) }), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "agent streamEvents start", "stream");
|
|
754
872
|
const allowVisibleStreamDeltas = isLangChainBinding(binding);
|
|
@@ -3,12 +3,17 @@ type MiddlewareConfig = Record<string, unknown>;
|
|
|
3
3
|
type MiddlewareFactoryContext = {
|
|
4
4
|
config: MiddlewareConfig;
|
|
5
5
|
resolveModel: (model: CompiledModel) => Promise<unknown>;
|
|
6
|
+
resolveBackend?: () => unknown;
|
|
7
|
+
resolveFilesystemBackend?: () => unknown;
|
|
8
|
+
binding?: CompiledAgentBinding;
|
|
6
9
|
};
|
|
7
10
|
type MiddlewareFactory = (context: MiddlewareFactoryContext) => Promise<unknown | unknown[] | null | undefined>;
|
|
8
11
|
export declare const DECLARATIVE_MIDDLEWARE_REGISTRY: Record<string, MiddlewareFactory>;
|
|
9
12
|
export declare const SUPPORTED_DECLARATIVE_MIDDLEWARE_KINDS: readonly string[];
|
|
10
13
|
export declare function resolveDeclaredMiddleware(middlewareConfigs: unknown[] | undefined, options: {
|
|
11
14
|
resolveModel: (model: CompiledModel) => Promise<unknown>;
|
|
15
|
+
resolveBackend?: (binding?: CompiledAgentBinding) => unknown;
|
|
16
|
+
resolveFilesystemBackend?: (binding?: CompiledAgentBinding) => unknown;
|
|
12
17
|
resolveCustom?: (input: {
|
|
13
18
|
kind: string;
|
|
14
19
|
config: Record<string, unknown>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { anthropicPromptCachingMiddleware, contextEditingMiddleware, humanInTheLoopMiddleware, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, piiMiddleware, summarizationMiddleware, todoListMiddleware, toolCallLimitMiddleware, toolEmulatorMiddleware, toolRetryMiddleware, } from "langchain";
|
|
1
|
+
import { anthropicPromptCachingMiddleware, contextEditingMiddleware, dynamicSystemPromptMiddleware, humanInTheLoopMiddleware, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, piiMiddleware, piiRedactionMiddleware, summarizationMiddleware, todoListMiddleware, toolCallLimitMiddleware, toolEmulatorMiddleware, toolRetryMiddleware, } from "langchain";
|
|
2
|
+
import { createFilesystemMiddleware, createPatchToolCallsMiddleware, createSummarizationMiddleware as createDeepAgentSummarizationMiddleware, } from "deepagents";
|
|
2
3
|
function asMiddlewareConfig(value) {
|
|
3
4
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? { ...value } : null;
|
|
4
5
|
}
|
|
@@ -26,6 +27,18 @@ async function resolveReferencedModelList(values, options) {
|
|
|
26
27
|
return Promise.all(values.map((value) => resolveReferencedModel(value, options)));
|
|
27
28
|
}
|
|
28
29
|
async function createSummarizationMiddleware({ config, resolveModel }) {
|
|
30
|
+
if (config.provider === "deepagents") {
|
|
31
|
+
const runtimeConfig = { ...config };
|
|
32
|
+
runtimeConfig.model = await resolveReferencedModel(runtimeConfig.model, { resolveModel });
|
|
33
|
+
if (runtimeConfig.model === undefined) {
|
|
34
|
+
throw new Error("deepagents summarization middleware requires model or modelRef");
|
|
35
|
+
}
|
|
36
|
+
if (runtimeConfig.backend === undefined) {
|
|
37
|
+
throw new Error("deepagents summarization middleware requires backend");
|
|
38
|
+
}
|
|
39
|
+
delete runtimeConfig.provider;
|
|
40
|
+
return createDeepAgentSummarizationMiddleware(runtimeConfig);
|
|
41
|
+
}
|
|
29
42
|
const runtimeConfig = { ...config };
|
|
30
43
|
runtimeConfig.model = await resolveReferencedModel(runtimeConfig.model, { resolveModel });
|
|
31
44
|
if (runtimeConfig.model === undefined) {
|
|
@@ -33,6 +46,17 @@ async function createSummarizationMiddleware({ config, resolveModel }) {
|
|
|
33
46
|
}
|
|
34
47
|
return summarizationMiddleware(runtimeConfig);
|
|
35
48
|
}
|
|
49
|
+
async function createBindingAwareSummarizationMiddleware(context) {
|
|
50
|
+
const runtimeConfig = { ...context.config };
|
|
51
|
+
if (context.binding?.agent.executionMode === "deepagent") {
|
|
52
|
+
runtimeConfig.provider = "deepagents";
|
|
53
|
+
runtimeConfig.backend ??= context.resolveBackend?.() ?? context.resolveFilesystemBackend?.();
|
|
54
|
+
}
|
|
55
|
+
return createSummarizationMiddleware({
|
|
56
|
+
...context,
|
|
57
|
+
config: runtimeConfig,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
36
60
|
async function createLlmToolSelectorMiddleware({ config, resolveModel }) {
|
|
37
61
|
const runtimeConfig = { ...config };
|
|
38
62
|
runtimeConfig.model = await resolveReferencedModel(runtimeConfig.model, { resolveModel });
|
|
@@ -54,8 +78,15 @@ async function createPiiDeclarativeMiddleware({ config }) {
|
|
|
54
78
|
const { piiType: _piiType, ...piiOptions } = config;
|
|
55
79
|
return piiMiddleware(piiType, piiOptions);
|
|
56
80
|
}
|
|
81
|
+
async function createFilesystemDeclarativeMiddleware({ config, resolveFilesystemBackend }) {
|
|
82
|
+
const runtimeConfig = { ...config };
|
|
83
|
+
runtimeConfig.backend ??= resolveFilesystemBackend?.();
|
|
84
|
+
return createFilesystemMiddleware(runtimeConfig);
|
|
85
|
+
}
|
|
57
86
|
export const DECLARATIVE_MIDDLEWARE_REGISTRY = {
|
|
58
|
-
|
|
87
|
+
filesystem: createFilesystemDeclarativeMiddleware,
|
|
88
|
+
patchToolCalls: async () => createPatchToolCallsMiddleware(),
|
|
89
|
+
summarization: createBindingAwareSummarizationMiddleware,
|
|
59
90
|
llmToolSelector: createLlmToolSelectorMiddleware,
|
|
60
91
|
modelRetry: async ({ config }) => modelRetryMiddleware(config),
|
|
61
92
|
modelFallback: createModelFallbackDeclarativeMiddleware,
|
|
@@ -64,10 +95,12 @@ export const DECLARATIVE_MIDDLEWARE_REGISTRY = {
|
|
|
64
95
|
modelCallLimit: async ({ config }) => modelCallLimitMiddleware(config),
|
|
65
96
|
todoList: async ({ config }) => todoListMiddleware(config),
|
|
66
97
|
contextEditing: async ({ config }) => contextEditingMiddleware(config),
|
|
98
|
+
dynamicSystemPrompt: async ({ config }) => dynamicSystemPromptMiddleware(config),
|
|
67
99
|
toolEmulator: async ({ config }) => toolEmulatorMiddleware(config),
|
|
68
100
|
humanInTheLoop: async ({ config }) => humanInTheLoopMiddleware(config),
|
|
69
101
|
openAIModeration: async ({ config }) => openAIModerationMiddleware(config),
|
|
70
102
|
pii: createPiiDeclarativeMiddleware,
|
|
103
|
+
piiRedaction: async ({ config }) => piiRedactionMiddleware(config),
|
|
71
104
|
anthropicPromptCaching: async ({ config }) => anthropicPromptCachingMiddleware(config),
|
|
72
105
|
};
|
|
73
106
|
export const SUPPORTED_DECLARATIVE_MIDDLEWARE_KINDS = Object.freeze(Object.keys(DECLARATIVE_MIDDLEWARE_REGISTRY).sort());
|
|
@@ -85,6 +118,9 @@ export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
|
|
|
85
118
|
const resolvedBuiltin = await registeredFactory({
|
|
86
119
|
config: runtimeConfig,
|
|
87
120
|
resolveModel: options.resolveModel,
|
|
121
|
+
resolveBackend: () => options.resolveBackend?.(options.binding),
|
|
122
|
+
resolveFilesystemBackend: () => options.resolveFilesystemBackend?.(options.binding),
|
|
123
|
+
binding: options.binding,
|
|
88
124
|
});
|
|
89
125
|
if (Array.isArray(resolvedBuiltin)) {
|
|
90
126
|
resolved.push(...resolvedBuiltin);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ApprovalRecord, HarnessEvent, HarnessStreamItem, MessageContent, RunStartOptions, RestartConversationOptions, RuntimeAdapterOptions, ResumeOptions, RunOptions, RunResult, ThreadSummary, ThreadRecord, WorkspaceBundle } from "../contracts/types.js";
|
|
2
2
|
import { type ToolMcpServerOptions } from "../mcp.js";
|
|
3
|
+
import { type InventoryAgentRecord, type InventorySkillRecord } from "./inventory.js";
|
|
4
|
+
import type { RequirementAssessmentOptions } from "./skill-requirements.js";
|
|
3
5
|
export declare class AgentHarnessRuntime {
|
|
4
6
|
private readonly workspace;
|
|
5
7
|
private readonly runtimeAdapterOptions;
|
|
@@ -53,6 +55,11 @@ export declare class AgentHarnessRuntime {
|
|
|
53
55
|
runId?: string;
|
|
54
56
|
}): Promise<ApprovalRecord[]>;
|
|
55
57
|
getApproval(approvalId: string): Promise<ApprovalRecord | null>;
|
|
58
|
+
listAgentSkills(agentId: string, options?: RequirementAssessmentOptions): InventorySkillRecord[];
|
|
59
|
+
describeWorkspaceInventory(options?: RequirementAssessmentOptions): {
|
|
60
|
+
workspaceRoot: string;
|
|
61
|
+
agents: InventoryAgentRecord[];
|
|
62
|
+
};
|
|
56
63
|
private deleteThreadCheckpoints;
|
|
57
64
|
deleteThread(threadId: string): Promise<boolean>;
|
|
58
65
|
createToolMcpServer(options: ToolMcpServerOptions): Promise<import("@modelcontextprotocol/sdk/server/mcp.js").McpServer>;
|
package/dist/runtime/harness.js
CHANGED
|
@@ -16,6 +16,7 @@ import { CheckpointMaintenanceLoop, discoverCheckpointMaintenanceTargets, readCh
|
|
|
16
16
|
import { extractMessageText, normalizeMessageContent } from "../utils/message-content.js";
|
|
17
17
|
import { createToolMcpServerFromTools, serveToolsOverStdioFromHarness } from "../mcp.js";
|
|
18
18
|
import { getBindingAdapterKind, getBindingPrimaryTools, getBindingStoreConfig } from "./support/compiled-binding.js";
|
|
19
|
+
import { describeWorkspaceInventory, listAgentSkills as listWorkspaceAgentSkills, } from "./inventory.js";
|
|
19
20
|
export class AgentHarnessRuntime {
|
|
20
21
|
workspace;
|
|
21
22
|
runtimeAdapterOptions;
|
|
@@ -286,6 +287,12 @@ export class AgentHarnessRuntime {
|
|
|
286
287
|
const approval = await this.persistence.getApproval(approvalId);
|
|
287
288
|
return approval ? this.toPublicApprovalRecord(approval) : null;
|
|
288
289
|
}
|
|
290
|
+
listAgentSkills(agentId, options = {}) {
|
|
291
|
+
return listWorkspaceAgentSkills(this.workspace, agentId, options);
|
|
292
|
+
}
|
|
293
|
+
describeWorkspaceInventory(options = {}) {
|
|
294
|
+
return describeWorkspaceInventory(this.workspace, options);
|
|
295
|
+
}
|
|
289
296
|
async deleteThreadCheckpoints(threadId) {
|
|
290
297
|
const resolver = this.resolvedRuntimeAdapterOptions.checkpointerResolver;
|
|
291
298
|
if (!resolver) {
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { CheckpointMaintenanceLoop, discoverCheckpointMaintenanceTargets, mainta
|
|
|
6
6
|
export { ManagedSqliteSaver } from "./sqlite-maintained-checkpoint-saver.js";
|
|
7
7
|
export { AgentHarnessRuntime, AgentHarness } from "./harness.js";
|
|
8
8
|
export { describeWorkspaceInventory, findAgentBinding, listAgentSkills, listAgentTools, listAvailableAgents, listSpecialists, } from "./inventory.js";
|
|
9
|
+
export { assessOpenClawRequirements, assessSkillRequirements, } from "./skill-requirements.js";
|
|
9
10
|
export * from "./parsing/index.js";
|
|
10
11
|
export { PolicyEngine } from "./policy-engine.js";
|
|
11
12
|
export { createInMemoryStore, FileBackedStore } from "./store.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export { CheckpointMaintenanceLoop, discoverCheckpointMaintenanceTargets, mainta
|
|
|
6
6
|
export { ManagedSqliteSaver } from "./sqlite-maintained-checkpoint-saver.js";
|
|
7
7
|
export { AgentHarnessRuntime, AgentHarness } from "./harness.js";
|
|
8
8
|
export { describeWorkspaceInventory, findAgentBinding, listAgentSkills, listAgentTools, listAvailableAgents, listSpecialists, } from "./inventory.js";
|
|
9
|
+
export { assessOpenClawRequirements, assessSkillRequirements, } from "./skill-requirements.js";
|
|
9
10
|
export * from "./parsing/index.js";
|
|
10
11
|
export { PolicyEngine } from "./policy-engine.js";
|
|
11
12
|
export { createInMemoryStore, FileBackedStore } from "./store.js";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { CompiledAgentBinding, WorkspaceBundle } from "../contracts/types.js";
|
|
2
|
+
import type { OpenClawSkillMetadata } from "./support/skill-metadata.js";
|
|
3
|
+
import { type RequirementAssessmentOptions, type SkillRequirementAssessment } from "./skill-requirements.js";
|
|
2
4
|
export type InventoryToolRecord = {
|
|
3
5
|
name: string;
|
|
4
6
|
description: string;
|
|
@@ -9,8 +11,11 @@ export type InventorySkillRecord = {
|
|
|
9
11
|
description?: string;
|
|
10
12
|
license?: string;
|
|
11
13
|
compatibility?: string;
|
|
12
|
-
metadata?: Record<string,
|
|
14
|
+
metadata?: Record<string, unknown>;
|
|
13
15
|
allowedTools?: string[];
|
|
16
|
+
userInvocable?: boolean;
|
|
17
|
+
openclaw?: OpenClawSkillMetadata;
|
|
18
|
+
requirements?: SkillRequirementAssessment;
|
|
14
19
|
};
|
|
15
20
|
export type InventoryAgentRecord = {
|
|
16
21
|
id: string;
|
|
@@ -21,10 +26,10 @@ export type InventoryAgentRecord = {
|
|
|
21
26
|
};
|
|
22
27
|
export declare function findAgentBinding(workspace: WorkspaceBundle, agentId: string): CompiledAgentBinding | undefined;
|
|
23
28
|
export declare function listAgentTools(workspace: WorkspaceBundle, agentId: string): InventoryToolRecord[];
|
|
24
|
-
export declare function listAgentSkills(workspace: WorkspaceBundle, agentId: string): InventorySkillRecord[];
|
|
25
|
-
export declare function listSpecialists(workspace: WorkspaceBundle): InventoryAgentRecord[];
|
|
26
|
-
export declare function listAvailableAgents(workspace: WorkspaceBundle): InventoryAgentRecord[];
|
|
27
|
-
export declare function describeWorkspaceInventory(workspace: WorkspaceBundle): {
|
|
29
|
+
export declare function listAgentSkills(workspace: WorkspaceBundle, agentId: string, options?: RequirementAssessmentOptions): InventorySkillRecord[];
|
|
30
|
+
export declare function listSpecialists(workspace: WorkspaceBundle, options?: RequirementAssessmentOptions): InventoryAgentRecord[];
|
|
31
|
+
export declare function listAvailableAgents(workspace: WorkspaceBundle, options?: RequirementAssessmentOptions): InventoryAgentRecord[];
|
|
32
|
+
export declare function describeWorkspaceInventory(workspace: WorkspaceBundle, options?: RequirementAssessmentOptions): {
|
|
28
33
|
workspaceRoot: string;
|
|
29
34
|
agents: InventoryAgentRecord[];
|
|
30
35
|
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { readSkillMetadata } from "./support/skill-metadata.js";
|
|
2
2
|
import { getBindingPrimaryTools } from "./support/compiled-binding.js";
|
|
3
|
+
import { assessSkillRequirements, } from "./skill-requirements.js";
|
|
4
|
+
import { createRuntimeEnv } from "./support/runtime-env.js";
|
|
3
5
|
function listHostBindings(workspace) {
|
|
4
6
|
return Array.from(workspace.bindings.values()).filter((binding) => binding.harnessRuntime.hostFacing);
|
|
5
7
|
}
|
|
@@ -13,7 +15,36 @@ function dedupeTools(tools) {
|
|
|
13
15
|
}
|
|
14
16
|
return Array.from(deduped.values());
|
|
15
17
|
}
|
|
16
|
-
function
|
|
18
|
+
function readBackendRequirementOptions(binding) {
|
|
19
|
+
const backend = binding.deepAgentParams?.backend && typeof binding.deepAgentParams.backend === "object"
|
|
20
|
+
? binding.deepAgentParams.backend
|
|
21
|
+
: undefined;
|
|
22
|
+
if (!backend) {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
const backendState = typeof backend.state === "object" && backend.state
|
|
26
|
+
? backend.state
|
|
27
|
+
: backend;
|
|
28
|
+
const env = typeof backendState.env === "object" && backendState.env
|
|
29
|
+
? Object.fromEntries(Object.entries(backendState.env).filter((entry) => typeof entry[1] === "string"))
|
|
30
|
+
: undefined;
|
|
31
|
+
const inheritedEnv = backendState.inheritEnv === false ? {} : process.env;
|
|
32
|
+
const runtimeEnv = createRuntimeEnv(env, inheritedEnv);
|
|
33
|
+
return {
|
|
34
|
+
env: runtimeEnv,
|
|
35
|
+
path: runtimeEnv.PATH,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function mergeRequirementOptions(binding, options = {}) {
|
|
39
|
+
const fromBackend = readBackendRequirementOptions(binding);
|
|
40
|
+
return {
|
|
41
|
+
...fromBackend,
|
|
42
|
+
...options,
|
|
43
|
+
env: options.env ? { ...(fromBackend.env ?? {}), ...options.env } : fromBackend.env,
|
|
44
|
+
path: options.path ?? fromBackend.path,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function toSkillRecords(skillPaths, options = {}) {
|
|
17
48
|
return Array.from(new Set(skillPaths)).map((skillPath) => {
|
|
18
49
|
const metadata = readSkillMetadata(skillPath);
|
|
19
50
|
return {
|
|
@@ -24,6 +55,9 @@ function toSkillRecords(skillPaths) {
|
|
|
24
55
|
compatibility: metadata.compatibility,
|
|
25
56
|
metadata: metadata.metadata,
|
|
26
57
|
allowedTools: metadata.allowedTools,
|
|
58
|
+
userInvocable: metadata.userInvocable,
|
|
59
|
+
openclaw: metadata.openclaw,
|
|
60
|
+
requirements: assessSkillRequirements(metadata, options),
|
|
27
61
|
};
|
|
28
62
|
});
|
|
29
63
|
}
|
|
@@ -34,38 +68,42 @@ export function listAgentTools(workspace, agentId) {
|
|
|
34
68
|
}
|
|
35
69
|
return dedupeTools(getBindingPrimaryTools(binding));
|
|
36
70
|
}
|
|
37
|
-
export function listAgentSkills(workspace, agentId) {
|
|
71
|
+
export function listAgentSkills(workspace, agentId, options = {}) {
|
|
38
72
|
const binding = findAgentBinding(workspace, agentId);
|
|
39
73
|
if (!binding) {
|
|
40
74
|
return [];
|
|
41
75
|
}
|
|
42
|
-
|
|
76
|
+
const resolvedOptions = mergeRequirementOptions(binding, options);
|
|
77
|
+
return toSkillRecords(binding.deepAgentParams?.skills ?? binding.langchainAgentParams?.skills ?? [], resolvedOptions);
|
|
43
78
|
}
|
|
44
|
-
function describeSubagent(subagent) {
|
|
79
|
+
function describeSubagent(subagent, options = {}) {
|
|
45
80
|
return {
|
|
46
81
|
id: subagent.name,
|
|
47
82
|
description: subagent.description,
|
|
48
83
|
role: "specialist",
|
|
49
84
|
tools: dedupeTools(subagent.tools ?? []),
|
|
50
|
-
skills: toSkillRecords(subagent.skills ?? []),
|
|
85
|
+
skills: toSkillRecords(subagent.skills ?? [], options),
|
|
51
86
|
};
|
|
52
87
|
}
|
|
53
|
-
export function listSpecialists(workspace) {
|
|
54
|
-
return listHostBindings(workspace).flatMap((binding) =>
|
|
88
|
+
export function listSpecialists(workspace, options = {}) {
|
|
89
|
+
return listHostBindings(workspace).flatMap((binding) => {
|
|
90
|
+
const resolvedOptions = mergeRequirementOptions(binding, options);
|
|
91
|
+
return (binding.deepAgentParams?.subagents ?? []).map((subagent) => describeSubagent(subagent, resolvedOptions));
|
|
92
|
+
});
|
|
55
93
|
}
|
|
56
|
-
export function listAvailableAgents(workspace) {
|
|
94
|
+
export function listAvailableAgents(workspace, options = {}) {
|
|
57
95
|
const topLevel = listHostBindings(workspace).map((binding) => ({
|
|
58
96
|
id: binding.agent.id,
|
|
59
97
|
description: binding.agent.description,
|
|
60
98
|
role: "host",
|
|
61
99
|
tools: listAgentTools(workspace, binding.agent.id),
|
|
62
|
-
skills: listAgentSkills(workspace, binding.agent.id),
|
|
100
|
+
skills: listAgentSkills(workspace, binding.agent.id, options),
|
|
63
101
|
}));
|
|
64
|
-
return [...topLevel, ...listSpecialists(workspace)];
|
|
102
|
+
return [...topLevel, ...listSpecialists(workspace, options)];
|
|
65
103
|
}
|
|
66
|
-
export function describeWorkspaceInventory(workspace) {
|
|
104
|
+
export function describeWorkspaceInventory(workspace, options = {}) {
|
|
67
105
|
return {
|
|
68
106
|
workspaceRoot: workspace.workspaceRoot,
|
|
69
|
-
agents: listAvailableAgents(workspace),
|
|
107
|
+
agents: listAvailableAgents(workspace, options),
|
|
70
108
|
};
|
|
71
109
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { OpenClawSkillMetadata, SkillMetadata } from "./support/skill-metadata.js";
|
|
2
|
+
export type RequirementStatus = "satisfied" | "missing" | "unknown";
|
|
3
|
+
export type RequirementCheckRecord = {
|
|
4
|
+
name: string;
|
|
5
|
+
status: RequirementStatus;
|
|
6
|
+
};
|
|
7
|
+
export type OpenClawRequirementAssessment = {
|
|
8
|
+
ready: boolean;
|
|
9
|
+
missing: boolean;
|
|
10
|
+
unknown: boolean;
|
|
11
|
+
bins: RequirementCheckRecord[];
|
|
12
|
+
anyBins: RequirementCheckRecord[];
|
|
13
|
+
env: RequirementCheckRecord[];
|
|
14
|
+
config: RequirementCheckRecord[];
|
|
15
|
+
primaryEnv?: RequirementCheckRecord;
|
|
16
|
+
};
|
|
17
|
+
export type SkillRequirementAssessment = {
|
|
18
|
+
openclaw?: OpenClawRequirementAssessment;
|
|
19
|
+
};
|
|
20
|
+
export type RequirementAssessmentOptions = {
|
|
21
|
+
env?: Record<string, string | undefined>;
|
|
22
|
+
path?: string;
|
|
23
|
+
availableBins?: string[];
|
|
24
|
+
config?: Record<string, unknown> | string[];
|
|
25
|
+
};
|
|
26
|
+
export declare function assessOpenClawRequirements(metadata: OpenClawSkillMetadata | undefined, options?: RequirementAssessmentOptions): OpenClawRequirementAssessment | undefined;
|
|
27
|
+
export declare function assessSkillRequirements(metadata: SkillMetadata, options?: RequirementAssessmentOptions): SkillRequirementAssessment;
|