pi-extensible-workflows 0.3.2 → 1.0.0
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 +9 -0
- package/dist/src/agent-execution.d.ts +81 -8
- package/dist/src/agent-execution.js +421 -71
- package/dist/src/doctor.d.ts +4 -1
- package/dist/src/doctor.js +56 -11
- package/dist/src/index.d.ts +217 -22
- package/dist/src/index.js +1416 -337
- package/dist/src/persistence.d.ts +26 -1
- package/dist/src/persistence.js +100 -6
- package/dist/src/session-inspector.d.ts +13 -1
- package/dist/src/session-inspector.js +22 -4
- package/dist/src/workflow-evals.js +1 -1
- package/package.json +1 -1
- package/skills/pi-extensible-workflows/SKILL.md +9 -5
- package/src/agent-execution.ts +350 -83
- package/src/doctor.ts +59 -12
- package/src/index.ts +1231 -360
- package/src/persistence.ts +76 -7
- package/src/session-inspector.ts +25 -7
- package/src/workflow-evals.ts +1 -1
package/src/persistence.ts
CHANGED
|
@@ -4,17 +4,26 @@ import { access, link, mkdir, open, readFile, readdir, rename, rm, stat, writeFi
|
|
|
4
4
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
|
-
import type { JsonValue, LaunchSnapshot, RunRecord } from "./index.js";
|
|
7
|
+
import type { BudgetApprovalRequest, JsonValue, LaunchSnapshot, RunRecord, WorkflowRunEvent } from "./index.js";
|
|
8
8
|
import type { OwnershipRecord } from "./agent-execution.js";
|
|
9
9
|
import { loadLaunchSnapshot, WorkflowError } from "./index.js";
|
|
10
10
|
|
|
11
11
|
export interface NativeSessionReference { sessionId: string; sessionFile: string }
|
|
12
12
|
export interface EffectiveSystemPrompt { sessionId: string; attempt: number; turn: number; sha256: string; prompt: string }
|
|
13
|
+
export interface ConversationHead { turn: number; sessionId: string; sessionFile: string; leafId: string; systemPrompt: string; systemPromptSha256: string; toolDefinitionsSha256: string }
|
|
14
|
+
export interface PersistedConversation { id: string; policy: JsonValue; head: ConversationHead }
|
|
15
|
+
type ConversationArtifact = { version: 1; conversations: Record<string, PersistedConversation> };
|
|
16
|
+
function isConversationArtifact(value: unknown): value is ConversationArtifact {
|
|
17
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
18
|
+
const artifact = value as { version?: unknown; conversations?: unknown };
|
|
19
|
+
return artifact.version === 1 && Boolean(artifact.conversations) && typeof artifact.conversations === "object" && !Array.isArray(artifact.conversations);
|
|
20
|
+
}
|
|
13
21
|
export interface PersistedRun extends RunRecord { nativeSessions: readonly NativeSessionReference[] }
|
|
14
22
|
export interface CompletedOperation { path: string; value: JsonValue }
|
|
15
23
|
export interface AwaitingCheckpoint { path: string; name: string; prompt: string; context: JsonValue }
|
|
24
|
+
export type PendingWorkflowDecision = BudgetApprovalRequest
|
|
16
25
|
export type PersistedOwnershipNode = OwnershipRecord
|
|
17
|
-
type Journal = { completed: Record<string, CompletedOperation>; awaiting?: Record<string, AwaitingCheckpoint> };
|
|
26
|
+
type Journal = { completed: Record<string, CompletedOperation>; awaiting?: Record<string, AwaitingCheckpoint>; decisions?: Record<string, PendingWorkflowDecision> };
|
|
18
27
|
export interface WorktreeReference { owner: string; path: string; branch: string; cwd: string; base: string }
|
|
19
28
|
|
|
20
29
|
const execute = promisify(execFile);
|
|
@@ -164,8 +173,10 @@ export class RunStore {
|
|
|
164
173
|
private stateWrite: Promise<void> = Promise.resolve();
|
|
165
174
|
private worktreeWrite: Promise<void> = Promise.resolve();
|
|
166
175
|
private snapshotWrite: Promise<void> = Promise.resolve();
|
|
176
|
+
private launchSnapshotWrite: Promise<void> = Promise.resolve();
|
|
167
177
|
// ponytail: the session lease prevents concurrent RunStore writers for one run.
|
|
168
178
|
private systemPromptWrite: Promise<void> = Promise.resolve();
|
|
179
|
+
private conversationWrite: Promise<void> = Promise.resolve();
|
|
169
180
|
constructor(readonly cwd: string, readonly sessionId: string, readonly runId: string, home = homedir()) {
|
|
170
181
|
this.cwd = resolve(cwd);
|
|
171
182
|
this.directory = join(runsDirectory(this.cwd, sessionId, home), safePart(runId));
|
|
@@ -177,12 +188,14 @@ export class RunStore {
|
|
|
177
188
|
await mkdir(dirname(this.directory), { recursive: true, mode: 0o700 });
|
|
178
189
|
await mkdir(temporary, { mode: 0o700 });
|
|
179
190
|
try {
|
|
191
|
+
await writeFile(join(temporary, "workflow.js"), snapshot.script, { encoding: "utf8", mode: 0o600 });
|
|
180
192
|
await atomicJson(join(temporary, "snapshot.json"), snapshot);
|
|
181
|
-
await atomicJson(join(temporary, "journal.json"), { completed: {}, awaiting: {} });
|
|
193
|
+
await atomicJson(join(temporary, "journal.json"), { completed: {}, awaiting: {}, decisions: {} });
|
|
182
194
|
await atomicJson(join(temporary, "ownership.json"), []);
|
|
183
195
|
await atomicJson(join(temporary, "worktrees.json"), []);
|
|
184
196
|
await atomicJson(join(temporary, "state.json"), run);
|
|
185
197
|
await atomicJson(join(temporary, "system-prompts.json"), { version: 1, entries: [] });
|
|
198
|
+
await atomicJson(join(temporary, "conversations.json"), { version: 1, conversations: {} });
|
|
186
199
|
await rename(temporary, this.directory);
|
|
187
200
|
} catch (error) {
|
|
188
201
|
await rm(temporary, { recursive: true, force: true });
|
|
@@ -225,6 +238,16 @@ export class RunStore {
|
|
|
225
238
|
return result;
|
|
226
239
|
}
|
|
227
240
|
|
|
241
|
+
async saveSnapshot(snapshot: Readonly<LaunchSnapshot>): Promise<void> {
|
|
242
|
+
const write = this.launchSnapshotWrite.then(() => atomicJson(join(this.directory, "snapshot.json"), snapshot));
|
|
243
|
+
this.launchSnapshotWrite = write.catch(() => undefined);
|
|
244
|
+
await write;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async appendEvent(event: WorkflowRunEvent): Promise<void> {
|
|
248
|
+
await this.updateState((run) => ({ ...run, events: [...(run.events ?? []), ...(run.events?.some((current) => current.message === event.message) ? [] : [event])] }));
|
|
249
|
+
}
|
|
250
|
+
|
|
228
251
|
async saveOwnership(nodes: readonly PersistedOwnershipNode[]): Promise<void> {
|
|
229
252
|
await atomicJson(join(this.directory, "ownership.json"), nodes);
|
|
230
253
|
}
|
|
@@ -251,6 +274,27 @@ export class RunStore {
|
|
|
251
274
|
return (await json<{ version: 1; entries: EffectiveSystemPrompt[] }>(this.systemPromptPath()).catch((error: unknown) => { if ((error as NodeJS.ErrnoException).code === "ENOENT") return { version: 1 as const, entries: [] }; throw error; })).entries;
|
|
252
275
|
}
|
|
253
276
|
|
|
277
|
+
conversationPath(): string { return join(this.directory, "conversations.json"); }
|
|
278
|
+
async conversation(id: string): Promise<PersistedConversation | undefined> {
|
|
279
|
+
await this.conversationWrite;
|
|
280
|
+
let artifact: ConversationArtifact;
|
|
281
|
+
try { const raw = await json<unknown>(this.conversationPath()); if (!isConversationArtifact(raw)) throw new WorkflowError("RESUME_INCOMPATIBLE", "Conversation state is corrupt"); artifact = raw; } catch (error) { if ((error as NodeJS.ErrnoException).code === "ENOENT") return undefined; if (error instanceof WorkflowError) throw error; throw new WorkflowError("RESUME_INCOMPATIBLE", `Cannot load conversation state: ${error instanceof Error ? error.message : String(error)}`); }
|
|
282
|
+
return artifact.conversations[id];
|
|
283
|
+
}
|
|
284
|
+
async saveConversation(conversation: PersistedConversation): Promise<void> {
|
|
285
|
+
const write = this.conversationWrite.then(async () => {
|
|
286
|
+
const path = this.conversationPath();
|
|
287
|
+
let artifact: ConversationArtifact;
|
|
288
|
+
try { const raw = await json<unknown>(path); if (!isConversationArtifact(raw)) throw new WorkflowError("RESUME_INCOMPATIBLE", "Conversation state is corrupt"); artifact = raw; } catch (error) { if ((error as NodeJS.ErrnoException).code === "ENOENT") artifact = { version: 1, conversations: {} }; else if (error instanceof WorkflowError) throw error; else throw new WorkflowError("RESUME_INCOMPATIBLE", `Cannot load conversation state: ${error instanceof Error ? error.message : String(error)}`); }
|
|
289
|
+
const previous = artifact.conversations[conversation.id];
|
|
290
|
+
if (previous && previous.head.turn + 1 !== conversation.head.turn) throw new WorkflowError("RESUME_INCOMPATIBLE", `Conversation head is not the previous turn: ${conversation.id}`);
|
|
291
|
+
if (!previous && conversation.head.turn !== 1) throw new WorkflowError("RESUME_INCOMPATIBLE", `Conversation must start at turn one: ${conversation.id}`);
|
|
292
|
+
artifact.conversations[conversation.id] = structuredClone(conversation);
|
|
293
|
+
await atomicJson(path, artifact);
|
|
294
|
+
});
|
|
295
|
+
this.conversationWrite = write.catch(() => undefined);
|
|
296
|
+
await write;
|
|
297
|
+
}
|
|
254
298
|
private async updateJournal<T>(update: (journal: Journal) => T | Promise<T>): Promise<T> {
|
|
255
299
|
let result!: T;
|
|
256
300
|
const write = this.journalWrite.then(async () => {
|
|
@@ -291,13 +335,30 @@ export class RunStore {
|
|
|
291
335
|
const journal = await json<Journal>(join(this.directory, "journal.json"));
|
|
292
336
|
return Object.values(journal.awaiting ?? {});
|
|
293
337
|
}
|
|
338
|
+
async requestWorkflowDecision(request: PendingWorkflowDecision): Promise<void> {
|
|
339
|
+
await this.updateJournal((journal) => { journal.decisions ??= {}; journal.decisions[request.proposalId] = request; });
|
|
340
|
+
}
|
|
341
|
+
async pendingWorkflowDecisions(): Promise<readonly PendingWorkflowDecision[]> {
|
|
342
|
+
await this.journalWrite;
|
|
343
|
+
const journal = await json<Journal>(join(this.directory, "journal.json"));
|
|
344
|
+
return Object.values(journal.decisions ?? {});
|
|
345
|
+
}
|
|
346
|
+
async answerWorkflowDecision(proposalId: string, approved: boolean): Promise<PendingWorkflowDecision | undefined> {
|
|
347
|
+
return this.updateJournal((journal) => {
|
|
348
|
+
const request = journal.decisions?.[proposalId];
|
|
349
|
+
if (!request) return undefined;
|
|
350
|
+
journal.completed[`decision/${proposalId}`] = { path: `decision/${proposalId}`, value: approved };
|
|
351
|
+
delete journal.decisions?.[proposalId];
|
|
352
|
+
return request;
|
|
353
|
+
});
|
|
354
|
+
}
|
|
294
355
|
|
|
295
356
|
async answerCheckpoint(name: string, approved: boolean): Promise<AwaitingCheckpoint | undefined> {
|
|
296
357
|
return this.updateJournal((journal) => {
|
|
297
|
-
const checkpoint = Object.values(journal.awaiting
|
|
358
|
+
const checkpoint = Object.values(journal.awaiting ?? {}).find((item) => item.name === name);
|
|
298
359
|
if (!checkpoint || journal.completed[checkpoint.path]) return undefined;
|
|
299
360
|
journal.completed[checkpoint.path] = { path: checkpoint.path, value: approved };
|
|
300
|
-
journal.awaiting = Object.fromEntries(Object.entries(journal.awaiting
|
|
361
|
+
journal.awaiting = Object.fromEntries(Object.entries(journal.awaiting ?? {}).filter(([path]) => path !== checkpoint.path));
|
|
301
362
|
return checkpoint;
|
|
302
363
|
});
|
|
303
364
|
}
|
|
@@ -412,8 +473,16 @@ export class RunStore {
|
|
|
412
473
|
try {
|
|
413
474
|
const write = this.snapshotWrite.then(async () => {
|
|
414
475
|
const record = await this.worktree(owner);
|
|
415
|
-
|
|
416
|
-
|
|
476
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
477
|
+
await git(record.path, ["add", "-A"]);
|
|
478
|
+
if (!(await git(record.path, ["status", "--porcelain"])).trim()) break;
|
|
479
|
+
try {
|
|
480
|
+
await git(record.path, ["commit", "-m", "pi-extensible-workflows runtime snapshot"], gitIdentity);
|
|
481
|
+
break;
|
|
482
|
+
} catch (error) {
|
|
483
|
+
if (attempt === 2) throw error;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
417
486
|
return (await git(record.path, ["rev-parse", "HEAD"])).trim();
|
|
418
487
|
});
|
|
419
488
|
this.snapshotWrite = write.then(() => undefined, () => undefined);
|
package/src/session-inspector.ts
CHANGED
|
@@ -4,13 +4,13 @@ import { emitKeypressEvents } from "node:readline";
|
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
5
5
|
import { stdin, stdout } from "node:process";
|
|
6
6
|
import { highlightCode, initTheme, SessionManager, truncateToVisualLines, type SessionEntry, type SessionInfo } from "@earendil-works/pi-coding-agent";
|
|
7
|
-
import { inspectWorkflowScript, type ModelSpec, type StaticWorkflowCall } from "./index.js";
|
|
7
|
+
import { formatBudgetStatus, inspectWorkflowScript, type AgentSetupSummary, type ModelSpec, type StaticWorkflowCall } from "./index.js";
|
|
8
8
|
import { listRunIds, RunStore, type PersistedRun } from "./persistence.js";
|
|
9
9
|
|
|
10
10
|
export interface ModelUsage { model: string; cost: number }
|
|
11
|
-
export interface AttemptReport { attempt: number; prompt: string; model: string; thinking?: ModelSpec["thinking"]; cost: number; models: readonly ModelUsage[]; error?: string }
|
|
12
|
-
export interface AgentReport { name: string; label?: string; state: string; role?: string; model: string; thinking?: ModelSpec["thinking"]; cost: number; attempts: readonly AttemptReport[] }
|
|
13
|
-
export interface WorkflowReport { name: string; description?: string; status: string; runId?: string; script?: string; calls: readonly StaticWorkflowCall[]; parseError?: string; cost: number; models: readonly ModelUsage[]; agents: readonly AgentReport[] }
|
|
11
|
+
export interface AttemptReport { attempt: number; prompt: string; model: string; thinking?: ModelSpec["thinking"]; cost: number; models: readonly ModelUsage[]; error?: string; setup?: AgentSetupSummary }
|
|
12
|
+
export interface AgentReport { name: string; label?: string; state: string; role?: string; requestedModel?: string; model: string; thinking?: ModelSpec["thinking"]; cost: number; attempts: readonly AttemptReport[]; setup?: AgentSetupSummary }
|
|
13
|
+
export interface WorkflowReport { name: string; description?: string; status: string; runId?: string; script?: string; calls: readonly StaticWorkflowCall[]; parseError?: string; cost: number; models: readonly ModelUsage[]; agents: readonly AgentReport[]; budget?: PersistedRun["budget"]; budgetVersion?: number; usage?: PersistedRun["usage"]; budgetEvents?: PersistedRun["budgetEvents"]; events?: readonly { type: string; message: string }[] }
|
|
14
14
|
export interface SessionReport { id: string; cwd: string; path: string; cost: number; models: readonly ModelUsage[]; workflows: readonly WorkflowReport[]; totalCost: number; totalModels: readonly ModelUsage[] }
|
|
15
15
|
export interface InspectorViewState { view: "list" | "detail" | "script"; selected: number; scroll: number }
|
|
16
16
|
|
|
@@ -163,6 +163,7 @@ async function agentReport(agent: PersistedRun["agents"][number]): Promise<Agent
|
|
|
163
163
|
cost,
|
|
164
164
|
models: log.models.length ? log.models : [{ model, cost }],
|
|
165
165
|
...(attempt.error ? { error: `${attempt.error.code}: ${attempt.error.message}` } : {}),
|
|
166
|
+
...(attempt.setup ? { setup: attempt.setup } : {}),
|
|
166
167
|
});
|
|
167
168
|
continue;
|
|
168
169
|
}
|
|
@@ -175,6 +176,7 @@ async function agentReport(agent: PersistedRun["agents"][number]): Promise<Agent
|
|
|
175
176
|
cost,
|
|
176
177
|
models: [{ model: fallbackModel, cost }],
|
|
177
178
|
...(attempt.error ? { error: `${attempt.error.code}: ${attempt.error.message}` } : {}),
|
|
179
|
+
...(attempt.setup ? { setup: attempt.setup } : {}),
|
|
178
180
|
});
|
|
179
181
|
}
|
|
180
182
|
if (!attempts.length) {
|
|
@@ -182,7 +184,7 @@ async function agentReport(agent: PersistedRun["agents"][number]): Promise<Agent
|
|
|
182
184
|
attempts.push({ attempt: 1, prompt: "(transcript unavailable)", model: fallbackModel, ...(fallbackThinking !== undefined ? { thinking: fallbackThinking } : {}), cost, models: [{ model: fallbackModel, cost }] });
|
|
183
185
|
}
|
|
184
186
|
const latest = attempts[attempts.length - 1];
|
|
185
|
-
return { name: agent.name, ...(agent.label ? { label: agent.label } : {}), state: agent.state, ...(agent.role ? { role: agent.role } : {}), model: latest?.model ?? fallbackModel, ...(latest?.thinking !== undefined ? { thinking: latest.thinking } : {}), cost: attempts.reduce((sum, attempt) => sum + attempt.cost, 0), attempts };
|
|
187
|
+
return { name: agent.name, ...(agent.label ? { label: agent.label } : {}), state: agent.state, ...(agent.role ? { role: agent.role } : {}), ...(agent.requestedModel ? { requestedModel: agent.requestedModel } : {}), model: latest?.model ?? fallbackModel, ...(latest?.thinking !== undefined ? { thinking: latest.thinking } : {}), cost: attempts.reduce((sum, attempt) => sum + attempt.cost, 0), attempts, ...(latest?.setup ? { setup: latest.setup } : {}) };
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
export function matchSession(query: string, sessions: readonly SessionInfo[]): SessionInfo {
|
|
@@ -229,6 +231,11 @@ export async function loadSessionReport(path: string, home = homedir()): Promise
|
|
|
229
231
|
cost: agents.reduce((sum, agent) => sum + agent.cost, 0),
|
|
230
232
|
models,
|
|
231
233
|
agents,
|
|
234
|
+
...(loaded?.run.budget ? { budget: loaded.run.budget } : {}),
|
|
235
|
+
...(loaded?.run.budgetVersion !== undefined ? { budgetVersion: loaded.run.budgetVersion } : {}),
|
|
236
|
+
...(loaded?.run.usage ? { usage: loaded.run.usage } : {}),
|
|
237
|
+
...(loaded?.run.budgetEvents ? { budgetEvents: loaded.run.budgetEvents } : {}),
|
|
238
|
+
...(loaded?.run.events?.length ? { events: loaded.run.events } : {})
|
|
232
239
|
});
|
|
233
240
|
}
|
|
234
241
|
const workflowCost = workflows.reduce((sum, workflow) => sum + workflow.cost, 0);
|
|
@@ -253,7 +260,9 @@ function detailLines(workflow: WorkflowReport): string[] {
|
|
|
253
260
|
style(ansi.bold + ansi.cyan, workflow.name),
|
|
254
261
|
`${workflow.status} · ${money(workflow.cost)}${workflow.runId ? ` · ${workflow.runId}` : ""}`,
|
|
255
262
|
workflow.description ?? "",
|
|
263
|
+
...(workflow.events?.length ? ["", style(ansi.bold, "Run events"), ...workflow.events.map((event) => `${event.type}: ${event.message}`)] : []),
|
|
256
264
|
"",
|
|
265
|
+
...(workflow.budget ? formatBudgetStatus({ budget: workflow.budget, ...(workflow.budgetVersion !== undefined ? { budgetVersion: workflow.budgetVersion } : {}), ...(workflow.usage ? { usage: workflow.usage } : {}), ...(workflow.budgetEvents ? { budgetEvents: workflow.budgetEvents } : {}) }).map((line) => `Budget ${line}`) : []),
|
|
257
266
|
style(ansi.bold, "Models"),
|
|
258
267
|
modelSummary(workflow.models),
|
|
259
268
|
"",
|
|
@@ -267,9 +276,18 @@ function detailLines(workflow: WorkflowReport): string[] {
|
|
|
267
276
|
];
|
|
268
277
|
if (!workflow.agents.length) lines.push("(no agent run was persisted)");
|
|
269
278
|
for (const agent of workflow.agents) {
|
|
270
|
-
lines.push("", style(agent.state === "completed" ? ansi.green : agent.state === "failed" ? ansi.red : ansi.yellow, `${agent.label ?? agent.name} [${agent.state}]`), `${agent.role ? `role=${agent.role} · ` : ""}${agent.model}${agent.thinking !== undefined ? `:${agent.thinking}` : ""} · ${money(agent.cost)}`);
|
|
279
|
+
lines.push("", style(agent.state === "completed" ? ansi.green : agent.state === "failed" ? ansi.red : ansi.yellow, `${agent.label ?? agent.name} [${agent.state}]`), `${agent.role ? `role=${agent.role} · ` : ""}${agent.requestedModel ? `requested=${agent.requestedModel} · ` : ""}${agent.model}${agent.thinking !== undefined ? `:${agent.thinking}` : ""} · ${money(agent.cost)}`);
|
|
271
280
|
for (const attempt of agent.attempts) {
|
|
272
|
-
lines.push(`Attempt ${String(attempt.attempt)} · ${attempt.model}${attempt.thinking !== undefined ? `:${attempt.thinking}` : ""} · ${money(attempt.cost)}${attempt.error ? ` · ${attempt.error}` : ""}`, `Prompt: ${attempt.prompt}
|
|
281
|
+
lines.push(`Attempt ${String(attempt.attempt)} · ${attempt.model}${attempt.thinking !== undefined ? `:${attempt.thinking}` : ""} · ${money(attempt.cost)}${attempt.error ? ` · ${attempt.error}` : ""}`, `Prompt: ${attempt.prompt}`, ...(attempt.setup ? [
|
|
282
|
+
`Hooks: ${attempt.setup.hookNames.join(", ") || "(none)"}`,
|
|
283
|
+
`Effective: model=${attempt.setup.model.provider}/${attempt.setup.model.model}${attempt.setup.model.thinking ? `:${attempt.setup.model.thinking}` : ""} tools=${attempt.setup.tools.join(",") || "(none)"} cwd=${attempt.setup.cwd}`,
|
|
284
|
+
...(attempt.setup.disabledAgentResources ? [
|
|
285
|
+
`Disabled skills: ${attempt.setup.disabledAgentResources.skills.join(", ") || "(none)"}`,
|
|
286
|
+
`Disabled extensions: ${attempt.setup.disabledAgentResources.extensions.join(", ") || "(none)"}`,
|
|
287
|
+
`Unmatched skills: ${attempt.setup.disabledAgentResources.unmatchedSkills.join(", ") || "(none)"}`,
|
|
288
|
+
`Unmatched extensions: ${attempt.setup.disabledAgentResources.unmatchedExtensions.join(", ") || "(none)"}`,
|
|
289
|
+
] : []),
|
|
290
|
+
] : []));
|
|
273
291
|
}
|
|
274
292
|
}
|
|
275
293
|
return lines.filter((line, index) => line || index !== 2);
|
package/src/workflow-evals.ts
CHANGED
|
@@ -95,7 +95,7 @@ export const SAFE_PARENT_EVAL_TOOLS = Object.freeze(["read", "grep", "find", "ba
|
|
|
95
95
|
const EVAL_MODEL_TOKEN = "$EVAL_MODEL";
|
|
96
96
|
const semantic = (description: string): readonly SemanticCriterion[] => [{ id: "intent", description }];
|
|
97
97
|
const JSON_RESULT_TYPES = ["null", "boolean", "number", "integer", "string", "array", "object"] as const;
|
|
98
|
-
const WORKFLOW_CALL_KINDS = ["agent", "parallel", "pipeline", "checkpoint", "phase", "withWorktree"] as const;
|
|
98
|
+
const WORKFLOW_CALL_KINDS = ["agent", "conversation", "parallel", "pipeline", "checkpoint", "phase", "withWorktree"] as const;
|
|
99
99
|
const AGENT_OPTION_NAMES = ["role", "model", "thinking", "tools", "retries"] as const;
|
|
100
100
|
const expectationKeys = ["firstSignificantAction", "firstTool", "firstBatchToolSequence", "parentToolSequence", "workflowCallCount", "requiredOperations", "forbiddenOperations", "requiredRoles", "minimumAgentCalls", "requireOutputSchema", "expectedResults", "agentPolicies", "requiredAgentOrder", "requiredAgentStructures", "requiredDataFlow"] as const;
|
|
101
101
|
const caseKeys = ["id", "prompt", "timeoutMs", "maxCost", "expectations", "expectedWorkflowCalls", "semanticCriteria"] as const;
|