@byok-sdk/client 0.1.1 → 0.2.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.
@@ -1,44 +1,17 @@
1
1
  import type { AgentEvent } from '@byok-sdk/protocol';
2
2
  import type { PiRpcMessage } from './rpc-client';
3
3
  /**
4
- * ROOT CAUSE of the 2026-07-16 live GLM run's "finding #2" hang (task stuck
5
- * `Running` forever after pi streamed its final answer; pi process alive,
6
- * idle, no sockets, only stdio pipes): this mapper used to listen for a pi
7
- * event type `agent_settled` to know a whole run had finished. That type
8
- * does not exist anywhere in the real, installed
9
- * `@earendil-works/pi-coding-agent@0.74.2` package — not in its bundled
10
- * `docs/rpc.md`, not in `dist/modes/rpc/rpc-types.d.ts`, not in
11
- * `pi-agent-core`'s own `AgentEvent` union (`dist/types.d.ts`), and not
12
- * observed even once across live probes against real GLM traffic (raw JSONL
13
- * frame capture). The real "whole run is done, pi is idle again" signal is
14
- * `agent_end` — confirmed both by `pi-agent-core`'s own doc comment ("
15
- * `agent_end` is the last event emitted for a run... The agent becomes idle
16
- * only after those listeners finish") and empirically: a live run's frame
17
- * sequence ended `...turn_end (tool call), ..., turn_end (final text),
18
- * agent_end` with nothing further arriving even after an 8s idle-grace
19
- * window. Because this switch had no `agent_end` case, it fell to
20
- * `default: return undefined` — silently dropped — so `task-runner.ts`'s
21
- * `pump()` loop never saw a `turn_end` `AgentEvent` and blocked forever on
22
- * the next one. This repo's own fixture (`fake-pi.mjs`) masked the bug for
23
- * the whole M0/M1 test suite by emitting a fictional `agent_settled` frame
24
- * of its own alongside the real `agent_end` one — fixed alongside this
25
- * change (see fake-pi.mjs's doc comment).
4
+ * Map pi 0.84.1 RPC frames into BYOK's runtime-neutral event contract.
26
5
  *
27
- * `agent_end` (not pi's own per-LLM-turn `turn_end`) is what maps to our
28
- * `turn_end`: a single pi prompt can produce several internal turns (tool
29
- * round-trips, each ending its own real `turn_end`); only once the whole
30
- * run is settled (no auto-retry, compaction-retry, or queued continuation
31
- * left) is the task actually done. Forwarding pi's own `turn_end` 1:1 would
32
- * emit multiple confusing `turn_end`s for what the daemon must treat as one
33
- * task — empirically confirmed: a single-tool-call prompt produced two real
34
- * `turn_end` frames (one after the tool call, one after the final text) and
35
- * exactly one `agent_end`.
6
+ * `agent_settled` is the only whole-task completion authority. `agent_end`
7
+ * ends one low-level agent run, but pi may still perform retry/compaction or
8
+ * consume queued work before it emits `agent_settled`. Pi's own `turn_end`
9
+ * is even narrower: a tool-using prompt can emit several of them. Mapping
10
+ * either earlier boundary to BYOK `turn_end` would acknowledge the task
11
+ * before the runtime is actually idle.
36
12
  *
37
- * Returns undefined for pi messages with no protocol equivalent (session/
38
- * compaction/retry bookkeeping see `ROUTINE_PI_EVENT_TYPES` below —
39
- * extension UI dialogs, which never reach here at all in production since
40
- * `PiRpcClient` answers them itself before they'd ever be queued as an
41
- * event; see rpc-client.ts).
13
+ * `message_update` is delta-only in this contract. The mapper forwards text
14
+ * deltas and never reads the removed cumulative `message`/`partial` fields.
42
15
  */
43
16
  export declare function mapPiMessageToAgentEvent(msg: PiRpcMessage): AgentEvent | undefined;
44
17
  /**
@@ -48,7 +21,7 @@ export declare function mapPiMessageToAgentEvent(msg: PiRpcMessage): AgentEvent
48
21
  * (pi-adapter.ts) calls `PiRpcClient.recordUnmappedFrame` for any message
49
22
  * type that maps to `undefined` AND isn't in this set — i.e. traffic nobody
50
23
  * has ever told this adapter to expect. That distinction is what makes a
51
- * regression like this file's root-cause bug (`agent_end` going unhandled)
24
+ * regression like a changed completion event
52
25
  * self-diagnosing: a warning fires the first time the new/renamed settle
53
26
  * event shows up, instead of the daemon just quietly hanging. `default`-only
54
27
  * unknowns (a type not listed in the switch at all) are equally "not
@@ -8,7 +8,7 @@ export interface PiPermissionMapping {
8
8
  }
9
9
  /**
10
10
  * Map an effective {@link PermissionPolicy} to `pi --mode rpc` CLI args,
11
- * fail-closed. Empirically grounded (see the M0-3 report):
11
+ * fail-closed against the exact pi 0.84.1 CLI contract:
12
12
  *
13
13
  * - `auto` / `readonly` are expressible via `--tools` / `--no-tools`.
14
14
  * - `confirm` and `plan` are NOT expressible: pi ships no built-in per-call
@@ -23,24 +23,8 @@ export interface PiPermissionMapping {
23
23
  * Workspace confinement is NOT a pi flag — the caller spawns pi with
24
24
  * `cwd: ctx.workspaceDir`, the daemon-created per-task directory.
25
25
  *
26
- * SECOND SELF-DISCOVERED FINDING, same class as the pi-adapter.ts
27
- * `--session-id` bug (this task, while hardening argv validation):
28
- * `--exclude-tools` what `denyTools` used to map to — is ALSO not a real
29
- * pi CLI flag. Confirmed against real pi 0.74.2: `pi --mode rpc
30
- * --exclude-tools bash` → `Error: Unknown option: --exclude-tools`, exit
31
- * code 1, before any model call — and it's absent from both `pi --help`'s
32
- * own listing and the CLI's actual arg parser (`dist/cli/args.js`), which
33
- * recognizes only `--tools`/`-t`, `--no-tools`/`-nt`, `--no-builtin-tools`/
34
- * `-nbt` for tool control. This crashed EVERY real pi invocation for any
35
- * policy with a non-empty `denyTools`, unconditionally — never caught by
36
- * this repo's own test suite for the exact same reason as the
37
- * `--session-id` bug (`fake-pi.mjs` never validated argv; fixed alongside
38
- * this change). pi has no "start from the default set, minus these" flag at
39
- * all — `--tools` always REPLACES the active set wholesale — so `denyTools`
40
- * is now resolved to an equivalent allowlist in-process: readonly mode
41
- * intersects with `READONLY_TOOLS` (as before), any other mode starts from
42
- * an explicit `allowTools` or pi's own `DEFAULT_ACTIVE_TOOLS`, and
43
- * `denyTools` is subtracted from that resolved set before it's ever handed
44
- * to pi as a single `--tools`/`--no-tools` pair of args.
26
+ * - `--tools` is an allowlist and `--exclude-tools` is a denylist. Passing
27
+ * both lets pi remain the authority for its active tool registry instead
28
+ * of duplicating pi's default tool list in this adapter.
45
29
  */
46
30
  export declare function mapPermissionPolicyToPiArgs(policy: PermissionPolicy): PiPermissionMapping;
@@ -5,30 +5,34 @@
5
5
  * `@mariozechner/pi` — the identifier this task was originally briefed with —
6
6
  * is NOT the coding agent. On npm it resolves to an unrelated "CLI tool for
7
7
  * managing vLLM deployments on GPU pods" (bin: `pi-pods`). The real coding
8
- * agent was `@mariozechner/pi-coding-agent`, which is now itself deprecated
9
- * in favor of this package (same maintainers: badlogic, mitsuhiko).
10
- *
11
- * This constant identifies the user-installed runtime for diagnostics and
12
- * documentation only. The client package deliberately does not install pi:
13
- * security-fixed pi releases require Node >=22.19 while this SDK supports
14
- * Node >=20, and runtime credentials/lifecycle remain user-owned.
8
+ * agent was `@mariozechner/pi-coding-agent`, which is now deprecated in
9
+ * favor of this package. `package.json` carries the exact supported version
10
+ * as a required dependency; pi is a core BYOK capability, not an optional
11
+ * enhancement or an unversioned global executable.
15
12
  */
16
13
  export declare const PI_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
17
14
  export interface ResolvedBin {
18
15
  command: string;
19
- source: 'path';
16
+ source: 'package' | 'env';
20
17
  }
21
18
  /**
22
- * Resolve the user-installed pi CLI executable.
19
+ * Resolve the pi CLI executable from the required package installed alongside
20
+ * `@byok-sdk/client`. There is intentionally no automatic PATH fallback: a
21
+ * global `pi` would create a second, unversioned authority for this contract.
23
22
  *
24
- * `BYOK_PI_BIN` overrides PATH lookup when set: `PiAdapterOptions.resolveBin`
23
+ * `BYOK_PI_BIN` explicitly overrides the package when set: `PiAdapterOptions.resolveBin`
25
24
  * is the injectable seam for in-process tests, but the `byok-agent` CLI bin
26
25
  * only ever constructs `new PiAdapter()` with no options (see `createDaemon`),
27
26
  * so an out-of-process substitution (e.g. examples/basic's e2e run swapping
28
- * in the fake-pi fixture ahead of a real pi install) has no other seam to use.
27
+ * in the fake-pi fixture, or a single-file product injecting its required
28
+ * Node 22.19+ pi sidecar) has no other seam to use.
29
29
  *
30
- * Resolution is deliberately the same authority shape as Claude Code and
31
- * Codex: an explicit product/test override, otherwise the user's PATH. The
32
- * SDK does not infer package-manager layouts or install a second runtime.
30
+ * Deliberately does NOT use `createRequire(...).resolve()`: this package is
31
+ * pure ESM with no `require` export condition (`exports["."]` only offers
32
+ * `import`), so CJS-style resolution fails with
33
+ * `ERR_PACKAGE_PATH_NOT_EXPORTED`. It also does NOT resolve the
34
+ * `./package.json` subpath directly (also not exported); instead it resolves
35
+ * the package's main entry via `import.meta.resolve` and walks upward to the
36
+ * package root identified by its manifest name.
33
37
  */
34
38
  export declare function resolvePiBin(): ResolvedBin;
@@ -58,10 +58,7 @@ export declare class PiRpcClient {
58
58
  * traffic. Logs once per distinct type (not per occurrence, so a
59
59
  * repeating unmapped type can't spam stdout); the running tally is also
60
60
  * folded into this client's exit-time error message (`buildExitError`) so
61
- * a post-mortem on a failed/hung task has it without needing separate log
62
- * scraping. This is the exact mechanism that would have turned this
63
- * task's root-cause hang (`agent_end` arriving with no mapping) into a
64
- * one-line, immediate warning instead of a silent stall.
61
+ * a post-mortem on a failed/hung task has it without separate log scraping.
65
62
  */
66
63
  recordUnmappedFrame(type: string): void;
67
64
  /** Best-effort teardown. SIGTERM on POSIX; `taskkill /T /F` on Windows to also reap child processes pi itself spawned (e.g. bash). */