@davidorex/pi-agent-dispatch 0.32.0 → 0.33.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/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to this package are documented here. Format follows [Keep a
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.33.0] - 2026-07-08
8
+
9
+ - Bundled agent-spec RESOLUTION from a fresh substrate: both dispatch loaders supply pi-workflows' bundled `agents/` directory as the LAST search tier (via `dispatchLoadContext(cwd)` in `dispatch-loader.ts`, consuming pi-workflows' `./bundled-dirs` subpath export); resolution order ahead of it is unchanged (substrate `agents/`, then `~/.pi/agent/agents/`, then bundled), so a local or user spec of the same name still wins. pi-behavior-monitors' classifier specs remain deliberately off this path (monitor-scoped via that package's own loader).
10
+ - Bundled specs now also COMPILE and acquire a MODEL on the dispatch path, completing fresh-substrate dispatchability through `call-agent` and `run-work-order-loop`: (1) template resolution — both dispatch entry points build their template env with `builtinDir = bundledTemplateDir()`, so a bundled spec's task/system templates resolve against the bundled pi-jit-agents `templates/` tier rather than rendering empty (the bundled `phase-author` spec's task-template reference was also corrected upstream to resolve there). (2) model resolution (`resolveDispatchModel`, `dispatch-model.ts`, mirroring the workflow executor's precedence per the derived dispatch model-policy decision): spec model → substrate `model-config` `by_role[role]` → `model-config` `default`. `run-work-order-loop` subprocess dispatch treats a still-unresolved model as "let pi pick its own default" (the `--model` flag is omitted and pi resolves the model itself inside the subprocess); in-process `call-agent`, which must resolve a concrete model + auth before it can call, throws an informed error naming the `model-config` block as the remedy when no model resolves.
11
+ - The work-order loop now clamps the dispatched agent's tool grant to the work-order's declared `scope.operations`: after composing the grant (`agentGrant ∩ spec.tools`) the loop intersects it with `scope.operations`, and that clamped set becomes the subprocess `--tools` allowlist — so the dispatched agent can never exceed the operations the work-order itself authorizes, regardless of the caller's `agent_grant` (e.g. a caller grant of `[write, bash]` under a work-order `scope.operations` of `[write]` dispatches with `--tools write`; `bash` is dropped). When `scope.operations` is absent or empty the composed grant is passed through unchanged. The loop also now validates the dispatch input (`{ work_order_id }`) against the work-order's declared `input_contract` (an inline JSON Schema, checked via pi-context's canonical AJV validator) before spawning the subprocess; a contract violation throws a descriptive error naming the work-order id, and an absent contract is a no-op pass-through.
12
+ - The work-order loop now dispatches its `target_agent` as a `pi` subprocess (`pi --mode json -p <task> --tools <grant> --model <spec>`, the same mechanism workflow steps use) instead of the in-process `executeAgent` primitive. `executeAgent` binds no executable tools — it only passes a phantom output-schema tool — so a dispatched agent granted `[write, bash]` previously received zero tools and could not act, and every work-order requiring a side-effect failed its real-check. The composed capability grant (`agentGrant ∩ spec.tools`, the dispatch-boundary capability clamp) now becomes the subprocess `--tools` allowlist (an empty grant emits `--no-tools`), so a dispatched agent has real, callable tools. Subprocess dispatch (`subprocess-dispatch.ts`, `runPiSubprocess` + testable `buildDispatchArgs`) carries a default timeout with SIGTERM→SIGKILL grace, cancellation-signal support, an `@tmpfile` prompt for long prompts, and a bounded stdout collector; a nonzero exit, timeout, or empty assistant output throws a descriptive error. Verified end to end: a work-order whose agent must write a file completes with the file written and its runtime-demo real-check passing.
13
+ - The work-order loop now reports `final_status: "aborted-non-interactive"` when a real-check fails in a non-interactive context (`ctx.hasUI === false`): it checks `ctx.hasUI` before prompting and does not call `ctx.ui.confirm`, so an environment default is no longer mislabeled as `aborted-by-human`. Interactive aborts (a human answering the confirm `false`) still report `aborted-by-human`.
14
+
7
15
  ## [0.32.0] - 2026-07-05
8
16
 
9
17
  - `resolveOperationVocabulary` reads the active substrate's `config.json` through pi-context's migration-aware loader instead of a raw parse: a config whose `schema_version` lags the bundled schema is walked forward through the registered chain before its `tool_operations` overrides apply, so the vocabulary can never diverge from the shape `loadConfig` sees. The fail-safe contract is unchanged — any load failure (absent, unparsable, unresolvable version, invalid) yields `TOOL_OPERATION_DEFAULTS`.
package/README.md CHANGED
@@ -27,6 +27,15 @@ Tool grants are operation-granular. Defaults are EMPTY. At each dispatch the gra
27
27
 
28
28
  The `run-work-order-loop` tool consolidates the orchestrator's prior per-iteration chain (call-agent → run-real-checks → on-pass commit-attested → on-fail decide-to-retry) into one Pi call. Every gate the prior chain enforced — capability composition at the call boundary, deterministic real-check verdict, writer-attestation footer, human-OK retry at the iteration boundary via `ctx.ui.confirm` — fires from inside the wrapped library. No path bypasses them.
29
29
 
30
+ ## Dispatch resolution tiers
31
+
32
+ Both dispatch entry points (`call-agent`, `run-work-order-loop`) resolve an agent for dispatch across layered searches, so a fresh substrate with no local files can resolve and compile the bundled agent set from the bundled tiers while a local or user copy of the same name still wins. (Compiling and dispatching are distinct: `call-agent` additionally requires a resolvable model — see the **Model** axis — so on a fresh substrate with no `model-config`, a bundled spec that carries no `model` compiles but `call-agent` still errors for want of a model; `run-work-order-loop` omits `--model` and lets the subprocess pick its default.)
33
+
34
+ - **Agent spec** — `<contextDir>/agents/` → `~/.pi/agent/agents/` → bundled pi-workflows `agents/`.
35
+ - **Templates** (the spec's task/system prompt bodies) — a relative template ref is first absolutized at parse when an adjacent file exists (or, for a spec matched from the bundled tier, when a package-root sibling file exists); otherwise it stays a bare name resolved through the Nunjucks loader's tiers: `<contextDir>/templates/` → `~/.pi/agent/templates/` → bundled pi-jit-agents `templates/`.
36
+ - **Output schema** (the spec's `output.schema`) — a `block:<name>` sentinel resolves to the active substrate's `<contextDir>/schemas/<name>.schema.json`; a relative path is resolved at parse against the spec's own directory first, then — for a spec matched from the bundled tier only — the spec directory's PARENT (the package-root sibling `schemas/` dir the bundled `agents/`+`schemas/` layout uses), absolutized to the first that exists on disk. The parent-sibling probe is bundled-tier-only, so a local/user spec's relative ref never absolutizes onto a same-basename substrate block schema or user-config sibling. Unlike templates, an output-schema ref gets no downstream loader-tier search — a relative ref that resolves at neither probe stays a bare name whose read fails loudly when the phantom validation tool is built.
37
+ - **Model** — the spec's own `model` → substrate `model-config` `by_role[role]` → `model-config` `default`. When none resolves, subprocess dispatch (`run-work-order-loop`) omits `--model` and pi picks its own default inside the subprocess; in-process dispatch (`call-agent`), which must resolve a concrete model + auth before it can call, instead requires a spec or `model-config` model and errors otherwise.
38
+
30
39
  ## Canonical rules
31
40
 
32
41
  - Harness-confined orchestrator (positive + negative clauses).
@@ -1 +1 @@
1
- {"version":3,"file":"call-agent-tool.d.ts","sourceRoot":"","sources":["../src/call-agent-tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErG,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AASlH;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,EAAE;IAAE,YAAY,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,cAAc,CAAC,CAAA;CAEzG,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;yBAuBX,MAAM,UACX;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,OAAO,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,UACO,WAAW,aACR,uBAAuB,OAC7B,gBAAgB,GACnB,OAAO,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;CAgD3C,CAAC"}
1
+ {"version":3,"file":"call-agent-tool.d.ts","sourceRoot":"","sources":["../src/call-agent-tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErG,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAWlH;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,EAAE;IAAE,YAAY,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,cAAc,CAAC,CAAA;CAEzG,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;yBAwBX,MAAM,UACX;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,OAAO,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,UACO,WAAW,aACR,uBAAuB,OAC7B,gBAAgB,GACnB,OAAO,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;CAuD3C,CAAC"}
@@ -8,9 +8,11 @@
8
8
  import { createAgentLoader } from "@davidorex/pi-jit-agents/agent-spec";
9
9
  import { compileAgent } from "@davidorex/pi-jit-agents/compile";
10
10
  import { executeAgent as canonicalExecuteAgent } from "@davidorex/pi-jit-agents/runtime";
11
- import { createTemplateEnv } from "@davidorex/pi-jit-agents/template";
11
+ import { bundledTemplateDir, createTemplateEnv } from "@davidorex/pi-jit-agents/template";
12
12
  import { Type } from "@earendil-works/pi-ai";
13
13
  import { composeToolGrant } from "./capability-composer.js";
14
+ import { dispatchLoadContext } from "./dispatch-loader.js";
15
+ import { resolveDispatchModel } from "./dispatch-model.js";
14
16
  function parseModelSpec(spec) {
15
17
  const slashIndex = spec.indexOf("/");
16
18
  if (slashIndex !== -1)
@@ -35,7 +37,7 @@ export const callAgentTool = {
35
37
  promptSnippet: "Dispatch a typed sub-agent with scoped capability grant.",
36
38
  parameters: Type.Object({
37
39
  spec_name: Type.String({
38
- description: "Name of the agent spec to load (resolves to <name>.agent.yaml in the agents tier).",
40
+ description: "Name of the agent spec to load (resolves to <name>.agent.yaml searched across the substrate agents/ dir, then ~/.pi/agent/agents/, then the bundled pi-workflows agents).",
39
41
  }),
40
42
  input: Type.Unknown({ description: "Typed input passed to the agent's compileAgent context." }),
41
43
  parent_grant: Type.Optional(Type.Array(Type.String(), { description: "The caller's own tool grant. Default-empty." })),
@@ -45,16 +47,21 @@ export const callAgentTool = {
45
47
  max_tokens: Type.Optional(Type.Number({ description: "Max tokens for the LLM call. Defaults to 1024." })),
46
48
  }),
47
49
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
48
- // 1. Load spec via jit-agents canonical loader
49
- const loadAgent = createAgentLoader({ cwd: ctx.cwd });
50
+ // 1. Load spec via jit-agents canonical loader (builtin tier = bundled pi-workflows agents/)
51
+ const loadAgent = createAgentLoader(dispatchLoadContext(ctx.cwd));
50
52
  const spec = loadAgent(params.spec_name);
51
- // 2. Compile spec with input
52
- const env = createTemplateEnv({ cwd: ctx.cwd });
53
+ // 2. Compile spec with input (builtinDir = bundled pi-jit-agents templates/,
54
+ // so a bundled spec's task/system templates resolve without a local copy)
55
+ const env = createTemplateEnv({ cwd: ctx.cwd, builtinDir: bundledTemplateDir() });
53
56
  const compiled = compileAgent(spec, { env, input: params.input, cwd: ctx.cwd });
54
- // 3. Resolve model + auth via ExtensionContext.modelRegistry
55
- const modelSpec = compiled.model ?? spec.model;
57
+ // 3. Resolve model + auth via ExtensionContext.modelRegistry. Precedence
58
+ // (DEC-0023): compiled/spec model model-config by_role[role] → default.
59
+ // In-process dispatch has no pi subprocess to fall through to, so a still-null
60
+ // resolution is an informed throw naming the model-config block as the remedy.
61
+ const modelSpec = compiled.model ?? spec.model ?? resolveDispatchModel(ctx.cwd, spec);
56
62
  if (!modelSpec) {
57
- throw new Error(`call-agent: agent '${params.spec_name}' has no model specified.`);
63
+ throw new Error(`call-agent: agent '${params.spec_name}' has no model — declare one on the spec, ` +
64
+ `or add a matching entry to the substrate's model-config block (by_role['${spec.role ?? ""}'] or default).`);
58
65
  }
59
66
  const { provider, modelId } = parseModelSpec(modelSpec);
60
67
  const model = ctx.modelRegistry.find(provider, modelId);
@@ -1 +1 @@
1
- {"version":3,"file":"call-agent-tool.js","sourceRoot":"","sources":["../src/call-agent-tool.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAE,YAAY,IAAI,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAGtE,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,SAAS,cAAc,CAAC,IAAY;IACnC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,UAAU,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC;IAC3G,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,UAAU,GAAwF;IAC9G,YAAY,EAAE,qBAAqB;CACnC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC5B,IAAI,EAAE,YAAY;IAClB,KAAK,EAAE,YAAY;IACnB,WAAW,EACV,0SAA0S;IAC3S,aAAa,EAAE,0DAA0D;IACzE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;YACtB,WAAW,EAAE,oFAAoF;SACjG,CAAC;QACF,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,yDAAyD,EAAE,CAAC;QAC/F,YAAY,EAAE,IAAI,CAAC,QAAQ,CAC1B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC,CACzF;QACD,eAAe,EAAE,IAAI,CAAC,QAAQ,CAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE;YACzB,WAAW,EACV,0GAA0G;SAC3G,CAAC,CACF;QACD,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,gDAAgD,EAAE,CAAC,CAAC;KACzG,CAAC;IACF,KAAK,CAAC,OAAO,CACZ,WAAmB,EACnB,MAMC,EACD,MAAmB,EACnB,SAAkC,EAClC,GAAqB;QAErB,+CAA+C;QAC/C,MAAM,SAAS,GAAG,iBAAiB,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAEzC,6BAA6B;QAC7B,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAEhF,6DAA6D;QAC7D,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC;QAC/C,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,CAAC,SAAS,2BAA2B,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,2CAA2C,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;QACjH,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAChE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,2CAA2C,SAAS,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACzF,CAAC;QAED,wEAAwE;QACxE,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;QAEpF,yFAAyF;QACzF,MAAM,QAAQ,GAAoB;YACjC,KAAK,EAAE,KAAmB;YAC1B,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE;YAChE,WAAW,EAAE,aAAa;YAC1B,SAAS,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI;YACpC,MAAM;SACN,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAEjE,OAAO;YACN,OAAO,EAAE,MAAM;YACf,OAAO,EAAE;gBACR;oBACC,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,qBAAqB,MAAM,CAAC,SAAS,aAAa,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,0BAA0B,OAAO,MAAM,CAAC,MAAM,EAAE;iBAChI;aACD;SACD,CAAC;IACH,CAAC;CACD,CAAC"}
1
+ {"version":3,"file":"call-agent-tool.js","sourceRoot":"","sources":["../src/call-agent-tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * dispatch-loader — the dispatch-side builtin agent tier (FGAP-127).
3
+ *
4
+ * Both dispatch entry points (call-agent, run-work-order-loop) build their
5
+ * pi-jit-agents `createAgentLoader` LoadContext here so the bundled
6
+ * pi-workflows `agents/` directory (26 shipped specs, e.g. `investigator`)
7
+ * becomes the LAST search tier: the active substrate's `<contextDir>/agents/`
8
+ * and the user tier (`~/.pi/agent/agents/`) still win on name collision.
9
+ *
10
+ * This is only the agent-spec RESOLUTION tier. A bundled spec also has to
11
+ * COMPILE from a fresh substrate: both entry points build their template env
12
+ * with `builtinDir = bundledTemplateDir()` so a bundled spec's task/system
13
+ * templates resolve against the bundled pi-jit-agents `templates/` tier (no
14
+ * local copy needed). Model resolution then follows the derived dispatch-model
15
+ * precedence (DEC-0023, `dispatch-model.ts`): spec → model-config `by_role` →
16
+ * `default`. work-order subprocess dispatch treats a still-null model as
17
+ * "let pi pick its own default" (no `--model` passed); in-process call-agent —
18
+ * which must resolve a concrete model + auth before it can call — keeps an
19
+ * informed throw naming the model-config block as the remedy.
20
+ *
21
+ * pi-behavior-monitors' classifier specs are deliberately NOT on this path —
22
+ * they are monitor-scoped, resolved via that package's own loader.
23
+ */
24
+ import type { LoadContext } from "@davidorex/pi-jit-agents/types";
25
+ export declare function dispatchLoadContext(cwd: string): LoadContext;
26
+ //# sourceMappingURL=dispatch-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-loader.d.ts","sourceRoot":"","sources":["../src/dispatch-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAGlE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAE5D"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * dispatch-loader — the dispatch-side builtin agent tier (FGAP-127).
3
+ *
4
+ * Both dispatch entry points (call-agent, run-work-order-loop) build their
5
+ * pi-jit-agents `createAgentLoader` LoadContext here so the bundled
6
+ * pi-workflows `agents/` directory (26 shipped specs, e.g. `investigator`)
7
+ * becomes the LAST search tier: the active substrate's `<contextDir>/agents/`
8
+ * and the user tier (`~/.pi/agent/agents/`) still win on name collision.
9
+ *
10
+ * This is only the agent-spec RESOLUTION tier. A bundled spec also has to
11
+ * COMPILE from a fresh substrate: both entry points build their template env
12
+ * with `builtinDir = bundledTemplateDir()` so a bundled spec's task/system
13
+ * templates resolve against the bundled pi-jit-agents `templates/` tier (no
14
+ * local copy needed). Model resolution then follows the derived dispatch-model
15
+ * precedence (DEC-0023, `dispatch-model.ts`): spec → model-config `by_role` →
16
+ * `default`. work-order subprocess dispatch treats a still-null model as
17
+ * "let pi pick its own default" (no `--model` passed); in-process call-agent —
18
+ * which must resolve a concrete model + auth before it can call — keeps an
19
+ * informed throw naming the model-config block as the remedy.
20
+ *
21
+ * pi-behavior-monitors' classifier specs are deliberately NOT on this path —
22
+ * they are monitor-scoped, resolved via that package's own loader.
23
+ */
24
+ import { bundledDir } from "@davidorex/pi-workflows/bundled-dirs";
25
+ export function dispatchLoadContext(cwd) {
26
+ return { cwd, builtinDir: bundledDir("agents") };
27
+ }
28
+ //# sourceMappingURL=dispatch-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-loader.js","sourceRoot":"","sources":["../src/dispatch-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAElE,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC9C,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * dispatch-model — derived dispatch-model resolution (DEC-0023).
3
+ *
4
+ * Mirrors the workflow executor's model-precedence policy at the agent-dispatch
5
+ * boundary: an agent spec that names no `model` of its own falls back to the
6
+ * active substrate's `model-config` block — first a per-role assignment
7
+ * (`by_role[role]`), then the block's `default`. This is the same precedence
8
+ * `packages/pi-workflows/src/dispatch.ts` (buildArgs) applies to workflow steps,
9
+ * lifted here so a bundled spec (which carries no model) can be dispatched
10
+ * without every caller hard-coding a model.
11
+ *
12
+ * The two dispatch entry points consume the resolved value differently, by
13
+ * design:
14
+ * - subprocess dispatch (work-order loop) treats a `null` result as "let pi
15
+ * pick its own default": no `--model` flag is passed and pi resolves the
16
+ * model from the operator's own configuration inside the subprocess.
17
+ * - in-process dispatch (call-agent, which must resolve a concrete model +
18
+ * auth through the ExtensionContext.modelRegistry before it can call) keeps
19
+ * an informed throw when the resolution is still `null` — there is no pi
20
+ * subprocess to fall through to.
21
+ *
22
+ * `model-config` is read through pi-context's `readBlock`, which THROWS when the
23
+ * block is absent; a missing/broken block is a fall-through, not an error, so
24
+ * the read is wrapped in try/catch-to-`undefined` (the same handling the
25
+ * workflow executor applies at `workflow-executor.ts`'s model-config load).
26
+ */
27
+ export declare function resolveDispatchModel(cwd: string, spec: {
28
+ model?: string;
29
+ role?: string;
30
+ }): string | null;
31
+ //# sourceMappingURL=dispatch-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-model.d.ts","sourceRoot":"","sources":["../src/dispatch-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AASH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CAYxG"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * dispatch-model — derived dispatch-model resolution (DEC-0023).
3
+ *
4
+ * Mirrors the workflow executor's model-precedence policy at the agent-dispatch
5
+ * boundary: an agent spec that names no `model` of its own falls back to the
6
+ * active substrate's `model-config` block — first a per-role assignment
7
+ * (`by_role[role]`), then the block's `default`. This is the same precedence
8
+ * `packages/pi-workflows/src/dispatch.ts` (buildArgs) applies to workflow steps,
9
+ * lifted here so a bundled spec (which carries no model) can be dispatched
10
+ * without every caller hard-coding a model.
11
+ *
12
+ * The two dispatch entry points consume the resolved value differently, by
13
+ * design:
14
+ * - subprocess dispatch (work-order loop) treats a `null` result as "let pi
15
+ * pick its own default": no `--model` flag is passed and pi resolves the
16
+ * model from the operator's own configuration inside the subprocess.
17
+ * - in-process dispatch (call-agent, which must resolve a concrete model +
18
+ * auth through the ExtensionContext.modelRegistry before it can call) keeps
19
+ * an informed throw when the resolution is still `null` — there is no pi
20
+ * subprocess to fall through to.
21
+ *
22
+ * `model-config` is read through pi-context's `readBlock`, which THROWS when the
23
+ * block is absent; a missing/broken block is a fall-through, not an error, so
24
+ * the read is wrapped in try/catch-to-`undefined` (the same handling the
25
+ * workflow executor applies at `workflow-executor.ts`'s model-config load).
26
+ */
27
+ import { readBlock } from "@davidorex/pi-context/block-api";
28
+ export function resolveDispatchModel(cwd, spec) {
29
+ if (spec.model)
30
+ return spec.model;
31
+ let modelConfig;
32
+ try {
33
+ modelConfig = readBlock(cwd, "model-config");
34
+ }
35
+ catch {
36
+ /* no model-config block — nothing to fall back to */
37
+ }
38
+ const byRole = spec.role ? modelConfig?.by_role?.[spec.role] : undefined;
39
+ return byRole ?? modelConfig?.default ?? null;
40
+ }
41
+ //# sourceMappingURL=dispatch-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-model.js","sourceRoot":"","sources":["../src/dispatch-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAO5D,MAAM,UAAU,oBAAoB,CAAC,GAAW,EAAE,IAAuC;IACxF,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC;IAElC,IAAI,WAAoC,CAAC;IACzC,IAAI,CAAC;QACJ,WAAW,GAAG,SAAS,CAAC,GAAG,EAAE,cAAc,CAAgB,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACR,qDAAqD;IACtD,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzE,OAAO,MAAM,IAAI,WAAW,EAAE,OAAO,IAAI,IAAI,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Subprocess dispatch for the work-order loop (FGAP-124).
3
+ *
4
+ * The work-order loop's target agent must ACT — write files, run bash — not
5
+ * merely produce structured output. pi-jit-agents `executeAgent` is a
6
+ * single-turn completion primitive that binds NO executable tools (it only
7
+ * ever passes a phantom output-schema tool; `compiled.tools` feeds the
8
+ * the grant clamp but is never materialized as callable tools). So an
9
+ * agent granted [write,bash] through that path receives zero tools and every
10
+ * real work-order fails.
11
+ *
12
+ * Real tool execution lives only in a `pi` subprocess — the same mechanism
13
+ * pi-workflows uses in production (`packages/pi-workflows/src/dispatch.ts`).
14
+ * This module mirrors that proven pattern, focused to what the work-order
15
+ * loop needs: build args, spawn `pi --mode json`, stream NDJSON stdout,
16
+ * collect the final assistant text + usage, with timeout + cancellation.
17
+ *
18
+ * pi-jit-agents stays the classify / structured-output primitive per JI-021;
19
+ * the acting-agent dispatch is a subprocess.
20
+ */
21
+ /** Default per-dispatch timeout (10 min) — an acting agent may build/test/write. */
22
+ export declare const DEFAULT_DISPATCH_TIMEOUT_MS = 600000;
23
+ export interface DispatchArgsParams {
24
+ /**
25
+ * Model spec string passed straight to `--model` (supports
26
+ * `provider/id[:thinking]`). Optional: when omitted the `--model` flag is not
27
+ * emitted at all, so pi resolves its own default model inside the subprocess
28
+ * (the fall-through the dispatch-model resolution takes when neither the spec
29
+ * nor the model-config block names a model — DEC-0023).
30
+ */
31
+ model?: string;
32
+ /** Composed tool grant (already intersected at the dispatch boundary). */
33
+ tools: string[];
34
+ /**
35
+ * Prompt argument value — either the literal prompt text or `@<tmpfile>`
36
+ * for long prompts (the caller decides and rewrites this before spawn).
37
+ */
38
+ promptArg: string;
39
+ }
40
+ /**
41
+ * Pure arg construction for the `pi` subprocess. Extracted so the exact CLI
42
+ * surface (mode, model, tools, prompt) is unit-testable without spawning.
43
+ *
44
+ * An EMPTY tool grant emits `--no-tools`, not an absent flag: a cleared grant
45
+ * means "no executable tools" (default-empty), whereas omitting
46
+ * `--tools` would let pi enable its full default tool set.
47
+ */
48
+ export declare function buildDispatchArgs({ model, tools, promptArg }: DispatchArgsParams): string[];
49
+ export interface SubprocessDispatchResult {
50
+ /** Concatenated assistant text across turns (final channel of the run). */
51
+ text: string;
52
+ /** The last assistant message object seen on the NDJSON stream (raw). */
53
+ lastAssistantMessage: unknown;
54
+ usage: {
55
+ input: number;
56
+ output: number;
57
+ cacheRead: number;
58
+ cacheWrite: number;
59
+ cost: number;
60
+ };
61
+ exitCode: number | null;
62
+ stderr: string;
63
+ timedOut: boolean;
64
+ }
65
+ export interface RunPiSubprocessOptions {
66
+ cwd: string;
67
+ /** Model spec; when omitted pi resolves its own default inside the subprocess. */
68
+ model?: string;
69
+ tools: string[];
70
+ prompt: string;
71
+ timeoutMs?: number;
72
+ signal?: AbortSignal;
73
+ }
74
+ /**
75
+ * Spawn `pi` in JSON mode, stream NDJSON stdout, and collect the final
76
+ * assistant text + usage. Auth + model resolution are pi's own responsibility
77
+ * inside the subprocess (it loads the operator's auth.json) — no DispatchContext
78
+ * auth is threaded here.
79
+ */
80
+ export declare function runPiSubprocess(options: RunPiSubprocessOptions): Promise<SubprocessDispatchResult>;
81
+ //# sourceMappingURL=subprocess-dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subprocess-dispatch.d.ts","sourceRoot":"","sources":["../src/subprocess-dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAUH,oFAAoF;AACpF,eAAO,MAAM,2BAA2B,SAAU,CAAC;AAWnD,MAAM,WAAW,kBAAkB;IAClC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAU3F;AAED,MAAM,WAAW,wBAAwB;IACxC,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,oBAAoB,EAAE,OAAO,CAAC;IAC9B,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9F,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CAClB;AAaD,MAAM,WAAW,sBAAsB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAsIxG"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Subprocess dispatch for the work-order loop (FGAP-124).
3
+ *
4
+ * The work-order loop's target agent must ACT — write files, run bash — not
5
+ * merely produce structured output. pi-jit-agents `executeAgent` is a
6
+ * single-turn completion primitive that binds NO executable tools (it only
7
+ * ever passes a phantom output-schema tool; `compiled.tools` feeds the
8
+ * the grant clamp but is never materialized as callable tools). So an
9
+ * agent granted [write,bash] through that path receives zero tools and every
10
+ * real work-order fails.
11
+ *
12
+ * Real tool execution lives only in a `pi` subprocess — the same mechanism
13
+ * pi-workflows uses in production (`packages/pi-workflows/src/dispatch.ts`).
14
+ * This module mirrors that proven pattern, focused to what the work-order
15
+ * loop needs: build args, spawn `pi --mode json`, stream NDJSON stdout,
16
+ * collect the final assistant text + usage, with timeout + cancellation.
17
+ *
18
+ * pi-jit-agents stays the classify / structured-output primitive per JI-021;
19
+ * the acting-agent dispatch is a subprocess.
20
+ */
21
+ import { spawn } from "node:child_process";
22
+ import fs from "node:fs";
23
+ import os from "node:os";
24
+ import path from "node:path";
25
+ /** Grace period between SIGTERM and SIGKILL when terminating the subprocess. */
26
+ const SIGKILL_GRACE_MS = 5000;
27
+ /** Default per-dispatch timeout (10 min) — an acting agent may build/test/write. */
28
+ export const DEFAULT_DISPATCH_TIMEOUT_MS = 600_000;
29
+ /**
30
+ * Prompt length threshold (chars) for switching to `@file` argument passing.
31
+ * Mirrors pi-workflows dispatch — avoids OS argv length limits with headroom.
32
+ */
33
+ const PROMPT_ARG_LIMIT = 8000;
34
+ /** Maximum stdout buffer size (10 MB) to bound memory from a runaway subprocess. */
35
+ const MAX_STDOUT_BYTES = 10 * 1024 * 1024;
36
+ /**
37
+ * Pure arg construction for the `pi` subprocess. Extracted so the exact CLI
38
+ * surface (mode, model, tools, prompt) is unit-testable without spawning.
39
+ *
40
+ * An EMPTY tool grant emits `--no-tools`, not an absent flag: a cleared grant
41
+ * means "no executable tools" (default-empty), whereas omitting
42
+ * `--tools` would let pi enable its full default tool set.
43
+ */
44
+ export function buildDispatchArgs({ model, tools, promptArg }) {
45
+ const args = ["--mode", "json"];
46
+ if (model)
47
+ args.push("--model", model);
48
+ if (tools.length > 0) {
49
+ args.push("--tools", tools.join(","));
50
+ }
51
+ else {
52
+ args.push("--no-tools");
53
+ }
54
+ args.push("-p", promptArg);
55
+ return args;
56
+ }
57
+ function extractText(content) {
58
+ if (!content || !Array.isArray(content))
59
+ return "";
60
+ const parts = [];
61
+ for (const part of content) {
62
+ if (part && typeof part === "object" && "type" in part && part.type === "text" && "text" in part) {
63
+ parts.push(String(part.text));
64
+ }
65
+ }
66
+ return parts.join("");
67
+ }
68
+ /**
69
+ * Spawn `pi` in JSON mode, stream NDJSON stdout, and collect the final
70
+ * assistant text + usage. Auth + model resolution are pi's own responsibility
71
+ * inside the subprocess (it loads the operator's auth.json) — no DispatchContext
72
+ * auth is threaded here.
73
+ */
74
+ export async function runPiSubprocess(options) {
75
+ const timeoutMs = options.timeoutMs ?? DEFAULT_DISPATCH_TIMEOUT_MS;
76
+ // Long prompts go to a temp file passed as `-p @<file>`.
77
+ let tmpDir = null;
78
+ let promptArg = options.prompt;
79
+ if (options.prompt.length > PROMPT_ARG_LIMIT) {
80
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-wo-"));
81
+ const promptFile = path.join(tmpDir, "prompt.md");
82
+ fs.writeFileSync(promptFile, options.prompt, { mode: 0o600 });
83
+ promptArg = `@${promptFile}`;
84
+ }
85
+ const args = buildDispatchArgs({ model: options.model, tools: options.tools, promptArg });
86
+ const proc = spawn("pi", args, {
87
+ cwd: options.cwd,
88
+ env: process.env,
89
+ stdio: ["ignore", "pipe", "pipe"],
90
+ });
91
+ // Cancellation
92
+ if (options.signal) {
93
+ const kill = () => {
94
+ proc.kill("SIGTERM");
95
+ setTimeout(() => {
96
+ if (!proc.killed)
97
+ proc.kill("SIGKILL");
98
+ }, SIGKILL_GRACE_MS);
99
+ };
100
+ if (options.signal.aborted)
101
+ kill();
102
+ else
103
+ options.signal.addEventListener("abort", kill, { once: true });
104
+ }
105
+ // Timeout: SIGTERM after deadline, SIGKILL after grace
106
+ let timedOut = false;
107
+ let killTimer;
108
+ const timeoutTimer = setTimeout(() => {
109
+ timedOut = true;
110
+ proc.kill("SIGTERM");
111
+ killTimer = setTimeout(() => {
112
+ if (!proc.killed)
113
+ proc.kill("SIGKILL");
114
+ }, SIGKILL_GRACE_MS);
115
+ }, timeoutMs);
116
+ const usage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
117
+ const textParts = [];
118
+ let lastAssistantMessage;
119
+ let stderrBuf = "";
120
+ function processEvent(evt) {
121
+ if (evt.type === "message_end" && evt.message && evt.message.role === "assistant") {
122
+ lastAssistantMessage = evt.message;
123
+ const u = evt.message.usage;
124
+ if (u) {
125
+ usage.input += u.input || 0;
126
+ usage.output += u.output || 0;
127
+ usage.cacheRead += u.cacheRead || 0;
128
+ usage.cacheWrite += u.cacheWrite || 0;
129
+ usage.cost += u.cost?.total || 0;
130
+ }
131
+ const text = extractText(evt.message.content);
132
+ if (text)
133
+ textParts.push(text);
134
+ }
135
+ }
136
+ let buf = "";
137
+ let bufBytes = 0;
138
+ let stdoutTruncated = false;
139
+ proc.stdout?.on("data", (chunk) => {
140
+ bufBytes += chunk.length;
141
+ if (bufBytes > MAX_STDOUT_BYTES) {
142
+ if (!stdoutTruncated) {
143
+ stdoutTruncated = true;
144
+ if (buf.trim()) {
145
+ try {
146
+ processEvent(JSON.parse(buf));
147
+ }
148
+ catch {
149
+ // incomplete trailing line — discard
150
+ }
151
+ buf = "";
152
+ }
153
+ }
154
+ return;
155
+ }
156
+ buf += chunk.toString();
157
+ const lines = buf.split("\n");
158
+ buf = lines.pop() || "";
159
+ for (const line of lines) {
160
+ if (!line.trim())
161
+ continue;
162
+ try {
163
+ processEvent(JSON.parse(line));
164
+ }
165
+ catch {
166
+ // non-JSON line — skip
167
+ }
168
+ }
169
+ });
170
+ proc.stderr?.on("data", (chunk) => {
171
+ stderrBuf += chunk.toString();
172
+ });
173
+ const exitCode = await new Promise((resolve) => {
174
+ proc.on("close", (code) => {
175
+ if (buf.trim()) {
176
+ try {
177
+ processEvent(JSON.parse(buf));
178
+ }
179
+ catch {
180
+ // skip unparseable remainder
181
+ }
182
+ }
183
+ resolve(code);
184
+ });
185
+ });
186
+ clearTimeout(timeoutTimer);
187
+ if (killTimer)
188
+ clearTimeout(killTimer);
189
+ if (tmpDir) {
190
+ try {
191
+ fs.rmSync(tmpDir, { recursive: true, force: true });
192
+ }
193
+ catch {
194
+ // best-effort cleanup
195
+ }
196
+ }
197
+ return {
198
+ text: textParts.join("\n"),
199
+ lastAssistantMessage,
200
+ usage,
201
+ exitCode,
202
+ stderr: stderrBuf.trim(),
203
+ timedOut,
204
+ };
205
+ }
206
+ //# sourceMappingURL=subprocess-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subprocess-dispatch.js","sourceRoot":"","sources":["../src/subprocess-dispatch.ts"],"names":[],"mappings":"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"}
@@ -5,10 +5,12 @@
5
5
  * drives the end-to-end loop the work-order encodes:
6
6
  *
7
7
  * for iteration in 0..max_iterations:
8
- * 1. dispatch the work-order's target_agent via the jit-agents library
9
- * (DEC-0044 narrowed; pi-jit-agents stays a library import per JI-021).
8
+ * 1. dispatch the work-order's target_agent as a `pi` subprocess (FGAP-124
9
+ * the only path that binds real, callable tools; pi-jit-agents'
10
+ * executeAgent binds none). pi-jit-agents stays the classify /
11
+ * structured-output library primitive per JI-021.
10
12
  * 2. run the work-order's real_check_criteria via runRealChecks
11
- * (deterministic verdict per DEC-0018 + DEC-0047 clause 5 — never the
13
+ * (deterministic verdict — never the
12
14
  * executing agent's self-report).
13
15
  * 3. on pass: commit-attested with writer-identity footer; final_status
14
16
  * = "completed".
@@ -21,10 +23,10 @@
21
23
  * / commit-attested per iteration.
22
24
  *
23
25
  * Per DEC-0014 the orchestrator-side composite is the only authorized
24
- * driver of this loop; per FEAT-005 the agent_grant the orchestrator
26
+ * driver of this loop; the agent_grant the orchestrator
25
27
  * passes is composed (intersected) at the call-agent dispatch boundary.
26
28
  */
27
- import type { CompiledAgent, DispatchContext, JitAgentResult } from "@davidorex/pi-jit-agents/types";
29
+ import type { JitAgentResult } from "@davidorex/pi-jit-agents/types";
28
30
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
29
31
  import { type AttestedCommitResult, attestedCommit as canonicalAttestedCommit } from "./attested-commit.js";
30
32
  import { runRealChecks as canonicalRunRealChecks, type RealCheckCriteria, type RealCheckResult } from "./real-check-runner.js";
@@ -41,7 +43,7 @@ export interface WorkOrderIteration {
41
43
  export interface WorkOrderLoopResult {
42
44
  work_order_id: string;
43
45
  iterations: WorkOrderIteration[];
44
- final_status: "completed" | "failed" | "aborted-by-human";
46
+ final_status: "completed" | "failed" | "aborted-by-human" | "aborted-non-interactive";
45
47
  commit_sha?: string;
46
48
  total_duration_ms: number;
47
49
  }
@@ -59,21 +61,39 @@ interface WorkOrderRecord {
59
61
  directories?: string[];
60
62
  operations?: string[];
61
63
  };
64
+ input_contract?: Record<string, unknown>;
62
65
  }
66
+ /**
67
+ * Clamp a composed tool grant to the operations the work-order's `scope`
68
+ * declares. The work-order's declared operation scope is the outer bound —
69
+ * the dispatched agent can never exceed the operations the work-order itself
70
+ * authorizes, regardless of the caller's agent_grant. When the work-order
71
+ * declares no `scope.operations` (absent or empty array), the composed grant
72
+ * is returned unchanged.
73
+ */
74
+ export declare function clampToScope(composedGrant: string[], operations?: string[]): string[];
75
+ /**
76
+ * Validate a work-order dispatch input against the work-order's declared
77
+ * `input_contract` (an inline JSON Schema). Reuses the canonical pi-context
78
+ * AJV validator (shared instance / strictness / formats) rather than standing
79
+ * up a parallel validator. On a contract violation THROWS an error naming the
80
+ * work-order id and the AJV error detail (the loop surfaces thrown errors);
81
+ * when no contract is declared this is a no-op pass-through.
82
+ */
83
+ export declare function validateWorkOrderInput(input: Record<string, unknown>, contract: Record<string, unknown> | undefined, workOrderId: string): void;
63
84
  /**
64
85
  * Internal indirection — tests substitute these to short-circuit the
65
- * jit-agents / real-check / commit paths. Production code path never
86
+ * subprocess dispatch / real-check / commit paths. Production code path never
66
87
  * reassigns; the same indirection pattern as call-agent-tool._internals.
67
88
  */
68
89
  type DispatchTargetAgent = (cwd: string, wo: WorkOrderRecord, agentGrant: string[], ctx: ExtensionContext) => Promise<JitAgentResult>;
69
90
  export declare const _internals: {
70
- executeAgent: (c: CompiledAgent, d: DispatchContext) => Promise<JitAgentResult>;
71
91
  runRealChecks: typeof canonicalRunRealChecks;
72
92
  attestedCommit: typeof canonicalAttestedCommit;
73
93
  /**
74
- * Tests reassign this to short-circuit the model/auth resolution +
75
- * jit-agents compile/dispatch chain. Production code path runs the
76
- * default canonical implementation.
94
+ * Tests reassign this to short-circuit the spec compile + `pi` subprocess
95
+ * dispatch chain. Production code path runs the default canonical
96
+ * implementation below.
77
97
  */
78
98
  dispatchTargetAgent: DispatchTargetAgent | undefined;
79
99
  };
@@ -1 +1 @@
1
- {"version":3,"file":"work-order-loop.d.ts","sourceRoot":"","sources":["../src/work-order-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,KAAK,oBAAoB,EAAE,cAAc,IAAI,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE5G,OAAO,EACN,aAAa,IAAI,sBAAsB,EACvC,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,MAAM,wBAAwB,CAAC;AAEhC,qBAAa,sBAAuB,SAAQ,KAAK;gBACpC,WAAW,EAAE,MAAM;CAI/B;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,eAAe,CAAC;IACnC,sBAAsB,CAAC,EAAE,oBAAoB,CAAC;IAC9C,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,YAAY,EAAE,WAAW,GAAG,QAAQ,GAAG,kBAAkB,CAAC;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,UAAU,eAAe;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,iBAAiB,CAAC;IACxC,KAAK,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC5E;AAQD;;;;GAIG;AACH,KAAK,mBAAmB,GAAG,CAC1B,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,EAAE,EACpB,GAAG,EAAE,gBAAgB,KACjB,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,eAAO,MAAM,UAAU;kBACiB,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,cAAc,CAAC;;;IAGxG;;;;OAIG;yBAC+B,mBAAmB,GAAG,SAAS;CACjE,CAAC;AAoCF,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,oBAAoB,EAC7B,GAAG,EAAE,gBAAgB,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAwE9B"}
1
+ {"version":3,"file":"work-order-loop.d.ts","sourceRoot":"","sources":["../src/work-order-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,KAAK,oBAAoB,EAAE,cAAc,IAAI,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAI5G,OAAO,EACN,aAAa,IAAI,sBAAsB,EACvC,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,MAAM,wBAAwB,CAAC;AAGhC,qBAAa,sBAAuB,SAAQ,KAAK;gBACpC,WAAW,EAAE,MAAM;CAI/B;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,eAAe,CAAC;IACnC,sBAAsB,CAAC,EAAE,oBAAoB,CAAC;IAC9C,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,YAAY,EAAE,WAAW,GAAG,QAAQ,GAAG,kBAAkB,GAAG,yBAAyB,CAAC;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,UAAU,eAAe;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,iBAAiB,CAAC;IACxC,KAAK,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAIrF;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC7C,WAAW,EAAE,MAAM,GACjB,IAAI,CAWN;AAED;;;;GAIG;AACH,KAAK,mBAAmB,GAAG,CAC1B,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,EAAE,EACpB,GAAG,EAAE,gBAAgB,KACjB,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,eAAO,MAAM,UAAU;;;IAGtB;;;;OAIG;yBAC+B,mBAAmB,GAAG,SAAS;CACjE,CAAC;AAwEF,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,oBAAoB,EAC7B,GAAG,EAAE,gBAAgB,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAiF9B"}
@@ -5,10 +5,12 @@
5
5
  * drives the end-to-end loop the work-order encodes:
6
6
  *
7
7
  * for iteration in 0..max_iterations:
8
- * 1. dispatch the work-order's target_agent via the jit-agents library
9
- * (DEC-0044 narrowed; pi-jit-agents stays a library import per JI-021).
8
+ * 1. dispatch the work-order's target_agent as a `pi` subprocess (FGAP-124
9
+ * the only path that binds real, callable tools; pi-jit-agents'
10
+ * executeAgent binds none). pi-jit-agents stays the classify /
11
+ * structured-output library primitive per JI-021.
10
12
  * 2. run the work-order's real_check_criteria via runRealChecks
11
- * (deterministic verdict per DEC-0018 + DEC-0047 clause 5 — never the
13
+ * (deterministic verdict — never the
12
14
  * executing agent's self-report).
13
15
  * 3. on pass: commit-attested with writer-identity footer; final_status
14
16
  * = "completed".
@@ -21,67 +23,127 @@
21
23
  * / commit-attested per iteration.
22
24
  *
23
25
  * Per DEC-0014 the orchestrator-side composite is the only authorized
24
- * driver of this loop; per FEAT-005 the agent_grant the orchestrator
26
+ * driver of this loop; the agent_grant the orchestrator
25
27
  * passes is composed (intersected) at the call-agent dispatch boundary.
26
28
  */
27
29
  import { readBlock } from "@davidorex/pi-context/block-api";
30
+ import { validate } from "@davidorex/pi-context/schema-validator";
28
31
  import { createAgentLoader } from "@davidorex/pi-jit-agents/agent-spec";
29
32
  import { compileAgent } from "@davidorex/pi-jit-agents/compile";
30
- import { executeAgent as canonicalExecuteAgent } from "@davidorex/pi-jit-agents/runtime";
31
- import { createTemplateEnv } from "@davidorex/pi-jit-agents/template";
33
+ import { bundledTemplateDir, createTemplateEnv } from "@davidorex/pi-jit-agents/template";
32
34
  import { attestedCommit as canonicalAttestedCommit } from "./attested-commit.js";
33
35
  import { composeToolGrant } from "./capability-composer.js";
36
+ import { dispatchLoadContext } from "./dispatch-loader.js";
37
+ import { resolveDispatchModel } from "./dispatch-model.js";
34
38
  import { runRealChecks as canonicalRunRealChecks, } from "./real-check-runner.js";
39
+ import { runPiSubprocess } from "./subprocess-dispatch.js";
35
40
  export class WorkOrderNotFoundError extends Error {
36
41
  constructor(workOrderId) {
37
42
  super(`work-order-loop: work-order '${workOrderId}' not found in work-orders block`);
38
43
  this.name = "WorkOrderNotFoundError";
39
44
  }
40
45
  }
41
- function parseModelSpec(spec) {
42
- const slashIndex = spec.indexOf("/");
43
- if (slashIndex !== -1)
44
- return { provider: spec.slice(0, slashIndex), modelId: spec.slice(slashIndex + 1) };
45
- return { provider: "anthropic", modelId: spec };
46
+ /**
47
+ * Clamp a composed tool grant to the operations the work-order's `scope`
48
+ * declares. The work-order's declared operation scope is the outer bound —
49
+ * the dispatched agent can never exceed the operations the work-order itself
50
+ * authorizes, regardless of the caller's agent_grant. When the work-order
51
+ * declares no `scope.operations` (absent or empty array), the composed grant
52
+ * is returned unchanged.
53
+ */
54
+ export function clampToScope(composedGrant, operations) {
55
+ if (!operations || operations.length === 0)
56
+ return composedGrant;
57
+ const allowed = new Set(operations);
58
+ return composedGrant.filter((t) => allowed.has(t));
59
+ }
60
+ /**
61
+ * Validate a work-order dispatch input against the work-order's declared
62
+ * `input_contract` (an inline JSON Schema). Reuses the canonical pi-context
63
+ * AJV validator (shared instance / strictness / formats) rather than standing
64
+ * up a parallel validator. On a contract violation THROWS an error naming the
65
+ * work-order id and the AJV error detail (the loop surfaces thrown errors);
66
+ * when no contract is declared this is a no-op pass-through.
67
+ */
68
+ export function validateWorkOrderInput(input, contract, workOrderId) {
69
+ if (!contract)
70
+ return;
71
+ try {
72
+ validate(contract, input, `work-order '${workOrderId}' input_contract`);
73
+ }
74
+ catch (err) {
75
+ throw new Error(`work-order-loop: dispatch input for work-order '${workOrderId}' violates its input_contract: ${err instanceof Error ? err.message : String(err)}`);
76
+ }
46
77
  }
47
78
  export const _internals = {
48
- executeAgent: canonicalExecuteAgent,
49
79
  runRealChecks: canonicalRunRealChecks,
50
80
  attestedCommit: canonicalAttestedCommit,
51
81
  /**
52
- * Tests reassign this to short-circuit the model/auth resolution +
53
- * jit-agents compile/dispatch chain. Production code path runs the
54
- * default canonical implementation.
82
+ * Tests reassign this to short-circuit the spec compile + `pi` subprocess
83
+ * dispatch chain. Production code path runs the default canonical
84
+ * implementation below.
55
85
  */
56
86
  dispatchTargetAgent: undefined,
57
87
  };
58
- async function dispatchTargetAgent(cwd, wo, agentGrant, ctx) {
59
- const loadAgent = createAgentLoader({ cwd });
88
+ /**
89
+ * Dispatch the work-order's target agent as a `pi` subprocess (FGAP-124).
90
+ *
91
+ * The subprocess is the ONLY execution path that binds real, callable tools —
92
+ * pi-jit-agents `executeAgent` binds none (it materializes only a phantom
93
+ * output-schema tool), so an agent granted [write,bash] through that library
94
+ * primitive can never act. We reuse pi-workflows' proven subprocess pattern:
95
+ * compile the spec for its rendered task prompt + model + tool grant, then
96
+ * spawn `pi --mode json --model <spec> --tools <composedGrant> -p <prompt>`
97
+ * in `cwd` and collect the final assistant output. pi resolves model + auth
98
+ * itself inside the subprocess (operator auth.json), so no DispatchContext
99
+ * auth is threaded — `ctx` is retained only to satisfy the seam signature.
100
+ */
101
+ async function dispatchTargetAgent(cwd, wo, agentGrant, _ctx) {
102
+ const loadAgent = createAgentLoader(dispatchLoadContext(cwd));
60
103
  const spec = loadAgent(wo.target_agent);
61
- const env = createTemplateEnv({ cwd });
62
- const compiled = compileAgent(spec, { env, input: { work_order_id: wo.id }, cwd });
63
- const modelSpec = compiled.model ?? spec.model;
64
- if (!modelSpec) {
65
- throw new Error(`work-order-loop: agent '${wo.target_agent}' has no model specified.`);
66
- }
67
- const { provider, modelId } = parseModelSpec(modelSpec);
68
- const model = ctx.modelRegistry.find(provider, modelId);
69
- if (!model) {
70
- throw new Error(`work-order-loop: model '${modelSpec}' not found for agent '${wo.target_agent}'.`);
104
+ // builtinDir = bundled pi-jit-agents templates/, so a bundled spec's task/system
105
+ // templates resolve without a local copy.
106
+ const env = createTemplateEnv({ cwd, builtinDir: bundledTemplateDir() });
107
+ // Guard the dispatch input against the work-order's declared input_contract
108
+ // BEFORE compiling/spawning; a contract violation throws and the loop
109
+ // surfaces it (no subprocess is spawned on a bad input).
110
+ const input = { work_order_id: wo.id };
111
+ validateWorkOrderInput(input, wo.input_contract, wo.id);
112
+ const compiled = compileAgent(spec, { env, input, cwd });
113
+ // Model precedence (DEC-0023): compiled/spec model model-config by_role[role]
114
+ // → default → null. A null result is NOT an error for subprocess dispatch — no
115
+ // `--model` is passed and pi resolves its own default inside the subprocess.
116
+ const modelSpec = compiled.model ?? spec.model ?? resolveDispatchModel(cwd, spec) ?? undefined;
117
+ // Intersect at dispatch boundary (parent ∩ requested = agentGrant ∩ spec.tools).
118
+ // The clamp now actually reaches execution: composedGrant becomes the
119
+ // subprocess `--tools` allowlist (empty grant → `--no-tools`).
120
+ const composedGrant = composeToolGrant(agentGrant, spec.tools);
121
+ // The work-order's declared operation scope is the outer bound — clamp the
122
+ // composed grant to wo.scope.operations so the dispatched agent can never
123
+ // exceed the operations the work-order itself authorizes, regardless of the
124
+ // caller's agent_grant. Absent/empty scope.operations → composedGrant
125
+ // unchanged.
126
+ const finalGrant = clampToScope(composedGrant, wo.scope?.operations);
127
+ const result = await runPiSubprocess({
128
+ cwd,
129
+ model: modelSpec,
130
+ tools: finalGrant,
131
+ prompt: compiled.taskPrompt,
132
+ });
133
+ if (result.exitCode !== 0 || result.timedOut) {
134
+ throw new Error(`work-order-loop: pi subprocess for agent '${wo.target_agent}' ` +
135
+ `${result.timedOut ? "timed out" : `exited with code ${result.exitCode}`}` +
136
+ `${result.stderr ? `: ${result.stderr}` : ""}`);
71
137
  }
72
- const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
73
- if (!auth.ok) {
74
- throw new Error(`work-order-loop: auth resolution failed for '${modelSpec}': ${auth.error}`);
138
+ if (!result.text) {
139
+ throw new Error(`work-order-loop: pi subprocess for agent '${wo.target_agent}' produced no assistant output ` +
140
+ `(exit ${result.exitCode})${result.stderr ? `: ${result.stderr}` : ""}`);
75
141
  }
76
- // Intersect at dispatch boundary per FEAT-005 (parent ∩ requested = agentGrant ∩ spec.tools).
77
- const composedGrant = composeToolGrant(agentGrant, spec.tools);
78
- const dispatch = {
79
- model: model,
80
- auth: { apiKey: auth.apiKey ?? "", headers: auth.headers ?? {} },
81
- parentGrant: composedGrant,
82
- maxTokens: 1024,
142
+ return {
143
+ output: result.text,
144
+ raw: result.lastAssistantMessage,
145
+ usage: result.usage,
83
146
  };
84
- return _internals.executeAgent(compiled, dispatch);
85
147
  }
86
148
  export async function runWorkOrderLoop(cwd, options, ctx) {
87
149
  const start = Date.now();
@@ -130,6 +192,15 @@ export async function runWorkOrderLoop(cwd, options, ctx) {
130
192
  // the loop will exit naturally as "failed" without asking the user
131
193
  // whether to retry past max_iterations.
132
194
  if (i < maxIterations - 1) {
195
+ // Non-interactive contexts have no human to ask. Do NOT call
196
+ // ctx.ui.confirm (which would return an environment default) and
197
+ // mislabel that default as a human decision. Mirror the auth-gate
198
+ // pattern (auth-gate.ts checks !ctx.hasUI first) and record the
199
+ // distinct "aborted-non-interactive" status.
200
+ if (ctx.hasUI === false) {
201
+ finalStatus = "aborted-non-interactive";
202
+ break;
203
+ }
133
204
  const failExcerpt = JSON.stringify(realCheck.details, null, 2).slice(0, 500);
134
205
  const proceed = await ctx.ui.confirm("Real-check failed", `Iteration ${i + 1}/${maxIterations} failed. Retry?\nFail-report: ${failExcerpt}`);
135
206
  if (!proceed) {
@@ -1 +1 @@
1
- {"version":3,"file":"work-order-loop.js","sourceRoot":"","sources":["../src/work-order-loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"work-order-loop.js","sourceRoot":"","sources":["../src/work-order-loop.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davidorex/pi-agent-dispatch",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -42,13 +42,13 @@
42
42
  "clean": "rm -rf dist",
43
43
  "build": "rm -rf dist && tsc -p tsconfig.build.json",
44
44
  "prepublishOnly": "npm run clean && npm run build",
45
- "test": "tsx --test src/*.test.ts"
45
+ "test": "tsx --test --test-timeout=120000 src/*.test.ts"
46
46
  },
47
47
  "dependencies": {
48
- "@davidorex/pi-behavior-monitors": "^0.32.0",
49
- "@davidorex/pi-context": "^0.32.0",
50
- "@davidorex/pi-jit-agents": "^0.32.0",
51
- "@davidorex/pi-workflows": "^0.32.0",
48
+ "@davidorex/pi-behavior-monitors": "^0.33.0",
49
+ "@davidorex/pi-context": "^0.33.0",
50
+ "@davidorex/pi-jit-agents": "^0.33.0",
51
+ "@davidorex/pi-workflows": "^0.33.0",
52
52
  "@earendil-works/pi-ai": "^0.75.4",
53
53
  "@earendil-works/pi-coding-agent": "^0.75.4",
54
54
  "yaml": "^2.7.1"
@@ -29,7 +29,7 @@ Dispatch a privileged JIT-agent as a typed tool call. Loads the named .agent.yam
29
29
 
30
30
  | Parameter | Type | Required | Description |
31
31
  |-----------|------|----------|-------------|
32
- | `spec_name` | string | yes | Name of the agent spec to load (resolves to <name>.agent.yaml in the agents tier). |
32
+ | `spec_name` | string | yes | Name of the agent spec to load (resolves to <name>.agent.yaml searched across the substrate agents/ dir, then ~/.pi/agent/agents/, then the bundled pi-workflows agents). |
33
33
  | `input` | unknown | yes | Typed input passed to the agent's compileAgent context. |
34
34
  | `parent_grant` | array | no | The caller's own tool grant. Default-empty. |
35
35
  | `requested_grant` | array | no | The grant requested for the dispatched sub-agent. Will be clamped to the intersection with parent_grant. |