@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.
- package/dist/api.d.ts +22 -0
- package/dist/api.js +48 -0
- package/dist/config/direct.yaml +48 -0
- package/dist/config/embedding-model.yaml +30 -0
- package/dist/config/model.yaml +44 -0
- package/dist/config/orchestra.yaml +92 -0
- package/dist/config/runtime.yaml +47 -0
- package/dist/config/vector-store.yaml +26 -0
- package/dist/contracts/types.d.ts +359 -0
- package/dist/contracts/types.js +1 -0
- package/dist/extensions.d.ts +16 -0
- package/dist/extensions.js +251 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/persistence/file-store.d.ts +39 -0
- package/dist/persistence/file-store.js +282 -0
- package/dist/presentation.d.ts +4 -0
- package/dist/presentation.js +175 -0
- package/dist/runtime/agent-runtime-adapter.d.ts +33 -0
- package/dist/runtime/agent-runtime-adapter.js +445 -0
- package/dist/runtime/event-bus.d.ts +6 -0
- package/dist/runtime/event-bus.js +15 -0
- package/dist/runtime/file-checkpoint-saver.d.ts +20 -0
- package/dist/runtime/file-checkpoint-saver.js +91 -0
- package/dist/runtime/harness.d.ts +57 -0
- package/dist/runtime/harness.js +696 -0
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/inventory.d.ts +25 -0
- package/dist/runtime/inventory.js +62 -0
- package/dist/runtime/parsing/index.d.ts +2 -0
- package/dist/runtime/parsing/index.js +2 -0
- package/dist/runtime/parsing/output-parsing.d.ts +12 -0
- package/dist/runtime/parsing/output-parsing.js +424 -0
- package/dist/runtime/parsing/stream-event-parsing.d.ts +27 -0
- package/dist/runtime/parsing/stream-event-parsing.js +161 -0
- package/dist/runtime/policy-engine.d.ts +9 -0
- package/dist/runtime/policy-engine.js +23 -0
- package/dist/runtime/store.d.ts +50 -0
- package/dist/runtime/store.js +118 -0
- package/dist/runtime/support/embedding-models.d.ts +4 -0
- package/dist/runtime/support/embedding-models.js +33 -0
- package/dist/runtime/support/harness-support.d.ts +27 -0
- package/dist/runtime/support/harness-support.js +116 -0
- package/dist/runtime/support/index.d.ts +4 -0
- package/dist/runtime/support/index.js +4 -0
- package/dist/runtime/support/llamaindex.d.ts +24 -0
- package/dist/runtime/support/llamaindex.js +108 -0
- package/dist/runtime/support/runtime-factories.d.ts +3 -0
- package/dist/runtime/support/runtime-factories.js +39 -0
- package/dist/runtime/support/skill-metadata.d.ts +1 -0
- package/dist/runtime/support/skill-metadata.js +34 -0
- package/dist/runtime/support/vector-stores.d.ts +7 -0
- package/dist/runtime/support/vector-stores.js +130 -0
- package/dist/runtime/thread-memory-sync.d.ts +14 -0
- package/dist/runtime/thread-memory-sync.js +88 -0
- package/dist/runtime/tool-hitl.d.ts +5 -0
- package/dist/runtime/tool-hitl.js +108 -0
- package/dist/utils/fs.d.ts +6 -0
- package/dist/utils/fs.js +39 -0
- package/dist/utils/id.d.ts +1 -0
- package/dist/utils/id.js +8 -0
- package/dist/vendor/builtins.d.ts +23 -0
- package/dist/vendor/builtins.js +103 -0
- package/dist/vendor/sources.d.ts +12 -0
- package/dist/vendor/sources.js +115 -0
- package/dist/workspace/agent-binding-compiler.d.ts +4 -0
- package/dist/workspace/agent-binding-compiler.js +181 -0
- package/dist/workspace/compile.d.ts +2 -0
- package/dist/workspace/compile.js +107 -0
- package/dist/workspace/index.d.ts +6 -0
- package/dist/workspace/index.js +6 -0
- package/dist/workspace/object-loader.d.ts +16 -0
- package/dist/workspace/object-loader.js +405 -0
- package/dist/workspace/resource-compilers.d.ts +13 -0
- package/dist/workspace/resource-compilers.js +182 -0
- package/dist/workspace/support/discovery.d.ts +5 -0
- package/dist/workspace/support/discovery.js +108 -0
- package/dist/workspace/support/index.d.ts +2 -0
- package/dist/workspace/support/index.js +2 -0
- package/dist/workspace/support/source-collectors.d.ts +3 -0
- package/dist/workspace/support/source-collectors.js +30 -0
- package/dist/workspace/support/workspace-ref-utils.d.ts +8 -0
- package/dist/workspace/support/workspace-ref-utils.js +50 -0
- package/dist/workspace/validate.d.ts +3 -0
- package/dist/workspace/validate.js +65 -0
- package/package.json +32 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
3
|
+
import { ensureDir, fileExists, readJson, writeJson } from "../utils/fs.js";
|
|
4
|
+
export class FilePersistence {
|
|
5
|
+
runRoot;
|
|
6
|
+
constructor(runRoot) {
|
|
7
|
+
this.runRoot = runRoot;
|
|
8
|
+
}
|
|
9
|
+
async initialize() {
|
|
10
|
+
await Promise.all([
|
|
11
|
+
"indexes/threads",
|
|
12
|
+
"indexes/runs",
|
|
13
|
+
"indexes/approvals",
|
|
14
|
+
"indexes/delegations",
|
|
15
|
+
"threads",
|
|
16
|
+
].map((segment) => ensureDir(path.join(this.runRoot, segment))));
|
|
17
|
+
}
|
|
18
|
+
threadDir(threadId) {
|
|
19
|
+
return path.join(this.runRoot, "threads", threadId);
|
|
20
|
+
}
|
|
21
|
+
runDir(threadId, runId) {
|
|
22
|
+
return path.join(this.threadDir(threadId), "runs", runId);
|
|
23
|
+
}
|
|
24
|
+
async createThread(input) {
|
|
25
|
+
const meta = {
|
|
26
|
+
threadId: input.threadId,
|
|
27
|
+
workspaceId: "default",
|
|
28
|
+
entryAgentId: input.agentId,
|
|
29
|
+
createdAt: input.createdAt,
|
|
30
|
+
updatedAt: input.createdAt,
|
|
31
|
+
status: input.status,
|
|
32
|
+
latestRunId: input.runId,
|
|
33
|
+
};
|
|
34
|
+
await writeJson(path.join(this.threadDir(input.threadId), "meta.json"), meta);
|
|
35
|
+
await writeJson(path.join(this.threadDir(input.threadId), "messages.json"), {
|
|
36
|
+
threadId: input.threadId,
|
|
37
|
+
items: [],
|
|
38
|
+
});
|
|
39
|
+
await writeJson(path.join(this.runRoot, "indexes", "threads", `${input.threadId}.json`), {
|
|
40
|
+
threadId: input.threadId,
|
|
41
|
+
status: input.status,
|
|
42
|
+
latestRunId: input.runId,
|
|
43
|
+
updatedAt: input.createdAt,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async createRun(input) {
|
|
47
|
+
const runDir = this.runDir(input.threadId, input.runId);
|
|
48
|
+
await ensureDir(path.join(runDir, "events"));
|
|
49
|
+
await ensureDir(path.join(runDir, "approvals"));
|
|
50
|
+
await ensureDir(path.join(runDir, "delegations"));
|
|
51
|
+
const meta = {
|
|
52
|
+
runId: input.runId,
|
|
53
|
+
threadId: input.threadId,
|
|
54
|
+
agentId: input.agentId,
|
|
55
|
+
executionMode: input.executionMode,
|
|
56
|
+
createdAt: input.createdAt,
|
|
57
|
+
updatedAt: input.createdAt,
|
|
58
|
+
};
|
|
59
|
+
const lifecycle = {
|
|
60
|
+
state: "running",
|
|
61
|
+
previousState: null,
|
|
62
|
+
stateEnteredAt: input.createdAt,
|
|
63
|
+
lastTransitionAt: input.createdAt,
|
|
64
|
+
resumable: false,
|
|
65
|
+
checkpointRef: null,
|
|
66
|
+
};
|
|
67
|
+
await Promise.all([
|
|
68
|
+
writeJson(path.join(runDir, "meta.json"), meta),
|
|
69
|
+
writeJson(path.join(runDir, "lifecycle.json"), lifecycle),
|
|
70
|
+
writeJson(path.join(runDir, "checkpoint-ref.json"), {
|
|
71
|
+
threadId: input.threadId,
|
|
72
|
+
runId: input.runId,
|
|
73
|
+
checkpointRef: null,
|
|
74
|
+
savedAt: input.createdAt,
|
|
75
|
+
kind: "langgraph-checkpoint",
|
|
76
|
+
}),
|
|
77
|
+
writeJson(path.join(runDir, "artifacts.json"), {
|
|
78
|
+
threadId: input.threadId,
|
|
79
|
+
runId: input.runId,
|
|
80
|
+
items: [],
|
|
81
|
+
}),
|
|
82
|
+
writeJson(path.join(runDir, "error.json"), {
|
|
83
|
+
hasError: false,
|
|
84
|
+
lastError: null,
|
|
85
|
+
}),
|
|
86
|
+
writeJson(path.join(this.runRoot, "indexes", "runs", `${input.runId}.json`), {
|
|
87
|
+
runId: input.runId,
|
|
88
|
+
threadId: input.threadId,
|
|
89
|
+
state: "running",
|
|
90
|
+
resumable: false,
|
|
91
|
+
updatedAt: input.createdAt,
|
|
92
|
+
}),
|
|
93
|
+
]);
|
|
94
|
+
}
|
|
95
|
+
async setRunState(threadId, runId, state, checkpointRef) {
|
|
96
|
+
const lifecyclePath = path.join(this.runDir(threadId, runId), "lifecycle.json");
|
|
97
|
+
const lifecycle = await readJson(lifecyclePath);
|
|
98
|
+
const now = new Date().toISOString();
|
|
99
|
+
const next = {
|
|
100
|
+
state,
|
|
101
|
+
previousState: lifecycle.state,
|
|
102
|
+
stateEnteredAt: now,
|
|
103
|
+
lastTransitionAt: now,
|
|
104
|
+
resumable: state === "waiting_for_approval",
|
|
105
|
+
checkpointRef: checkpointRef ?? lifecycle.checkpointRef,
|
|
106
|
+
};
|
|
107
|
+
await writeJson(lifecyclePath, next);
|
|
108
|
+
if (checkpointRef !== undefined) {
|
|
109
|
+
await writeJson(path.join(this.runDir(threadId, runId), "checkpoint-ref.json"), {
|
|
110
|
+
threadId,
|
|
111
|
+
runId,
|
|
112
|
+
checkpointRef,
|
|
113
|
+
savedAt: now,
|
|
114
|
+
kind: "langgraph-checkpoint",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
await writeJson(path.join(this.runRoot, "indexes", "runs", `${runId}.json`), {
|
|
118
|
+
runId,
|
|
119
|
+
threadId,
|
|
120
|
+
state,
|
|
121
|
+
resumable: next.resumable,
|
|
122
|
+
updatedAt: now,
|
|
123
|
+
});
|
|
124
|
+
const threadMetaPath = path.join(this.threadDir(threadId), "meta.json");
|
|
125
|
+
const threadMeta = await readJson(threadMetaPath);
|
|
126
|
+
threadMeta.status = state;
|
|
127
|
+
threadMeta.updatedAt = now;
|
|
128
|
+
threadMeta.latestRunId = runId;
|
|
129
|
+
await writeJson(threadMetaPath, threadMeta);
|
|
130
|
+
await writeJson(path.join(this.runRoot, "indexes", "threads", `${threadId}.json`), {
|
|
131
|
+
threadId,
|
|
132
|
+
status: state,
|
|
133
|
+
latestRunId: runId,
|
|
134
|
+
updatedAt: now,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async appendEvent(event) {
|
|
138
|
+
const sequenceId = String(event.sequence).padStart(6, "0");
|
|
139
|
+
await writeJson(path.join(this.runDir(event.threadId, event.runId), "events", `${sequenceId}.json`), event);
|
|
140
|
+
}
|
|
141
|
+
async listSessions() {
|
|
142
|
+
const threadIndexDir = path.join(this.runRoot, "indexes", "threads");
|
|
143
|
+
if (!(await fileExists(threadIndexDir))) {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
const entries = await readdir(threadIndexDir);
|
|
147
|
+
const records = await Promise.all(entries.map(async (entry) => {
|
|
148
|
+
const index = await readJson(path.join(threadIndexDir, entry));
|
|
149
|
+
const meta = await readJson(path.join(this.threadDir(index.threadId), "meta.json"));
|
|
150
|
+
return {
|
|
151
|
+
agentId: meta.entryAgentId,
|
|
152
|
+
threadId: index.threadId,
|
|
153
|
+
latestRunId: index.latestRunId,
|
|
154
|
+
createdAt: meta.createdAt,
|
|
155
|
+
updatedAt: index.updatedAt,
|
|
156
|
+
status: index.status,
|
|
157
|
+
};
|
|
158
|
+
}));
|
|
159
|
+
return records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
160
|
+
}
|
|
161
|
+
async getSession(threadId) {
|
|
162
|
+
const filePath = path.join(this.runRoot, "indexes", "threads", `${threadId}.json`);
|
|
163
|
+
if (!(await fileExists(filePath))) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const [index, meta] = await Promise.all([
|
|
167
|
+
readJson(filePath),
|
|
168
|
+
readJson(path.join(this.threadDir(threadId), "meta.json")),
|
|
169
|
+
]);
|
|
170
|
+
return {
|
|
171
|
+
agentId: meta.entryAgentId,
|
|
172
|
+
threadId,
|
|
173
|
+
latestRunId: index.latestRunId,
|
|
174
|
+
createdAt: meta.createdAt,
|
|
175
|
+
updatedAt: index.updatedAt,
|
|
176
|
+
status: index.status,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
async listRunEvents(threadId, runId) {
|
|
180
|
+
const eventsDir = path.join(this.runDir(threadId, runId), "events");
|
|
181
|
+
if (!(await fileExists(eventsDir))) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
const entries = (await readdir(eventsDir)).sort();
|
|
185
|
+
return Promise.all(entries.map((entry) => readJson(path.join(eventsDir, entry))));
|
|
186
|
+
}
|
|
187
|
+
async listApprovals() {
|
|
188
|
+
const approvalsDir = path.join(this.runRoot, "indexes", "approvals");
|
|
189
|
+
if (!(await fileExists(approvalsDir))) {
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
const entries = (await readdir(approvalsDir)).sort();
|
|
193
|
+
return Promise.all(entries.map((entry) => readJson(path.join(approvalsDir, entry))));
|
|
194
|
+
}
|
|
195
|
+
async getApproval(approvalId) {
|
|
196
|
+
const approvalPath = path.join(this.runRoot, "indexes", "approvals", `${approvalId}.json`);
|
|
197
|
+
if (!(await fileExists(approvalPath))) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
return readJson(approvalPath);
|
|
201
|
+
}
|
|
202
|
+
async getRunApprovals(threadId, runId) {
|
|
203
|
+
const approvalsDir = path.join(this.runDir(threadId, runId), "approvals");
|
|
204
|
+
if (!(await fileExists(approvalsDir))) {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
const entries = (await readdir(approvalsDir)).sort();
|
|
208
|
+
return Promise.all(entries.map((entry) => readJson(path.join(approvalsDir, entry))));
|
|
209
|
+
}
|
|
210
|
+
async listDelegations() {
|
|
211
|
+
const delegationsDir = path.join(this.runRoot, "indexes", "delegations");
|
|
212
|
+
if (!(await fileExists(delegationsDir))) {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
const entries = (await readdir(delegationsDir)).sort();
|
|
216
|
+
return Promise.all(entries.map((entry) => readJson(path.join(delegationsDir, entry))));
|
|
217
|
+
}
|
|
218
|
+
async createApproval(record) {
|
|
219
|
+
await Promise.all([
|
|
220
|
+
writeJson(path.join(this.runDir(record.threadId, record.runId), "approvals", `${record.approvalId}.json`), record),
|
|
221
|
+
writeJson(path.join(this.runRoot, "indexes", "approvals", `${record.approvalId}.json`), record),
|
|
222
|
+
]);
|
|
223
|
+
}
|
|
224
|
+
async resolveApproval(threadId, runId, approvalId, status) {
|
|
225
|
+
const approvalPath = path.join(this.runDir(threadId, runId), "approvals", `${approvalId}.json`);
|
|
226
|
+
const current = await readJson(approvalPath);
|
|
227
|
+
const updated = {
|
|
228
|
+
...current,
|
|
229
|
+
status,
|
|
230
|
+
resolvedAt: new Date().toISOString(),
|
|
231
|
+
};
|
|
232
|
+
await Promise.all([
|
|
233
|
+
writeJson(approvalPath, updated),
|
|
234
|
+
writeJson(path.join(this.runRoot, "indexes", "approvals", `${approvalId}.json`), updated),
|
|
235
|
+
]);
|
|
236
|
+
return updated;
|
|
237
|
+
}
|
|
238
|
+
async createDelegation(record) {
|
|
239
|
+
await Promise.all([
|
|
240
|
+
writeJson(path.join(this.runDir(record.threadId, record.runId), "delegations", `${record.delegationId}.json`), record),
|
|
241
|
+
writeJson(path.join(this.runRoot, "indexes", "delegations", `${record.delegationId}.json`), record),
|
|
242
|
+
]);
|
|
243
|
+
}
|
|
244
|
+
async updateDelegation(threadId, runId, delegationId, patch) {
|
|
245
|
+
const delegationPath = path.join(this.runDir(threadId, runId), "delegations", `${delegationId}.json`);
|
|
246
|
+
const current = await readJson(delegationPath);
|
|
247
|
+
const updated = { ...current, ...patch };
|
|
248
|
+
await Promise.all([
|
|
249
|
+
writeJson(delegationPath, updated),
|
|
250
|
+
writeJson(path.join(this.runRoot, "indexes", "delegations", `${delegationId}.json`), updated),
|
|
251
|
+
]);
|
|
252
|
+
return updated;
|
|
253
|
+
}
|
|
254
|
+
async createArtifact(threadId, runId, artifact, content) {
|
|
255
|
+
const runDir = this.runDir(threadId, runId);
|
|
256
|
+
await writeJson(path.join(runDir, artifact.path), content);
|
|
257
|
+
const artifactsPath = path.join(runDir, "artifacts.json");
|
|
258
|
+
const current = await readJson(artifactsPath);
|
|
259
|
+
current.items.push(artifact);
|
|
260
|
+
await writeJson(artifactsPath, current);
|
|
261
|
+
return artifact;
|
|
262
|
+
}
|
|
263
|
+
async listArtifacts(threadId, runId) {
|
|
264
|
+
return readJson(path.join(this.runDir(threadId, runId), "artifacts.json"));
|
|
265
|
+
}
|
|
266
|
+
async appendThreadMessage(threadId, message) {
|
|
267
|
+
const messagesPath = path.join(this.threadDir(threadId), "messages.json");
|
|
268
|
+
const current = (await fileExists(messagesPath))
|
|
269
|
+
? await readJson(messagesPath)
|
|
270
|
+
: { threadId, items: [] };
|
|
271
|
+
current.items.push(message);
|
|
272
|
+
await writeJson(messagesPath, current);
|
|
273
|
+
}
|
|
274
|
+
async listThreadMessages(threadId, limit = 12) {
|
|
275
|
+
const messagesPath = path.join(this.threadDir(threadId), "messages.json");
|
|
276
|
+
if (!(await fileExists(messagesPath))) {
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
const current = await readJson(messagesPath);
|
|
280
|
+
return current.items.slice(-limit);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function escapeHtml(value: string): string;
|
|
2
|
+
export declare function markdownToHtml(markdown: string): string;
|
|
3
|
+
export declare function markdownToConsole(markdown: string): string;
|
|
4
|
+
export declare function renderTemplate(data: Record<string, unknown>, template: string): string;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import Mustache from "mustache";
|
|
3
|
+
export function escapeHtml(value) {
|
|
4
|
+
return value
|
|
5
|
+
.replaceAll("&", "&")
|
|
6
|
+
.replaceAll("<", "<")
|
|
7
|
+
.replaceAll(">", ">")
|
|
8
|
+
.replaceAll('"', """)
|
|
9
|
+
.replaceAll("'", "'");
|
|
10
|
+
}
|
|
11
|
+
function renderInlineMarkdown(text) {
|
|
12
|
+
const escaped = escapeHtml(text);
|
|
13
|
+
return escaped
|
|
14
|
+
.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>")
|
|
15
|
+
.replace(/\*(.+?)\*/g, "<em>$1</em>")
|
|
16
|
+
.replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
17
|
+
}
|
|
18
|
+
function renderInlineConsoleMarkdown(text) {
|
|
19
|
+
return text
|
|
20
|
+
.replace(/`([^`]+)`/g, "\u001b[100m $1 \u001b[0m")
|
|
21
|
+
.replace(/\*\*([^*]+)\*\*/g, "\u001b[1m$1\u001b[0m")
|
|
22
|
+
.replace(/\*([^*]+)\*/g, "\u001b[3m$1\u001b[0m")
|
|
23
|
+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1 ($2)");
|
|
24
|
+
}
|
|
25
|
+
function stripAnsi(text) {
|
|
26
|
+
return text.replace(/\u001b\[[0-9;]*m/g, "");
|
|
27
|
+
}
|
|
28
|
+
function parseMarkdownTableRow(line) {
|
|
29
|
+
const normalized = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
30
|
+
return normalized.split("|").map((cell) => cell.trim());
|
|
31
|
+
}
|
|
32
|
+
function isMarkdownTableSeparator(line) {
|
|
33
|
+
const cells = parseMarkdownTableRow(line);
|
|
34
|
+
return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
|
|
35
|
+
}
|
|
36
|
+
function renderMarkdownTable(block) {
|
|
37
|
+
const lines = block
|
|
38
|
+
.split("\n")
|
|
39
|
+
.map((line) => line.trimEnd())
|
|
40
|
+
.filter((line) => line.trim().length > 0);
|
|
41
|
+
if (lines.length < 2 || !lines.every((line) => line.includes("|")) || !isMarkdownTableSeparator(lines[1] ?? "")) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const rows = lines.map(parseMarkdownTableRow);
|
|
45
|
+
const header = rows[0] ?? [];
|
|
46
|
+
const body = rows.slice(2);
|
|
47
|
+
const columnCount = Math.max(header.length, ...body.map((row) => row.length));
|
|
48
|
+
const normalizedRows = [header, ...body].map((row) => Array.from({ length: columnCount }, (_, index) => renderInlineConsoleMarkdown(row[index] ?? "")));
|
|
49
|
+
const widths = Array.from({ length: columnCount }, (_, index) => Math.max(...normalizedRows.map((row) => stripAnsi(row[index] ?? "").length), 0));
|
|
50
|
+
const renderRow = (row) => `| ${row
|
|
51
|
+
.map((cell, index) => cell.padEnd(widths[index] + (cell.length - stripAnsi(cell).length)))
|
|
52
|
+
.join(" | ")} |`;
|
|
53
|
+
const separator = `|-${widths.map((width) => "-".repeat(Math.max(3, width))).join("-|-")}-|`;
|
|
54
|
+
return [renderRow(normalizedRows[0] ?? []), separator, ...normalizedRows.slice(1).map(renderRow)].join("\n");
|
|
55
|
+
}
|
|
56
|
+
export function markdownToHtml(markdown) {
|
|
57
|
+
const normalized = markdown.replace(/\r\n/g, "\n");
|
|
58
|
+
const blocks = normalized.split(/\n\n+/);
|
|
59
|
+
const html = [];
|
|
60
|
+
for (const block of blocks) {
|
|
61
|
+
const trimmed = block.trim();
|
|
62
|
+
if (!trimmed) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (trimmed.startsWith("```") && trimmed.endsWith("```")) {
|
|
66
|
+
const lines = trimmed.split("\n");
|
|
67
|
+
const language = lines[0]?.slice(3).trim();
|
|
68
|
+
const code = lines.slice(1, -1).join("\n");
|
|
69
|
+
html.push(`<pre class="ah-code"><code${language ? ` data-language="${escapeHtml(language)}"` : ""}>${escapeHtml(code)}</code></pre>`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (/^#{1,6}\s/.test(trimmed)) {
|
|
73
|
+
const match = trimmed.match(/^(#{1,6})\s+(.*)$/);
|
|
74
|
+
const level = match?.[1].length ?? 1;
|
|
75
|
+
const content = renderInlineMarkdown(match?.[2] ?? trimmed);
|
|
76
|
+
html.push(`<h${level}>${content}</h${level}>`);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (trimmed.split("\n").every((line) => /^[-*]\s+/.test(line))) {
|
|
80
|
+
const items = trimmed
|
|
81
|
+
.split("\n")
|
|
82
|
+
.map((line) => line.replace(/^[-*]\s+/, ""))
|
|
83
|
+
.map((line) => `<li>${renderInlineMarkdown(line)}</li>`)
|
|
84
|
+
.join("");
|
|
85
|
+
html.push(`<ul>${items}</ul>`);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
html.push(`<p>${trimmed
|
|
89
|
+
.split("\n")
|
|
90
|
+
.map((line) => renderInlineMarkdown(line))
|
|
91
|
+
.join("<br />")}</p>`);
|
|
92
|
+
}
|
|
93
|
+
return html.join("");
|
|
94
|
+
}
|
|
95
|
+
export function markdownToConsole(markdown) {
|
|
96
|
+
if (!markdown.includes("\n")) {
|
|
97
|
+
return renderInlineConsoleMarkdown(markdown);
|
|
98
|
+
}
|
|
99
|
+
const normalized = markdown.replace(/\r\n/g, "\n");
|
|
100
|
+
const blocks = normalized.split(/\n\n+/);
|
|
101
|
+
const rendered = [];
|
|
102
|
+
for (const block of blocks) {
|
|
103
|
+
const trimmed = block.trim();
|
|
104
|
+
if (!trimmed) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const table = renderMarkdownTable(trimmed);
|
|
108
|
+
if (table) {
|
|
109
|
+
rendered.push(table);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (trimmed.startsWith("```") && trimmed.endsWith("```")) {
|
|
113
|
+
const lines = trimmed.split("\n");
|
|
114
|
+
const language = lines[0]?.slice(3).trim();
|
|
115
|
+
const code = lines.slice(1, -1);
|
|
116
|
+
const label = language ? ` ${language} ` : " code ";
|
|
117
|
+
rendered.push([
|
|
118
|
+
`\u001b[2m┌${"─".repeat(Math.max(label.length, 6))}\u001b[0m`,
|
|
119
|
+
`\u001b[2m│\u001b[0m${label}`,
|
|
120
|
+
...code.map((line) => ` ${line}`),
|
|
121
|
+
"\u001b[2m└──────\u001b[0m",
|
|
122
|
+
].join("\n"));
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (/^#{1,6}\s/.test(trimmed)) {
|
|
126
|
+
const match = trimmed.match(/^(#{1,6})\s+(.*)$/);
|
|
127
|
+
const level = match?.[1].length ?? 1;
|
|
128
|
+
const title = renderInlineConsoleMarkdown(match?.[2] ?? trimmed);
|
|
129
|
+
const underline = level === 1 ? "=" : "-";
|
|
130
|
+
rendered.push(`\u001b[1m${title}\u001b[0m\n\u001b[2m${underline.repeat(Math.max(3, title.replace(/\u001b\[[0-9;]*m/g, "").length))}\u001b[0m`);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (trimmed.split("\n").every((line) => /^[-*]\s+/.test(line))) {
|
|
134
|
+
rendered.push(trimmed
|
|
135
|
+
.split("\n")
|
|
136
|
+
.map((line) => line.replace(/^[-*]\s+/, "• "))
|
|
137
|
+
.map((line) => renderInlineConsoleMarkdown(line))
|
|
138
|
+
.join("\n"));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (trimmed.split("\n").every((line) => /^\d+\.\s+/.test(line))) {
|
|
142
|
+
rendered.push(trimmed
|
|
143
|
+
.split("\n")
|
|
144
|
+
.map((line) => renderInlineConsoleMarkdown(line))
|
|
145
|
+
.join("\n"));
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (trimmed.split("\n").every((line) => /^>\s?/.test(line))) {
|
|
149
|
+
rendered.push(trimmed
|
|
150
|
+
.split("\n")
|
|
151
|
+
.map((line) => line.replace(/^>\s?/, ""))
|
|
152
|
+
.map((line) => `\u001b[2m│\u001b[0m ${renderInlineConsoleMarkdown(line)}`)
|
|
153
|
+
.join("\n"));
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (/^([-*_])(?:\s*\1){2,}$/.test(trimmed)) {
|
|
157
|
+
rendered.push(`\u001b[2m${"─".repeat(24)}\u001b[0m`);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
rendered.push(trimmed
|
|
161
|
+
.split("\n")
|
|
162
|
+
.map((line) => renderInlineConsoleMarkdown(line))
|
|
163
|
+
.join("\n"));
|
|
164
|
+
}
|
|
165
|
+
return rendered.join("\n\n");
|
|
166
|
+
}
|
|
167
|
+
function resolveTemplateSource(template) {
|
|
168
|
+
if (existsSync(template)) {
|
|
169
|
+
return readFileSync(template, "utf8");
|
|
170
|
+
}
|
|
171
|
+
return template;
|
|
172
|
+
}
|
|
173
|
+
export function renderTemplate(data, template) {
|
|
174
|
+
return Mustache.render(resolveTemplateSource(template), data);
|
|
175
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { CompiledAgentBinding, RunResult, RuntimeAdapterOptions, TranscriptMessage } from "../contracts/types.js";
|
|
2
|
+
import { type RuntimeStreamChunk } from "./parsing/stream-event-parsing.js";
|
|
3
|
+
type RunnableLike = {
|
|
4
|
+
invoke: (input: unknown, config?: Record<string, unknown>) => Promise<unknown>;
|
|
5
|
+
stream?: (input: unknown, config?: Record<string, unknown>) => Promise<AsyncIterable<unknown>>;
|
|
6
|
+
streamEvents?: (input: unknown, config?: Record<string, unknown>) => Promise<AsyncIterable<unknown>>;
|
|
7
|
+
};
|
|
8
|
+
declare const AGENT_INTERRUPT_SENTINEL_PREFIX = "__agent_harness_interrupt__:";
|
|
9
|
+
export declare class AgentRuntimeAdapter {
|
|
10
|
+
private readonly options;
|
|
11
|
+
constructor(options?: RuntimeAdapterOptions);
|
|
12
|
+
private materializeModelStream;
|
|
13
|
+
private createModelFallbackRunnable;
|
|
14
|
+
private applyStrictToolJsonInstruction;
|
|
15
|
+
private synthesizeDeepAgentAnswer;
|
|
16
|
+
private resolveModel;
|
|
17
|
+
private resolveTools;
|
|
18
|
+
private normalizeInterruptPolicy;
|
|
19
|
+
private compileInterruptOn;
|
|
20
|
+
private resolveInterruptOn;
|
|
21
|
+
private resolveMiddleware;
|
|
22
|
+
private resolveCheckpointer;
|
|
23
|
+
private buildRouteSystemPrompt;
|
|
24
|
+
private resolveSubagents;
|
|
25
|
+
private buildConversation;
|
|
26
|
+
create(binding: CompiledAgentBinding): Promise<RunnableLike>;
|
|
27
|
+
route(input: string, primaryBinding: CompiledAgentBinding, secondaryBinding: CompiledAgentBinding, options?: {
|
|
28
|
+
systemPrompt?: string;
|
|
29
|
+
}): Promise<string>;
|
|
30
|
+
invoke(binding: CompiledAgentBinding, input: string, threadId: string, runId: string, resumePayload?: unknown, history?: TranscriptMessage[]): Promise<RunResult>;
|
|
31
|
+
stream(binding: CompiledAgentBinding, input: string, threadId: string, history?: TranscriptMessage[]): AsyncGenerator<RuntimeStreamChunk | string>;
|
|
32
|
+
}
|
|
33
|
+
export { AgentRuntimeAdapter as RuntimeAdapter, AGENT_INTERRUPT_SENTINEL_PREFIX, AGENT_INTERRUPT_SENTINEL_PREFIX as INTERRUPT_SENTINEL_PREFIX, };
|