@botbotgo/agent-harness 0.0.1

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.
Files changed (87) hide show
  1. package/dist/api.d.ts +22 -0
  2. package/dist/api.js +48 -0
  3. package/dist/config/direct.yaml +48 -0
  4. package/dist/config/embedding-model.yaml +30 -0
  5. package/dist/config/model.yaml +44 -0
  6. package/dist/config/orchestra.yaml +92 -0
  7. package/dist/config/runtime.yaml +47 -0
  8. package/dist/config/vector-store.yaml +26 -0
  9. package/dist/contracts/types.d.ts +359 -0
  10. package/dist/contracts/types.js +1 -0
  11. package/dist/extensions.d.ts +16 -0
  12. package/dist/extensions.js +251 -0
  13. package/dist/index.d.ts +7 -0
  14. package/dist/index.js +7 -0
  15. package/dist/persistence/file-store.d.ts +39 -0
  16. package/dist/persistence/file-store.js +282 -0
  17. package/dist/presentation.d.ts +4 -0
  18. package/dist/presentation.js +175 -0
  19. package/dist/runtime/agent-runtime-adapter.d.ts +33 -0
  20. package/dist/runtime/agent-runtime-adapter.js +445 -0
  21. package/dist/runtime/event-bus.d.ts +6 -0
  22. package/dist/runtime/event-bus.js +15 -0
  23. package/dist/runtime/file-checkpoint-saver.d.ts +20 -0
  24. package/dist/runtime/file-checkpoint-saver.js +91 -0
  25. package/dist/runtime/harness.d.ts +57 -0
  26. package/dist/runtime/harness.js +696 -0
  27. package/dist/runtime/index.d.ts +10 -0
  28. package/dist/runtime/index.js +10 -0
  29. package/dist/runtime/inventory.d.ts +25 -0
  30. package/dist/runtime/inventory.js +62 -0
  31. package/dist/runtime/parsing/index.d.ts +2 -0
  32. package/dist/runtime/parsing/index.js +2 -0
  33. package/dist/runtime/parsing/output-parsing.d.ts +12 -0
  34. package/dist/runtime/parsing/output-parsing.js +424 -0
  35. package/dist/runtime/parsing/stream-event-parsing.d.ts +27 -0
  36. package/dist/runtime/parsing/stream-event-parsing.js +161 -0
  37. package/dist/runtime/policy-engine.d.ts +9 -0
  38. package/dist/runtime/policy-engine.js +23 -0
  39. package/dist/runtime/store.d.ts +50 -0
  40. package/dist/runtime/store.js +118 -0
  41. package/dist/runtime/support/embedding-models.d.ts +4 -0
  42. package/dist/runtime/support/embedding-models.js +33 -0
  43. package/dist/runtime/support/harness-support.d.ts +27 -0
  44. package/dist/runtime/support/harness-support.js +116 -0
  45. package/dist/runtime/support/index.d.ts +4 -0
  46. package/dist/runtime/support/index.js +4 -0
  47. package/dist/runtime/support/llamaindex.d.ts +24 -0
  48. package/dist/runtime/support/llamaindex.js +108 -0
  49. package/dist/runtime/support/runtime-factories.d.ts +3 -0
  50. package/dist/runtime/support/runtime-factories.js +39 -0
  51. package/dist/runtime/support/skill-metadata.d.ts +1 -0
  52. package/dist/runtime/support/skill-metadata.js +34 -0
  53. package/dist/runtime/support/vector-stores.d.ts +7 -0
  54. package/dist/runtime/support/vector-stores.js +130 -0
  55. package/dist/runtime/thread-memory-sync.d.ts +14 -0
  56. package/dist/runtime/thread-memory-sync.js +88 -0
  57. package/dist/runtime/tool-hitl.d.ts +5 -0
  58. package/dist/runtime/tool-hitl.js +108 -0
  59. package/dist/utils/fs.d.ts +6 -0
  60. package/dist/utils/fs.js +39 -0
  61. package/dist/utils/id.d.ts +1 -0
  62. package/dist/utils/id.js +8 -0
  63. package/dist/vendor/builtins.d.ts +23 -0
  64. package/dist/vendor/builtins.js +103 -0
  65. package/dist/vendor/sources.d.ts +12 -0
  66. package/dist/vendor/sources.js +115 -0
  67. package/dist/workspace/agent-binding-compiler.d.ts +4 -0
  68. package/dist/workspace/agent-binding-compiler.js +181 -0
  69. package/dist/workspace/compile.d.ts +2 -0
  70. package/dist/workspace/compile.js +107 -0
  71. package/dist/workspace/index.d.ts +6 -0
  72. package/dist/workspace/index.js +6 -0
  73. package/dist/workspace/object-loader.d.ts +16 -0
  74. package/dist/workspace/object-loader.js +405 -0
  75. package/dist/workspace/resource-compilers.d.ts +13 -0
  76. package/dist/workspace/resource-compilers.js +182 -0
  77. package/dist/workspace/support/discovery.d.ts +5 -0
  78. package/dist/workspace/support/discovery.js +108 -0
  79. package/dist/workspace/support/index.d.ts +2 -0
  80. package/dist/workspace/support/index.js +2 -0
  81. package/dist/workspace/support/source-collectors.d.ts +3 -0
  82. package/dist/workspace/support/source-collectors.js +30 -0
  83. package/dist/workspace/support/workspace-ref-utils.d.ts +8 -0
  84. package/dist/workspace/support/workspace-ref-utils.js +50 -0
  85. package/dist/workspace/validate.d.ts +3 -0
  86. package/dist/workspace/validate.js +65 -0
  87. package/package.json +32 -0
@@ -0,0 +1,161 @@
1
+ import { extractReasoningText, extractVisibleOutput, hasToolCalls, readTextContent } from "./output-parsing.js";
2
+ function formatStepValue(value, maxLength = 120) {
3
+ if (value == null)
4
+ return "";
5
+ const normalized = typeof value === "string"
6
+ ? parseMaybeJson(value)
7
+ : value;
8
+ const summarized = summarizeStepValue(normalized);
9
+ const serialized = typeof summarized === "string"
10
+ ? summarized
11
+ : (() => {
12
+ try {
13
+ return JSON.stringify(summarized);
14
+ }
15
+ catch {
16
+ return String(summarized);
17
+ }
18
+ })();
19
+ return serialized.length > maxLength ? serialized.slice(0, maxLength) + "…" : serialized;
20
+ }
21
+ function parseMaybeJson(value) {
22
+ const trimmed = value.trim();
23
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
24
+ return value;
25
+ }
26
+ try {
27
+ return JSON.parse(trimmed);
28
+ }
29
+ catch {
30
+ return value;
31
+ }
32
+ }
33
+ function summarizeStepValue(value) {
34
+ if (typeof value !== "object" || !value) {
35
+ return value;
36
+ }
37
+ const record = value;
38
+ if (typeof record.url === "string" && typeof record.status === "number") {
39
+ const warnings = Array.isArray(record.warnings) ? record.warnings.filter((item) => typeof item === "string") : [];
40
+ return {
41
+ status: record.status,
42
+ ok: record.ok,
43
+ quality: record.quality,
44
+ source: record.source,
45
+ warnings,
46
+ };
47
+ }
48
+ return value;
49
+ }
50
+ function humanizeEventName(name) {
51
+ return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[._-]+/g, " ").replace(/\s+/g, " ").trim().toLowerCase();
52
+ }
53
+ export function extractTerminalStreamOutput(event) {
54
+ if (typeof event !== "object" || !event)
55
+ return "";
56
+ const typed = event;
57
+ if (typed.event === "on_chat_model_end") {
58
+ if (hasToolCalls(typed.data?.output))
59
+ return "";
60
+ return extractVisibleOutput(typed.data?.output);
61
+ }
62
+ if (typed.event === "on_chain_end") {
63
+ const name = typeof typed.name === "string" ? typed.name : "";
64
+ if (/middleware|after_model/i.test(name))
65
+ return "";
66
+ return extractVisibleOutput(typed.data?.output);
67
+ }
68
+ return "";
69
+ }
70
+ export function extractReasoningStreamOutput(event) {
71
+ if (typeof event !== "object" || !event)
72
+ return "";
73
+ const typed = event;
74
+ return typed.event === "on_chat_model_stream" ? extractReasoningText(typed.data?.chunk) : "";
75
+ }
76
+ export function extractAgentStep(event) {
77
+ if (typeof event !== "object" || !event)
78
+ return null;
79
+ const typed = event;
80
+ const name = typeof typed.name === "string" ? typed.name : "";
81
+ if (typed.event === "on_tool_start" || (typed.event === "on_chain_start" && typed.run_type === "tool")) {
82
+ const inputSummary = formatStepValue(typed.data?.input);
83
+ return inputSummary ? `tool ${name || "tool"} ${inputSummary}` : `tool ${name || "tool"}`;
84
+ }
85
+ if (typed.event === "on_tool_end" || (typed.event === "on_chain_end" && typed.run_type === "tool")) {
86
+ const outputSummary = formatStepValue(typed.data?.output, 80);
87
+ return outputSummary ? `tool ${name || "tool"} done ${outputSummary}` : `tool ${name || "tool"} done`;
88
+ }
89
+ if (typed.event === "on_chat_model_start") {
90
+ const inputTools = typed.data?.input?.tools;
91
+ const tools = typed.invocation_params?.tools ?? inputTools ?? [];
92
+ const toolNames = tools.map((tool) => tool.name ?? tool.function?.name).filter((toolName) => typeof toolName === "string").join(", ");
93
+ return toolNames ? `calling model tools: [${toolNames}]` : "calling model…";
94
+ }
95
+ if (typed.event === "on_chain_start") {
96
+ if (/SkillsMiddleware/i.test(name))
97
+ return "loading skills…";
98
+ if (/MemoryMiddleware/i.test(name))
99
+ return "loading memory…";
100
+ if (/patchToolCallsMiddleware/i.test(name))
101
+ return "normalizing tool calls…";
102
+ if (/HumanInTheLoopMiddleware/i.test(name))
103
+ return "checking approvals…";
104
+ if (/todoListMiddleware/i.test(name))
105
+ return "updating plan…";
106
+ if (/model_request/i.test(name))
107
+ return "preparing model request…";
108
+ if (/RunnableLambda/i.test(name) || /^__start__$/.test(name))
109
+ return null;
110
+ if (/specialist/i.test(name))
111
+ return `starting ${humanizeEventName(name)}…`;
112
+ if (/agent$/i.test(name))
113
+ return `running ${humanizeEventName(name)}…`;
114
+ }
115
+ if (typed.event === "on_chain_end") {
116
+ if (/specialist/i.test(name))
117
+ return `${humanizeEventName(name)} done`;
118
+ if (/agent$/i.test(name) && !/^__start__$/.test(name))
119
+ return `${humanizeEventName(name)} done`;
120
+ }
121
+ return null;
122
+ }
123
+ export function extractToolResult(event) {
124
+ if (typeof event !== "object" || !event)
125
+ return null;
126
+ const typed = event;
127
+ const isToolEnd = typed.event === "on_tool_end" || (typed.event === "on_chain_end" && typed.run_type === "tool");
128
+ const toolName = typeof typed.name === "string" ? typed.name : "";
129
+ if (!isToolEnd || !toolName) {
130
+ return null;
131
+ }
132
+ const rawOutput = typed.data?.output;
133
+ return {
134
+ toolName,
135
+ output: typeof rawOutput === "string" ? parseMaybeJson(rawOutput) : rawOutput,
136
+ };
137
+ }
138
+ export function extractInterruptPayload(event) {
139
+ if (typeof event !== "object" || !event)
140
+ return null;
141
+ const typed = event;
142
+ if (typed.event === "on_chain_stream") {
143
+ const chunk = typed.data?.chunk;
144
+ if (typeof chunk === "object" && chunk && "__interrupt__" in chunk) {
145
+ return JSON.stringify(chunk.__interrupt__);
146
+ }
147
+ }
148
+ if (typed.event === "on_chain_end") {
149
+ const output = typed.data?.output;
150
+ if (typeof output === "object" && output && "__interrupt__" in output) {
151
+ return JSON.stringify(output.__interrupt__);
152
+ }
153
+ }
154
+ return null;
155
+ }
156
+ export function normalizeTerminalOutputKey(value) {
157
+ return value.trim();
158
+ }
159
+ export function readStreamDelta(chunk) {
160
+ return readTextContent(chunk);
161
+ }
@@ -0,0 +1,9 @@
1
+ import type { CompiledAgentBinding } from "../contracts/types.js";
2
+ export type PolicyEngineDecision = {
3
+ allowed: boolean;
4
+ reasons: string[];
5
+ };
6
+ export declare class PolicyEngine {
7
+ evaluate(binding: CompiledAgentBinding): PolicyEngineDecision;
8
+ }
9
+ export { PolicyEngineDecision as GovernanceDecision, PolicyEngine as GovernanceEngine, };
@@ -0,0 +1,23 @@
1
+ import { getPolicyEvaluators } from "../extensions.js";
2
+ export class PolicyEngine {
3
+ evaluate(binding) {
4
+ const reasons = [];
5
+ let allowed = true;
6
+ if (!binding.harnessRuntime.hostFacing) {
7
+ allowed = false;
8
+ reasons.push("internal subagents cannot be used as host-facing entrypoints");
9
+ }
10
+ for (const evaluator of getPolicyEvaluators()) {
11
+ const decision = evaluator.evaluate(binding);
12
+ if (!decision) {
13
+ continue;
14
+ }
15
+ if (!decision.allowed) {
16
+ allowed = false;
17
+ }
18
+ reasons.push(...decision.reasons);
19
+ }
20
+ return { allowed, reasons };
21
+ }
22
+ }
23
+ export { PolicyEngine as GovernanceEngine, };
@@ -0,0 +1,50 @@
1
+ import { InMemoryStore } from "@langchain/langgraph";
2
+ export type StoreLike = {
3
+ batch: (...args: any[]) => Promise<readonly unknown[]>;
4
+ get: (namespace: string[], key: string) => Promise<{
5
+ value: unknown;
6
+ key: string;
7
+ namespace: string[];
8
+ createdAt: Date;
9
+ updatedAt: Date;
10
+ } | null>;
11
+ search: (namespacePrefix: string[], options?: any) => Promise<Array<{
12
+ value: unknown;
13
+ key: string;
14
+ namespace: string[];
15
+ createdAt: Date;
16
+ updatedAt: Date;
17
+ score?: number;
18
+ }>>;
19
+ put: (namespace: string[], key: string, value: Record<string, any>, index?: false | string[]) => Promise<void>;
20
+ delete: (namespace: string[], key: string) => Promise<void>;
21
+ listNamespaces: (options?: any) => Promise<string[][]>;
22
+ };
23
+ export declare class FileBackedStore {
24
+ private readonly filePath;
25
+ private readonly delegate;
26
+ private loaded;
27
+ constructor(filePath: string);
28
+ private ensureLoaded;
29
+ private persist;
30
+ batch(operations: Parameters<InMemoryStore["batch"]>[0]): Promise<readonly unknown[]>;
31
+ get(namespace: string[], key: string): Promise<{
32
+ value: unknown;
33
+ key: string;
34
+ namespace: string[];
35
+ createdAt: Date;
36
+ updatedAt: Date;
37
+ } | null>;
38
+ search(namespacePrefix: string[], options?: Parameters<InMemoryStore["search"]>[1]): Promise<Array<{
39
+ value: unknown;
40
+ key: string;
41
+ namespace: string[];
42
+ createdAt: Date;
43
+ updatedAt: Date;
44
+ score?: number;
45
+ }>>;
46
+ put(namespace: string[], key: string, value: Record<string, any>, index?: false | string[]): Promise<void>;
47
+ delete(namespace: string[], key: string): Promise<void>;
48
+ listNamespaces(options?: Parameters<InMemoryStore["listNamespaces"]>[0]): Promise<string[][]>;
49
+ }
50
+ export declare function createInMemoryStore(): StoreLike;
@@ -0,0 +1,118 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { InMemoryStore } from "@langchain/langgraph";
4
+ function encodeValue(value) {
5
+ if (value instanceof Date) {
6
+ return {
7
+ __type: "Date",
8
+ value: value.toISOString(),
9
+ };
10
+ }
11
+ if (value instanceof Uint8Array) {
12
+ return {
13
+ __type: "Uint8Array",
14
+ data: Array.from(value),
15
+ };
16
+ }
17
+ if (value instanceof Map) {
18
+ return {
19
+ __type: "Map",
20
+ entries: Array.from(value.entries()).map(([key, entry]) => [encodeValue(key), encodeValue(entry)]),
21
+ };
22
+ }
23
+ if (Array.isArray(value)) {
24
+ return value.map((item) => encodeValue(item));
25
+ }
26
+ if (typeof value === "object" && value) {
27
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, encodeValue(entry)]));
28
+ }
29
+ return value;
30
+ }
31
+ function decodeValue(value) {
32
+ if (Array.isArray(value)) {
33
+ return value.map((item) => decodeValue(item));
34
+ }
35
+ if (typeof value === "object" && value) {
36
+ const typed = value;
37
+ if (typed.__type === "Date" && typeof typed.value === "string") {
38
+ return new Date(typed.value);
39
+ }
40
+ if (typed.__type === "Uint8Array" && Array.isArray(typed.data)) {
41
+ return new Uint8Array(typed.data.map((item) => Number(item)));
42
+ }
43
+ if (typed.__type === "Map" && Array.isArray(typed.entries)) {
44
+ return new Map(typed.entries.map((entry) => {
45
+ const [key, item] = Array.isArray(entry) ? entry : [undefined, undefined];
46
+ return [decodeValue(key), decodeValue(item)];
47
+ }));
48
+ }
49
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, decodeValue(entry)]));
50
+ }
51
+ return value;
52
+ }
53
+ export class FileBackedStore {
54
+ filePath;
55
+ delegate = new InMemoryStore();
56
+ loaded = false;
57
+ constructor(filePath) {
58
+ this.filePath = filePath;
59
+ }
60
+ async ensureLoaded() {
61
+ if (this.loaded) {
62
+ return;
63
+ }
64
+ try {
65
+ const raw = await readFile(this.filePath, "utf8");
66
+ const parsed = JSON.parse(raw);
67
+ this.delegate.data = decodeValue(parsed.data);
68
+ this.delegate.vectors = decodeValue(parsed.vectors);
69
+ }
70
+ catch {
71
+ this.delegate.data = new Map();
72
+ this.delegate.vectors = new Map();
73
+ }
74
+ this.loaded = true;
75
+ }
76
+ async persist() {
77
+ await mkdir(path.dirname(this.filePath), { recursive: true });
78
+ await writeFile(this.filePath, JSON.stringify({
79
+ data: encodeValue(this.delegate.data),
80
+ vectors: encodeValue(this.delegate.vectors),
81
+ }, null, 2), "utf8");
82
+ }
83
+ async batch(operations) {
84
+ await this.ensureLoaded();
85
+ const result = await this.delegate.batch(operations);
86
+ if (operations.some((operation) => "value" in operation)) {
87
+ await this.persist();
88
+ }
89
+ return result;
90
+ }
91
+ async get(namespace, key) {
92
+ await this.ensureLoaded();
93
+ return this.delegate.get(namespace, key);
94
+ }
95
+ async search(namespacePrefix, options) {
96
+ await this.ensureLoaded();
97
+ return this.delegate.search(namespacePrefix, options);
98
+ }
99
+ async put(namespace, key, value, index) {
100
+ await this.ensureLoaded();
101
+ const result = await this.delegate.put(namespace, key, value, index);
102
+ await this.persist();
103
+ return result;
104
+ }
105
+ async delete(namespace, key) {
106
+ await this.ensureLoaded();
107
+ const result = await this.delegate.delete(namespace, key);
108
+ await this.persist();
109
+ return result;
110
+ }
111
+ async listNamespaces(options) {
112
+ await this.ensureLoaded();
113
+ return this.delegate.listNamespaces(options);
114
+ }
115
+ }
116
+ export function createInMemoryStore() {
117
+ return new InMemoryStore();
118
+ }
@@ -0,0 +1,4 @@
1
+ import type { CompiledEmbeddingModel, RuntimeEmbeddingModelResolver, WorkspaceBundle } from "../../contracts/types.js";
2
+ import { type EmbeddingRuntimeLike } from "./llamaindex.js";
3
+ export declare function resolveCompiledEmbeddingModelRef(workspace: WorkspaceBundle, embeddingModelRef?: string): CompiledEmbeddingModel;
4
+ export declare function resolveCompiledEmbeddingModel(embeddingModel: CompiledEmbeddingModel, resolver?: RuntimeEmbeddingModelResolver): Promise<EmbeddingRuntimeLike>;
@@ -0,0 +1,33 @@
1
+ import { OllamaEmbeddings } from "@langchain/ollama";
2
+ import { compileEmbeddingModel } from "../../workspace/resource-compilers.js";
3
+ import { resolveRefId } from "../../workspace/support/workspace-ref-utils.js";
4
+ import { createLlamaIndexEmbeddingModel } from "./llamaindex.js";
5
+ export function resolveCompiledEmbeddingModelRef(workspace, embeddingModelRef) {
6
+ const resolvedId = embeddingModelRef ? resolveRefId(embeddingModelRef) : "default";
7
+ const embeddingModel = workspace.embeddings.get(resolvedId);
8
+ if (embeddingModel) {
9
+ return compileEmbeddingModel(embeddingModel);
10
+ }
11
+ if (!embeddingModelRef && workspace.embeddings.size === 1) {
12
+ const soleModel = workspace.embeddings.values().next().value;
13
+ if (soleModel) {
14
+ return compileEmbeddingModel(soleModel);
15
+ }
16
+ }
17
+ throw new Error(`Missing embedding model ${embeddingModelRef ?? "embedding-model/default"}`);
18
+ }
19
+ export async function resolveCompiledEmbeddingModel(embeddingModel, resolver) {
20
+ if (resolver) {
21
+ return resolver(embeddingModel.id);
22
+ }
23
+ if (embeddingModel.provider === "ollama") {
24
+ return new OllamaEmbeddings({
25
+ model: embeddingModel.model,
26
+ ...(embeddingModel.init ?? {}),
27
+ });
28
+ }
29
+ if (embeddingModel.provider === "llamaindex-ollama") {
30
+ return createLlamaIndexEmbeddingModel(embeddingModel);
31
+ }
32
+ throw new Error(`Embedding model provider ${embeddingModel.provider} is not supported by the built-in runtime. Configure embeddingModelResolver or use ollama/llamaindex-ollama.`);
33
+ }
@@ -0,0 +1,27 @@
1
+ import type { ApprovalRecord, HarnessEvent, WorkspaceBundle } from "../../contracts/types.js";
2
+ export declare function renderRuntimeFailure(error: unknown): string;
3
+ export declare function parseInterruptContent(content: string): {
4
+ toolName?: string;
5
+ toolId?: string;
6
+ allowedDecisions?: Array<"approve" | "edit" | "reject">;
7
+ inputPreview?: Record<string, unknown>;
8
+ };
9
+ export declare function requiresResearchRoute(normalizedInput: string): boolean;
10
+ export declare function resolveDeterministicRouteIntent(normalizedInput: string): "primary" | "secondary" | "research" | undefined;
11
+ export declare function heuristicRoute(input: string, primaryBinding?: {
12
+ agent: {
13
+ id: string;
14
+ };
15
+ }, secondaryBinding?: {
16
+ agent: {
17
+ id: string;
18
+ };
19
+ }): string;
20
+ export declare function createHarnessEvent(threadId: string, runId: string, sequence: number, eventType: string, payload: Record<string, unknown>, source?: HarnessEvent["source"]): HarnessEvent;
21
+ export declare function createPendingApproval(threadId: string, runId: string, checkpointRef: string, input: string, interruptContent?: string): ApprovalRecord;
22
+ export declare function inferRoutingBindings(workspace: WorkspaceBundle): {
23
+ primaryBinding: import("../../contracts/types.js").CompiledAgentBinding;
24
+ secondaryBinding: import("../../contracts/types.js").CompiledAgentBinding | undefined;
25
+ researchBinding: import("../../contracts/types.js").CompiledAgentBinding | undefined;
26
+ hostBindings: import("../../contracts/types.js").CompiledAgentBinding[];
27
+ };
@@ -0,0 +1,116 @@
1
+ import { createPersistentId } from "../../utils/id.js";
2
+ export function renderRuntimeFailure(error) {
3
+ const message = error instanceof Error ? error.message : String(error);
4
+ return `runtime_error=${message}`.trim();
5
+ }
6
+ export function parseInterruptContent(content) {
7
+ try {
8
+ const raw = JSON.parse(content);
9
+ const parsed = Array.isArray(raw) && raw.length > 0 && typeof raw[0] === "object" && raw[0]
10
+ ? raw[0]
11
+ : typeof raw === "object" && raw
12
+ ? raw
13
+ : {};
14
+ const allowedDecisions = Array.isArray(parsed.allowedDecisions)
15
+ ? parsed.allowedDecisions.filter((item) => item === "approve" || item === "edit" || item === "reject")
16
+ : undefined;
17
+ return {
18
+ toolName: typeof parsed.toolName === "string" ? parsed.toolName : undefined,
19
+ toolId: typeof parsed.toolId === "string" ? parsed.toolId : undefined,
20
+ allowedDecisions,
21
+ inputPreview: typeof parsed.inputPreview === "object" && parsed.inputPreview ? parsed.inputPreview : undefined,
22
+ };
23
+ }
24
+ catch {
25
+ return {};
26
+ }
27
+ }
28
+ export function requiresResearchRoute(normalizedInput) {
29
+ return (/\b(latest|recent|today|current|news|headlines|research|compare|comparison|best options?)\b/i.test(normalizedInput) ||
30
+ /(最新|最近|今天|当前|新闻|头条|研究|调研|比较|对比)/.test(normalizedInput));
31
+ }
32
+ export function resolveDeterministicRouteIntent(normalizedInput) {
33
+ if (!normalizedInput) {
34
+ return "primary";
35
+ }
36
+ if (requiresResearchRoute(normalizedInput)) {
37
+ return "research";
38
+ }
39
+ if (/^(hi|hello|hey|thanks|thank you|你好|您好|谢谢)\b/.test(normalizedInput)) {
40
+ return "primary";
41
+ }
42
+ if (normalizedInput.length > 240 ||
43
+ normalizedInput.split(/\n+/).length > 3 ||
44
+ /\b(create|build|implement|fix|debug|refactor|review|test|ship|release|deploy|code|bug|repo|repository|file|files|download|clone|inspect|analy[sz]e|explore)\b/i.test(normalizedInput) ||
45
+ /(写代码|实现|修复|排查|调试|重构|评审|测试|发布|部署|仓库|代码|文件|下载|克隆|分析|检查|探索)/.test(normalizedInput)) {
46
+ return "secondary";
47
+ }
48
+ if (/^(what|why|how|when|who|which|explain|summarize|总结|解释|说明|是什么|为什么|怎么|如何)\b/i.test(normalizedInput) &&
49
+ normalizedInput.length < 160) {
50
+ return "primary";
51
+ }
52
+ return undefined;
53
+ }
54
+ export function heuristicRoute(input, primaryBinding, secondaryBinding) {
55
+ const normalized = input.trim().toLowerCase();
56
+ const intent = resolveDeterministicRouteIntent(normalized);
57
+ if (intent === "research") {
58
+ return secondaryBinding?.agent.id ?? primaryBinding?.agent.id ?? "agent";
59
+ }
60
+ if (intent === "primary") {
61
+ return primaryBinding?.agent.id ?? "agent";
62
+ }
63
+ if (intent === "secondary") {
64
+ return secondaryBinding?.agent.id ?? primaryBinding?.agent.id ?? "agent";
65
+ }
66
+ if (!normalized) {
67
+ return primaryBinding?.agent.id ?? "agent";
68
+ }
69
+ return secondaryBinding?.agent.id ?? primaryBinding?.agent.id ?? "agent";
70
+ }
71
+ export function createHarnessEvent(threadId, runId, sequence, eventType, payload, source = "runtime") {
72
+ return {
73
+ eventId: `evt-${String(sequence).padStart(6, "0")}`,
74
+ eventType,
75
+ timestamp: new Date().toISOString(),
76
+ threadId,
77
+ runId,
78
+ sequence,
79
+ source,
80
+ payload,
81
+ };
82
+ }
83
+ export function createPendingApproval(threadId, runId, checkpointRef, input, interruptContent) {
84
+ const requestedAt = new Date().toISOString();
85
+ const interrupt = interruptContent ? parseInterruptContent(interruptContent) : {};
86
+ const approvalId = `approval-${createPersistentId()}`;
87
+ return {
88
+ approvalId,
89
+ pendingActionId: approvalId,
90
+ threadId,
91
+ runId,
92
+ toolCallId: interrupt.toolId ?? `tool-${runId}`,
93
+ toolName: interrupt.toolName ?? "write_file",
94
+ status: "pending",
95
+ requestedAt,
96
+ resolvedAt: null,
97
+ allowedDecisions: interrupt.allowedDecisions ?? ["approve", "edit", "reject"],
98
+ inputPreview: interrupt.inputPreview ?? { input },
99
+ checkpointRef,
100
+ eventRefs: ["000003.json", "000004.json"],
101
+ };
102
+ }
103
+ export function inferRoutingBindings(workspace) {
104
+ const hostBindings = Array.from(workspace.bindings.values()).filter((binding) => binding.harnessRuntime.hostFacing);
105
+ const researchBinding = hostBindings.find((binding) => binding.agent.id === "research-lite" || binding.agent.id === "research");
106
+ const directBinding = hostBindings.find((binding) => binding.agent.id === "direct");
107
+ const langchainHost = hostBindings.find((binding) => binding.agent.executionMode === "langchain-v1" && binding.agent.id !== researchBinding?.agent.id);
108
+ const deepagentHosts = hostBindings.filter((binding) => binding.agent.executionMode === "deepagent");
109
+ const deepagentWithSubagents = deepagentHosts.find((binding) => (binding.deepAgentParams?.subagents.length ?? 0) > 0) ??
110
+ deepagentHosts[0];
111
+ const primaryBinding = directBinding ?? langchainHost ?? hostBindings[0];
112
+ const secondaryBinding = deepagentWithSubagents && deepagentWithSubagents.agent.id !== primaryBinding?.agent.id
113
+ ? deepagentWithSubagents
114
+ : hostBindings.find((binding) => binding.agent.id !== primaryBinding?.agent.id);
115
+ return { primaryBinding, secondaryBinding, researchBinding, hostBindings };
116
+ }
@@ -0,0 +1,4 @@
1
+ export { createHarnessEvent, createPendingApproval, heuristicRoute, inferRoutingBindings, parseInterruptContent, renderRuntimeFailure, requiresResearchRoute, } from "./harness-support.js";
2
+ export { resolveCompiledEmbeddingModel, resolveCompiledEmbeddingModelRef } from "./embedding-models.js";
3
+ export { createCheckpointerForConfig, createStoreForConfig } from "./runtime-factories.js";
4
+ export { resolveCompiledVectorStore, resolveCompiledVectorStoreRef } from "./vector-stores.js";
@@ -0,0 +1,4 @@
1
+ export { createHarnessEvent, createPendingApproval, heuristicRoute, inferRoutingBindings, parseInterruptContent, renderRuntimeFailure, requiresResearchRoute, } from "./harness-support.js";
2
+ export { resolveCompiledEmbeddingModel, resolveCompiledEmbeddingModelRef } from "./embedding-models.js";
3
+ export { createCheckpointerForConfig, createStoreForConfig } from "./runtime-factories.js";
4
+ export { resolveCompiledVectorStore, resolveCompiledVectorStoreRef } from "./vector-stores.js";
@@ -0,0 +1,24 @@
1
+ import type { CompiledEmbeddingModel, CompiledVectorStore } from "../../contracts/types.js";
2
+ export type EmbeddingRuntimeLike = {
3
+ embedDocuments: (texts: string[]) => Promise<number[][]>;
4
+ embedQuery: (text: string) => Promise<number[]>;
5
+ };
6
+ export type VectorStoreRuntimeLike = {
7
+ kind: string;
8
+ embeddingModelRef?: string;
9
+ addDocuments: (documents: Array<{
10
+ pageContent: string;
11
+ metadata?: Record<string, unknown>;
12
+ }>) => Promise<string[]>;
13
+ similaritySearch: (query: string, limit: number) => Promise<Array<{
14
+ pageContent: string;
15
+ metadata?: Record<string, unknown>;
16
+ score?: number;
17
+ }>>;
18
+ delete: (params: {
19
+ deleteAll?: boolean;
20
+ ids?: string[];
21
+ }) => Promise<void>;
22
+ };
23
+ export declare function createLlamaIndexEmbeddingModel(embeddingModel: CompiledEmbeddingModel): EmbeddingRuntimeLike;
24
+ export declare function createLlamaIndexVectorStore(workspaceRoot: string, vectorStore: CompiledVectorStore, embeddings: EmbeddingRuntimeLike): Promise<VectorStoreRuntimeLike>;