@sagentlab/navarch-runtime 0.1.79 → 0.1.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/dist/adapters/index.cjs +6 -1
- package/dist/adapters/pi-local.cjs +20 -0
- package/dist/adapters/pi.cjs +45 -10
- package/dist/config.cjs +9 -1
- package/dist/session.cjs +6 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -941,3 +941,37 @@ over the project's session model for the selected adapter only; switching agent
|
|
|
941
941
|
types does not reuse another adapter's pin. Reconnect without `--model` to return
|
|
942
942
|
to project-controlled model selection. Older identities without a model keep
|
|
943
943
|
using the control-plane execution policy.
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
### Pi on your own machine
|
|
947
|
+
|
|
948
|
+
Select **Pi (local)** in Connect an agent, or set `NAVARCH_AGENT=pi-local`
|
|
949
|
+
and `NAVARCH_RUNTIMES=pi-local`. Use a current Pi CLI with native MCP support
|
|
950
|
+
and Node.js 22.19 or newer. Host mode requires `NAVARCH_WORKTREE_GUARD=off`:
|
|
951
|
+
Pi's shell tools do not enforce the runtime's worktree boundary. The UI's
|
|
952
|
+
connect and supervise commands include this opt-out. Use a dedicated worker.
|
|
953
|
+
Docker is not advertised for this adapter yet.
|
|
954
|
+
|
|
955
|
+
The initial model is `qwen3.8-flash-next-iq2_xs`, served by a local
|
|
956
|
+
OpenAI-compatible endpoint at `http://127.0.0.1:8080/v1`. Start that model server
|
|
957
|
+
separately. Set `NAVARCH_PI_LOCAL_BASE_URL` in the worker environment for a
|
|
958
|
+
different endpoint (for example, Ollama's `http://127.0.0.1:11434/v1`).
|
|
959
|
+
`NAVARCH_PI_BIN` overrides the executable; `NAVARCH_PI_EXTRA_ARGS` adds CLI
|
|
960
|
+
arguments. `--model` at connect pins this machine's model as for other agents.
|
|
961
|
+
|
|
962
|
+
Bare model IDs use the generated `local` provider. Exact `provider/model`
|
|
963
|
+
references use the machine's existing Pi catalog and credentials from
|
|
964
|
+
`~/.pi/agent/models.json` and `auth.json` (or `PI_CODING_AGENT_DIR`). Run
|
|
965
|
+
`pi --list-models` to inspect that catalog. The UI puts the local default first
|
|
966
|
+
and labels public cloud suggestions by provider; suggestions do not imply
|
|
967
|
+
credentials or access. Custom model IDs remain editable.
|
|
968
|
+
|
|
969
|
+
Per-session configuration lives in a temporary agent directory, including
|
|
970
|
+
Navarch's authenticated `mcp.json`. Pi runs without persisted sessions,
|
|
971
|
+
automatically loaded extensions, skills, or project configuration. Temporary
|
|
972
|
+
configuration is removed at exit. Hosted Pi keeps its separate `pi` runtime,
|
|
973
|
+
DeepSeek provider, and billing policy; local sessions use `pi-local` and the
|
|
974
|
+
project's `pi_local_model` policy.
|
|
975
|
+
|
|
976
|
+
Pi CLI and model configuration reference:
|
|
977
|
+
https://github.com/earendil-works/pi/tree/main/packages/coding-agent/docs
|
package/dist/adapters/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runQoderAdapter = exports.qoderAdapter = exports.runAcpAdapter = exports.acpAdapter = exports.runPiAdapter = exports.piAdapter = exports.runOpenCodeAdapter = exports.openCodeAdapter = exports.runGeminiAdapter = exports.geminiAdapter = exports.runCodexAdapter = exports.codexAdapter = exports.runClaudeCodeAdapter = exports.claudeCodeAdapter = void 0;
|
|
3
|
+
exports.runQoderAdapter = exports.qoderAdapter = exports.runAcpAdapter = exports.acpAdapter = exports.runPiAdapter = exports.piAdapter = exports.runLocalPiAdapter = exports.localPiAdapter = exports.runOpenCodeAdapter = exports.openCodeAdapter = exports.runGeminiAdapter = exports.geminiAdapter = exports.runCodexAdapter = exports.codexAdapter = exports.runClaudeCodeAdapter = exports.claudeCodeAdapter = void 0;
|
|
4
4
|
exports.selectAdapter = selectAdapter;
|
|
5
5
|
const claude_cjs_1 = require("./claude.cjs");
|
|
6
6
|
Object.defineProperty(exports, "claudeCodeAdapter", { enumerable: true, get: function () { return claude_cjs_1.claudeCodeAdapter; } });
|
|
@@ -14,6 +14,9 @@ Object.defineProperty(exports, "runGeminiAdapter", { enumerable: true, get: func
|
|
|
14
14
|
const opencode_cjs_1 = require("./opencode.cjs");
|
|
15
15
|
Object.defineProperty(exports, "openCodeAdapter", { enumerable: true, get: function () { return opencode_cjs_1.openCodeAdapter; } });
|
|
16
16
|
Object.defineProperty(exports, "runOpenCodeAdapter", { enumerable: true, get: function () { return opencode_cjs_1.runOpenCodeAdapter; } });
|
|
17
|
+
const pi_local_cjs_1 = require("./pi-local.cjs");
|
|
18
|
+
Object.defineProperty(exports, "localPiAdapter", { enumerable: true, get: function () { return pi_local_cjs_1.localPiAdapter; } });
|
|
19
|
+
Object.defineProperty(exports, "runLocalPiAdapter", { enumerable: true, get: function () { return pi_local_cjs_1.runLocalPiAdapter; } });
|
|
17
20
|
const pi_cjs_1 = require("./pi.cjs");
|
|
18
21
|
Object.defineProperty(exports, "piAdapter", { enumerable: true, get: function () { return pi_cjs_1.piAdapter; } });
|
|
19
22
|
Object.defineProperty(exports, "runPiAdapter", { enumerable: true, get: function () { return pi_cjs_1.runPiAdapter; } });
|
|
@@ -44,6 +47,8 @@ function selectAdapter(agentType) {
|
|
|
44
47
|
return qoder_cjs_1.qoderAdapter;
|
|
45
48
|
case "claude-code":
|
|
46
49
|
return claude_cjs_1.claudeCodeAdapter;
|
|
50
|
+
case "pi-local":
|
|
51
|
+
return pi_local_cjs_1.localPiAdapter;
|
|
47
52
|
case "pi":
|
|
48
53
|
// Managed hosted runtime (#885): reachable only on a managed runner
|
|
49
54
|
// executing a `runtime: "pi"` claim — config.cts never produces "pi"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.localPiAdapter = void 0;
|
|
4
|
+
exports.runLocalPiAdapter = runLocalPiAdapter;
|
|
5
|
+
const pi_cjs_1 = require("./pi.cjs");
|
|
6
|
+
/** BYO Pi: native MCP, operator provider catalog, and a local OpenAI-compatible default. */
|
|
7
|
+
async function runLocalPiAdapter(options) {
|
|
8
|
+
if (options.dockerExec)
|
|
9
|
+
throw new Error("Pi (local) requires host mode");
|
|
10
|
+
if (options.signal?.aborted)
|
|
11
|
+
return { exitCode: null, timedOut: false, killedByLeaseLoss: true, stdout: "", stderr: "" };
|
|
12
|
+
const model = options.model ?? "qwen3.8-flash-next-iq2_xs";
|
|
13
|
+
const args = ["--mode", "json", "--no-session", "--no-extensions", "--no-skills", "--no-approve", ...options.extraArgs,
|
|
14
|
+
"--model", model.includes("/") ? model : `local/${model}`];
|
|
15
|
+
if (options.reasoningEffort)
|
|
16
|
+
args.push("--thinking", options.reasoningEffort === "max" ? "xhigh" : options.reasoningEffort);
|
|
17
|
+
args.push("-p", options.prompt);
|
|
18
|
+
return (0, pi_cjs_1.attachPiOutput)(await (0, pi_cjs_1.runOnHost)(options, args, true));
|
|
19
|
+
}
|
|
20
|
+
exports.localPiAdapter = { agentType: "pi-local", run: runLocalPiAdapter };
|
package/dist/adapters/pi.cjs
CHANGED
|
@@ -8,7 +8,9 @@ exports.buildHostedPiBudgetExtension = buildHostedPiBudgetExtension;
|
|
|
8
8
|
exports.resolveHostedPiModel = resolveHostedPiModel;
|
|
9
9
|
exports.buildPiProviderConfig = buildPiProviderConfig;
|
|
10
10
|
exports.parsePiJsonEvents = parsePiJsonEvents;
|
|
11
|
+
exports.attachPiOutput = attachPiOutput;
|
|
11
12
|
exports.runPiAdapter = runPiAdapter;
|
|
13
|
+
exports.runOnHost = runOnHost;
|
|
12
14
|
const node_child_process_1 = require("node:child_process");
|
|
13
15
|
const node_fs_1 = require("node:fs");
|
|
14
16
|
const node_os_1 = __importDefault(require("node:os"));
|
|
@@ -245,18 +247,51 @@ async function runPiAdapter(options) {
|
|
|
245
247
|
: await runOnHost(options, args);
|
|
246
248
|
return attachPiOutput(raw);
|
|
247
249
|
}
|
|
248
|
-
async function runOnHost(options, args) {
|
|
249
|
-
//
|
|
250
|
-
//
|
|
250
|
+
async function runOnHost(options, args, local = false) {
|
|
251
|
+
// Hosted sessions never read operator auth; BYO sessions copy only provider
|
|
252
|
+
// config and credentials. Both paths clean up their isolated agent directory.
|
|
251
253
|
const agentDir = await node_fs_1.promises.mkdtemp(node_path_1.default.join(node_os_1.default.tmpdir(), "navarch-pi-agent-"));
|
|
252
|
-
await node_fs_1.promises.writeFile(node_path_1.default.join(agentDir, "models.json"), buildPiProviderConfig(), { mode: 0o600 });
|
|
253
|
-
const budgetExtensionPath = node_path_1.default.join(agentDir, BUDGET_EXTENSION_NAME);
|
|
254
|
-
await node_fs_1.promises.writeFile(budgetExtensionPath, buildHostedPiBudgetExtension(), {
|
|
255
|
-
mode: 0o600,
|
|
256
|
-
});
|
|
257
|
-
const env = { ...options.env, PI_CODING_AGENT_DIR: agentDir };
|
|
258
|
-
const boundedArgs = withBudgetExtension(args, budgetExtensionPath);
|
|
259
254
|
try {
|
|
255
|
+
if (local) {
|
|
256
|
+
const sourceDir = options.env.PI_CODING_AGENT_DIR ?? process.env.PI_CODING_AGENT_DIR ?? node_path_1.default.join(node_os_1.default.homedir(), ".pi", "agent");
|
|
257
|
+
for (const name of ["models.json", "auth.json"]) {
|
|
258
|
+
try {
|
|
259
|
+
await node_fs_1.promises.copyFile(node_path_1.default.join(sourceDir, name), node_path_1.default.join(agentDir, name));
|
|
260
|
+
await node_fs_1.promises.chmod(node_path_1.default.join(agentDir, name), 0o600);
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
if (error.code !== "ENOENT")
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const model = options.model ?? "qwen3.8-flash-next-iq2_xs";
|
|
268
|
+
if (!model.includes("/")) {
|
|
269
|
+
const configPath = node_path_1.default.join(agentDir, "models.json");
|
|
270
|
+
const config = JSON.parse(await node_fs_1.promises.readFile(configPath, "utf8").catch(() => "{}"));
|
|
271
|
+
config.providers ??= {};
|
|
272
|
+
// Explicit provider/model references use the machine's catalog unchanged.
|
|
273
|
+
config.providers.local = {
|
|
274
|
+
baseUrl: options.env.NAVARCH_PI_LOCAL_BASE_URL ?? process.env.NAVARCH_PI_LOCAL_BASE_URL ?? "http://127.0.0.1:8080/v1",
|
|
275
|
+
api: "openai-completions", apiKey: "local",
|
|
276
|
+
models: [{ id: model, reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } }],
|
|
277
|
+
};
|
|
278
|
+
await node_fs_1.promises.writeFile(configPath, JSON.stringify(config), { mode: 0o600 });
|
|
279
|
+
}
|
|
280
|
+
if (options.mcpConfigPath) {
|
|
281
|
+
await node_fs_1.promises.copyFile(options.mcpConfigPath, node_path_1.default.join(agentDir, "mcp.json"));
|
|
282
|
+
await node_fs_1.promises.chmod(node_path_1.default.join(agentDir, "mcp.json"), 0o600);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
await node_fs_1.promises.writeFile(node_path_1.default.join(agentDir, "models.json"), buildPiProviderConfig(), { mode: 0o600 });
|
|
287
|
+
}
|
|
288
|
+
const budgetExtensionPath = node_path_1.default.join(agentDir, BUDGET_EXTENSION_NAME);
|
|
289
|
+
if (!local)
|
|
290
|
+
await node_fs_1.promises.writeFile(budgetExtensionPath, buildHostedPiBudgetExtension(), {
|
|
291
|
+
mode: 0o600,
|
|
292
|
+
});
|
|
293
|
+
const env = { ...options.env, PI_CODING_AGENT_DIR: agentDir };
|
|
294
|
+
const boundedArgs = local ? args : withBudgetExtension(args, budgetExtensionPath);
|
|
260
295
|
return await new Promise((resolve) => {
|
|
261
296
|
let stdout = "";
|
|
262
297
|
let stderr = "";
|
package/dist/config.cjs
CHANGED
|
@@ -25,6 +25,7 @@ exports.RUNTIME_AGENT_TYPES = [
|
|
|
25
25
|
"opencode",
|
|
26
26
|
"acp",
|
|
27
27
|
"qoder",
|
|
28
|
+
"pi-local",
|
|
28
29
|
];
|
|
29
30
|
function isRuntimeAgentType(value) {
|
|
30
31
|
return typeof value === "string" && exports.RUNTIME_AGENT_TYPES.includes(value);
|
|
@@ -105,7 +106,12 @@ function loadRuntimeConfig(env = process.env) {
|
|
|
105
106
|
// fails closed there (adapters/opencode.cts). Advertising it anyway meant
|
|
106
107
|
// the machine claimed OpenCode tasks it could only fail, one lease at a
|
|
107
108
|
// time; keep it out of the claim instead of discovering this per session.
|
|
108
|
-
const runnableRuntimes = requestedRuntimes.filter((runtime) => runtime
|
|
109
|
+
const runnableRuntimes = requestedRuntimes.filter((runtime) => runtime === "pi-local"
|
|
110
|
+
? sandboxMode === "host" && !worktreeGuard
|
|
111
|
+
: runtime !== "opencode" || !opencodeBlockedOnHost(sandboxMode, worktreeGuard));
|
|
112
|
+
if (requestedRuntimes.includes("pi-local") && runnableRuntimes.length === 0) {
|
|
113
|
+
throw new Error("Pi (local) requires NAVARCH_SANDBOX_MODE=host and NAVARCH_WORKTREE_GUARD=off");
|
|
114
|
+
}
|
|
109
115
|
if (requestedRuntimes.includes("opencode") && runnableRuntimes.length === 0) {
|
|
110
116
|
throw new Error(exports.OPENCODE_HOST_GUARD_MESSAGE);
|
|
111
117
|
}
|
|
@@ -143,6 +149,8 @@ function loadRuntimeConfig(env = process.env) {
|
|
|
143
149
|
opencodeExtraArgs: envList(env, "NAVARCH_OPENCODE_EXTRA_ARGS", []),
|
|
144
150
|
acpBin: env.NAVARCH_ACP_BIN ?? "dsh",
|
|
145
151
|
acpExtraArgs: envList(env, "NAVARCH_ACP_EXTRA_ARGS", ["--profile", "acp"]),
|
|
152
|
+
piBin: env.NAVARCH_PI_BIN ?? "pi",
|
|
153
|
+
piExtraArgs: envList(env, "NAVARCH_PI_EXTRA_ARGS", []),
|
|
146
154
|
qoderBin: env.NAVARCH_QODER_BIN ?? "qoder",
|
|
147
155
|
qoderExtraArgs: envList(env, "NAVARCH_QODER_EXTRA_ARGS", []),
|
|
148
156
|
gitAuthorName: env.NAVARCH_GIT_AUTHOR_NAME ?? "sagentlab",
|
package/dist/session.cjs
CHANGED
|
@@ -46,9 +46,10 @@ function resolveSessionExecution(config, claimed) {
|
|
|
46
46
|
const execution = claimed.context_bundle.execution ?? {
|
|
47
47
|
profile: claimed.task.execution_profile ?? "standard",
|
|
48
48
|
model: runtime === "codex" ? "gpt-6-astra"
|
|
49
|
-
: runtime === "
|
|
50
|
-
: runtime === "
|
|
51
|
-
: "
|
|
49
|
+
: runtime === "pi-local" ? "qwen3.8-flash-next-iq2_xs"
|
|
50
|
+
: runtime === "gemini" ? "auto"
|
|
51
|
+
: runtime === "opencode" || runtime === "acp" || runtime === "qoder" ? "default"
|
|
52
|
+
: "claude-opus-5-5",
|
|
52
53
|
reasoning_effort: "medium",
|
|
53
54
|
};
|
|
54
55
|
return {
|
|
@@ -865,6 +866,8 @@ function adapterCommand(config, runtime) {
|
|
|
865
866
|
return { bin: config.opencodeBin, extraArgs: config.opencodeExtraArgs };
|
|
866
867
|
case "acp":
|
|
867
868
|
return { bin: config.acpBin, extraArgs: config.acpExtraArgs };
|
|
869
|
+
case "pi-local":
|
|
870
|
+
return { bin: config.piBin, extraArgs: config.piExtraArgs };
|
|
868
871
|
case "qoder":
|
|
869
872
|
return { bin: config.qoderBin, extraArgs: config.qoderExtraArgs };
|
|
870
873
|
}
|
package/package.json
CHANGED