@botbotgo/agent-harness 0.0.37 → 0.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -137
- package/dist/api.d.ts +15 -12
- package/dist/api.js +25 -41
- package/dist/config/embedding-model.yaml +2 -2
- package/dist/config/workspace.yaml +37 -3
- package/dist/contracts/types.d.ts +17 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +8 -3
- package/dist/mcp.js +10 -11
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/resource/resource-impl.d.ts +2 -1
- package/dist/resource/resource-impl.js +16 -11
- package/dist/resource/resource.d.ts +1 -1
- package/dist/resource/resource.js +1 -1
- package/dist/runtime/agent-runtime-adapter.js +4 -2
- package/dist/runtime/event-bus.d.ts +5 -4
- package/dist/runtime/event-bus.js +7 -9
- package/dist/runtime/event-sink.d.ts +9 -0
- package/dist/runtime/event-sink.js +35 -0
- package/dist/runtime/harness.d.ts +21 -12
- package/dist/runtime/harness.js +81 -31
- package/dist/runtime/index.d.ts +3 -1
- package/dist/runtime/index.js +2 -1
- package/dist/runtime/parsing/stream-event-parsing.d.ts +2 -0
- package/dist/runtime/parsing/stream-event-parsing.js +35 -3
- package/dist/runtime/support/harness-support.d.ts +1 -0
- package/dist/runtime/support/harness-support.js +38 -4
- package/dist/runtime/thread-memory-sync.d.ts +4 -2
- package/dist/runtime/thread-memory-sync.js +10 -1
- package/dist/workspace/agent-binding-compiler.js +0 -3
- package/dist/workspace/compile.js +0 -1
- package/dist/workspace/support/discovery.js +11 -8
- package/dist/workspace/support/source-collectors.js +1 -1
- package/dist/workspace/support/workspace-ref-utils.d.ts +19 -0
- package/dist/workspace/support/workspace-ref-utils.js +112 -6
- package/package.json +3 -3
|
@@ -50,6 +50,31 @@ function summarizeStepValue(value) {
|
|
|
50
50
|
function humanizeEventName(name) {
|
|
51
51
|
return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[._-]+/g, " ").replace(/\s+/g, " ").trim().toLowerCase();
|
|
52
52
|
}
|
|
53
|
+
function readToolErrorText(value) {
|
|
54
|
+
if (typeof value === "string") {
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
if (value instanceof Error) {
|
|
58
|
+
return value.message;
|
|
59
|
+
}
|
|
60
|
+
if (typeof value !== "object" || !value) {
|
|
61
|
+
return "";
|
|
62
|
+
}
|
|
63
|
+
const record = value;
|
|
64
|
+
for (const candidate of [record.error, record.message, record.detail, record.details]) {
|
|
65
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
66
|
+
return candidate;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
function isErrorLikeToolOutput(value) {
|
|
72
|
+
const message = readToolErrorText(value).trim();
|
|
73
|
+
if (!message) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return /(^|\b)(error|exception|failed|failure|denied|timed out|timeout|not permitted|eperm|eacces)(\b|:)/i.test(message);
|
|
77
|
+
}
|
|
53
78
|
export function extractTerminalStreamOutput(event) {
|
|
54
79
|
if (typeof event !== "object" || !event)
|
|
55
80
|
return "";
|
|
@@ -109,6 +134,10 @@ export function extractAgentStep(event) {
|
|
|
109
134
|
const outputSummary = formatStepValue(typed.data?.output, 80);
|
|
110
135
|
return outputSummary ? `tool ${name || "tool"} done ${outputSummary}` : `tool ${name || "tool"} done`;
|
|
111
136
|
}
|
|
137
|
+
if (typed.event === "on_tool_error" || (typed.event === "on_chain_error" && typed.run_type === "tool")) {
|
|
138
|
+
const errorSummary = formatStepValue(typed.data?.error ?? typed.data?.output, 80);
|
|
139
|
+
return errorSummary ? `tool ${name || "tool"} error ${errorSummary}` : `tool ${name || "tool"} error`;
|
|
140
|
+
}
|
|
112
141
|
if (typed.event === "on_chat_model_start") {
|
|
113
142
|
const inputTools = typed.data?.input?.tools;
|
|
114
143
|
const tools = typed.invocation_params?.tools ?? inputTools ?? [];
|
|
@@ -148,14 +177,17 @@ export function extractToolResult(event) {
|
|
|
148
177
|
return null;
|
|
149
178
|
const typed = event;
|
|
150
179
|
const isToolEnd = typed.event === "on_tool_end" || (typed.event === "on_chain_end" && typed.run_type === "tool");
|
|
180
|
+
const isToolError = typed.event === "on_tool_error" || (typed.event === "on_chain_error" && typed.run_type === "tool");
|
|
151
181
|
const toolName = typeof typed.name === "string" ? typed.name : "";
|
|
152
|
-
if (!isToolEnd || !toolName) {
|
|
182
|
+
if ((!isToolEnd && !isToolError) || !toolName) {
|
|
153
183
|
return null;
|
|
154
184
|
}
|
|
155
|
-
const rawOutput = typed.data?.output;
|
|
185
|
+
const rawOutput = isToolError ? typed.data?.error ?? typed.data?.output : typed.data?.output;
|
|
186
|
+
const normalizedOutput = typeof rawOutput === "string" ? parseMaybeJson(rawOutput) : rawOutput;
|
|
156
187
|
return {
|
|
157
188
|
toolName,
|
|
158
|
-
output:
|
|
189
|
+
output: normalizedOutput,
|
|
190
|
+
isError: isToolError || isErrorLikeToolOutput(normalizedOutput),
|
|
159
191
|
};
|
|
160
192
|
}
|
|
161
193
|
export function extractInterruptPayload(event) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ApprovalRecord, HarnessEvent, WorkspaceBundle } from "../../contracts/types.js";
|
|
2
2
|
export declare function renderRuntimeFailure(error: unknown): string;
|
|
3
|
+
export declare function renderToolFailure(toolName: string, output: unknown): string;
|
|
3
4
|
export declare function parseInterruptContent(content: string): {
|
|
4
5
|
toolName?: string;
|
|
5
6
|
toolId?: string;
|
|
@@ -3,6 +3,33 @@ export function renderRuntimeFailure(error) {
|
|
|
3
3
|
const message = error instanceof Error ? error.message : String(error);
|
|
4
4
|
return `runtime_error=${message}`.trim();
|
|
5
5
|
}
|
|
6
|
+
function readToolErrorMessage(output) {
|
|
7
|
+
if (typeof output === "string" && output.trim()) {
|
|
8
|
+
return output.trim();
|
|
9
|
+
}
|
|
10
|
+
if (output instanceof Error) {
|
|
11
|
+
return output.message;
|
|
12
|
+
}
|
|
13
|
+
if (typeof output !== "object" || !output) {
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
const record = output;
|
|
17
|
+
for (const candidate of [record.error, record.message, record.detail, record.details]) {
|
|
18
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
19
|
+
return candidate.trim();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return JSON.stringify(output);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return String(output);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function renderToolFailure(toolName, output) {
|
|
30
|
+
const detail = readToolErrorMessage(output);
|
|
31
|
+
return detail ? `Tool ${toolName} failed: ${detail}` : `Tool ${toolName} failed.`;
|
|
32
|
+
}
|
|
6
33
|
export function parseInterruptContent(content) {
|
|
7
34
|
try {
|
|
8
35
|
const raw = JSON.parse(content);
|
|
@@ -106,11 +133,18 @@ export function inferRoutingBindings(workspace) {
|
|
|
106
133
|
const directBinding = hostBindings.find((binding) => binding.agent.id === "direct");
|
|
107
134
|
const langchainHost = hostBindings.find((binding) => binding.agent.executionMode === "langchain-v1" && binding.agent.id !== researchBinding?.agent.id);
|
|
108
135
|
const deepagentHosts = hostBindings.filter((binding) => binding.agent.executionMode === "deepagent");
|
|
136
|
+
const defaultDeepagentHost = deepagentHosts.find((binding) => binding.agent.id === "orchestra") ??
|
|
137
|
+
deepagentHosts.find((binding) => (binding.deepAgentParams?.subagents.length ?? 0) > 0) ??
|
|
138
|
+
deepagentHosts[0];
|
|
109
139
|
const deepagentWithSubagents = deepagentHosts.find((binding) => (binding.deepAgentParams?.subagents.length ?? 0) > 0) ??
|
|
110
140
|
deepagentHosts[0];
|
|
111
|
-
const primaryBinding = directBinding ?? langchainHost ?? hostBindings[0];
|
|
112
|
-
const secondaryBinding =
|
|
113
|
-
?
|
|
114
|
-
:
|
|
141
|
+
const primaryBinding = defaultDeepagentHost ?? directBinding ?? langchainHost ?? hostBindings[0];
|
|
142
|
+
const secondaryBinding = langchainHost && langchainHost.agent.id !== primaryBinding?.agent.id
|
|
143
|
+
? langchainHost
|
|
144
|
+
: directBinding && directBinding.agent.id !== primaryBinding?.agent.id
|
|
145
|
+
? directBinding
|
|
146
|
+
: deepagentWithSubagents && deepagentWithSubagents.agent.id !== primaryBinding?.agent.id
|
|
147
|
+
? deepagentWithSubagents
|
|
148
|
+
: hostBindings.find((binding) => binding.agent.id !== primaryBinding?.agent.id);
|
|
115
149
|
return { primaryBinding, secondaryBinding, researchBinding, hostBindings };
|
|
116
150
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import type { HarnessEvent } from "../contracts/types.js";
|
|
1
|
+
import type { HarnessEvent, HarnessEventProjection } from "../contracts/types.js";
|
|
2
2
|
import type { FilePersistence } from "../persistence/file-store.js";
|
|
3
|
-
export declare class ThreadMemorySync {
|
|
3
|
+
export declare class ThreadMemorySync implements HarnessEventProjection {
|
|
4
4
|
private readonly persistence;
|
|
5
5
|
private readonly store?;
|
|
6
6
|
private readonly pending;
|
|
7
|
+
readonly name = "thread-memory-sync";
|
|
7
8
|
constructor(persistence: FilePersistence, store?: {
|
|
8
9
|
put: (namespace: string[], key: string, value: Record<string, any>) => Promise<void>;
|
|
9
10
|
} | undefined);
|
|
11
|
+
shouldHandle(event: HarnessEvent): boolean;
|
|
10
12
|
handleEvent(event: HarnessEvent): Promise<void>;
|
|
11
13
|
private syncThread;
|
|
12
14
|
close(): Promise<void>;
|
|
@@ -42,16 +42,25 @@ function renderOpenApprovalsMarkdown(approvals) {
|
|
|
42
42
|
}
|
|
43
43
|
return lines.join("\n");
|
|
44
44
|
}
|
|
45
|
+
const THREAD_MEMORY_EVENT_TYPES = new Set([
|
|
46
|
+
"run.state.changed",
|
|
47
|
+
"approval.resolved",
|
|
48
|
+
"approval.requested",
|
|
49
|
+
]);
|
|
45
50
|
export class ThreadMemorySync {
|
|
46
51
|
persistence;
|
|
47
52
|
store;
|
|
48
53
|
pending = new Set();
|
|
54
|
+
name = "thread-memory-sync";
|
|
49
55
|
constructor(persistence, store) {
|
|
50
56
|
this.persistence = persistence;
|
|
51
57
|
this.store = store;
|
|
52
58
|
}
|
|
59
|
+
shouldHandle(event) {
|
|
60
|
+
return THREAD_MEMORY_EVENT_TYPES.has(event.eventType);
|
|
61
|
+
}
|
|
53
62
|
async handleEvent(event) {
|
|
54
|
-
if (
|
|
63
|
+
if (!this.shouldHandle(event)) {
|
|
55
64
|
return;
|
|
56
65
|
}
|
|
57
66
|
const task = this.syncThread(event.threadId)
|
|
@@ -52,9 +52,6 @@ function resolveAgentRuntimeName(agent) {
|
|
|
52
52
|
return baseName;
|
|
53
53
|
}
|
|
54
54
|
const normalizedSourcePath = agent.sourcePath.split(path.sep).join("/");
|
|
55
|
-
if (normalizedSourcePath.includes("/packages/builtins/")) {
|
|
56
|
-
return `builtin.${baseName}`;
|
|
57
|
-
}
|
|
58
55
|
if (normalizedSourcePath.includes("/packages/framework/")) {
|
|
59
56
|
return `core.${baseName}`;
|
|
60
57
|
}
|
|
@@ -4,11 +4,14 @@ import { defaultResourceConfigRoot, defaultResourceSkillsRoot } from "../../reso
|
|
|
4
4
|
import { validateSkillMetadata } from "../../runtime/support/skill-metadata.js";
|
|
5
5
|
import { ensureExternalResourceSource, isDirectoryPath, isExternalSourceLocator, resolveExternalResourcePath, resolveResourcePackageRoot, } from "../../resource/sources.js";
|
|
6
6
|
import { parseAgentItem, readYamlItems } from "../object-loader.js";
|
|
7
|
-
function
|
|
8
|
-
|
|
7
|
+
function isBundledResourceRef(ref) {
|
|
8
|
+
return ref.startsWith("resource://") || ref.startsWith("builtin://");
|
|
9
|
+
}
|
|
10
|
+
function resolveBundledResourcePath(kind, ref) {
|
|
11
|
+
const normalized = ref.replace(/^(resource|builtin):\/\//, "").replace(/^\/+/, "");
|
|
9
12
|
if (kind === "skills") {
|
|
10
13
|
if (!normalized.startsWith("skills")) {
|
|
11
|
-
throw new Error(`Unsupported
|
|
14
|
+
throw new Error(`Unsupported resource skill discovery path ${ref}`);
|
|
12
15
|
}
|
|
13
16
|
const suffix = normalized.replace(/^skills\/?/, "");
|
|
14
17
|
const root = defaultResourceSkillsRoot();
|
|
@@ -28,7 +31,7 @@ function resolveBuiltinPath(kind, ref) {
|
|
|
28
31
|
return candidate;
|
|
29
32
|
}
|
|
30
33
|
if (!normalized.startsWith("agents")) {
|
|
31
|
-
throw new Error(`Unsupported
|
|
34
|
+
throw new Error(`Unsupported resource subagent discovery path ${ref}`);
|
|
32
35
|
}
|
|
33
36
|
const suffix = normalized.replace(/^agents\/?/, "");
|
|
34
37
|
const root = path.join(defaultResourceConfigRoot(), "agents");
|
|
@@ -69,8 +72,8 @@ export async function ensureDiscoverySources(locators, workspaceRoot) {
|
|
|
69
72
|
.map((locator) => ensureExternalResourceSource(locator, workspaceRoot)));
|
|
70
73
|
}
|
|
71
74
|
export function resolveDiscoveryRoot(ref, workspaceRoot, kind) {
|
|
72
|
-
if (ref
|
|
73
|
-
return
|
|
75
|
+
if (isBundledResourceRef(ref)) {
|
|
76
|
+
return resolveBundledResourcePath(kind, ref);
|
|
74
77
|
}
|
|
75
78
|
if (isExternalSourceLocator(ref)) {
|
|
76
79
|
return preferPackageConvention(resolveExternalResourcePath(ref, workspaceRoot), kind);
|
|
@@ -78,8 +81,8 @@ export function resolveDiscoveryRoot(ref, workspaceRoot, kind) {
|
|
|
78
81
|
return preferPackageConvention(path.resolve(workspaceRoot, ref), kind);
|
|
79
82
|
}
|
|
80
83
|
async function resolveDiscoveryRootAsync(ref, workspaceRoot, kind) {
|
|
81
|
-
if (ref
|
|
82
|
-
return
|
|
84
|
+
if (isBundledResourceRef(ref)) {
|
|
85
|
+
return resolveBundledResourcePath(kind, ref);
|
|
83
86
|
}
|
|
84
87
|
if (isExternalSourceLocator(ref)) {
|
|
85
88
|
return preferPackageConvention(await ensureExternalResourceSource(ref, workspaceRoot), kind);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isExternalSourceLocator } from "../../resource/sources.js";
|
|
2
2
|
export function collectToolSourceRefs(tools, agents, options) {
|
|
3
|
-
const refs = new Set(options.resourceSources ??
|
|
3
|
+
const refs = new Set(options.resourceSources ?? []);
|
|
4
4
|
for (const tool of tools.values()) {
|
|
5
5
|
for (const ref of tool.bundleRefs) {
|
|
6
6
|
if (isExternalSourceLocator(ref)) {
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
import type { ParsedAgentObject, WorkspaceObject } from "../../contracts/types.js";
|
|
2
|
+
export type RoutingRule = {
|
|
3
|
+
agentId: string;
|
|
4
|
+
equals?: string[];
|
|
5
|
+
startsWith?: string[];
|
|
6
|
+
contains?: string[];
|
|
7
|
+
regex?: string[];
|
|
8
|
+
minLength?: number;
|
|
9
|
+
maxLength?: number;
|
|
10
|
+
minLines?: number;
|
|
11
|
+
maxLines?: number;
|
|
12
|
+
hasThreadId?: boolean;
|
|
13
|
+
caseSensitive?: boolean;
|
|
14
|
+
};
|
|
2
15
|
export declare function getWorkspaceObject(refs: Map<string, WorkspaceObject | ParsedAgentObject>, ref: string | undefined): WorkspaceObject | undefined;
|
|
3
16
|
export declare function getRuntimeDefaults(refs: Map<string, WorkspaceObject | ParsedAgentObject>): Record<string, unknown> | undefined;
|
|
4
17
|
export declare function getRoutingSystemPrompt(refs: Map<string, WorkspaceObject | ParsedAgentObject>): string | undefined;
|
|
18
|
+
export declare function getRoutingDefaultAgentId(refs: Map<string, WorkspaceObject | ParsedAgentObject>): string | undefined;
|
|
19
|
+
export declare function isModelRoutingEnabled(refs: Map<string, WorkspaceObject | ParsedAgentObject>): boolean;
|
|
20
|
+
export declare function getRoutingRules(refs: Map<string, WorkspaceObject | ParsedAgentObject>): RoutingRule[];
|
|
21
|
+
export declare function matchRoutingRule(input: string, rule: RoutingRule, options?: {
|
|
22
|
+
threadId?: string;
|
|
23
|
+
}): boolean;
|
|
5
24
|
export declare function resolvePromptValue(promptConfig: unknown): string | undefined;
|
|
6
25
|
export declare function resolveRefId(ref: string): string;
|
|
7
26
|
export declare function resolvePathList(refs: Map<string, WorkspaceObject | ParsedAgentObject>, workspaceRoot: string, refList: string[]): string[];
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
function getRoutingObject(refs) {
|
|
3
|
+
const runtimeDefaults = getRuntimeDefaults(refs);
|
|
4
|
+
return typeof runtimeDefaults?.routing === "object" && runtimeDefaults.routing
|
|
5
|
+
? runtimeDefaults.routing
|
|
6
|
+
: undefined;
|
|
7
|
+
}
|
|
2
8
|
export function getWorkspaceObject(refs, ref) {
|
|
3
9
|
if (!ref) {
|
|
4
10
|
return undefined;
|
|
@@ -20,12 +26,108 @@ export function getRuntimeDefaults(refs) {
|
|
|
20
26
|
return runtimes[0].value;
|
|
21
27
|
}
|
|
22
28
|
export function getRoutingSystemPrompt(refs) {
|
|
23
|
-
const
|
|
24
|
-
const routing = typeof runtimeDefaults?.routing === "object" && runtimeDefaults.routing
|
|
25
|
-
? runtimeDefaults.routing
|
|
26
|
-
: undefined;
|
|
29
|
+
const routing = getRoutingObject(refs);
|
|
27
30
|
return typeof routing?.systemPrompt === "string" && routing.systemPrompt.trim() ? routing.systemPrompt : undefined;
|
|
28
31
|
}
|
|
32
|
+
export function getRoutingDefaultAgentId(refs) {
|
|
33
|
+
const routing = getRoutingObject(refs);
|
|
34
|
+
return typeof routing?.defaultAgentId === "string" && routing.defaultAgentId.trim()
|
|
35
|
+
? routing.defaultAgentId.trim()
|
|
36
|
+
: undefined;
|
|
37
|
+
}
|
|
38
|
+
export function isModelRoutingEnabled(refs) {
|
|
39
|
+
const routing = getRoutingObject(refs);
|
|
40
|
+
return routing?.modelRouting === true;
|
|
41
|
+
}
|
|
42
|
+
function toStringList(value) {
|
|
43
|
+
if (typeof value === "string" && value.trim()) {
|
|
44
|
+
return [value];
|
|
45
|
+
}
|
|
46
|
+
if (!Array.isArray(value)) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const items = value
|
|
50
|
+
.filter((item) => typeof item === "string" && item.trim().length > 0)
|
|
51
|
+
.map((item) => item.trim());
|
|
52
|
+
return items.length > 0 ? items : undefined;
|
|
53
|
+
}
|
|
54
|
+
function toPositiveNumber(value) {
|
|
55
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
56
|
+
}
|
|
57
|
+
export function getRoutingRules(refs) {
|
|
58
|
+
const routing = getRoutingObject(refs);
|
|
59
|
+
if (!Array.isArray(routing?.rules)) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
return routing.rules.flatMap((rule, index) => {
|
|
63
|
+
if (typeof rule !== "object" || rule === null || Array.isArray(rule)) {
|
|
64
|
+
throw new Error(`Runtime routing.rules[${index}] must be an object`);
|
|
65
|
+
}
|
|
66
|
+
const typed = rule;
|
|
67
|
+
if (typeof typed.agentId !== "string" || !typed.agentId.trim()) {
|
|
68
|
+
throw new Error(`Runtime routing.rules[${index}] requires a non-empty agentId`);
|
|
69
|
+
}
|
|
70
|
+
const regex = toStringList(typed.regex);
|
|
71
|
+
if (regex) {
|
|
72
|
+
for (const pattern of regex) {
|
|
73
|
+
try {
|
|
74
|
+
new RegExp(pattern);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
78
|
+
throw new Error(`Runtime routing.rules[${index}] has invalid regex ${JSON.stringify(pattern)}: ${detail}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return [{
|
|
83
|
+
agentId: typed.agentId.trim(),
|
|
84
|
+
equals: toStringList(typed.equals),
|
|
85
|
+
startsWith: toStringList(typed.startsWith),
|
|
86
|
+
contains: toStringList(typed.contains),
|
|
87
|
+
regex,
|
|
88
|
+
minLength: toPositiveNumber(typed.minLength),
|
|
89
|
+
maxLength: toPositiveNumber(typed.maxLength),
|
|
90
|
+
minLines: toPositiveNumber(typed.minLines),
|
|
91
|
+
maxLines: toPositiveNumber(typed.maxLines),
|
|
92
|
+
hasThreadId: typeof typed.hasThreadId === "boolean" ? typed.hasThreadId : undefined,
|
|
93
|
+
caseSensitive: typed.caseSensitive === true,
|
|
94
|
+
}];
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export function matchRoutingRule(input, rule, options = {}) {
|
|
98
|
+
const text = input.trim();
|
|
99
|
+
const source = rule.caseSensitive ? text : text.toLowerCase();
|
|
100
|
+
const lineCount = text ? text.split(/\n+/).length : 0;
|
|
101
|
+
const normalize = (value) => (rule.caseSensitive ? value : value.toLowerCase());
|
|
102
|
+
if (rule.hasThreadId !== undefined && rule.hasThreadId !== Boolean(options.threadId)) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
if (rule.minLength !== undefined && text.length < rule.minLength) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
if (rule.maxLength !== undefined && text.length > rule.maxLength) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
if (rule.minLines !== undefined && lineCount < rule.minLines) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
if (rule.maxLines !== undefined && lineCount > rule.maxLines) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
if (rule.equals && !rule.equals.some((candidate) => source === normalize(candidate.trim()))) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
if (rule.startsWith && !rule.startsWith.some((candidate) => source.startsWith(normalize(candidate.trim())))) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
if (rule.contains && !rule.contains.some((candidate) => source.includes(normalize(candidate.trim())))) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
if (rule.regex && !rule.regex.some((pattern) => new RegExp(pattern, rule.caseSensitive ? undefined : "i").test(text))) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
29
131
|
export function resolvePromptValue(promptConfig) {
|
|
30
132
|
if (typeof promptConfig === "string" && promptConfig.trim()) {
|
|
31
133
|
return promptConfig;
|
|
@@ -33,10 +135,14 @@ export function resolvePromptValue(promptConfig) {
|
|
|
33
135
|
return undefined;
|
|
34
136
|
}
|
|
35
137
|
export function resolveRefId(ref) {
|
|
36
|
-
|
|
138
|
+
const [namespace, ...rest] = ref.split("/");
|
|
139
|
+
if (rest.length === 0) {
|
|
37
140
|
return ref;
|
|
38
141
|
}
|
|
39
|
-
|
|
142
|
+
if (["agent", "embedding-model", "mcp", "model", "object", "prompt", "runtime", "tool", "vector-store"].includes(namespace)) {
|
|
143
|
+
return rest.join("/");
|
|
144
|
+
}
|
|
145
|
+
return ref;
|
|
40
146
|
}
|
|
41
147
|
export function resolvePathList(refs, workspaceRoot, refList) {
|
|
42
148
|
return refList.map((ref) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botbotgo/agent-harness",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.39",
|
|
4
|
+
"description": "Workspace runtime for multi-agent applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@10.9.2",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc -p tsconfig.json && cp -R config dist/",
|
|
52
52
|
"check": "tsc -p tsconfig.json --noEmit",
|
|
53
|
-
"test": "vitest run test/public-api.test.ts test/resource-optional-provider.test.ts test/resource-isolation.test.ts test/stock-research-app-load-harness.test.ts test/stock-research-app-run.test.ts test/release-workflow.test.ts test/release-version.test.ts test/gitignore.test.ts test/package-lock.test.ts test/readme.test.ts test/runtime-adapter-regressions.test.ts test/tool-extension-gaps.test.ts test/checkpoint-maintenance.test.ts test/llamaindex-dependency-compat.test.ts",
|
|
53
|
+
"test": "vitest run test/public-api.test.ts test/resource-optional-provider.test.ts test/resource-isolation.test.ts test/stock-research-app-load-harness.test.ts test/stock-research-app-run.test.ts test/release-workflow.test.ts test/release-version.test.ts test/gitignore.test.ts test/package-lock.test.ts test/readme.test.ts test/runtime-adapter-regressions.test.ts test/tool-extension-gaps.test.ts test/checkpoint-maintenance.test.ts test/llamaindex-dependency-compat.test.ts test/skill-standard.test.ts test/routing-config.test.ts test/workspace-compat-regressions.test.ts",
|
|
54
54
|
"test:real-providers": "vitest run test/real-provider-harness.test.ts",
|
|
55
55
|
"release:prepare": "npm version patch --no-git-tag-version && node ./scripts/sync-example-version.mjs",
|
|
56
56
|
"release:pack": "npm pack --dry-run",
|