mirror of
https://github.com/alphaXiv/OpenResearch.git
synced 2026-11-11 09:59:34 +08:00
cbe099dfa97466ea17c6c695388c83f1cddfbf76
59
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cbe099dfa9 |
Use native skill discovery for all OpenResearch agents (#826)
* Enable shared native skills for ACP agents * Exercise ACP native skill installation end to end * Confirm ACP disconnect before testing skill restore * Combine native skill discovery and remove duplicate catalog |
||
|
|
08048f3f1f |
OR-626: Open papers from openresearch:// links in the macOS app (#797)
* Open papers from openresearch:// links in the macOS app openresearch.sh's per-paper download page links to openresearch://reproduce?arxiv=arXiv:<id>. The macOS bundle now claims the scheme; the app opens /reproduce, which shows the New Project dialog already set to that paper, and seeds the new project's first chat with a "Reproduce the paper …" prompt (not sent). A link reaching the running app navigates in-page so unsaved-work guards still apply; a cold launch holds it until the dashboard server answers. Windows and Linux registration follows separately. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Hold deep links until the page can take them; skip linked-paper warm-up A link that arrives after the window shows but before the dashboard's script has loaded now waits for the page-load Finished event instead of being dispatched to a page with no listener. A paper filled in from a link no longer pre-warms starter prompts (a model call) until the user picks it themselves, so cancelling the dialog spends nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Deep-link papers by alphaXiv id, including alphaXiv exclusives openresearch.sh now links to openresearch://reproduce/<paper id>, where the id is alphaXiv's universal id: an arXiv id or an alphaXiv-exclusive slug like 2610.learning-spectrum-matched-shellsort. The id rides in the path (/reproduce/$) because TanStack reads ?id=2401.10000 as 2401.1. The New Project dialog resolves the id directly, exclusive papers' PDFs come from alphaxiv.org/abs/<id>.pdf, and version stripping follows alphaXiv's rule (a v after a dash is part of the name). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c51b9e7435 |
Run relevant PR checks and reserve packaging for releases (#763)
* Run relevant PR checks and reserve packaging for merged releases * Select embedded JavaScript tests and skip platform documentation builds * Fetch only comparison commits for CI metadata checks * Parallelize Windows PR validation and isolated timeout fixtures * Reuse cached Cargo resolution and consolidate CLI test harnesses * Overlap ARM PR lint and native linking with timing diagnostics * Drop unproven cache preparation and measure ARM codegen parallelism * Keep measured CI wins and remove duplicate frontend generation |
||
|
|
228231a0e2 |
Fix compaction across agent harnesses and clear completed progress (#761)
* Fix compaction lifecycle and completion across agent harnesses * Keep unsupported compaction commands accessible from the keyboard * Silently consume unsupported compaction commands * Skip unsupported compaction before checking for a saved chat * Credit the original Codex compaction contributor Co-authored-by: Aleksandr Rodionov <rexarrior@yandex.ru> --------- Co-authored-by: Aleksandr Rodionov <rexarrior@yandex.ru> |
||
|
|
dceecf929a |
Trackio: Spaces, hf runs, zero-setup local, Visualize view, and orx metrics (#756)
* Trackio: Spaces, hf runs, zero-setup local, embedded charts, and orx metrics - TRACKIO_SPACE_ID support (wins over TRACKIO_SERVER_URL, as in Trackio), with a Settings check of the Space, its stage and HF_TOKEN write access. - hf Jobs receive the Trackio settings (URL and write token as secrets). - With nothing saved, local runs log to Trackio's local store and orx up starts `trackio show` on demand, stopping its process group on exit. - Every run gets ORX_EXPERIMENT, ORX_EXPERIMENT_TITLE, ORX_PARENT_EXPERIMENT, ORX_COMMIT and TRACKIO_PROJECT (per pod on k8s). - Visualize opens a run's Trackio charts in the right pane, only for runs that logged; private Spaces get HF's read-only __sign token. - `orx metrics <runId>...` summarizes logged curves for agents; the compute and experiment-tree skills use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address review: orphan-proof local dashboard, Space caching, Visualize everywhere - The local `trackio show` exits when orx's stdin pipe closes, so restarts, crashes, SIGKILL and Ctrl-C never orphan it; startup runs in its own task. - Space lookups are cached (failures included) so polls never reach whoami; sign cache keyed by token; HF token only sent to private Spaces; 401/3xx reported plainly; HF_ENDPOINT honoured. - Runs route returns 502 on failure so an open embed survives blips; a Space not created yet is a normal 200 with no dashboard. - `orx metrics` reports per-run errors, exits non-zero when nothing could be read, and explains missing local data or Spaces. - k8s: manifest values win over run context (except ORX_RUN_ID), listed first for $(VAR) expansion. - Launch warns when remote runs would keep Trackio metrics on the remote box. - UI: tree cards get a labelled Visualize button that opens the in-app view (cards widen to 336px), refetch once a run ends, embed follows the theme, loading/error states, gesture handlers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix Windows clippy and address Greptile review - Box the local dashboard child: on Windows a tokio Child makes LocalState::Running trip clippy's large_enum_variant. - An SSH workspace host offers no embed for its loopback-only local dashboard, which the user's browser cannot reach. - k8s: TRACKIO_PROJECT joins ORX_RUN_ID as forced, since orx finds a run's Trackio data by both; other run-context vars still yield to the manifest. - `orx metrics` reports a failed alert read instead of showing no alerts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f1b6c2d8f0 |
Use selected OpenCode models and remove AI skill screening (#670)
* fix: avoid inference during OpenCode detection * Bind OpenCode auxiliary generation and remove AI skill screening --------- Co-authored-by: Daniel Kim <sox8502@gmail.com> |
||
|
|
3f5bac6541 |
Unify interactive questions across Codex, Claude, and OpenCode (#752)
* Unify interactive questions and repair harness approval handling * Preserve answers across skipped and batched questions |
||
|
|
2149a29467 |
OR-397: Improve onboarding demos, charts, and image previews (#593)
* Make the nanochat demo quick and render interactive experiment figures * Fix chart ranges and bound inline preview sizing * Refine demo results, chart interactions, and image carousels * Split experiment evidence skills and address chart review feedback * Preserve zoom selections and format small axis ticks * Choose axis label precision from tick spacing * Keep single training-step ticks exact after zoom * Retain visible confidence bands and skip empty keyboard slices * Load results guidance before experiment summaries and avoid duplicate comparisons |
||
|
|
ea3b9689c2 |
feat: add durable model and experiment telemetry (v0.2.14) (#482)
* feat: add durable model and experiment telemetry for v0.2.14 * Fix telemetry opt-out, partial accounting, and identity retention |
||
|
|
35c687066f |
OR-304: Compute CLI, custom instructions, and Slurm recovery (#429)
* Add compute management CLI, custom guidance, and Slurm recovery * Fix Windows test access to shared SSH request fields * Clarify compute instruction updates and remove review checklist |
||
|
|
a15b3a61a4 |
Add /compact, which every coding agent can run (#411)
* Add composer commands that work the same on every coding agent The composer's `/` menu now offers /new (alias /clear), /resume, /model, /plan, /copy and /export on every harness. The dashboard runs each one itself, so behavior no longer depends on what the selected agent's own CLI supports — none of them act on slash text in the mode orx runs them in except Claude Code, and only partially. `planCommand.ts` becomes `composerCommands.ts`, a registry the menu, the chips and the send path all read from. A skill whose bare name collides with a command is dropped from the menu: the composer inserts, and the server resolves, skills by bare name, so it would otherwise shadow. Only /plan composes with a prompt. The rest run as a whole message, so prose that merely mentions `/export` still reaches the agent, and a command is chipped only where it would actually run. /resume lists chats across every project: GET /api/chat/sessions now takes `scope=all` (400 without it or a projectId) and returns the 500 newest. Picking a chat in another project switches to it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add /compact, which every coding agent can run (#384) The composer's /compact (alias /summarize) shortens a chat's context on every harness. Claude Code and Codex compact their own context in place and OpenCode summarizes through its endpoint, so the session survives; Cursor and the legacy `codex exec` path have nothing to call, so orx summarizes the transcript itself and reseeds a fresh native session with it through `bootstrap_context`, which is injected exactly while no native session exists. An agent that is merely not running is never traded for a summary: a resumable session reports "send a message first" instead, since a summary keeps only the newest 32 KiB of the chat. Compaction runs as a turn. It holds the session's turn slot, reports itself as a transcript row that shimmers while it works, and every write is gated on still owning that slot — Stop cancels it, and a cancelled row settles as failed rather than sitting at running. The row is the progress: it survives a reload, reaches every open client, and carries the reason when it fails. Codex waits for the compaction turn it started rather than the RPC ack, filtering by that turn's own id; Claude retires its child if its /compact fails, so an abandoned result cannot land in the next turn. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
38a880f4be |
Show original paper figures inline and improve literature review (#367)
* Render local images inline in chat and guide literature-review figures * Open inline figures in the viewer and separate contextual captions * Polish inline figure viewer and streamline grounded literature review * Restore literature retrieval procedure and prioritize comparative visual evidence * Keep skill routing generic and simplify visual guidance Preserve canonical descriptions in the generic skill list because crowded native catalogs can abbreviate them. This intentionally trades a small prompt increase for complete routing context. Keep the full retrieval procedure and clarify source PDF extraction. |
||
|
|
05132f3c50 |
Fix harness setup recovery and release v0.2.6 (#393)
* Fix harness setup recovery and native installer verification * Bump version to 0.2.6 |
||
|
|
866c507ba3 |
✨ feat(harness): add agy coding agent integration (#332)
* ✨ feat(harness): add agy coding agent integration - Implement Harness trait for agy harness adapter - Support streaming NDJSON turns via agy --output-format stream-json - Support multi-turn conversation resumption via --conversation <id> - Support project worktree directory and session skills via .agents/skills - Support dynamic model enumeration and auth verification via agy models - Support permission modes (ask, auto, bypass) and effort tiers (low, medium, high) - Add agy alias to orx install-skills - Add brand logo mark and model picker labels to web UI - Include comprehensive unit and stream folding tests Closes #223 * 🐛 fix(harness): handle Antigravity failure states * Complete Antigravity approvals, cancellation, and product integration --------- Co-authored-by: Daniel Kim <sox8502@gmail.com> |
||
|
|
5fa74d1c3b |
Support OpenCode V2 alongside V1 with safe history migration (#348)
* Support OpenCode V2 alongside V1 with safe history migration * Avoid guessing OpenCode V2 authentication method * Remove OpenCode migration backups after validated upgrade |
||
|
|
19f91fd26a |
Add Cursor as a first-class orx up harness (#313)
* feat: add Cursor as a first-class orx up harness Spawn isolated Cursor CLI sessions from orx up like Claude Code, Codex, and OpenCode, so included Cursor usage can drive the auto-research loop. Co-authored-by: Cursor <cursoragent@cursor.com> * fix: use Cursor's 2.5D cube mark in the model picker The 2D silhouette collapsed to a diamond at 14px; the brand-kit cube stays recognizable. Co-authored-by: Cursor <cursoragent@cursor.com> * Polish Cursor harness integration and shared chat interactions * Make Cursor skill-path assertion respect XDG configuration --------- Co-authored-by: ZeguanXiao <www.hainanxzg@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Daniel Kim <sox8502@gmail.com> |
||
|
|
eaba8668b6 |
OR-272: Improve skill picker and reusable library management (#306)
* Improve skill discovery, picker, and reusable library management * Move customization guidance into bundled orx-customize skill |
||
|
|
9b05f9771c |
OR-199 Windows support for the CLI and dashboard (#299)
* Make orx build and resolve its tools on Windows Block A of the Windows beta: the fixes that need no Windows machine to write, so the branch is ready to clone the moment one is set up. - Extend a bare binary name with PATHEXT when searching PATH. Every harness is looked up by bare name, so on Windows the picker reported Claude Code, Codex and OpenCode all absent and the dashboard could do nothing. - Compose a child's PATH with `;` rather than a hardcoded `:`. - Find bash through `git` rather than PATH. The `bash.exe` usually on PATH is the WSL launcher in System32, which sees a different filesystem than the run directory it would be handed. - Give git an empty path it understands. `/dev/null` reads as a missing relative path on Windows, silently re-enabling repository hooks. - Check a local run's liveness with a zero-timeout wait; there is no `ps` to shell out to. - Link through native_store::create_symlink, which already has both branches, instead of calling the unix symlink directly. - Add a windows-latest CI job so none of this regresses. The Windows branches here have not been compiled yet — that is the next step, on the machine. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Allow CI to be dispatched against a branch * Compile the remaining unix-only code paths out on Windows Round one of the Windows compile, from the first CI run: 25 diagnostics, seven root causes. - Give remote_host the `#[cfg(not(unix))]` twins its uid/mode helpers were missing, matching what `directory_writable` already does. Windows keeps only the symlink and directory checks in `ensure_private_dir`, which is a weaker guarantee than the unix path makes. - Gate the control channel itself. It is a Unix domain socket, so `--remote-host` is now refused up front on Windows rather than starting a host nothing could attach to. Local `orx up` is untouched. - Annotate `signal`, whose type came only from the cfg(unix) block. - Gate the EXDEV rename fallback, the inode and mode assertions, and the shell-hook tests, all of which assert on things Windows does not have. - Silence the parameters that are only read on unix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Gate the remote-host command surface off on Windows Round two, from the cascade the unresolved socket import had been suppressing: every caller of the six control-channel functions. The module splits cleanly in two. `orx up` uses its types and its dashboard locking — HostDescriptor, DashboardLock, canonical_data_dir — and none of that needs a socket. The `orx remote-host` command surface is socket-backed all the way down, so it is gated as a unit and the command now refuses on Windows instead of failing somewhere further in. Also: the two imports only the gated half reached, and `signal`, which loses its one assignment on Windows and with it the need for `mut`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Keep the compiled-out remote-host half rather than gate it item by item Round three was 24 dead-code and unused-import lints and no real compile errors — the tail of removing a feature's entry points while its machinery stays behind. One scoped allow on the module says that plainly. Gating each constant, helper and request type would be bulkier than the code it guards, would have to be unpicked the moment the control channel gets a Windows transport, and would say nothing the module comment does not. updates.rs is the same shape at smaller scale: relaunch_target and relaunch_args keep their tests on every platform and lose only their caller in the binary. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Stop handing git a verbatim path, and let test cleanup fail The Windows suite ran for the first time: 662 passed, 46 failed. Two causes account for 27 of them. `repository_git_dir` canonicalizes, and Windows answers canonicalize with a `\\?\C:\…` verbatim path. Git rejects those outright — "not a git repository" — so importing any existing repository failed. This is a real bug, not a test artifact; the prefix now comes off for drive paths, which are the only ones with a plain form. The other 21 were `remove_dir_all(root).unwrap()` in test teardown, which Windows refuses while any handle into the tree is still open. The codebase already prefers a tolerant cleanup in 146 other places; these 86 now match. All of them are inside `#[cfg(test)]`. Also: the probe fixtures asserted on POSIX PATHs, which are not absolute on Windows and so were rejected by the parser under test. They are parameterized rather than gated — the parsing they cover is not platform-specific, only the fixture was. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Check out LF on every platform Git for Windows defaults to core.autocrlf=true, and SYSTEM_PROMPT.md and the agent-skills SKILL.md files are include_str!'d at build time. A Windows build therefore embedded CRLF and then failed to parse it: playbook_md() splits the template on `-->\n\n` to drop its leading HTML comment, that split stopped matching, and `unwrap_or` kept the comment — so every agent session would have been handed OpenResearch's internal notes as the opening of its system prompt. Two tests caught it, one of them by scanning the rendered playbook for unresolved `{token}` placeholders rather than a fixed list. That is the only reason this surfaced as a test failure and not as a shipped binary. Nothing renormalizes: no tracked text file has CRLF in the index today, so this only governs what lands in a working tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Fix what Windows found: exec bits, remote paths, cancellation Round two of the Windows suite: 691 passed, 17 failed. Four of those were real bugs rather than test artifacts. Demo onboarding rejected the demo it had just built. NTFS has no executable bit, so runcpu.sh committed as 100644, the tree hash moved, and the commit ids drifted off the BASELINE_SHA/EXPERIMENT_SHA the demo validates itself against. The mode now reaches the tree through the index, where it does not depend on the filesystem. Remote paths were validated with local rules. `storage_root` asked `Path::is_absolute` about `/home/me/.cargo/bin/orx`, which is false under Windows, so a Windows client rejected every legitimate remote path — and the PathBuf it built would have reached a Linux shell separated by backslashes. Remote paths are POSIX whatever the client runs, so they are handled as strings now. `manage_local_file` took `reports/result.md` from the dashboard and answered `reports\summary.md`, which the next request would have carried straight back. Relative paths cross the API `/`-separated. Cancelling a local run did nothing: there is no process group to TERM. `taskkill /T` takes the tree instead, which is what TERMing the group was for. The rest were fixtures asserting on POSIX shapes, a filename using a character Windows reserves, and two LaTeX tests that need a symlink and a shebang. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Let the index own the demo's exec bit Setting the mode through `update-index` fixed the commit ids but left the index at 100755 against a working tree NTFS always reports as 0644. With `core.filemode true` git believed the filesystem, read runcpu.sh as modified, and refused to check main back out. Windows trusts the index instead, which is where the mode came from. The two telemetry failures are not diagnosed. HTTP delivery itself works on Windows — `sender_posts_the_first_party_endpoint` asserts an Acknowledged post and passes — so what fails is the removal that follows it, and reading has not told me why. Both assertions now report what a second removal says, which separates a blocked delete from a delete that succeeded while the name lingered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Keep the demo's origin path native, and judge cancel by liveness Three down to two. `join("demo-repos/nanochat.git")` embeds a separator the platform did not choose, so on Windows the bare origin came out as `...\data\demo-repos/nanochat.git` — mixed, and textually unequal to what git echoes back for the remote it was given. Filesystem calls did not care; comparing the recorded URL to git's answer did. Split into two joins, in product code as well as the tests that caught it. `taskkill /T` returns non-zero when any descendant has already exited on its own, which says nothing about whether the run stopped. Cancellation now reads the leader's liveness, which is the question actually being asked. The telemetry pair is one step from diagnosed. The retry in the previous round answered Ok(()), so the file was there and freely deletable and the removal was never reached — delivery must have come back Retryable. The assertion now names the outcome, which separates a request that never landed from a response classified unexpectedly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Read the request before answering it in the telemetry mock servers The last two Windows failures, and they were the tests' fault rather than delivery's. Two of the three mock servers accepted a connection and wrote their response without ever reading the request. Closing a socket that still holds unread data aborts the connection on Windows instead of closing it gracefully, so the client saw a reset rather than the reply it had already been sent, and classified a 400 as Retryable — which left the outbox file the assertion expected to be gone. The third server always read, which is why it passed and misled the search toward the removal. The read loop it already had is now shared by all three. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Canonicalize into paths a child process can actually use An audit of the `orx up` paths no test exercises. Every bug this branch has fixed so far was in code a test happened to touch; the dashboard's own request handling was the largest area where that was not true. Windows `canonicalize` answers with a verbatim `\\?\C:\…` path, and `CreateProcessW` will not take one as a working directory. The dashboard canonicalizes a session's checkout root and then runs git in it — twelve call sites behind `resolve_checkout_root`, covering the code tree, file reads and writes, and diffs — so none of that could have worked. The same root reaches `run_shell_command` as the cwd for a `!` command, and Codex receives canonicalized paths as its sandbox writable roots. Consistency matters as much as the spelling: containment checks compare a canonicalized child against a canonicalized root, and a mix of the two forms denies access to paths that are genuinely inside. So every canonicalization in the crate now goes through one helper rather than the handful that happened to be reachable from a failing test — that is what makes the property hold rather than the individual fixes. The earlier one-off in `repository_git_dir`, which the import failure found, is folded into it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Look for the harness binaries under the names they actually have Second audit pass, over the spawn path. `find_claude` and `find_opencode` fall back to their installers' drop locations when PATH does not answer, and both spell them as bare names — `~/.local/bin/claude`, `~/.opencode/bin/opencode` — which match no file on Windows. `~/.local/bin` is exactly where Claude Code's own Windows installer puts claude.exe, so the fallback was dead precisely where it was needed. Both now look for the same names PATH does. The rest of the spawn path holds up: config directories travel as environment variables, where a raw path is correct; Codex's config.toml is written through serde_json, whose backslash escape is the one TOML wants; and the binaries themselves come from find_on_path, which learned about PATHEXT earlier on this branch. One gap left deliberately: the PATH guard writes zsh and bash startup hooks and needs ZDOTDIR or HOME to place them, neither of which Windows sets, so it returns early and the guard is simply absent there. It fails closed — a session gets no hook rather than a broken one — and building a Windows equivalent is worth more than a beta needs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Address review round one Six blockers, all real. `orx_bin_dir` dropped any directory whose name contains a colon, which on Windows is every absolute path, so agents were never handed the running orx on PATH — and the separator constant added earlier sat in a branch that never ran. It filters on that constant now. A dashboard shell command that hit its timeout killed nothing on Windows and then waited on the child with no timeout, hanging the turn forever. The non-unix arm terminates the tree, the shape latex already used. BIBINPUTS/BSTINPUTS joined with a colon, so bibtex on Windows lost both the paper's own directory and the system defaults. `restore_local_repository` never pinned core.autocrlf, so a restored demo clone was written CRLF against LF blobs and then failed the cleanliness check that reads it with global config disabled — telling the user their demo "is not the OpenResearch nanochat demo". The remove_dir_all sweep had converted four setup removals along with the teardown, letting tests pass while testing nothing. The Windows uid/mode stubs were unreachable: their whole chain is rooted in cfg(unix) entry points. Gated instead, stubs deleted, and with them a comment claiming a weaker-but-working private runtime directory that does not exist. Also from review: prefix stripping now matches the parsed prefix, so a non-UTF-8 name cannot keep `\\?\` while its root loses it and fail its own containment check; UNC verbatim paths are decoded rather than passed through. PATHEXT set-but-empty no longer reports every tool missing. The bash fallback no longer resolves back to the WSL launcher it rejects. pdfPath goes through the same API path rule as every other relative path. The telemetry signature widened for a test message is reverted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Address review round two Two blockers, both introduced by round one's own fixes. Deleting the Windows uid/mode stubs was wrong: `open_lock` is ungated and calls all three, and `DashboardLock::acquire` reaches it on every `orx up`. That is a Windows compile error on the one platform this branch exists for, and macOS cannot see it. The ownership and mode checks are gated inside `open_lock` now, which keeps the file-type check everywhere and states plainly what Windows does not enforce. Teaching `orx_bin_dir` about the platform separator also handed `ORX_BIN_DIR` to PATH_GUARD, a POSIX snippet that joins `PATH` on colons. Under Git Bash a drive letter split it in two and the guard re-prepended on every startup. The stamp is skipped off unix; `prepare_env` still fronts the directory, which was the point. Also: `cancel_job`'s cfg'd `return` is the function's last statement once stripped, which the Windows clippy job would have rejected; the restore path pins `core.eol` alongside autocrlf so a global `core.eol=crlf` cannot reproduce the same dirty checkout; the verbatim UNC head is built from `OsString` like the tail it is joined to; and the null-device comment no longer claims git falls back to the repository's own hooks, which it does not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Polish from review round three No blockers in either round-three review. Taking the nits: `open_lock` fstats once instead of twice; the Windows branch of the `ORX_BIN_DIR` stamp is a `#[cfg]` rather than a runtime-false `cfg!`, so it stops resolving the executable only to discard it; two doc comments that described one platform now describe both; and the ownership comment names the case it does not cover — a lock under a shared `ORX_DATA_DIR` has only its ACL on Windows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Keep the windows job out of the release gate release.yml calls ci.yml and requires it to pass, so the windows job added here would have held up a macOS or Linux release over a platform those releases ship nothing for. `plan` is passed only by release.yml, so skipping on it draws the line where it belongs: Windows still gates pull requests, which is what keeps it from rotting, and never gates a release. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Upload a release orx.exe, not a debug one The artifact is what a tester is handed, and a debug build is slow enough to colour their impression of the dashboard rather than the code's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Turn SSH multiplexing off explicitly on Windows Win32-OpenSSH implements no connection multiplexing: it accepts ControlMaster and ControlPath and then never creates a master. Omitting them is not enough, because the user's own ssh_config can still set a ControlPath, and one it honours fails the connection outright with "getsockname failed: Not a socket". Passing ControlMaster=no and ControlPath=none is what overrides that. The socket machinery goes with it — the control directory, its path hash and its preparation are unix's, and `master_is_running` can only answer false where no master is ever created. Nothing changes on unix, where the shared master still covers later status, log and job commands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Address review Two tests asserted the unix option set unconditionally and would have failed on Windows — the very platform this change is for, and one CI never builds. Both derive the expectation from the platform now. `PathBuf`'s only uses became unix-gated, so its import would have failed the Windows clippy job under -D warnings. git shells out to ssh with its own command line, which never carried the override, so a user's ssh_config could still break git-over-SSH on Windows for exactly the reason this change exists. Routed through one helper. The rest: a doc comment my new test had come between and its rightful test; four comments still promising multiplexing unconditionally, the `interactive_args` one worst because it states the invariant that is false on Windows; the new test pinned to the exact vector the way its neighbour already is; and BatchMode coverage split out, since it holds on every platform and was about to be gated away with the ControlPath half. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Address review round two No blockers in either round-two review. Taking the nits. Deriving the option count from `multiplexing_opts` had quietly removed the only assertion pinning the unix vector — ControlPersist could have been deleted and nothing in the tree would have failed. Pinned alongside the Windows one. The rest: a test whose name promised reuse on a platform that reuses nothing; `git_ssh_command` says which command it builds; two more doc comments of the class round one fixed, in the two other files that carry them; and the Windows sentence dropped from `ssh_opts`, where it was the third statement of the same fact within 150 lines. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Point git's config paths at an empty file, not the null device Onboarding died on Windows at the demo's first `git init`: fatal: unable to access 'NUL': Invalid argument `NUL` is right for `diff --no-index`, which recognizes it before touching the path, and wrong everywhere a path is actually read. Git skips a config file that reports ENOENT and fatals on any other error, and Windows cannot `access()` its null device by name at all. A real empty file behaves the same on every platform, and this file already had that idiom in `clone_public_repository`. Shared now, and pointing `hooksPath` at it still disables hooks, since git finds no hook inside a file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Give the spawned bash its own toolchain on PATH A local run died at `run.sh: line 6: mkdir: command not found`. bash was running; it just had no coreutils. Git for Windows keeps those in `usr\bin` and puts only `cmd` on the Windows PATH, so a bash started from a Windows process inherits a PATH with no Unix tools at all. Fronted for the two bash spawns only — a local run's launcher and the composer's `!` command. Doing it for every child would shadow Windows' own `find` and `sort` with the MSYS ones, which is a worse bug than the one being fixed. prepare_env's PATH is now a function the bash spawn can extend, so the running orx still comes first and the toolchain sits ahead of both. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Fold the toolchain into the PATH run.sh exports The previous commit set the toolchain PATH on the spawn, which run.sh then overwrote on its second line: localrun exports the shell's PATH into the script so a user's own command finds python and uv, and that export wins over anything the process was started with. Caught by the agent inside the dashboard, which read the generated run.sh rather than the launcher and saw the hardcoded Windows PATH for what it was. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Let the demo probe run under Git Bash Two things differ there, and the probe hit both. uv ships no shell installer for Windows, so the setup uses its PowerShell one; and uv lays the venv out as `Scripts/` rather than `bin/`, so both activations are tried — either platform can have either layout depending on how the venv was made. These are Rust constants rather than files in the demo repository, so the commit ids the demo validates itself against do not move. `runs/runcpu.sh` carries the same POSIX assumption and is committed, so making the project's own run command portable is a separate change that regenerates those ids. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Stop writing a Windows PATH into a bash script The run script exported the process PATH so a user's command could find python and uv. On Windows that value is semicolon-separated, and bash splits PATH on `:` — so it collapsed at the first drive colon and nothing resolved, `mkdir` included. Adding the Git toolchain to it, as the last two commits did, only added more entries to the same unusable string. Git Bash converts the PATH it inherits into POSIX form for itself, so the fix is to leave it alone: the launcher sets the process PATH, and the script no longer overwrites it. The `cd` on the next line had the same shape — bash reads a quoted `C:\…` literally — so the run directory is forward-slashed now. Found by the agent running inside the dashboard, which read the generated run.sh, spotted the separator mismatch, and verified a candidate PATH against both splitters before proposing anything. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Hand the shell paths it can read, not Windows ones `tar: Cannot connect to C: resolve failed` — GNU tar reads a colon before the first slash as a `host:path` remote spec, so the snapshot archive's Windows path made it try to resolve `C:` as a hostname. Forward slashes would not have helped; the colon is what triggers it. One conversion now covers both places a local path reaches the shell: the archive tar unpacks, and the `cd` the launcher writes. `/c/Users/…` has no colon at all. The HF backend passes a Linux container path and is deliberately left alone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Give runs a UTF-8 stdout A run died mid-training on `UnicodeEncodeError`: CPython encodes stdout in the console's codepage, cp1252 on a default Windows install, and the script printed a banner outside Latin-1. Nothing to do with the experiment — it had already trained a tokenizer by then. `PYTHONIOENCODING=utf-8` joins `PYTHONUNBUFFERED` as a default the author can override, through the same helper every backend already calls, and open-coded once more for kubernetes, whose env is a JSON array. Set on every platform rather than only Windows: a Linux container with `LANG=C` has the same ASCII default and would fail the same way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Let git write paths past Windows' 260-character cap Creating a session worktree for a deep repository failed partway through with "Filename too long". Windows refuses paths over 260 characters unless a program opts into the wide API, and a session worktree spends about a hundred of them on `worktrees/<project>/chat_<session>` before the repository's own paths begin. `core.longpaths=true` on the invocations that write a working tree: the shared helper every worktree and checkout goes through, the authenticated fetch, and the anonymous clone. Read-only plumbing does not need it. This was graded Minor in the original survey. It is a blocker for any repository with a deep tree, which is most of them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Link the agent's config without asking Windows for a privilege Windows grants symlinks only to an elevated process or one in Developer Mode, so preparing the isolated agent home failed onboarding outright with os error 1314. Fall back to the links that need no privilege: a junction for a directory, which reads back exactly like a symlink, and a hard link for a file, which does not — so the reconcile now recognizes one instead of filing a conflict against it on every launch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Stop asking Windows' ssh to multiplex Windows' OpenSSH cannot create the AF_UNIX socket ControlMaster needs, and rather than decline the option it kills the connection outright with "getsockname failed: Not a socket" — so every ssh call orx made from Windows failed, whatever the destination. Drop the Control* options there and pay a handshake per call. Same option vector, same platform: `UserKnownHostsFile=/dev/null` is a name Windows' ssh takes literally, creating a `\dev\null` on the current drive. It now gets a scratch file of orx's own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Count the Windows ssh opts the Windows way Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Revert the duplicate multiplexing fix PR #302 already turns Windows' multiplexing off, and does it by setting ControlMaster=no explicitly rather than by omission — which is what overrides a ControlPath in the user's own ssh_config — and covers git's ssh besides. Take that one instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Give Windows a real file for the host keys it must forget `UserKnownHostsFile=/dev/null` is a name Windows' ssh takes literally, creating a `\dev\null` on whichever drive is current. Point it at a scratch file of orx's own instead; StrictHostKeyChecking=no is what makes a recycled provider key acceptable, so the behaviour is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Ship a Windows binary and a way to install it The demo's own run command reached for a POSIX uv installer and `.venv/bin/activate`, neither of which exists on Windows, so the nanochat demo could not run there; both now branch at runtime. That changes the experiment tree, hence the new EXPERIMENT_SHA. Releases built no Windows artifact at all, which is what the CI job's non-blocking rationale rested on. Add the target and a PowerShell installer so a beta tester has something to install. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tell Windows testers what they need before they need it Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Let Windows hold up a release now that a release ships it The job skipped release runs because releases carried no Windows artifact. They do now, so a regression on main would ship broken rather than fail loudly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Say what signing will and will not fix Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Say Git for Windows is missing at startup, not at the first run Without it there is no usable bash, so experiments and the demo die on their first command with a spawn error naming a path the user has never heard of. The agents check next to it already warns this way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Make a second click reach the dashboard, not die on its port Double-clicking orx.exe runs `orx up`. Doing it while orx is already running failed the bind, printed an error into a console Explorer then closed, and looked to the user like nothing happened at all. Open the running dashboard instead, and hold the console open for whatever else a startup failure has to say. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Make a failed start say so where a console cannot The console Explorer opens for a double-clicked orx.exe dies with the process, so both ways this program exits with something to say — a returned error and a panic — reached a window that was already gone. Put the message in a dialog instead, and only when no terminal is attached to read the printed one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Start the dashboard when orx.exe is double-clicked A bare `orx` prints usage and exits, which is right at a prompt and useless from Explorer: the console it printed into closes with the process, so the gesture looked like nothing happening. Owning the console is what tells the two apart, and it now starts `up` — the same trade the macOS .app makes for the same gesture. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Keep demo installs seeded before the Windows change working Moving EXPERIMENT_SHA left every existing mac and linux install pointing at a commit its repository does not contain. Each agent turn resolves the session worktree from that commit, so all three demo chats would have failed on their next message after upgrading. An install now starts its sessions from whichever known experiment its demo branch descends from. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Address review round four - Release verify job reads the Windows .zip and orx.exe; without it no release would have published for any platform. - "Already running" reuse only for a double-click, and only of a dashboard speaking this build's protocol. On mac and linux a second `orx up` fails on the port again, as it did before this branch. - An old demo install whose cache was wiped but origin kept restores its own experiment rather than building a sibling it cannot push. - Same-file probe errors fall through to the old reconcile; the demo probe only puts ~/.local/bin on PATH after installing uv; the panic hook is Windows-only. - Docs name the assets cargo-dist actually publishes. - Comments cut to the one-or-two-line house rule; three doc comments moved back onto the functions they describe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Address review round five - A double-click keeps the flags it was given (`--no-telemetry` from a shortcut no longer turns telemetry back on). - A kept demo origin is validated before a clone is restored from it, so a foreign or moved origin is named as the problem instead of the cache. - The ssh opt-vector test reads the Windows known-hosts path once; it follows XDG_CONFIG_HOME, which telemetry tests mutate in parallel. - Every comment this branch adds is now one or two lines. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Address review round six - Remote storage paths accept an interior `.` again. `Path::components` skipped it on main, so `ORX_DATA_DIR=./orx` on a remote box — probed as `/home/u/./orx/orx.db` — broke `orx up --remote` on this branch. - A foreign kept demo origin is rejected before anything is restored from it, now with a test; `install_repository` keeps main's shape, since the restore helper creates its own parent. - Comments trimmed last round get back the why they lost, and the PYTHONIOENCODING one no longer claims the console codepage: redirected output uses the ANSI one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
00fe5ab7b7 |
Add local endpoints to the OpenCode model picker (OR-245) (#300)
* Support local OpenCode models in onboarding * Add local endpoint setup to OpenCode settings and model picker * Handle recovered OpenCode context compaction without false failures * Bump version to 0.1.122 for local model release |
||
|
|
82aec9834b |
OR-267: Prefer uv through shared Python environment guidance (#291)
* Prefer uv through shared Python environment guidance * Address Python guidance review feedback * Finalize concise Python environment policy * Keep Python policy in the shared prompt |
||
|
|
db0ca91d0c | OR-263: Guide agents to organize project artifacts (#289) | ||
|
|
c5b49fe37f |
OR-247 feat: simplify the skills experience (#272)
* feat: simplify the skills experience The Customize tab was five sections deep in choices that no longer earned their place: a Global/This project scope picker on every card, a separate "import from your agent" list, and two split skill lists. - Skills installed in a coding agent are now mirrored automatically — read live from its skills dir on every listing and every session write, so a skill edited in Claude Code is the one the next session runs. The import step and its two endpoints are gone. A session hosted by the agent a skill came from is not handed a copy it already loads. - Claude Code's installed plugins are mirrored too, discovered through installed_plugins.json so only real installs count. - Every skill and LaTeX template is global. Project scope is removed from the store, the API, and the UI; anything already saved under it is migrated into the single store on first access. - Skill frontmatter is parsed the way skills are actually written: folded and literal blocks, and values wrapped over indented lines. A skill whose frontmatter we cannot read is a skill the user never sees. - ~/.agents/skills is read whenever it exists, rather than only when ~/.codex does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: harden the skills mirror after review Review of the mirroring change turned up defects worth fixing before it ships: - A plugin's skills are registered namespaced (`runpod:flash`), so the bare `/name` only resolves from a copy. They are no longer treated as natively loaded by the agent that installed them. - Uploaded skills resolve through their folder name again, not the frontmatter `name` a hand-edit can change out from under them. - The hosting agent's own skills are dropped only after they have won their `/name`, so a same-named skill from another agent can't take their place in the worktree while the dashboard shows the first. - Session skill dirs are replaced and pruned only when the manifest says we wrote them, so a `.claude/skills` the project itself commits is left alone; manifest names are re-validated before any removal. - A folder whose source is unchanged is not re-copied, folders over the upload budget are skipped, and neither the copy nor the size walk follows symlinks. - The retired per-project store is emptied, never deleted: anything that can't move stays put as the user's only copy. - A `#` comment no longer folds into the value above it, and a long description truncates instead of dropping the skill. - The Customize tab distinguishes a failed skills fetch from an empty one, and ignores drops while an upload is in flight. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: keep one answer for what a skill name resolves to Second review round: - `source_dirs` resolves uploads through the same listing the dashboard reads, so a folder whose SKILL.md won't parse can't win a name in the worktree while the tab shows the mirrored skill it shadowed. - A folder tally now carries a digest over every (path, size) pair, so a rename or a move inside a skill brings the session copy forward; each source and destination is walked once per turn instead of three times. - A destination whose content already matches its source is adopted as ours, so a lost manifest heals instead of freezing that skill forever. - A mirrored folder over the upload budget is left out of the listing too, rather than offering a `/name` that never reaches the worktree. - LaTeX templates get the same skip-if-unchanged treatment. - Archive junk under the retired per-project store no longer keeps it alive on every call. The freshness test now watches the inode: `fs::copy` carries the mtime across on macOS, so the timestamp it asserted on could never have failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix: never let an adopted skill dir become prunable Round three: adopting a destination whose content already matches its source healed a lost manifest, but it also recorded a directory orx had never written — so once the source went away, the prune deleted a skill the project itself commits. Adoption is now limited to the case it was for: no manifest at all. While a manifest exists it stays the whole truth about what we own. Also from that round: the upload budget moved into `source_dirs`, so the menu, the hover preview and the session write agree on which `/name` exists; a stray `.DS_Store` beside the retired per-project store no longer keeps it alive; and the uncapped walks stopped pretending they can fail. The fingerprint test never reached the SKILL.md byte comparison it was supposed to cover, and the migration test never asserted the retired tree was gone — both fixed, and both verified by reverting the fix under them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor: one budget answer for uploads too The listing kept sizing uploads with an uncapped walk while the resolver had started budgeting them, so a hand-edited store could list a skill no session would be given. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
01473da5d7 | feat: capture richer CLI telemetry (#265) | ||
|
|
a9af660f9e |
OR-216 Add an orx-figures skill for publication-quality figures (#260)
* Add an orx-figures skill for publication-quality figures Figures were left to matplotlib defaults: screen-sized, titled where a caption belongs, and rasterized where the document wants vector. This adds a bundled skill that routes by the question a figure answers and ships the style layer rather than describing it. `orx-figures` follows the `orx-compute` shape — one SKILL.md carrying the non-negotiables, then exactly one of six references (curves, scaling, comparison, pareto, matrix, diagram). Two assets install beside them: `orx_figstyle.py`, vendored into the project so a figure stays reproducible after the session ends, and a TikZ scaffold sharing its palette. `save()` audits every figure and prints the result: printed width against the known column widths, Type 42 font embedding, stray axes titles, missing axis labels, sub-5pt text, overlapping text, and text running off the canvas. Prose the agent can skip is how the first unusable figures shipped; these checks run whether or not the guidance was read. The playbook and the `orx skill` overview both direct figure work here — a session with the skill installed still plotted raw matplotlib until they did. Content is calibrated against 39 popular recent alphaXiv papers (283 captions) and 10 arXiv e-print sources: 87% of real figure PDFs are built wider than any single-column page, so the width check is the load-bearing one; multi-panel is 27% of figures; and captions run a median of 28 words. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Fix review findings in the figures skill Correctness: - `label_ends` computed the reserved x-room in the pre-`set_xlim` scale, so the labels overhung the spine by need^2/(width+need) — about a quarter of a long label. Solve for the limit at which the original span occupies (axes width - label width) pixels instead. - The audit's categorical-axis exemption keyed off whether tick text parsed as a number, but log formatters emit mathtext, so every log axis was classified categorical and escaped the missing-axis-label check. Decide by scale. - `save()` audited before writing, and the audit needs an Agg-family renderer that is not guaranteed in the very case its first check reports. Write the files first; the audit can no longer be the reason a figure is lost. - `curves.md` interpolated every seed onto the first seed's grid, and `np.interp` clamps, so a run that stopped early gained a fabricated flat tail. Clip to the range every seed reached. - `comparison.md` hardcoded `ylim(0, 90)`: any score above it drew as a bar clipped at the axes edge, which is the dishonesty that reference is about. - `scaling.md` zipped families against three markers, silently dropping a fourth family from the main panel while still plotting its residuals. - Guards for degenerate input: zero-variance `diff_ci`, all-NaN heatmaps, empty confusion rows, resamples that fail to fit, empty label lists. Consistency: - `diagram.md` still taught the retired natural-size include, and its inline path dropped `\familydefault`, which would render a serif diagram beside sans plots. Both contradicted SKILL.md. - `orx-paper` and `orx-reports` examples named a rasterized plot. - The audit emits a font-fallback finding the docs never listed, and it is the one finding an agent should hand over rather than fix. Tests now assert the rendered playbook rather than the raw template, and pin the audit's problem strings rather than text that also appears in docstrings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Fix round-two review findings The round-one TikZ fix was worse than the bug: it told the agent to move `\renewcommand{\familydefault}{\sfdefault}` into the paper's preamble, which is document-wide and would have set the body text, headings, and captions of a submission to sans. The face now rides in the `orx`, `edgelbl`, and `stagelbl` styles, so it travels with the picture and touches nothing else. Also from review: - `diagram.md` still carried the broken relative `cp assets/...`, which does not resolve from a session's cwd. - The new "write a report figure to the artifacts directory" note contradicted "keep the generating script beside its output"; both destinations now keep the pair together. - A `WIDE` figure only gets a 6.75in `\linewidth` inside `figure*`; in a plain `figure` it silently halves, which non-negotiable #1 now says. - Skipping all text on an axis-off axes also exempted the user's own content, which on such an axes is the figure. Exclude only the undrawn axis artists. - `save()` leaked the figure when the audit raised, and did not create the stem's parent directory. - A single seed drew a zero-height band that reads as certainty; `mean_ci` and `diff_ci` now warn, matching what the references demand of the caption. - Guards for disjoint seed ranges and all-zero scores. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Close the round-three review findings None were blockers, but three were real defects on secondary paths: - The inline `\input` route omitted `\usepackage{tikz}` and the `\usetikzlibrary` line, so a paper following it literally would not compile: `trapezium`, `Stealth`, `fit=`, and `on background layer` each need one. - Vendoring was hardcoded to `figs/`, so a report script written under the artifacts directory could not import the style module beside it. - Removing `\familydefault` left no documented way back to a serif diagram while `use_style(family="serif")` still exists for plots. The colorbar guard now accepts `ax.get_label() == "<colorbar>"` as well as the private `_colorbar`; verified against matplotlib 3.11 that both hold today, so a rename can no longer make `clean` unreachable for every heatmap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
2d54154b33 |
Isolate native agent chat stores (#248)
* Isolate native agent chat stores * Fix legacy Codex rollout fallback * Simplify native chat store isolation * Handle missing native sessions without regexes * Harden isolated native chat sessions |
||
|
|
1304986749 |
Fix trusted run supervision and post-cancel Codex turns (#243)
* fix: launch run supervisors through orx up * fix: restart Codex after interrupted turns |
||
|
|
8996b8297b |
OR-184: Polish chat styling and skill workflows (#240)
* OR-184 Align composer controls and inline chips * OR-184 Refine composer and panel styling * OR-184 Polish chat styling and skill workflows |
||
|
|
8b6b6d9b84 | OR-220 Remove generated PROJECT.md (#238) | ||
|
|
0bfeb1ebbe |
Find the LaTeX toolchain on the user's PATH, and recommend Tectonic (#227)
* Give shell_env the one PATH search every lookup uses `find_on_path` sat in `harness::detect` as `pub(super)`, so anything outside the harness registry that needed a shell-PATH lookup wrote the loop again — `find_opencode` and `resolves_on_path` both had a copy, the former commented "Mirrors `find_on_path`". Move it to `shell_env`, which already owns `search_path()` and whose module doc is about which PATH orx searches, and point all four call sites at it. The shared lookup now also drops *relative* PATH entries, not just empty ones. A relative entry names no fixed directory: it resolved against orx's own cwd, which for a Finder-launched bundle is never where a user's tool lives, and the child that later ran it would resolve the same name somewhere else again. `other_orx_on_path` in install_cli.rs keeps its own loop — it needs every candidate and canonicalizes them, so it is a different search. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Find the LaTeX toolchain on the user's PATH, not launchd's A `.tex` file opened in the macOS app reported "No LaTeX toolchain found on PATH" on a machine with tectonic installed. The bundle is started by launchd with `PATH=/usr/bin:/bin:/usr/sbin:/sbin`, where no TeX lives, and `latex.rs` was the one lookup still resolving against the process environment — the harnesses had gone through `shell_env`'s probed shell PATH for exactly this reason. Verified against a bundle launched with launchd's environment: `/api/latex/engine` returns `tectonic` where the installed build returns null. Finding the tool is not enough on its own: latexmk finds the engine, biber and bibtex on PATH itself, so the child is handed the same PATH we found it on. The tool is spawned by its absolute path but symlinks are left unresolved — TeX picks its format file from the name it was invoked as, so canonicalizing `pdflatex` to `pdftex` would silently run plain TeX. `on_path` no longer spawns `<binary> --version` to decide. It costs a probe that a present-but-unrunnable binary would have caught, and buys back five subprocesses on every `.tex` tab open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Point a user with no LaTeX at Tectonic rather than MacTeX The no-engine hint led with MacTeX and offered `brew install --cask mactex` as the command to copy — a multi-gigabyte install for someone who just wants to see their paper. Tectonic is one self-contained binary that fetches each document's packages, so it is the install a user can actually finish, and it is what the copyable command now installs. The distribution stays named second, because Tectonic runs only XeTeX. The hint says so: it is the last screen that can, since the hint disappears the moment an engine exists and the amber substitution note only fires for a document that names its engine explicitly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
51e510f1a2 |
Compile LaTeX papers to PDF in the file viewer (#225)
A `.tex` file in the live checkout now compiles on open and shows the real PDF, with a toggle to a live source editor that recompiles on save. Compilation targets Overleaf's behaviour: `latexmk` drives whichever engine the document asks for via `% !TeX program`, running biber or bibtex and repeating passes until references settle. Without latexmk the engine is driven directly and that orchestration is done here; with neither, `tectonic` stands in and says so, since it is XeTeX and cannot honour a LuaLaTeX document. Users can upload their own templates — a conference class, a house style — as a `.tex` or a `.zip` carrying its `.cls`/`.sty`/`.bst`. Templates are global or scoped to one project, and are written into each session worktree so the agent can start a paper from one. Uploading and managing them lives in the renamed Customize tab. The `orx-paper` skill and the `/write-paper` command teach the agent to write papers as `.tex` in the working tree, follow an uploaded template when one exists, and ground every reported number in a run rather than in memory. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
e6c1c6813d | OR-196 Slim agent prompt and modularize skills (#224) | ||
|
|
a0c30df38a |
OR-129 Let an agent delegate a task to a second agent session (#221)
* Let an agent delegate a task to a second agent session An agent could only do work itself or queue it behind the current turn. `orx agent spawn "<task>"` now starts a helper in its own top-level session — visible in Recents, its own transcript, its own worktree — and resumes this chat with the helper's closing reply when it finishes. The CLI only writes rows: the child's `chat_sessions` row (carrying a new `parent_session_id`) and a `chat_spawns` record. The resident `orx up` watcher starts the child's first turn and later reports back, the same store-and-watcher split as `orx exp wake` and for the same reason — the spawning `orx` is a short-lived subprocess with no harness to run a turn on. It is a CLI verb rather than an MCP tool because the mcp-gate bridge is Claude-only, while all three harnesses already shell out to `orx` with `ORX_CHAT_SESSION_ID` exported. Spawn rows walk pending → starting → running → notifying → done. The two claimed states carry a token so a watcher that dies mid-step leaves work reclaimable rather than lost, and a helper whose parent was deleted retires quietly instead of stranding the row. Spawned agents cannot spawn their own. A helper that can delegate turns one request into an unbounded tree of paid sessions, and nothing downstream bounds it. Settings carry over only when parent and child share a harness: a model or permission-mode id from one CLI means nothing to another. Plan never carries over — a helper is spawned to do the task, not to plan it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Harden spawned agents against losing the delegated task Review of the spawn feature found several ways a delegated task could be accepted and then quietly not happen. A helper's completion was read from `ChatHost::is_busy`, a map this process owns. A second `orx up` — or the same one after a restart — sees an empty map, so a helper working under it was reported "finished" within 3s and the delegation was abandoned. The gate now consults the durable turn lease, and `finish_turn` stamps the spawn row, so an idle helper with no stamp is reported as interrupted rather than as a false completion carrying half-written text. A failed start returned the row to Pending and retried every 3s forever. The brief is persisted before `send_message_showing` can report the turn didn't start, so each retry appended it again. Retries now skip the already-recorded brief, stop after three attempts, and wake the parent with "could not be started" — the CLI had promised it a wake-up. Claude activates Plan through its permission mode, not the plan axis, so clearing `plan_mode` still handed a planning parent's helper a mode that only ever produces a plan. The plan permission id is now dropped when inheriting. The closing reply was read from the last assistant message. An answered prompt card rides its own text-less message and becomes the branch tip, so an opencode helper that hit one card reported "no written reply" and its actual answer was lost. A turn that died on a harness error reported the same thing, reading as "nothing to say" rather than "it failed". The report now walks back to the newest message with text and distinguishes a reply, a failure, and genuine silence. Depth was capped at one level; breadth was not, so a looping parent could create as many paid sessions and worktrees as it liked. Five in flight. Also: the transcript's squash key ignored the spawned ids, collapsing two adjacent spawns into one row and stranding the second helper; following a spawn card set the one session filter that hides archived rows; the delegation playbook told agents to hand helpers a node this session owns, which cardinal rule 1 and one-branch-one-owner both forbid, and never told them to bound a helper's compute. The playbook placeholder test checked a hardcoded token list, so it could not catch a newly added token — it now scans the rendered prompt, and fails on the `{max_spawns}` this change introduced if its substitution is removed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Never retire a delegation before its report is delivered Round-two review found four more ways a spawned task could be lost. The give-up notification was fire-and-forget: it returned silently when the parent's turn slot was taken, then retired the row anyway. The parent is busy in exactly the expected case — it spawned from inside a turn, and the third failed attempt lands ~9s later — so the promised "could not be started" usually never arrived. Both wake-ups now go through one `deliver_wake_up`, which retires the row only once the message actually started a turn and otherwise leaves it for the next tick. `--no-wake` settled to Done the instant the turn started, and the in-flight cap counts only rows that are not Done. A looping parent could spawn five, wait one tick, and spawn five more forever. Fire-and-forget rows now stay Running until the helper is genuinely idle, so "in flight" means the same thing for both kinds. `interrupted` was read from the listing snapshot while the liveness check was live. A helper finishing cleanly while an earlier iteration awaited a whole turn was reported as interrupted and its reply thrown away — the same loss the stamp was added to prevent, inverted. It is re-read after the liveness check. A user pressing Stop reaches the same `finish_turn`, so a manually stopped helper was stamped finished and its half-written text handed back as a closing reply. `spawn_outcome` now recognizes the interrupt marker. The wake-up also claimed the helper's commits were "on its own branch". Session worktrees start detached, so a helper only has a branch if it ran `orx create-experiment`, and for the delegations the playbook recommends there are usually no commits at all. Restored the accurate wording, in the report and the playbook, and the clause is omitted entirely when the worktree isn't there. Also: a reclaimed `starting` claim now counts as an attempt, so a watcher that dies inside the send cannot retry forever; `ChatSpawn` no longer carries a `state` no reader used, and the INSERT hardcodes `pending`; branch-local dev slots get ALTERs for the renamed columns. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
505b272317 | refactor: keep research state local (#202) | ||
|
|
e9d322e547 |
Add lightweight project briefs and refresh onboarding (#200)
* feat: add lightweight project briefs and onboarding refresh * fix: refine onboarding and project workspace interactions * fix: harden demo onboarding state * fix: satisfy current clippy lint * chore: bump version to 0.1.105 |
||
|
|
fab62eae90 |
refactor: retire server-managed experiment runs (#199)
* refactor: retire server-managed experiment runs * refactor: unify bundled compute skill * refactor: retire server project creation * docs: make local workflow canonical * chore: release 0.1.104 |
||
|
|
46d359ff5e |
OR-173 Make the macOS app find harnesses, and stop it fighting a CLI install (#195)
* fix(app): detect harnesses in the macOS app by adopting the shell PATH Finder launches OpenResearch.app through launchd, so the bundle starts with PATH=/usr/bin:/bin:/usr/sbin:/sbin and no shell rc ever sourced. Harness detection resolves `claude`/`codex`/`opencode` off that PATH, so a DMG user with a Homebrew, nvm, or npm-global install saw every harness missing -- including an already-signed-in Claude Code session -- while a terminal `orx up` on the same machine detected them all. App mode now probes the user's shell once at startup and installs the result via `local::search_path`, which harness lookup and harness children consult instead of the process PATH. The probe is `$SHELL -ilc`: interactive, because zsh reads .zshrc only for interactive shells and that is where PATH edits live -- a login-only probe missed the ~/.local/bin holding `claude`. It runs an inner `sh -c` so fish reports a colon-separated PATH rather than its own list-valued $PATH, fences the value between per-probe nonce markers so rc-file chatter cannot forge one, and requires an absolute directory in the result. Best-effort throughout: a 5s cap, and every outcome logged. The five detection probes that spawned a harness binary with no env prep (`bin_version`, `claude_accepts_ultracode`, `claude_list_models`, `codex_model_list`, `run_models`) now go through `prepare_env` like `probe_auth` already did. Without that, a node-shebang install resolves via the hydrated PATH but its `--version` fails for want of `node`, and `gate_oauth_version` turns the missing version into `Unknown` -- telling a signed-in user to sign in. Verified end to end: a bundle run under launchd's PATH with an isolated ORX_DATA_DIR reports Claude Code agentReady, and finds a `codex` reachable only through the hydrated PATH -- codex has no fallback drop-location, so that resolution can only have come from the override. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(app): stop the bundle and a CLI install from conflicting Three ways the DMG app and a curl-installed `orx` stepped on each other. `orx delete` takes an exclusive lifecycle lock and refuses when another OpenResearch process holds it -- "Close `orx up`, `orx serve`, and any active runs before trying again." CLI `orx up` holds the matching read lock via `dispatch`, but app mode returns from `main` before `dispatch` runs, so it held nothing: `orx delete` from a CLI install would wipe the store out from under a live app. App mode now takes the same read lock for the life of the process. Agents shell out to `orx`, and `chat::prepare_env` prepends the running executable's directory so they get THIS build. In the bundle that directory held only `OpenResearch`, so `orx` fell through to whatever CLI the user had -- a different version, or nothing at all for a DMG-only user. The bundle now ships `Contents/MacOS/orx` as a symlink to the executable. Verified the symlink survives `codesign --options runtime` + `--verify --strict`. That alias would otherwise open a second dashboard, since a bare `orx` reaches app mode's no-arguments condition. `launched_as_app_bundle` now also requires that the process was invoked under the bundle executable's own name, which keeps the alias a plain CLI while leaving a direct run of the executable path -- the documented way to watch the app's logs -- in GUI mode. macOS `current_exe` reports the launch path symlink and all, so it is canonicalized before the comparison. Verified safe already, and left alone: the app binds an ephemeral port rather than 4791; the store is WAL with a 5s busy timeout; and run supervisors hold a per-run exclusive lock, so a second server recovering the same active run exits instead of double-driving it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(app): address review of the PATH and coexistence work Blocker: `launched_as_app_bundle` had grown real logic -- four distinct outcomes turning on a subtle platform fact -- with no coverage, and being macOS-gated it could not get any, since CI runs ubuntu only. The decision is now the pure `is_bundle_exe_launch(exe, argv0)`, compiled everywhere and table-tested for all four cases; only the process-state read stays gated. Same seam `extract_path` uses. The lifecycle lock moves ahead of the PATH probe. Taking it afterwards left the store unprotected for however long the probe ran -- up to 5s -- which is exactly when an `orx delete` racing app startup would land. A failed `read()` is now logged too; it was the one outcome in this module that could pass silently, and silently is how the app would then run unlocked. `orx delete` blocks on a running app now, so its message says so instead of naming three things the user isn't running. Probe diagnostics split the timeout from the spawn failure and name the shell, since "which shell, and did it hang or fail to start" is the whole question a report needs to answer. `bin_version` gets the `NO_COLOR` guard its siblings already carry: it feeds `parse_version`, an escape-laden version line parses as `None`, and `gate_oauth_version` turns that into `Unknown` -- reproducing the bug this branch exists to fix, via the synced env the probe now inherits. `find_opencode` skips empty PATH components, matching `find_on_path`. Packaging asserts the `orx` symlink survived staging. Every step preserves it today, but a dereferencing copy would fail silently -- the app builds, signs, notarizes and runs, and agents just quietly fall back to the user's own CLI. Docs: corrected the same overstatement in `search_path`'s module doc that DISTRIBUTION.md already fixed, and recorded the known gap that the probe imports only PATH, so `ORX_DATA_DIR`/`XDG_*` from a shell rc reach the CLI but not a Finder-launched app. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(app): import the shell's data and config dirs, not just PATH `ORX_DATA_DIR`, `XDG_DATA_HOME`, and `XDG_CONFIG_HOME` exported from a shell rc reached the CLI but never a Finder-launched app, so the two resolved different directories: the dashboard opened the default database while `orx` on the same machine used the user's, and the lifecycle lock added last commit guarded a file neither of them shared. Same root cause as the PATH bug, one layer down. `search_path` generalizes to `shell_env`: an allowlist (`IMPORTED`) the startup probe reads, NUL-separated so a directory can contain anything but NUL, behind `var()` -- process environment when no override is installed, so nothing changes for a terminal `orx`. `store::env_path` and `config::config_dir` are the only two places that resolve these, and both now go through it. The allowlist stays short on purpose: these are the variables whose divergence makes the app and the CLI act like separate installs, while credentials already reach harness children via `prepare_env`. This moves the lifecycle lock back after the probe, undoing last commit's reordering. The reason is now structural rather than incidental: the lock path is derived from `config_dir()`, so taking it before the probe would lock the default path while the CLI locks the user's -- protecting nothing. A correct lock a few hundred milliseconds late beats an immediate lock on the wrong file. Verified with the app's process environment stripped of both variables while the probe shell exported them: `orx.db` lands in the shell's data dir and `orx.lifecycle.lock` in the shell's config dir, and the HOME-derived defaults are never created. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(app): carry the imported environment into orx child processes Importing the shell's directories fixed the app's own resolution but not its children's, which made things worse rather than better for anyone exporting `ORX_DATA_DIR`. `spawn_detached_supervise` and the harness adapters spawn plain CLI processes; those never probe, so they re-resolved to the default store while the app read the user's. A run launched from the app would have been supervised against a different database than the dashboard was showing — before this branch both landed on the default and at least agreed. `shell_env::export_to` hands the imported variables to a child. `prepare_env` applies it, so an agent's `orx exp run` shares the dashboard's store, and `spawn_detached_supervise` applies it plus PATH, which also reaches the run payload it launches (`localbox` spawns `bash run.sh` with an inherited env, so it was losing the user's PATH entirely — no `python`, no `uv`, no `conda`). `opencode::spawn_agent` had hand-rolled a copy of `prepare_env`; it now calls it rather than growing a third copy of the same fix. Verified with the app's process environment stripped of both variables while the probe shell exported them: a harness child is handed ORX_DATA_DIR and XDG_CONFIG_HOME, and an `orx` run with that environment creates no default store. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(cli): print a runnable command in the hints the bundle breaks A DMG user has no `orx` anywhere on PATH, so every hint telling them to run `orx exp wait …` names a command their shell cannot find. Agents are already covered -- `prepare_env` puts the bundle's `orx` first on their PATH -- but a human driving the bundle's CLI is not. `invocation::orx()` resolves the spelling once: plain `orx` when it is on PATH, which is every CLI install and every agent, otherwise this binary's own path, shell-quoted when it needs it. Nothing changes for anyone who installed the CLI. Applied to the three hints the report named, each of which had been copied per backend: the post-launch "Follow it with …" line (nine copies), the missing run-command error (eight), and the outdated-version warning. Both hint bodies move into `invocation`, so the eight backends now share one line each -- a net deletion, and one place to fix the next time the wording moves. `warning_for` takes the spelling as an argument rather than reading process state, keeping its tests deterministic. Not covered: the long tail of `orx login`-style hints in error strings, which still print a literal `orx`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(app): close the environment gaps review found A dashboard-synced `ORX_DATA_DIR`/`XDG_*` silently beat the shell-imported one for harness children: `prepare_env` exported the imported vars, then the synced loop overwrote any whose key was absent from the *process* env -- which in app mode is exactly these. The app read one store while claude and opencode wrote another. The guard now consults `shell_env::var`, so the imported value counts as present. codex escaped this only because it re-pins `ORX_DATA_DIR` after `prepare_env`; claude and opencode have no such pin. Local run payloads were never actually fixed. The previous commit claimed the supervisor passed its environment to `bash run.sh`, but the supervisor does not spawn it -- `localbox::run_job` does, in the launching process, from `LocalJobSpec::env`. A run started from the app still executed the user's script under launchd's PATH, with no python, uv, or conda. The env now carries the imported PATH and directories, and the supervisor comment drops the wrong claim. Three more readers of these same variables were still going to the process env, and two of them made harness detection itself diverge between app and terminal: `harness::xdg_config_home` (whose doc claims to mirror `config::config_dir`) and `opencode_auth_path`, which would report opencode signed out in the app while the CLI saw it signed in. `invocation::resolves_on_path` was the third -- it decides whether a hint can say plain `orx`, and the reader pastes that into the shell whose PATH we imported. Also: `orx login` -- the first hint a fresh DMG user meets -- now resolves like the rest; `export_to` iterates in `IMPORTED` order so the startup log is diffable; and the doc drift is repaired, including the octal-escape invariant that makes the nonce's leading underscore load-bearing, the reopened `orx delete` window, and the scope note listing what still inherits the process environment (`git`, `gh`, `kubectl`, `ssh`, `publish-branch`). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(app): allow dead_code for the launch check off macOS `is_bundle_exe_launch` is deliberately un-gated so its tests run on CI's Linux runner, but its only non-test caller is `#[cfg(target_os = "macos")]`, so the Linux bin target sees it as dead. `mod local` carries a blanket `#[allow(dead_code)]`, which is why `shell_env::parse_probe` -- same shape -- did not trip; `mod commands` does not. Verified by rebuilding with every `target_os = "macos"` in `src/` swapped to `"linux"`, which reproduces exactly what the runner cfgs out. Clean, and no other item on this branch is dead off macOS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
c43180cf68 |
OR-161: make experiment wake-ups opt-in (#192)
* OR-161: make experiment wake-ups opt-in * Bump version to 0.1.101 |
||
|
|
4cffa77922 |
OR-171: Make file references clickable (#191)
* OR-171: require clickable file references * OR-171: restore evidence citation guidance |
||
|
|
82ea072291 |
OR-158 Decouple compute runs from GitHub
Ships direct source snapshots across compute backends, optional GitHub experiment publication, and CLI v0.1.98. |
||
|
|
4738715e94 |
OR-134 Add Skills tab: upload, import, and /-invoke agent skills (#175)
* Add Skills tab: upload, /-invoke, and import agent skills Adds a left-rail Skills section where users manage custom agent skills: - Upload a SKILL.md or a .zip of a skill folder (Global or per-project). - Import skills already installed in the user's coding agents. - Uploaded skills are written into each session worktree beside the built-in orx-* skills and surfaced in the composer's / menu. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Rebuild ui/dist for the Skills tab Regenerated committed assets (`pnpm build`) after the Skills tab UI and the merge with main's Tailwind migration, per AGENTS.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Address code review on the Skills tab - Prune deleted/renamed user skills from session worktrees via a manifest, and replace (not merge) each skill dir so shadows and re-uploads are clean. - Bound zip entry reads to the extract budget (deflate-bomb guard). - Accept a quoted SKILL.md `name:`; import keys strictly off the frontmatter name so folder==name always holds. - Dedupe the composer `/` menu (project shadows global); drop dead helpers. - Surface delete errors, guard re-entrant uploads, a11y + timeAgo tweaks. - Add tests for prune, clean shadow, zip caps, and quoted names. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Rebuild ui/dist after review fixes Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
7dc5155084 |
OR-148: Make agent guidance UI-agnostic (#160)
* Fix stale UI guidance in agent prompts * Clarify local compute default guidance |
||
|
|
6e4f998597 |
OR-131: make local file projects the default (#150)
* feat: make local projects the default * fix: complete local-first project workflow |
||
|
|
cec874e47c | Simplify project files as artifacts (#145) | ||
|
|
3e934765e1 |
Add Ray Jobs compute backend (v0.1.88) (#141)
* Add Ray Jobs as a first-class local compute backend. Submit via the Ray Jobs API with Settings → Compute → Ray, optional cpu/gpu/mem flavors, and the same supervise/log/cancel path as other backends. Co-authored-by: Cursor <cursoragent@cursor.com> * Review fixes: sync cloud skill, reject inapplicable flags, panic-safe log tail, fmt/clippy, dist rebuild (v0.1.87) * Round-1 review fixes: synced env for ray jobs, server-plane ray arm, help text, honest configured flag, resolver/preflight simplification, NaN guard, address validation * Round-2 review fixes: GONE debounce for purged ray jobs, cancel re-issue, prefix-guarded log tailer, drop SubmitResponse/Explicit, single URL normalization point * Round-3 nits: dirty-flag log tailer invariant, slurm-shaped cancel gate on transitions, doc accuracy * Rebase on v0.1.87; bump to v0.1.88 and rebuild ui/dist * Use official Ray and OpenResearch marks in BackendLogos --------- Co-authored-by: Sébastien Fabbro <sebfabbro@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
43852e42c0 |
Route run-completion notifications to the launching chat session (v0.1.75) (#115)
* Route run-completion notifications to the launching chat session Runs carried no owning-session id, so the run watcher guessed the recipient from project_id alone — the most-recently-touched, non-busy session in the project. With two agents in one project, the launcher was skipped by the is_busy guard (it was in its exp-wait loop) and an idle bystander got the '[orx] Run ... finished ... continue the loop' poke. Persist the launching chat session on the run (new runs.chat_session_id, migrated in), stamped from ORX_CHAT_SESSION_ID which every per-session harness child now exports (claude, codex app-server, codex sandboxed exec, opencode). The agent's 'orx exp run' subprocess inherits it, so run creation records the owner. watch_runs now routes to that session only (via notify_target); a busy owner is skipped as before, and an orphan run (CLI-launched / pre-migration) pokes nobody. Ownership is immutable: chat_session_id is excluded from the upsert ON CONFLICT clause, so a later status upsert never rewrites it. * Trim redundant routing-invariant comments (review nits) * Bump version to v0.1.75 |
||
|
|
d0388778ae |
One persistent Claude Code child per chat session (#112)
* Persistent Claude Code child per chat session
Replace the spawn-per-turn + --resume fork with one long-lived
`claude --print --input-format stream-json` child per chat session
(new src/local/claude.rs ClaudeHost/ClaudeClient, mirroring codex.rs),
collapsing ~3-6s of per-turn spawn/config/MCP-handshake overhead.
- Respawn policy: child keyed by SpawnConfig; permission-mode/effort/
bridge change or a cleared model -> kill + respawn with --resume;
model-only change -> set_model control request; identical -> reuse.
- run_turn rewritten around a pure, store-free apply_event(ctx, state,
event) folded over the child's stream-json output; native-session-id
and flush stay in the caller.
- Gate token minted only at spawn (re-minting would strand a live
bridge child); process_group(0) so terminal SIGINT can't kill a
resident child mid-turn.
- ChatHost gains a claude host; interrupt/delete/shutdown and up.rs's
project-delete loop kill the resident child (it survives task-abort).
- Tests: child_action matrix, classify_line variants, apply_event
fixture tests over hand-written stream-json.
* Review round 1 fixes: drop ClaudeHost back-ref, fix achieved bridge_active, prune dead code
- spawn_client: force config.bridge_active = false before the plan block so a
failed bridge write records false (was inheriting wanted=true, which both
suppressed plan cards with no bridge to hold them and defeated the
respawn-to-retry recovery)
- SpawnSpec carries the ChatHost directly (transient, no cycle); deletes the
Weak attach/OnceLock apparatus and the duplicated up_port
- drop dead ClaudeHost::client_for; claude_effort back to private
- truthful docs: write_mcp_config and gate_tokens are per-spawn/per-child now
- new fixture tests: result without is_error falls back to subtype; errored
tool_result flips the tool part to error
* Comment nit from clean review round: gate token is per-child, not per-turn
* Stream partial text/thinking deltas into the transcript
Without --include-partial-messages the CLI only emits complete assistant
messages, so each text block landed at once instead of streaming. Deltas
build the part under the same {mid}-{index} id the final assistant event
upserts, so the authoritative text overwrites the accumulated one; a
subagent's nested stream (parent_tool_use_id) is ignored.
* Note the stream-protocol invariants the delta overwrite leans on
|
||
|
|
a0b6f3ea5f |
Persistent cross-session agent memory (user + project memory files, {memory} playbook token) (#89)
* Persistent cross-session agent memory: user + project memory files inlined via {memory} playbook token
* Mention files/ + memory/ in datadir module doc
|
||
|
|
f633b80f9c |
Native modular agent skills: per-session worktree install + orx skill modules (v0.1.62) (#87)
* Native modular agent skills: per-session worktree install + orx skill modules (v0.1.62)
- Factor the 66KB SKILL.md into 10 embedded modules under agent-skills/
- Write the Local set as native SKILL.md skills into each orx up session
worktree (harness-specific dir), fresh every turn beside the playbook
- Slim the playbook: compute/k8s/report detail moves to skills, generated
skills index added; cardinal rules and command surface stay inline
- orx skill <name> serves bundled modules (API fallback unchanged);
no-arg prints the slim root + module index
- orx install-skills --full writes the Full set globally (cloud box);
Codex shim migrates to ~/.agents/skills (native, model-discoverable),
legacy prompt kept
* agent-skills: store modules as literal SKILL.md files, installed verbatim
Each module is now a complete, GitHub-readable skill at
agent-skills/<name>/SKILL.md (frontmatter included); local-mode body
variants live as SKILL.local.md siblings. The render() step is gone —
files are embedded and installed byte-for-byte, and the frontmatter
drift test now validates the files against the code's name/description.
* Revert incidental ui/dist rebuild (no UI source changes in this branch)
* Drop leftover rebuilt dist assets — ui/dist now matches origin/main exactly
* agent-skills: trigger-rich descriptions with explicit liberal 'Use when' cues
Descriptions are the model's trigger surface; err toward false-positive
loads. Bound raised 150 -> 400 chars (Codex ambient budget is ~8k across
the set).
* Playbook: dedupe against skills + extract to literal SYSTEM_PROMPT.md
The system prompt is now a GitHub-readable template at repo root; playbook_md
strips the leading doc comment and substitutes {tokens} (project facts,
compute default, skills index). Content duplicated by the installed skills is
trimmed to pointers: the five per-backend exp-run table rows collapse to one,
the loop keeps only its skeleton, and the sizing/analysis sections fold into
one-liners. The prompt now explicitly tells the agent to load the relevant
skill before acting in its area (long-horizon staleness guard). Placeholder
test extended to all ten tokens + comment-stripping.
* orx-compute skill: add missing slurm + openresearch backend sections
The playbook trim removed the slurm/openresearch table rows, but orx-compute's
body (extracted from the old SKILL.md) never had sections for them — the
detail existed only in the playbook. Content moved from the pre-PR playbook
rows in the same per-backend section style. Also restore the shell-tool
time-limit rationale on the wait loop step in SYSTEM_PROMPT.md.
|
||
|
|
7450249cec |
Compute tab redesign: unified target list + default compute target (#86)
* Settings: persist default compute target (backend + flavor) with pure resolver * Launch paths: resolve the default compute target; widen HTTP run to all 7 backends * API: compute-targets summary, default-target POST, local hardware + openresearch status endpoints * Agent guidance: reveal the default compute target in the playbook, SKILL.md, and skill templates * Compute tab: unified target accordion with This-machine + OpenResearch rows and default picker * cargo fmt * Polish: summary casing, a11y-clean row controls, instances subtitle * Review round 1: coherent no-flavor default prompt, 500 on settings io errors, UI dedup + summary refresh, doc fixes * Clean-round nits: refetch race guard, aligned token-source labels, flavor-required const, doc accuracy * Quiet the agent-disclosure footnote: muted text instead of amber callout * Info icon on the agent-disclosure footnote |
||
|
|
7d1aed6f7d |
Plan mode: synthesized plan card fallback + accept-edits option (#81)
* Plan mode: synthesize a plan card when ExitPlanMode never fires + accept-edits option
Observed failure: a plan-mode session ended with the plan as plain chat
text and no ExitPlanMode call — and since only a plan-card answer
switches the resume mode, the user's chat 'yes' resumed still in plan
mode, stranding the session read-only. Root cause of the missing call:
the shared playbook still said 'Never call an interactive
question/elicitation tool — it will hang', guidance that predates the
prompt-card work in #37/#40.
- run_turn tracks (plan_mode, saw_prompt, turn_errored, last_text) and
synthesizes a WirePrompt{kind:plan, synthesized:true} from the final
text when a plan-mode turn ends card-less and error-free; the pure
condition fn is unit-tested
- WirePrompt/ChatPrompt gain ; the UI softens the header to
'Plan mode — ready to proceed?' for synthesized cards
- playbook: interactive tools surface as cards now; in plan mode, always
present the finished plan via ExitPlanMode
- plan card gains 'Approve & accept edits' (resumeMode accept-edits —
synthesize_resume already honors it)
* chore: drop stray npm lockfile (ui uses pnpm)
|