agent-phonon 0.2.3 → 0.2.5

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/dist/daemon.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { ModelInfo } from '@agent-phonon/protocol';
2
+
1
3
  /**
2
4
  * daemon 配置(bug-bash B4)。
3
5
  *
@@ -25,10 +27,12 @@ interface AdapterConfig {
25
27
  claudeBaseUrl?: string;
26
28
  claudeAuthToken?: string;
27
29
  claudeDefaultModel?: string;
30
+ claudeModels?: ModelInfo[];
28
31
  /** codex:网关 baseUrl(/v1)/key/默认模型/wireApi。 */
29
32
  codexBaseUrl?: string;
30
33
  codexApiKey?: string;
31
34
  codexDefaultModel?: string;
35
+ codexModels?: ModelInfo[];
32
36
  codexWireApi?: "responses" | "chat";
33
37
  /** hermes:默认模型/provider(用现有 hermes config)。 */
34
38
  hermesModel?: string;
package/dist/daemon.js CHANGED
@@ -3190,8 +3190,8 @@ var FileManager = class {
3190
3190
  if (abs !== root && !abs.startsWith(root + sep2)) {
3191
3191
  throw new PhononError("errPolicyDenied", `file path escapes project/worktree: ${rel}`);
3192
3192
  }
3193
- const probe = !followFinal && abs !== root ? dirname3(abs) : abs;
3194
- const real = await this.realpathBoundary(probe);
3193
+ const probe2 = !followFinal && abs !== root ? dirname3(abs) : abs;
3194
+ const real = await this.realpathBoundary(probe2);
3195
3195
  if (real !== root && !real.startsWith(root + sep2)) {
3196
3196
  throw new PhononError("errPolicyDenied", `file path escapes project/worktree via symlink: ${rel}`);
3197
3197
  }
@@ -4244,11 +4244,12 @@ var OpenClawGatewayAdapter = class {
4244
4244
  if (subAgents.length === 0)
4245
4245
  subAgents = [{ id: this.defaultAgent }];
4246
4246
  const now = (/* @__PURE__ */ new Date()).toISOString();
4247
+ const gatewayModels = await this.listGatewayModels();
4247
4248
  return subAgents.map((a) => {
4248
4249
  if (a.workspace)
4249
4250
  this.workspaceCache.set(`openclaw:${a.id}`, a.workspace);
4250
4251
  const primaryModel = typeof a.model === "string" ? a.model : a.model?.primary;
4251
- const models = primaryModel ? [{ id: primaryModel, available: true }] : [];
4252
+ const models = gatewayModels.length > 0 ? gatewayModels : primaryModel ? [{ id: primaryModel, available: true }] : [];
4252
4253
  return {
4253
4254
  // 复合 agentId:openclaw:<subAgentId>(design D32)
4254
4255
  agentId: `openclaw:${a.id}`,
@@ -4261,6 +4262,32 @@ var OpenClawGatewayAdapter = class {
4261
4262
  };
4262
4263
  });
4263
4264
  }
4265
+ async listGatewayModels() {
4266
+ try {
4267
+ const r = await this.gw.rpc("models.list", { view: "all" }, 8e3);
4268
+ const rows = Array.isArray(r.models) ? r.models : [];
4269
+ const models = [];
4270
+ const seen = /* @__PURE__ */ new Set();
4271
+ for (const row of rows) {
4272
+ const id = typeof row.key === "string" ? row.key : typeof row.id === "string" ? row.id : void 0;
4273
+ if (!id || seen.has(id))
4274
+ continue;
4275
+ if (row.available === false || row.missing === true)
4276
+ continue;
4277
+ seen.add(id);
4278
+ const contextWindow = typeof row.contextWindow === "number" ? row.contextWindow : typeof row.contextTokens === "number" ? row.contextTokens : void 0;
4279
+ models.push({
4280
+ id,
4281
+ ...typeof row.name === "string" ? { displayName: row.name } : {},
4282
+ ...contextWindow && contextWindow > 0 ? { contextWindow } : {},
4283
+ available: true
4284
+ });
4285
+ }
4286
+ return models;
4287
+ } catch {
4288
+ return [];
4289
+ }
4290
+ }
4264
4291
  async createSession(params) {
4265
4292
  await this.gw.connect();
4266
4293
  const subAgent = params.agentConfig?.openclawAgent ?? (params.agentId.includes(":") ? params.agentId.split(":")[1] : this.defaultAgent);
@@ -4662,6 +4689,8 @@ var CodexSession = class {
4662
4689
  this.env = env;
4663
4690
  }
4664
4691
  providerArgs() {
4692
+ if (!this.env.baseUrl || !this.env.apiKey)
4693
+ return [];
4665
4694
  const id = this.env.providerId ?? "phonon_gateway";
4666
4695
  const name = this.env.providerName ?? "phonon-gateway";
4667
4696
  return [
@@ -4689,14 +4718,14 @@ var CodexSession = class {
4689
4718
 
4690
4719
  ${prompt}`;
4691
4720
  }
4692
- const args = this.threadId ? ["exec", "resume", this.threadId, "-", "--json", ...this.providerArgs(), "--model", this.model, "--dangerously-bypass-approvals-and-sandbox"] : ["exec", "-", "--json", ...this.providerArgs(), "--model", this.model, "--dangerously-bypass-approvals-and-sandbox"];
4721
+ const args = this.threadId ? ["exec", "resume", this.threadId, "-", "--json", ...this.providerArgs(), ...this.model !== "default" ? ["--model", this.model] : [], "--dangerously-bypass-approvals-and-sandbox"] : ["exec", "-", "--json", ...this.providerArgs(), ...this.model !== "default" ? ["--model", this.model] : [], "--dangerously-bypass-approvals-and-sandbox"];
4693
4722
  await this.run(args, prompt, turnId, emit, opts);
4694
4723
  }
4695
4724
  run(args, stdin, turnId, emit, opts) {
4696
4725
  return new Promise((resolve5) => {
4697
4726
  const child = spawn3("codex", args, {
4698
4727
  cwd: this.cwd,
4699
- env: { ...process.env, ...opts.environment ?? {}, OPENAI_API_KEY: this.env.apiKey }
4728
+ env: { ...process.env, ...opts.environment ?? {}, ...this.env.apiKey ? { OPENAI_API_KEY: this.env.apiKey } : {} }
4700
4729
  });
4701
4730
  this.current = child;
4702
4731
  let buf = "";
@@ -4813,10 +4842,7 @@ var CodexAdapter = class {
4813
4842
  available,
4814
4843
  ...available ? {} : { unavailableReason: "codex CLI not found" },
4815
4844
  ...version ? { version } : {},
4816
- models: [
4817
- { id: "gpt-5.5", displayName: "GPT-5.5", available: true },
4818
- { id: "gpt-5.3-codex", displayName: "GPT-5.3 Codex", available: true }
4819
- ],
4845
+ models: this.env.models?.length ? this.env.models : [{ id: this.env.defaultModel, available: true }],
4820
4846
  capabilities: CAPABILITIES2,
4821
4847
  scannedAt: (/* @__PURE__ */ new Date()).toISOString()
4822
4848
  }];
@@ -5464,16 +5490,20 @@ var CAPABILITIES5 = {
5464
5490
  limits: { maxConcurrentSessions: 4 }
5465
5491
  };
5466
5492
  function writeSettingsFile(env, model) {
5493
+ if (!env.baseUrl || !env.authToken)
5494
+ return void 0;
5467
5495
  const dir = mkdtempSync(join10(tmpdir2(), "phonon-cc-"));
5468
5496
  const file = join10(dir, "settings.json");
5469
5497
  const content = JSON.stringify({
5470
5498
  env: {
5471
5499
  ANTHROPIC_BASE_URL: env.baseUrl,
5472
5500
  ANTHROPIC_AUTH_TOKEN: env.authToken,
5473
- ANTHROPIC_MODEL: model,
5474
- ANTHROPIC_DEFAULT_OPUS_MODEL: model,
5475
- ANTHROPIC_DEFAULT_SONNET_MODEL: model,
5476
- ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
5501
+ ...model !== "default" ? {
5502
+ ANTHROPIC_MODEL: model,
5503
+ ANTHROPIC_DEFAULT_OPUS_MODEL: model,
5504
+ ANTHROPIC_DEFAULT_SONNET_MODEL: model,
5505
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: model
5506
+ } : {},
5477
5507
  CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1"
5478
5508
  }
5479
5509
  });
@@ -5526,12 +5556,13 @@ ${prompt}`;
5526
5556
  // 最高权限:bypassPermissions 跳过所有权限确认;不限定 allowedTools = 所有工具可用
5527
5557
  // (phonon 定位:全自动执行,牺牲安全换自动化)
5528
5558
  "--permission-mode",
5529
- "bypassPermissions",
5530
- "--settings",
5531
- this.settingsFile(),
5532
- "--model",
5533
- this.model
5559
+ "bypassPermissions"
5534
5560
  ];
5561
+ const settings = this.settingsFile();
5562
+ if (settings)
5563
+ args.push("--settings", settings);
5564
+ if (this.model !== "default")
5565
+ args.push("--model", this.model);
5535
5566
  if (this.started)
5536
5567
  args.push("--resume", this.uuid);
5537
5568
  else
@@ -5684,11 +5715,7 @@ var ClaudeCodeAdapter = class {
5684
5715
  available,
5685
5716
  ...available ? {} : { unavailableReason: "claude CLI not found" },
5686
5717
  ...version ? { version } : {},
5687
- models: [
5688
- { id: "claude-opus-4.6", displayName: "Claude Opus 4.6", available: true },
5689
- { id: "claude-opus-4.7", displayName: "Claude Opus 4.7", available: true },
5690
- { id: "claude-sonnet-4.6", displayName: "Claude Sonnet 4.6", available: true }
5691
- ],
5718
+ models: this.env.models?.length ? this.env.models : [{ id: this.env.defaultModel, available: true }],
5692
5719
  capabilities: CAPABILITIES5,
5693
5720
  scannedAt: (/* @__PURE__ */ new Date()).toISOString()
5694
5721
  }];
@@ -6055,6 +6082,31 @@ function readOpenClawGatewayToken() {
6055
6082
  }
6056
6083
  }
6057
6084
 
6085
+ // src/commands.ts
6086
+ import { spawnSync } from "node:child_process";
6087
+ import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync5 } from "node:fs";
6088
+ import { homedir as homedir10 } from "node:os";
6089
+ import { join as join12, dirname as dirname5 } from "node:path";
6090
+ import { fileURLToPath } from "node:url";
6091
+ function probe(bin, args = ["--version"]) {
6092
+ const r = spawnSync(bin, args, { timeout: 8e3 });
6093
+ return { ok: r.status === 0, out: (r.stdout?.toString() ?? "").trim().split("\n")[0] ?? "" };
6094
+ }
6095
+ function openCodeBin() {
6096
+ const bundled = join12(homedir10(), ".opencode", "bin", "opencode");
6097
+ return existsSync12(bundled) ? bundled : "opencode";
6098
+ }
6099
+ function autoDetectAdapters(adapters) {
6100
+ const out = [...adapters];
6101
+ const has = (type2) => out.some((a) => a.type === type2);
6102
+ if (!has("hermes") && probe("hermes").ok) out.push({ type: "hermes" });
6103
+ const ocBin = openCodeBin();
6104
+ if (!has("opencode") && probe(ocBin).ok) out.push({ type: "opencode", opencodeBinPath: ocBin === "opencode" ? void 0 : ocBin });
6105
+ if (!has("claude-code") && probe("claude").ok) out.push({ type: "claude-code", claudeDefaultModel: "default" });
6106
+ if (!has("codex") && probe("codex").ok) out.push({ type: "codex", codexDefaultModel: "default" });
6107
+ return out;
6108
+ }
6109
+
6058
6110
  // src/obs-server.ts
6059
6111
  import { createServer as createServer2 } from "node:http";
6060
6112
  var ObsServer = class {
@@ -6182,7 +6234,7 @@ var PhononDaemon = class {
6182
6234
  this.registerAdapters();
6183
6235
  }
6184
6236
  registerAdapters() {
6185
- for (const a of this.cfg.adapters) {
6237
+ for (const a of autoDetectAdapters(this.cfg.adapters)) {
6186
6238
  if (a.type === "openclaw-gateway") {
6187
6239
  const token = a.gatewayToken ?? readOpenClawGatewayToken();
6188
6240
  if (!token) {
@@ -6196,17 +6248,9 @@ var PhononDaemon = class {
6196
6248
  this.gatewayAdapters.push(ad);
6197
6249
  this.registry.register(ad);
6198
6250
  } else if (a.type === "claude-code") {
6199
- if (a.claudeBaseUrl && a.claudeAuthToken) {
6200
- this.registry.register(new ClaudeCodeAdapter({ env: { baseUrl: a.claudeBaseUrl, authToken: a.claudeAuthToken, defaultModel: a.claudeDefaultModel ?? "claude-opus-4.6" } }));
6201
- } else {
6202
- console.warn("[daemon] claude-code adapter skipped: need claudeBaseUrl + claudeAuthToken");
6203
- }
6251
+ this.registry.register(new ClaudeCodeAdapter({ env: { baseUrl: a.claudeBaseUrl, authToken: a.claudeAuthToken, defaultModel: a.claudeDefaultModel ?? "default", models: a.claudeModels } }));
6204
6252
  } else if (a.type === "codex") {
6205
- if (a.codexBaseUrl && a.codexApiKey) {
6206
- this.registry.register(new CodexAdapter({ env: { baseUrl: a.codexBaseUrl, apiKey: a.codexApiKey, defaultModel: a.codexDefaultModel ?? "gpt-5.5", wireApi: a.codexWireApi ?? "responses" } }));
6207
- } else {
6208
- console.warn("[daemon] codex adapter skipped: need codexBaseUrl + codexApiKey");
6209
- }
6253
+ this.registry.register(new CodexAdapter({ env: { baseUrl: a.codexBaseUrl, apiKey: a.codexApiKey, defaultModel: a.codexDefaultModel ?? "default", models: a.codexModels, wireApi: a.codexWireApi ?? "responses" } }));
6210
6254
  } else if (a.type === "hermes") {
6211
6255
  this.registry.register(new HermesAdapter({ env: { defaultModel: a.hermesModel, provider: a.hermesProvider } }));
6212
6256
  } else if (a.type === "opencode") {