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.
@@ -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
- const visit = (directory: string): string | undefined => {
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: [] }; }