Commit graph

7241 commits

Author SHA1 Message Date
triagent
6100617ba9 fix(tui): treat Apple Terminal ESC+Return with Shift held as Shift+Enter 2026-10-29 18:54:52 +00:00
Mario Zechner
babe30a7e6 docs(chord): slice 7a spec: the dependency model; slice 7 split into 7a and 7b 2026-10-29 08:32:56 +00:00
Mario Zechner
39b16b2281 docs(chord): the dependency model is decided 2026-10-29 08:31:59 +00:00
Mario Zechner
a5609aae81 docs(chord): decision: no cycle probe; parked_long diagnostic and authoring rules 2026-10-29 08:31:15 +00:00
robopipi[bot]
6fed3cfb99
fix(coding-agent): let the SDK stream resolve auth for summaries (#11556)
In sessions created by `createAgentSession`, compaction, branch
summaries and bug-report summaries resolved the stored OAuth credential
in `AgentSession._getSummarizationRequestAuth`, then passed the access
token on as `options.apiKey`. The SDK's stream function calls
`modelRuntime.streamSimple`, which resolves auth again. Because it was
given an explicit `apiKey`, `resolveProviderAuth` took the API-key
override branch instead of using stored OAuth. Built-in providers accept
the token either way. A provider whose API-key path differs from its
OAuth path, such as one that refuses explicit keys, failed every summary
while normal prompts worked.

`createAgentSession` now marks its stream function with
`markRuntimeStreamFunction`. This records it in a module-level `WeakMap`
keyed by the function, mapped to its `ModelRuntime`.
`_getSummarizationRequestAuth` skips pre-resolution when the agent's
stream function is marked for the session's own runtime, so that runtime
resolves auth once, as it does for normal prompts. The check runs after
virtual-model routing. Bare `streamSimple` and custom `streamFn`s still
receive resolved credentials, so the fixes for #6324 and #7579 are
unchanged. If a caller replaces `agent.streamFunction`, the old behavior
applies.

**Testing**
- Added `test/suite/regressions/11520-sdk-summary-oauth-auth.test.ts`.
It builds an SDK session on a provider that has stored OAuth and also an
API-key method, runs a branch summary, and asserts two things: no
`getAuth` call carries an `apiKey` override, and the provider receives
the OAuth access token. It fails without the change and passes with it.
- `npm run check` passes and `./test.sh` passes. I also ran the related
tests: 6324 branch-summary auth, compaction model overrides,
auto-compaction cancellation, SDK stream options, virtual models, and
the compaction and branch-summary tests.
- Manual reproduction: an SDK script with an `openai` OAuth credential
that logs `ModelRuntime.getAuth` during `navigateTree(..., { summarize:
true })`. Before the change there were two calls, the second with
`apiKey = <oauth token>`. After the change there is one call, with no
override.

Fixes #11520

Requested by @badlogic

Co-authored-by: triagent <triagent@localhost>
2026-10-29 09:24:53 +01:00
Mario Zechner
249f24bfc5 docs(chord): getters decision: reviewer votes 2026-10-29 08:03:10 +00:00
Mario Zechner
a54f250fb4 docs(chord): decision: getters wait through waiting until their readyTimeout 2026-10-29 08:00:54 +00:00
Mario Zechner
aee933269b docs(chord): dependency model: hostAddress wording 2026-10-29 07:44:21 +00:00
Mario Zechner
373fbcc706 docs(chord): dependency model: hostAddress 2026-10-29 07:37:56 +00:00
Mario Zechner
5ec2418820 feat(chord): hostAddress instead of placement, required on remote types; only hosts with an address serve remote types
The contract field placement is hostAddress, required on every remote() (type and declaration error); the
fallback for remote types without one is gone. invalid/placement is invalid/host_address. host/placement.ts
(Placement) is host/destination.ts (Destination); here is decided by address alone, and a host without an
address refuses to serve a remote type. A hold always carries its address on the wire (the binary codec's
ADDRESS flag is gone, the text codec requires it). Tests and examples declare their host addresses.
2026-10-29 07:37:37 +00:00
Mario Zechner
d0687bce85 docs(chord): only hosts with an address serve remote types; holds always carry their address 2026-10-29 07:29:25 +00:00
Mario Zechner
943f30c909 docs(chord): design: hostAddress instead of placement 2026-10-29 07:25:19 +00:00
Mario Zechner
599127ea36 docs(chord): decision: hostAddress instead of placement 2026-10-29 07:24:20 +00:00
Mario Zechner
0ddc953102 docs(chord): dependency model: placement required on remote types 2026-10-29 07:17:49 +00:00
Mario Zechner
13dee75529 docs(chord): every remote type declares its placement 2026-10-29 07:17:22 +00:00
Mario Zechner
1b760044ec docs(chord): note: every object may contribute (for later) 2026-10-29 07:06:37 +00:00
Mario Zechner
67c63c0f7f docs(chord): dependency model: the dependency check applies R18 after live, not a rule of its own 2026-10-29 06:49:17 +00:00
Mario Zechner
e65b3b88c0 docs(chord): dependency model proposal for slice 7 and its explainer (Parked Until Resolved) 2026-10-29 00:51:57 +00:00
Mario Zechner
556860a386 docs(chord): no client providers for now 2026-10-28 23:16:28 +00:00
Christian Klotz
c466a35957
fix(coding-agent): cap pi.exec output at 256 MiB (#11546)
Closes #11360.

## Summary
- Cap combined stdout/stderr with `ExecOptions.maxBuffer`, defaulting to
the smaller of 256 MiB and the runtime string limit. Invalid explicit
limits reject before spawning.
- Terminate oversized commands and return `truncated: true`, `killed:
true`, and a nonzero exit code. Close output pipes so writing
descendants cannot keep the call pending, and discard incomplete UTF-8
suffixes rather than adding replacement characters.
- Fix SIGKILL escalation for children that ignore SIGTERM, and simplify
completion to `await` with one cleanup block and result.
- Document the API and add regressions for byte limits, shell
descendants, UTF-8 chunk boundaries, and 32-bit runtime limits.

`ExecResult.truncated` is required. Existing extensions reading
execution results continue working; typed mocks or wrappers constructing
results must add the field.

## Verification
- `npm run build` and the post-rebase `npm run build:offline`
- `npm run check`
- 39 focused execution and extension tests
- `./test.sh` passes after building the env daemon. Earlier runs hit
remote-cleanup and reftable-watcher timeouts; both passed in focused
reruns and the final full run.
2026-10-29 00:13:41 +02:00
Mario Zechner
6eb99ad65b feat(chord): Chord v2 slice 8, registries and host.root
Registries: shared tokens (defineRegistry), one provider per host (host.serve(R, { compose, accepts })),
contributions from facets and host-lifetime objects, plain values or followed Chord watchables, a table
sorted by plugin, lazy compose in the batch that changed the table, failures left out and reported with
the last good value kept; self.registry as a declared dependency, host.registry outside objects, older
readers mapped by accepts[old].value; keyedEntries and orderedEntries. Native sources: self.writable,
registry values and ref.state. self.retryOn wakes failed objects on registry values. host.root gives code
outside objects a call scope sealed at settle, abort and host.close.

Durable: registryReader(value, context); a Session close ends synchronous observers failed
("session closed"), watches still end ended.
2026-10-28 21:34:56 +00:00
Mario Zechner
edab3efa83 docs(chord): slice 8: only Chord watchables are followed as contributions 2026-10-28 21:07:42 +00:00
Mario Zechner
790a98b9ab docs(chord): design §17 compose failure and helper names as built 2026-10-28 21:07:05 +00:00
Mario Zechner
1ce44bedeb docs(chord): slice 8 S2 and S3 wording as refined 2026-10-28 21:05:01 +00:00
Petr Houška
a87b742ff4 docs(env): Windows commands' descendants survive a terminated daemon
The job object uses silent breakaway, as libuv does, so it only kills each
command's own process.
2026-10-28 21:09:58 +01:00
Petr Houška
b6d5c2ecdc fix(env): kill the daemon's commands when it is terminated
Connection.close() ends stdin and sends SIGTERM at once. The daemon did not
handle SIGTERM, so it died before its end-of-input kill_all, and running
commands were reparented to init. The daemon now blocks SIGTERM, SIGINT and
SIGHUP before starting any thread and waits for them on its own thread, which
kills every process group it started and exits. On Windows the job object
already kills commands with the daemon.
2026-10-28 21:09:58 +01:00
Mario Zechner
391e83fb17 fix(chord): Chord v2 follows its design where the audit of slices 1-6a found it did not
A failed activation releases its references after its natives closed; a dependency going live while
the dependent activates retries it at once; a call on a local object runs with the host's principal
and incarnation; retiring an unloaded document checks its stored version and fingerprint, and a cut
retirement no longer fails its successor; ref.retry() re-runs a refused hold's start on the same id
(the provider keeps refused holds), and ends released/closed on a closed host; a relayed hold waits
while the parent link is down; a link drop while a dependency is still loading is no failure.
2026-10-28 19:50:41 +00:00
robopipi[bot]
92c1da1f62
fix(env): fail exec and pty with spawn_error when a helper thread cannot start (#11540)
The pi-env daemon started an `exec`'s stdout and stderr readers and its
waiter with `thread::spawn`. `thread::spawn` panics when no thread can
be created, for example when a cgroup `TasksMax` or `RLIMIT_NPROC` limit
is reached. When that happened after the child was already running:
- only the request thread unwound, so the exec never got a reply;
- its control channel was dropped, so `cancel` and `kill` reached
nobody;
- the child kept running, even after the daemon exited.

`pty` started its reader, input writer and waiter threads the same way.

## Changes
- `exec.rs`: `spawn_reader` now uses `thread::Builder::spawn` and
returns an `io::Result`. If a reader or the waiter cannot start, `run`
sets `stop`, interrupts any readers already started, kills the process
group, reaps the child, removes it from `groups`, and returns
`spawn_error`.
- The waiter thread now gets the `Child` through a channel once it is
running. If the waiter cannot start, the child stays with the caller,
which can still reap it. Before, the failed thread's closure dropped the
child without waiting for it.
- `pty.rs`: the same handling for the reader, writer and waiter threads.
On failure the terminal is also removed from `terminals`.

## Testing
- Manual reproduction with a script that runs the daemon as `prlimit
--nproc=N -- pi-env`. It starts 30 `sleep 30` execs 200 ms apart, aborts
them all, then closes the connection. N ran from 37 to 70.
- Before: for most N, one or two execs stayed pending forever after
abort, and a `sleep 30` kept running after the daemon was closed.
- After: every exec settles, either `aborted` or `spawn_error`, and no
`sleep` is left running.
- `cargo build`, `cargo clippy --all-targets`, `cargo fmt --check` and
`cargo test` all pass. The `packages/env` vitest suite passes (78
passed), and `npm run check` passes.
- There is no automated regression test. A thread-creation failure
cannot be triggered reliably in a test: `RLIMIT_NPROC` counts all of the
user's tasks and does not apply to root, and the daemon has no
fault-injection hook.
- The Windows build was not compiled. The `exec.rs` change uses only
existing cross-platform calls, and the `pty.rs` change is Unix-only.

Fixes #11433

Requested by @petrroll

---------

Co-authored-by: triagent <triagent@localhost>
Co-authored-by: Petr Houška <houskape@gmail.com>
2026-10-28 20:44:25 +01:00
Mario Zechner
6975eb18a6 docs(chord): design §3 route context, §7 retry of a refused hold 2026-10-28 19:44:10 +00:00
Mario Zechner
e613c7487b docs(chord): design §3 placement: a parent link that is down waits 2026-10-28 19:41:25 +00:00
Mario Zechner
9017ce0813 docs(chord): slice 6b built 2026-10-28 19:27:58 +00:00
Mario Zechner
14b4c56e57 feat(chord,durable): Chord v2 slice 6b, Durable and jobs on the store
StoreStorage (Durable's storage on Chord v2's store, @earendil-works/pi-durable/storage/store) passes
Durable's storage conformance suite and runs Durable's harness tests (npm run test:store). The store
gets owner names and claims, one id allocator, Durable's Storage semantics for refused steps, history
none/latest/rewindable with reads at a point, archive revisions and applyBatch. self.follow follows
Durable's synchronous observers as Chord sources. Persisted jobs: records and state in the owner's
store, restarts as Durable's tasks, abort stored, deferred state. Chord's ./next export returns for
the adapter surface.
2026-10-28 19:18:30 +00:00
Petr Houška
b5fc6dc84f fix(coding-agent): strip private-parameter CSI sequences in stripAnsi
stripAnsi treated <, = and > after ESC [ as final bytes, so ESC[<35;59;1M
(SGR mouse report) left 35;59;1M in tool output. Accept one private prefix
byte only directly after a CSI introducer (ESC [ or 0x9B). After a bare ESC
these bytes stay final bytes, so ESC= and ESC> (keypad modes) keep the
digits of the text that follows.

closes #11377
2026-10-28 20:14:09 +01:00
Mario Zechner
4e5cd1a973 docs(chord): slice 6b resume watch cost accepted 2026-10-28 19:03:49 +00:00
Mario Zechner
33385f9572 docs(chord): attribution of the StoreStorage.close rule 2026-10-28 18:53:50 +00:00
Mario Zechner
ec2c8ed311 docs(chord): slice 6b reopen and commit numbers accepted 2026-10-28 18:51:30 +00:00
Mario Zechner
97553d10f2 docs(chord): design text after the audit of slices 1-6a 2026-10-28 18:10:32 +00:00
Mario Zechner
cc41246b9d docs(chord): design audit of slices 1-6a, decisions 6a and 7a 2026-10-28 18:10:01 +00:00
Petr Houška
3bae85274a fix(tui,coding-agent): handle selection page keys in all scrolling lists
tui.select.pageUp/pageDown were configurable but ignored by SelectList,
SettingsList, editor autocomplete, and most coding-agent selectors. In
fullscreen mode, the default PageUp/PageDown also scrolled the transcript
instead of reaching the focused list.

- add getSelectPageIndex() and handle page keys in SelectList, SettingsList,
  editor autocomplete, and the model, scoped models, auth, user message,
  settings submenu, llama search, and /mcp selectors
- add Component.capturesViewportInput: a focused component that sets it
  receives fullscreen viewport keys instead of the transcript, as a focused
  overlay already does
- let page keys move an open autocomplete menu before app actions, so a
  remapped Ctrl+V pages the menu instead of pasting an image

closes #7629

Co-authored-by: muyiyr <940955635@qq.com>
2026-10-28 19:05:21 +01:00
Mario Zechner
9ae3d8814c docs(chord): design §6 seal fence: staged job changes adopted 2026-10-28 17:58:27 +00:00
Mario Zechner
dc35ae2d92 docs(chord): slice 8: ref.state is a native source too 2026-10-28 17:56:37 +00:00
Mario Zechner
568f6c47eb docs(chord): slice 8 ready to build 2026-10-28 17:53:56 +00:00
Mario Zechner
82a0d646e5 docs(chord): slice 8 review 2 leftovers; design §24 harness example 2026-10-28 17:52:54 +00:00
Mario Zechner
eb9d443462 docs(chord): slice 8 review 2 fixes; design §17 and slices folded 2026-10-28 17:51:28 +00:00
Mario Zechner
02a2b2532d docs(chord): slice 8 accepts adapters guarded; example shape 2026-10-28 17:49:48 +00:00
Mario Zechner
5f75cd77f8 docs(chord): slice 8 S3, self.registry is a dependency 2026-10-28 17:48:15 +00:00
Mario Zechner
376ccf6e89 docs(chord): slice 8 revised: self.registry is a dependency; S1-S3; review gaps 2026-10-28 17:48:03 +00:00
Mario Zechner
677e8067b3 docs(chord): slice 6b revision part and examples as built 2026-10-28 17:46:55 +00:00
Mario Zechner
b0eb8ace19 docs(chord): slice 6b entry_heads table 2026-10-28 17:43:57 +00:00
Mario Zechner
df9275d434 docs(chord): slice 8 S2, registry readers of an older version 2026-10-28 17:39:33 +00:00