pi-extensible-workflows 1.0.0 → 1.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/src/agent-execution.js +47 -7
- package/dist/src/ambient-workflow-evals.js +14 -33
- package/dist/src/doctor.js +3 -5
- package/dist/src/index.d.ts +7 -4
- package/dist/src/index.js +176 -117
- package/dist/src/persistence.d.ts +2 -0
- package/dist/src/persistence.js +27 -4
- package/dist/src/workflow-evals.d.ts +1 -0
- package/dist/src/workflow-evals.js +23 -25
- package/package.json +5 -2
- package/skills/pi-extensible-workflows/SKILL.md +6 -2
- package/src/agent-execution.ts +45 -7
- package/src/ambient-workflow-evals.ts +18 -28
- package/src/doctor.ts +2 -5
- package/src/index.ts +145 -79
- package/src/persistence.ts +23 -4
- package/src/workflow-evals.ts +13 -16
package/src/workflow-evals.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { Value } from "typebox/value";
|
|
|
8
8
|
import { getAgentDir, parseFrontmatter, SessionManager } from "@earendil-works/pi-coding-agent";
|
|
9
9
|
import { CAPTURE_ERROR_PREFIX, CAPTURE_IDENTITY, resolveWorkflowSkillPath } from "./eval-capture-extension.js";
|
|
10
10
|
export { resolveWorkflowSkillPath } from "./eval-capture-extension.js";
|
|
11
|
-
import { ERROR_CODES, inspectWorkflowScript, loadAgentDefinitions, runWorkflow, WorkflowError, type AgentIdentity, type JsonSchema, type JsonValue, type StaticWorkflowCall, type StaticWorkflowExecution, type WorkflowErrorCode } from "./index.js";
|
|
11
|
+
import { ERROR_CODES, inspectWorkflowScript, isObject, loadAgentDefinitions, runWorkflow, WORKFLOW_CALL_KINDS, WorkflowError, type AgentIdentity, type JsonSchema, type JsonValue, type StaticWorkflowCall, type StaticWorkflowExecution, type WorkflowErrorCode } from "./index.js";
|
|
12
12
|
|
|
13
13
|
export type SignificantAction = { kind: "tool"; name: string } | { kind: "text" } | { kind: "thinking" };
|
|
14
14
|
export type SequenceExpectation = readonly string[] | { equals?: readonly string[]; startsWith?: readonly string[] };
|
|
@@ -95,7 +95,6 @@ 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", "conversation", "parallel", "pipeline", "checkpoint", "phase", "withWorktree"] as const;
|
|
99
98
|
const AGENT_OPTION_NAMES = ["role", "model", "thinking", "tools", "retries"] as const;
|
|
100
99
|
const expectationKeys = ["firstSignificantAction", "firstTool", "firstBatchToolSequence", "parentToolSequence", "workflowCallCount", "requiredOperations", "forbiddenOperations", "requiredRoles", "minimumAgentCalls", "requireOutputSchema", "expectedResults", "agentPolicies", "requiredAgentOrder", "requiredAgentStructures", "requiredDataFlow"] as const;
|
|
101
100
|
const caseKeys = ["id", "prompt", "timeoutMs", "maxCost", "expectations", "expectedWorkflowCalls", "semanticCriteria"] as const;
|
|
@@ -130,7 +129,6 @@ export function loadWorkflowEvalCases(directory = evalCasesDirectory()): readonl
|
|
|
130
129
|
export const INITIAL_WORKFLOW_EVAL_CASES: readonly WorkflowEvalCase[] = loadWorkflowEvalCases();
|
|
131
130
|
|
|
132
131
|
|
|
133
|
-
function isObject(value: unknown): value is Record<string, unknown> { return typeof value === "object" && value !== null && !Array.isArray(value); }
|
|
134
132
|
function isJson(value: unknown): value is JsonValue { if (value === null || typeof value === "string" || typeof value === "boolean") return true; if (typeof value === "number") return Number.isFinite(value); if (Array.isArray(value)) return value.every(isJson); return isObject(value) && Object.values(value).every(isJson); }
|
|
135
133
|
function asJsonObject(value: unknown): Readonly<Record<string, JsonValue>> | undefined { return isObject(value) && Object.values(value).every(isJson) ? value as Readonly<Record<string, JsonValue>> : undefined; }
|
|
136
134
|
function jsonType(value: JsonValue): JsonResultType { if (value === null) return "null"; if (Array.isArray(value)) return "array"; if (typeof value === "number") return Number.isInteger(value) ? "integer" : "number"; if (typeof value === "object") return "object"; if (typeof value === "string") return "string"; if (typeof value === "boolean") return "boolean"; return "null"; }
|
|
@@ -646,21 +644,20 @@ function seedEvalProject(cwd: string, home: string, model: string): void {
|
|
|
646
644
|
if (frontmatterEnd >= 0) writeFileSync(path, `${content.slice(0, frontmatterEnd).replace(/^model:.*$/m, `model: ${model}`)}${content.slice(frontmatterEnd)}`);
|
|
647
645
|
}
|
|
648
646
|
}
|
|
649
|
-
|
|
647
|
+
export function findSessionFile(directory: string, sessionId: string): string | undefined {
|
|
648
|
+
if (!existsSync(directory)) return undefined;
|
|
649
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
650
|
+
const path = join(directory, entry.name);
|
|
651
|
+
if (entry.isDirectory()) { const found = findSessionFile(path, sessionId); if (found) return found; }
|
|
652
|
+
else if (entry.name.endsWith(".jsonl")) {
|
|
653
|
+
try { const header = JSON.parse(readFileSync(path, "utf8").split("\n")[0] ?? "{}") as unknown; if (isObject(header) && header.id === sessionId) return path; } catch { /* Ignore incomplete sessions. */ }
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return undefined;
|
|
657
|
+
}
|
|
650
658
|
async function findParentSession(cwd: string, sessionDir: string, sessionId: string): Promise<string | undefined> {
|
|
651
659
|
try { const sessions = await SessionManager.list(cwd, sessionDir); const found = sessions.find((session) => session.id === sessionId); if (found) return found.path; } catch { /* Fall through to the JSONL scan. */ }
|
|
652
|
-
|
|
653
|
-
if (!existsSync(directory)) return undefined;
|
|
654
|
-
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
655
|
-
const path = join(directory, entry.name);
|
|
656
|
-
if (entry.isDirectory()) { const found = visit(path); if (found) return found; }
|
|
657
|
-
else if (entry.name.endsWith(".jsonl")) {
|
|
658
|
-
try { const header = JSON.parse(readFileSync(path, "utf8").split("\n")[0] ?? "{}") as unknown; if (isObject(header) && header.id === sessionId) return path; } catch { /* Ignore incomplete files. */ }
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
return undefined;
|
|
662
|
-
};
|
|
663
|
-
return visit(sessionDir);
|
|
660
|
+
return findSessionFile(sessionDir, sessionId);
|
|
664
661
|
}
|
|
665
662
|
|
|
666
663
|
function emptyAccounting(cost = 0): EvalAccounting { return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost, models: [] }; }
|