Skip to content

Lousho × Pi harnesses: native kits, pi provider, piAgent + coding-pi production kit - #405

Merged
LinuxDevil merged 11 commits into
mainfrom
integration/harnesses
Oct 5, 2026
Merged

LinuxDevil merged 11 commits into
mainfrom
integration/harnesses

Conversation

@LinuxDevil

Copy link
Copy Markdown
Owner

Summary

Three coding-agent harnesses, integrated, validated live over OpenRouter, and composed into a production candidate:

  • H1 native kits (7aaac1a6): agent.* config keys (permissionMode, permissions, compaction, hooks, approve, limits), instructions/<family>.md, registry kit item type, registry/coding-kit - e2e through lousho add → loadAgentDir → lousho build → POST /chat.
  • H2 pi provider (4ea5259a): pi/<provider>/<model> over @earendil-works/pi-ai@1.0.3 (optional peer): complete/stream, message/tool/schema/usage mapping, faux + live tests, worker-bundle shim (Node-only).
  • H3 pi coder (ee4b55df): piAgent() RemoteSubagent over @earendil-works/pi-coding-agent@1.0.2, defineRemoteSubagent() + SubagentApprovalPause exported, durable approval pause/resume by session id.
  • Production harness (17647b88): engine: 'pi' sub-agent directories + registry/coding-pi - the kit on the full Pi stack (pi-provider lead + dir-declared pi coder sharing the workspace), plus loadAgentDir's piAgent override for injecting runtimes/session dirs.

Verification

  • Offline: 306 test files / 4443 tests green; typecheck, lint, build, registry:check, api:check, docs:llms:check all pass.
  • Live (valid OPENROUTER_API_KEY): coding-kit ✅, pi provider 3/3 ✅, piAgent 10/10 ✅, coding-pi full stack ✅ (pi lead → real Pi coder fixes the fixture, node --test passes, test file untouched, rm denied + audited).
  • Docs site synced (agent-sdk-docs 7f13fe0): agent-directories, providers, sub-agents, registry, changelog pages regenerated; Arabic pages marked pending.

Test plan

  • npx vitest run - full suite green
  • npm run typecheck && npm run lint && npm run build && npm run registry:check && npm run api:check
  • Live: OPENROUTER_API_KEY=... npx vitest run examples/coding-harness + vitest.live.config.ts suites
  • Report: docs/plan/harness-validation-report.md

Generated with Devin

LinuxDevil and others added 11 commits October 5, 2026 13:17
…; coding-kit harness (H1)

Agent directories learn the rest of createAgent()'s run options:
permissionMode, permissions (a serializable rule form - 'when' is a record
of argument names to regular expressions, or a predicate in a code
config), compaction, limits, plus 'hooks' and 'approve' as paths to files
default-exporting the hook(s) / the approver (inline values work in code
configs). instructions/<family>.md appends to instructions.md when the
resolved model id contains <family>. A 'subagents' override replaces the
discovered sub-agent directories, and onPermissionDecision is forwarded.

The registry gains a 'kit' item type: one item is a whole agent directory,
so its files may sit at any (still safe) relative path. The first kit is
coding-kit, the examples/coding-harness baseline expressed as a directory:
workspace tools with checkpoint rewind, an allow-listed shell, permission
rules, a loop-guard + output-cap hooks file, a test-file-refusing
approver, compaction, a cost cap, a fix-failing-test skill and a read-only
explorer sub-agent.

lousho build --target=node-server (and docker) bundles root hooks.* /
approve.* files and resolves the compiled .js sibling, and leaves the
install receipt (whose hashes name the .ts sources) out of the bundle. The
Cloudflare worker target carries the new options through, refusing 'hooks'
/ 'approve' file paths (a Worker cannot import files).

examples/coding-harness/kit.test.ts installs the kit with lousho add,
runs the scripted harness scenario through loadAgentDir (mock provider
inherited by the explorer sub-agent), and builds it into a node-server
deployment whose POST /chat answers the same task; a live test runs
against openrouter/openai/gpt-4o-mini when OPENROUTER_API_KEY is set.
Adds piAgent({ cwd, model, description, permissions, ... }), a Node-only
adapter that runs @earendil-works/pi-coding-agent (new optional peer,
pinned 1.0.2 alongside pi-ai 1.0.3 as dev deps) in process behind the
task tool. Each task call is one Pi session under the task's sessionId,
so taskId resumes and approval resumes reopen the same transcript even
across a restart.

Permission rules (the same PermissionRule shape as createAgent()) gate
every Pi tool_call extension event: deny refuses the call, ask throws
SubagentApprovalPause so the lead pauses durably for approval, and a
resume installs a one-shot exact-match allow for the blocked call (Pi
has no run-blocked-call API; a decision prompt asks the model to
re-issue it). Rejections go in as the next turn's note. Pi usage rolls
into the lead's result.usage and aborts propagate to the session.

Also public: defineRemoteSubagent(impl) registers any RemoteSubagent
implementation for subagents (remoteAgent() now delegates to it), and
SubagentApprovalPause is re-exported for such adapters.

Offline acceptance tests cover delegation, usage rollup, approval
pause/resume, durable resume across a SqliteStore restart, rejection,
denied rm, taskId resume, fork refusal and the non-pausable path; a
skipped live test runs the fixture end to end on OpenRouter under $0.05.
createAgent({ model: 'pi/<pi-provider>/<model>' }) routes calls through
the optional peer @earendil-works/pi-ai (the engine pi-coding-agent runs
on), so pi's whole catalog is usable natively - e.g.
pi/openrouter/openai/gpt-4o-mini for OpenRouter's openai/gpt-4o-mini.
The first slash after 'pi/' splits the nested provider from the model
id, so model ids with slashes work.

- PiProvider: a native LLMProvider lazily loading pi's /compat and
  /providers/all entrypoints; a missing package fails with the standard
  MissingPeerDependencyError. generate()/stream() use completeSimple/
  streamSimple so reasoning, toolChoice and thinkingBudgets map.
- Message adapter: system -> systemPrompt, assistant reasoning blocks ->
  thinking parts, tool calls/results linked by id, image bytes/data-URLs
  -> pi image parts, http(s) images and file parts degrade to text notes
  with a one-time warning.
- Schema adapter: tool parameters (raw JSON Schema, zod 3/4, Standard
  Schema, ai jsonSchema() wrappers) -> JSON Schema, converted once.
- Usage: pi's usage (incl. cacheRead and its own cost) maps to
  ProviderUsage (new optional costUsd); catalog pricing registers the
  model so runs price it via estimateCost().
- Credentials are per nested provider: providerSpec no longer injects
  env vars into pi specs (envForInfoOnly); pi resolves each provider's
  own env key, and a missing named one fails with
  LOUSHO_PROVIDER_MISSING_API_KEY.
- pi's maxRetries is pinned off; withRetry()/withFallback() stay the
  only retry layer.
- pi is Node-only: not in WORKER_SUPPORTED_PROVIDERS; the worker entry's
  build redirects @earendil-works/pi-ai* to deploy/shims/pi.worker.ts and
  tsup keeps the package external on the Node entries.
- Offline suite runs against pi's own faux provider (16 tests); a live
  OpenRouter fixture (skipped without OPENROUTER_API_KEY, capped at
  $0.05) covers a real coding task, event parity and fallback.
# Conflicts:
#	examples/coding-harness/README.md
# Conflicts:
#	CHANGELOG.md
#	package-lock.json
#	package.json
# Conflicts:
#	CHANGELOG.md
#	api/executor.api.md
#	api/hooks.api.md
#	api/mcp.api.md
#	api/react.api.md
#	api/svelte.api.md
#	api/tools.api.md
#	api/triggers.api.md
#	api/vue.api.md
#	api/worker.api.md
#	package-lock.json
#	package.json
… handling, doctor dedupe

- pin @earendil-works/pi-ai + pi-coding-agent peers/devDeps at exact versions
  (brief requirement) and align PI_PEER range/accepts + install hints
- providerSpec: expose envForInfoOnly on ProviderInfo; init templates emit the
  right .env.example hint for pi (not Ollama's base-URL text); scaffold pi on ai 7
- doctor: report pi-ai once (provider+feature peer overlap) and stop claiming a
  default endpoint for pi's nested-provider env var
- examples/README: index the coding-harness example
- build: raise tsup heap to 8192 - the merged DTS graph no longer fits in 6144
A subagents/<name>/ config may now set "engine": "pi" to become a
piAgent() coding sub-agent in the parent's subagents map (the task tool)
instead of a delegate_to_<name> tool. Its sessions run in the parent's
directory - the shared workspace - with the config's pi/<provider>/<model>
id and serializable permissions gating the Pi session's own tool calls.
loadAgentDir's new piAgent override injects PiAgentOptions (faux runtimes
in tests, sessionDir/agentDir for durable approvals). Worker targets
reject engine (Node-only).

registry/coding-pi composes all three harnesses into the production
candidate: coding-kit's rails (checkpoints, allow-listed shell, permission
rules, loop guard, cost cap, family instructions) + pi-provider lead +
dir-declared pi coder, installable as one lousho add command.

Verified: full suite green, kit-pi offline e2e (mock lead -> task -> faux
pi session edits the workspace), and the whole stack live on OpenRouter.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The README now reflects what ships: pi provider in the model-string space,
remote sub-agents (remoteAgent/piAgent/defineRemoteSubagent), agent-dir
run options and engine:'pi' sub-agent dirs, registry kits, a coding-pi
usage snippet, and the Node-only limitation in the status section.
llms.txt regenerated.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@LinuxDevil
LinuxDevil merged commit 224cef6 into main Oct 5, 2026
4 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant