Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .commandcode/taste/taste.md
Empty file.
10 changes: 10 additions & 0 deletions docs/EDITORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ tool starts the way you already have it configured, and wally wires nothing.
| `openclaw` | your own `openclaw.json` plus one provider, written for the run and named by `OPENCLAW_CONFIG_PATH` |
| `deepseek` | a `--patch` overlay on the argv that adds the provider to dsh's `llm-pi-ai` row; nothing enters `$DSH_HOME` |
| `prime-agent` | a temporary extension loaded with `-e` that registers the provider for the run, with the key in `RUNANYWHERE_API_KEY`; nothing enters `~/.prime/agent` |
| `command-code` | a `runanywhere-wally` provider merged into `~/.commandcode/providers.json` (it reads providers from nowhere else) and taken out when it exits: the original bytes go back if the file is unchanged, otherwise only that provider comes out. The file names `$WALLY_COMMAND_CODE_API_KEY` rather than holding the key. A local model, or a person with no Command Code sign-in, runs with `CMD_LOCAL_ONLY=1` (no Command Code gateway models, `/share`, `/usage` or server-side web tools); with no sign-in a placeholder `COMMAND_CODE_API_KEY` gets past Command Code's login screen. `--skip-onboarding --no-auto-update` are passed, `-t` is left to you. One run at a time (a lock in `~/.commandcode/`). Its own subcommands (`-- status`, `-- login`, …) run untouched; `-- acp` is wired, and there the editor picks the model |

Two flags go with `-m`. `--serve` holds the endpoint open and prints it instead
of launching anything, which is how a tool nobody has taught wally about gets
Expand Down Expand Up @@ -76,6 +77,15 @@ runs at `agent.reasoning_effort` in `~/.hermes/config.yaml` (per model under
each model's levels up to its highest and starts at the app's own default.
Prime Agent is given no reasoning levels yet: its models run at the
endpoint's default, and a level has to be named in Prime Agent itself.
Command Code is given each model's levels from `low` to `max` as
`reasoningEfforts` (`--effort`, or `/model`), and starts at its own default.
The endpoint attributes its traffic as `unknown` until the console learns a
`command_code` harness.
Wally ends when Command Code ends: Ctrl-C reaches both, and wally cleans up
after the tool exits. A signal sent to wally alone leaves it waiting for the
tool; signal the process group to stop both. A `kill -9` leaves the provider in
`providers.json` until the next `wally command-code` drops it, and a bare
`cmd -c` afterwards cannot find that provider for a resumed session.

Codex is told the model's context window through the catalog file, so its
context meter and auto-compaction work against the real limit. Its hosted web
Expand Down
2 changes: 2 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ pub fn configure_app(app: &mut App) {
"openclaw",
"deepseek",
"prime-agent",
"command-code",
],
},
Section {
Expand Down Expand Up @@ -176,6 +177,7 @@ fn is_passthrough_command(token: &str) -> bool {
"openclaw",
"deepseek",
"prime-agent",
"command-code",
];
NAMES.contains(&token)
}
Expand Down
5 changes: 5 additions & 0 deletions src/cli_formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,11 @@ mod tests {
"Open Prime Agent with a model",
"Coding tools",
),
leaf(
"command-code",
"Open Command Code with a model",
"Coding tools",
),
namespace(
"account",
"Account",
Expand Down
29 changes: 24 additions & 5 deletions src/harness/agents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ pub enum Handoff {
/// Prime Agent 0.10 has no `-e` extension flag. The provider is written
/// into `models.json` in the agent directory.
Extension,
/// Command Code reads custom providers only from
/// `~/.commandcode/providers.json`, and no variable moves that file; see
/// `command_code`.
ProvidersFile,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -72,13 +76,22 @@ pub fn agents() -> &'static [Agent] {
handoff: Handoff::Extension,
default_args: "",
},
// `command-code` rather than `cmd`: on Windows `cmd` is cmd.exe, and
// the package ships the long name on every platform.
Agent {
id: "command-code",
command: "command-code",
summary: "Open Command Code with a model",
handoff: Handoff::ProvidersFile,
default_args: "",
},
];
AGENTS
}

/// An OpenAI client sends an Authorization header whatever is in it, and the
/// local server ignores the value. A placeholder keeps both ends happy.
fn key_or_placeholder(api_key: &str) -> &str {
pub(super) fn key_or_placeholder(api_key: &str) -> &str {
if api_key.is_empty() {
"local"
} else {
Expand Down Expand Up @@ -119,15 +132,15 @@ fn unset_environment(name: &str) {
/// The process outlives one launch — tests run several, and the REPL can too
/// — so a value left behind would silently configure the next tool that
/// named no model.
struct ScopedEnv {
pub(super) struct ScopedEnv {
name: String,
previous: Option<std::ffi::OsString>,
had_previous: bool,
applied: bool,
}

impl ScopedEnv {
fn new(name: &str, value: &str) -> Self {
pub(super) fn new(name: &str, value: &str) -> Self {
let previous = std::env::var_os(name);
let had_previous = previous.is_some();
let applied = set_environment(name, value);
Expand All @@ -139,7 +152,7 @@ impl ScopedEnv {
}
}

fn applied(&self) -> bool {
pub(super) fn applied(&self) -> bool {
self.applied
}
}
Expand Down Expand Up @@ -485,7 +498,7 @@ fn drop_stale_open_claw_provider(state: &Path, config: &str) {
/// The OS home: HOME, falling back to USERPROFILE on Windows the way
/// `open_claw_state_directory` does (PowerShell and cmd.exe leave HOME
/// unset).
fn os_home() -> Option<OsString> {
pub(super) fn os_home() -> Option<OsString> {
let home = std::env::var_os("HOME").filter(|home| !home.is_empty());
#[cfg(windows)]
let home = home.or_else(|| std::env::var_os("USERPROFILE").filter(|home| !home.is_empty()));
Expand Down Expand Up @@ -1416,6 +1429,11 @@ pub fn build_deep_seek_patch(llm_config: &str, model: &str) -> String {
}

pub fn launch_agent(agent: &Agent, model: &str, args: &[String], options: &GlobalOptions) -> i32 {
// Command Code takes its lock and checks for its own subcommands before
// an endpoint is resolved, so it runs its own launch from the start.
if agent.handoff == Handoff::ProvidersFile {
return super::command_code::launch(agent, model, args, options);
}
// A launch killed before its own Drop runs (crash, kill -9, a closed
// terminal) leaves its config behind; sweep those before this one
// possibly writes another, rather than only ever growing the pile.
Expand Down Expand Up @@ -1656,6 +1674,7 @@ pub fn launch_agent(agent: &Agent, model: &str, args: &[String], options: &Globa
options,
)
}
Handoff::ProvidersFile => unreachable!("command-code is dispatched before resolve"),
};

release(&endpoint);
Expand Down
Loading
Loading