@ouro.bot/cli 0.1.0-alpha.917 → 0.1.0-alpha.919

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/changelog.json CHANGED
@@ -1,6 +1,20 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.919",
6
+ "changes": [
7
+ "Shepherd now sends the agent's owner a short Teams message for every coding-agent return it judges, saying what it did and why; set senses.shepherd.notify to needs-me or off to hear less.",
8
+ "Link a new account, such as Teams, to yourself by sending your agent a one-time code from it, and merge duplicate friend records with ouro friend dedupe.",
9
+ "Your agent can now type an instruction or press a key in one of your coding agents' terminals when you ask it to, so you can steer them from your phone."
10
+ ]
11
+ },
12
+ {
13
+ "version": "0.1.0-alpha.918",
14
+ "changes": [
15
+ "The model table now lists today's Claude 5.5 and GPT 5.5 through 6.1 models with their reasoning levels and image support, new agents default to Claude Opus 5.5, retired 4.6, GPT-5.4 and GPT-5.3 Codex entries are gone, and Claude through GitHub Copilot no longer fails every turn with a tool_choice error."
16
+ ]
17
+ },
4
18
  {
5
19
  "version": "0.1.0-alpha.917",
6
20
  "changes": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "runtimeVersion": "0.1.0-alpha.917",
2
+ "runtimeVersion": "0.1.0-alpha.919",
3
3
  "bundleSchemaVersion": 3,
4
4
  "lastUpdated": "2026-09-03T00:00:00.000Z"
5
5
  }
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0"?>
2
2
  <Container version="2">
3
3
  <Name>ouro-butler</Name>
4
- <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.917</Repository>
4
+ <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.919</Repository>
5
5
  <Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
6
6
  <Network>host</Network>
7
7
  <Shell>sh</Shell>
@@ -123,7 +123,7 @@ const registryData = [
123
123
  path: "humanFacing.model",
124
124
  tier: "self",
125
125
  description: "Model name for human-facing interactions.",
126
- default: "claude-opus-4-6",
126
+ default: "claude-opus-5-5",
127
127
  effects: "Changes the specific model used for human-facing conversations.",
128
128
  topics: ["model", "provider", "llm", "human"],
129
129
  validate: validateString,
@@ -141,7 +141,7 @@ const registryData = [
141
141
  path: "agentFacing.model",
142
142
  tier: "self",
143
143
  description: "Model name for agent-facing interactions.",
144
- default: "claude-opus-4-6",
144
+ default: "claude-opus-5-5",
145
145
  effects: "Changes the specific model used for private agent-facing turns and agent-to-agent communication.",
146
146
  topics: ["model", "provider", "llm", "agent", "inner-lane"],
147
147
  validate: validateString,
@@ -62,6 +62,8 @@ const semver = __importStar(require("semver"));
62
62
  const identity_1 = require("../identity");
63
63
  const runtime_1 = require("../../nerves/runtime");
64
64
  const friends_1 = require("@ouro.bot/friends");
65
+ const friend_merge_1 = require("../../mind/friend-merge");
66
+ const friend_link_codes_1 = require("../../mind/friend-link-codes");
65
67
  const runtime_metadata_1 = require("./runtime-metadata");
66
68
  const runtime_mode_1 = require("./runtime-mode");
67
69
  const platform_1 = require("../platform");
@@ -506,6 +508,9 @@ function agentResolutionFailureMode(command) {
506
508
  case "friend.show":
507
509
  case "friend.create":
508
510
  case "friend.update":
511
+ case "friend.linkCode":
512
+ case "friend.merge":
513
+ case "friend.dedupe":
509
514
  case "habit.list":
510
515
  case "habit.create":
511
516
  case "habit.runs":
@@ -6145,7 +6150,30 @@ async function performSystemSetup(deps) {
6145
6150
  await registerOuroBundleTypeNonBlocking(deps);
6146
6151
  }
6147
6152
  // ── Friend command execution ──
6148
- async function executeFriendCommand(command, store) {
6153
+ async function executeFriendCommand(command, store, paths) {
6154
+ if (command.kind === "friend.linkCode")
6155
+ return executeFriendLinkCode(command, store, paths.agentRoot);
6156
+ if (command.kind === "friend.merge") {
6157
+ const result = await (0, friend_merge_1.mergeFriends)({
6158
+ store,
6159
+ friendsDir: paths.friendsDir,
6160
+ targetId: command.targetId,
6161
+ sourceIds: command.sourceIds,
6162
+ actor: "cli:friend-merge",
6163
+ reason: "owner merged records from the CLI",
6164
+ dryRun: !command.apply,
6165
+ });
6166
+ if (!result.ok)
6167
+ return `error: ${result.message}`;
6168
+ return renderFriendMerge(result.target, result.retired.map((retired) => retired.friendId), result.preservedNoteKeys, result.addedExternalIds, result.dryRun);
6169
+ }
6170
+ if (command.kind === "friend.dedupe") {
6171
+ const result = await (0, friend_merge_1.dedupeFriends)({ store, friendsDir: paths.friendsDir, actor: "cli:friend-dedupe", dryRun: !command.apply });
6172
+ if (result.groups.length === 0)
6173
+ return "no duplicate friend records found";
6174
+ const blocks = result.groups.map((group) => renderFriendMerge(group.canonical, group.duplicateIds, group.preservedNoteKeys, group.addedExternalIds, result.dryRun));
6175
+ return [...blocks, ...(result.dryRun ? ["", "dry run: nothing changed. Re-run with --apply to merge."] : [])].join("\n");
6176
+ }
6149
6177
  if (command.kind === "friend.list") {
6150
6178
  const listAll = store.listAll;
6151
6179
  if (!listAll)
@@ -6229,6 +6257,50 @@ async function executeFriendCommand(command, store) {
6229
6257
  return `identity not linked: ${command.provider}:${command.externalId}`;
6230
6258
  return `unlinked ${command.provider}:${command.externalId} from ${command.friendId}`;
6231
6259
  }
6260
+ function renderFriendMerge(target, retiredIds, preservedNoteKeys, addedExternalIds, dryRun) {
6261
+ const verb = dryRun ? "would merge" : "merged";
6262
+ const lines = [`${verb} ${retiredIds.length} record(s) into ${target.id} (${target.name}, ${target.trustLevel})`];
6263
+ for (const id of retiredIds)
6264
+ lines.push(` ${dryRun ? "would retire" : "retired"} ${id}`);
6265
+ for (const externalId of addedExternalIds)
6266
+ lines.push(` ${dryRun ? "would link" : "linked"} ${externalId.provider}:${externalId.externalId}${externalId.tenantId ? ` (tenant ${externalId.tenantId})` : ""}`);
6267
+ if (preservedNoteKeys.length > 0)
6268
+ lines.push(` kept conflicting notes as: ${preservedNoteKeys.join(", ")}`);
6269
+ return lines.join("\n");
6270
+ }
6271
+ async function executeFriendLinkCode(command, store, agentRoot) {
6272
+ let friend;
6273
+ if (command.friendId) {
6274
+ friend = await store.get(command.friendId);
6275
+ if (!friend || friend.id !== command.friendId)
6276
+ return `friend not found: ${command.friendId}`;
6277
+ }
6278
+ else {
6279
+ // The person at this terminal owns the agent: their family record carries a local identity for this OS user.
6280
+ const owner = (0, friends_1.machineOwnerUsername)();
6281
+ const all = store.listAll ? await store.listAll() : [];
6282
+ const candidates = all.filter((record) => record.trustLevel === "family"
6283
+ && record.externalIds.some((externalId) => (0, friends_1.isLocalMachineOwnerIdentity)(externalId.provider, externalId.externalId, owner)));
6284
+ if (candidates.length === 0)
6285
+ return "error: no family record names this machine's owner. Pass --friend <friend-id>.";
6286
+ if (candidates.length > 1)
6287
+ return `error: ${candidates.length} family records name this machine's owner. Run \`ouro friend dedupe --apply\` first, or pass --friend <friend-id>.`;
6288
+ friend = candidates[0];
6289
+ }
6290
+ const issued = (0, friend_link_codes_1.issueLinkCode)({
6291
+ agentRoot,
6292
+ friend,
6293
+ ...(command.channel ? { channel: command.channel } : {}),
6294
+ ...(command.ttlMinutes ? { ttlMs: command.ttlMinutes * 60 * 1000 } : {}),
6295
+ issuedBy: "cli",
6296
+ });
6297
+ const minutes = Math.round((Date.parse(issued.expiresAt) - Date.now()) / 60000);
6298
+ const where = issued.channel ? `from your ${issued.channel} account` : "from the account you want to link";
6299
+ return [
6300
+ `link code for ${friend.name} (${friend.trustLevel}): ${issued.code}`,
6301
+ `Send exactly this code to ${path.basename(agentRoot, ".ouro")} ${where}, in a 1:1 chat, within ${minutes} minutes. It works once.`,
6302
+ ].join("\n");
6303
+ }
6232
6304
  async function executeA2AClientCommand(command, deps) {
6233
6305
  const { loadOrMintA2AIdentityFile } = await Promise.resolve().then(() => __importStar(require("../../a2a/identity")));
6234
6306
  /* v8 ignore next -- production CLI keeps the client key under the home dir; tests pass an explicit file @preserve */
@@ -8107,19 +8179,16 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
8107
8179
  }
8108
8180
  // ── friend subcommands (local, no daemon socket needed) ──
8109
8181
  if (command.kind === "friend.list" || command.kind === "friend.show" || command.kind === "friend.create" ||
8110
- command.kind === "friend.update" || command.kind === "friend.link" || command.kind === "friend.unlink") {
8111
- /* v8 ignore start -- production default: requires full identity setup @preserve */
8112
- let store = deps.friendStore;
8113
- if (!store) {
8114
- // Derive agent-scoped friends dir from --agent flag or link/unlink's agent field
8115
- const agentName = ("agent" in command && command.agent) ? command.agent : undefined;
8116
- const friendsDir = agentName
8117
- ? path.join(deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(), `${agentName}.ouro`, "friends")
8118
- : path.join(deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)(), "friends");
8119
- store = new friends_1.FileFriendStore(friendsDir);
8120
- }
8121
- /* v8 ignore stop */
8122
- const message = await executeFriendCommand(command, store);
8182
+ command.kind === "friend.update" || command.kind === "friend.link" || command.kind === "friend.unlink" ||
8183
+ command.kind === "friend.linkCode" || command.kind === "friend.merge" || command.kind === "friend.dedupe") {
8184
+ // Derive agent-scoped friends dir from --agent flag or link/unlink's agent field
8185
+ const agentName = ("agent" in command && command.agent) ? command.agent : undefined;
8186
+ const bundlesRoot = deps.bundlesRoot ?? /* v8 ignore next -- production default @preserve */ (0, identity_1.getAgentBundlesRoot)();
8187
+ const agentRoot = agentName ? path.join(bundlesRoot, `${agentName}.ouro`) : bundlesRoot;
8188
+ const friendsDir = path.join(agentRoot, "friends");
8189
+ /* v8 ignore next -- production default: requires full identity setup @preserve */
8190
+ const store = deps.friendStore ?? new friends_1.FileFriendStore(friendsDir);
8191
+ const message = await executeFriendCommand(command, store, { agentRoot, friendsDir });
8123
8192
  deps.writeStdout(message);
8124
8193
  return message;
8125
8194
  }
@@ -240,9 +240,9 @@ exports.COMMAND_REGISTRY = {
240
240
  friend: {
241
241
  category: "Friends",
242
242
  description: "Manage agent friends and identity links",
243
- usage: "ouro friend <subcommand> [--agent <name>]",
244
- example: "ouro friend list",
245
- subcommands: ["list", "show", "create", "update", "link", "unlink"],
243
+ usage: "ouro friend <subcommand> [--agent <name>] (link --channel <channel> issues a one-time code; merge/dedupe preview unless --apply)",
244
+ example: "ouro friend link --agent ouroboros --channel teams",
245
+ subcommands: ["list", "show", "create", "update", "link", "unlink", "merge", "dedupe"],
246
246
  },
247
247
  link: {
248
248
  category: "Friends",
@@ -1631,12 +1631,76 @@ function parseFriendCommand(args) {
1631
1631
  ...(agent ? { agent } : {}),
1632
1632
  };
1633
1633
  }
1634
- if (sub === "link")
1635
- return parseLinkCommand(rest, "friend.link");
1634
+ if (sub === "link") {
1635
+ // Without an explicit identity, `link` issues a code the person sends from the new account.
1636
+ if (!rest.includes("--provider") && !rest.includes("--external-id") && (agent || rest[0]?.startsWith("--"))) {
1637
+ return parseFriendLinkCodeCommand(rest, agent);
1638
+ }
1639
+ return parseLinkCommand(agent ? [agent, ...rest] : rest, "friend.link");
1640
+ }
1636
1641
  if (sub === "unlink")
1637
- return parseLinkCommand(rest, "friend.unlink");
1642
+ return parseLinkCommand(agent ? [agent, ...rest] : rest, "friend.unlink");
1643
+ if (sub === "merge") {
1644
+ const usage = "Usage: ouro friend merge --into <friend-id> <friend-id>... [--agent <name>] [--apply]";
1645
+ let targetId;
1646
+ let apply = false;
1647
+ const sourceIds = [];
1648
+ for (let i = 0; i < rest.length; i += 1) {
1649
+ const token = rest[i];
1650
+ if (token === "--into") {
1651
+ targetId = rest[i + 1];
1652
+ i += 1;
1653
+ }
1654
+ else if (token === "--apply") {
1655
+ apply = true;
1656
+ }
1657
+ else if (token.startsWith("--")) {
1658
+ throw new Error(usage);
1659
+ }
1660
+ else {
1661
+ sourceIds.push(token);
1662
+ }
1663
+ }
1664
+ if (!targetId || sourceIds.length === 0)
1665
+ throw new Error(usage);
1666
+ return { kind: "friend.merge", targetId, sourceIds, apply, ...(agent ? { agent } : {}) };
1667
+ }
1668
+ if (sub === "dedupe") {
1669
+ const usage = "Usage: ouro friend dedupe [--agent <name>] [--apply]";
1670
+ if (rest.some((token) => token !== "--apply"))
1671
+ throw new Error(usage);
1672
+ return { kind: "friend.dedupe", apply: rest.includes("--apply"), ...(agent ? { agent } : {}) };
1673
+ }
1638
1674
  throw new Error(`Usage\n${usage()}`);
1639
1675
  }
1676
+ const FRIEND_LINK_CODE_USAGE = "Usage: ouro friend link --agent <name> [--channel <teams|bluebubbles|telegram|mail|voice|mcp|cli>] [--friend <friend-id>] [--ttl-minutes <n>]";
1677
+ const LINK_CODE_CHANNELS = ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "mcp", "telegram"];
1678
+ function parseFriendLinkCodeCommand(rest, agent) {
1679
+ let friendId;
1680
+ let channel;
1681
+ let ttlMinutes;
1682
+ for (let i = 0; i < rest.length; i += 2) {
1683
+ const token = rest[i];
1684
+ const value = rest[i + 1];
1685
+ if (!value)
1686
+ throw new Error(FRIEND_LINK_CODE_USAGE);
1687
+ if (token === "--friend")
1688
+ friendId = value;
1689
+ else if (token === "--channel" && LINK_CODE_CHANNELS.includes(value))
1690
+ channel = value;
1691
+ else if (token === "--ttl-minutes" && /^[1-9][0-9]*$/.test(value))
1692
+ ttlMinutes = Number(value);
1693
+ else
1694
+ throw new Error(FRIEND_LINK_CODE_USAGE);
1695
+ }
1696
+ return {
1697
+ kind: "friend.linkCode",
1698
+ ...(agent ? { agent } : {}),
1699
+ ...(friendId ? { friendId } : {}),
1700
+ ...(channel ? { channel } : {}),
1701
+ ...(ttlMinutes ? { ttlMinutes } : {}),
1702
+ };
1703
+ }
1640
1704
  function parseA2ACommand(args) {
1641
1705
  const { agent, rest: cleaned } = extractAgentFlag(args);
1642
1706
  const [sub, ...rest] = cleaned;
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.HARNESS_CANONICAL_REPO_URL = exports.DEFAULT_AGENT_SENSES = exports.LEGACY_VAULT_SERVER_URL_ALIASES = exports.DEFAULT_VAULT_SERVER_URL = exports.DEFAULT_AGENT_PHRASES = exports.DEFAULT_AGENT_CONTEXT = exports.PROVIDER_CREDENTIALS = exports.normalizeHabitPaidTurnsPerDay = void 0;
36
+ exports.HARNESS_CANONICAL_REPO_URL = exports.DEFAULT_AGENT_SENSES = exports.LEGACY_VAULT_SERVER_URL_ALIASES = exports.DEFAULT_VAULT_SERVER_URL = exports.DEFAULT_AGENT_PHRASES = exports.DEFAULT_AGENT_CONTEXT = exports.SHEPHERD_NOTICE_POLICIES = exports.PROVIDER_CREDENTIALS = exports.normalizeHabitPaidTurnsPerDay = void 0;
37
37
  exports.normalizeVaultServerUrl = normalizeVaultServerUrl;
38
38
  exports.getVaultServerUrlCandidates = getVaultServerUrlCandidates;
39
39
  exports.defaultStableVaultEmail = defaultStableVaultEmail;
@@ -75,6 +75,7 @@ exports.PROVIDER_CREDENTIALS = {
75
75
  "openai-compatible": { required: ["apiKey", "baseUrl"], envVars: {}, promptLabels: { apiKey: "Z.ai API key", baseUrl: "Z.ai canonical base URL" } },
76
76
  "openai-compatible-gemini": { required: ["apiKey", "baseUrl"], envVars: {}, promptLabels: { apiKey: "Gemini API key", baseUrl: "Gemini canonical base URL" } },
77
77
  };
78
+ exports.SHEPHERD_NOTICE_POLICIES = ["every", "needs-me", "off"];
78
79
  exports.DEFAULT_AGENT_CONTEXT = {
79
80
  maxTokens: 80000,
80
81
  contextMargin: 20,
@@ -215,6 +216,21 @@ function normalizeSenses(value, configFile) {
215
216
  defaults[senseName] = { enabled, hostUsername: hostUsername.trim() };
216
217
  continue;
217
218
  }
219
+ const notify = rawSense.notify;
220
+ if (senseName === "shepherd" && notify !== undefined) {
221
+ if (!exports.SHEPHERD_NOTICE_POLICIES.includes(notify)) {
222
+ (0, runtime_1.emitNervesEvent)({
223
+ level: "error",
224
+ event: "config_identity.error",
225
+ component: "config/identity",
226
+ message: "agent config has invalid Shepherd notice policy",
227
+ meta: { path: configFile, sense: senseName },
228
+ });
229
+ throw new Error(`agent.json at ${configFile}: senses.shepherd.notify must be one of ${exports.SHEPHERD_NOTICE_POLICIES.join(", ")}.`);
230
+ }
231
+ defaults[senseName] = { enabled, notify: notify };
232
+ continue;
233
+ }
218
234
  defaults[senseName] = { enabled };
219
235
  }
220
236
  return defaults;
@@ -223,8 +239,8 @@ function buildDefaultAgentTemplate(_agentName) {
223
239
  return {
224
240
  version: 2,
225
241
  enabled: true,
226
- humanFacing: { provider: "anthropic", model: "claude-opus-4-6" },
227
- agentFacing: { provider: "anthropic", model: "claude-opus-4-6" },
242
+ humanFacing: { provider: "anthropic", model: "claude-opus-5-5" },
243
+ agentFacing: { provider: "anthropic", model: "claude-opus-5-5" },
228
244
  context: { ...exports.DEFAULT_AGENT_CONTEXT },
229
245
  habitPaidTurnsPerDay: autonomy_budget_1.DEFAULT_HABIT_PAID_TURNS_PER_DAY,
230
246
  senses: {
@@ -3,39 +3,95 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MODEL_CAPABILITIES = void 0;
4
4
  exports.getModelCapabilities = getModelCapabilities;
5
5
  const runtime_1 = require("../nerves/runtime");
6
+ // Copilot rows (dot-named ids) mirror GitHub Copilot's /models endpoint as of
7
+ // 2026-10-12. Direct Anthropic rows (dash-named ids) copy their Copilot twins.
6
8
  exports.MODEL_CAPABILITIES = {
7
- "claude-opus-4-6": {
8
- reasoningEffort: ["low", "medium", "high", "max"],
9
+ "claude-opus-5.5": {
10
+ reasoningEffort: ["low", "medium", "high", "xhigh", "max"],
11
+ maxOutputTokens: 128000,
12
+ vision: true,
13
+ },
14
+ "claude-sonnet-5.5": {
15
+ reasoningEffort: ["low", "medium", "high", "xhigh", "max"],
16
+ maxOutputTokens: 128000,
17
+ vision: true,
18
+ },
19
+ "claude-haiku-5.5": {
20
+ reasoningEffort: ["low", "medium", "high", "xhigh", "max"],
21
+ maxOutputTokens: 128000,
22
+ vision: true,
23
+ },
24
+ "claude-opus-5-5": {
25
+ reasoningEffort: ["low", "medium", "high", "xhigh", "max"],
26
+ thinkingFormat: "anthropic",
27
+ maxOutputTokens: 128000,
28
+ vision: true,
29
+ },
30
+ "claude-sonnet-5-5": {
31
+ reasoningEffort: ["low", "medium", "high", "xhigh", "max"],
9
32
  thinkingFormat: "anthropic",
10
33
  maxOutputTokens: 128000,
11
34
  vision: true,
12
35
  },
13
- "claude-sonnet-4-6": {
14
- reasoningEffort: ["low", "medium", "high"],
36
+ "claude-haiku-5-5": {
37
+ reasoningEffort: ["low", "medium", "high", "xhigh", "max"],
15
38
  thinkingFormat: "anthropic",
16
- maxOutputTokens: 64000,
39
+ maxOutputTokens: 128000,
40
+ vision: true,
41
+ },
42
+ "gpt-6.1-sol": {
43
+ reasoningEffort: ["none", "low", "medium", "high", "xhigh", "max"],
44
+ phase: true,
45
+ maxOutputTokens: 128000,
46
+ vision: true,
47
+ },
48
+ "gpt-6-sol": {
49
+ reasoningEffort: ["none", "low", "medium", "high", "xhigh", "max"],
50
+ phase: true,
51
+ maxOutputTokens: 128000,
52
+ vision: true,
53
+ },
54
+ "gpt-6-luna": {
55
+ reasoningEffort: ["none", "low", "medium", "high", "xhigh", "max"],
56
+ phase: true,
57
+ maxOutputTokens: 128000,
58
+ vision: true,
59
+ },
60
+ "gpt-6-astra": {
61
+ reasoningEffort: ["low", "medium", "high", "xhigh", "max"],
62
+ phase: true,
63
+ maxOutputTokens: 128000,
17
64
  vision: true,
18
65
  },
19
- "claude-opus-4.6": {
20
- reasoningEffort: ["low", "medium", "high", "max"],
66
+ "gpt-5.6-sol": {
67
+ reasoningEffort: ["none", "low", "medium", "high", "xhigh", "max"],
68
+ phase: true,
69
+ maxOutputTokens: 128000,
70
+ vision: true,
71
+ },
72
+ "gpt-5.6-sol-fast": {
73
+ reasoningEffort: ["none", "low", "medium", "high", "xhigh", "max"],
74
+ phase: true,
21
75
  maxOutputTokens: 128000,
22
76
  vision: true,
23
77
  },
24
- "claude-sonnet-4.6": {
25
- reasoningEffort: ["low", "medium", "high"],
26
- maxOutputTokens: 64000,
78
+ "gpt-5.6-luna": {
79
+ reasoningEffort: ["none", "low", "medium", "high", "xhigh", "max"],
80
+ phase: true,
81
+ maxOutputTokens: 128000,
27
82
  vision: true,
28
83
  },
29
- "gpt-5.4": {
30
- reasoningEffort: ["low", "medium", "high"],
84
+ "gpt-5.6-terra": {
85
+ reasoningEffort: ["none", "low", "medium", "high", "xhigh", "max"],
31
86
  phase: true,
32
- maxOutputTokens: 100000,
87
+ maxOutputTokens: 128000,
33
88
  vision: true,
34
89
  },
35
- "gpt-5.3-codex": {
36
- reasoningEffort: ["low", "medium", "high"],
90
+ "gpt-5.5": {
91
+ reasoningEffort: ["none", "low", "medium", "high", "xhigh"],
37
92
  phase: true,
38
- maxOutputTokens: 100000,
93
+ maxOutputTokens: 128000,
94
+ vision: true,
39
95
  },
40
96
  "MiniMax-Text-01": {
41
97
  vision: true,
@@ -9,11 +9,11 @@ exports.resolveModelForProviderDisplay = resolveModelForProviderDisplay;
9
9
  exports.getProviderModelMismatchMessage = getProviderModelMismatchMessage;
10
10
  const runtime_1 = require("../nerves/runtime");
11
11
  exports.DEFAULT_PROVIDER_MODELS = {
12
- anthropic: "claude-opus-4-6",
12
+ anthropic: "claude-opus-5-5",
13
13
  azure: "gpt-4o-mini",
14
14
  minimax: "MiniMax-M3",
15
- "openai-codex": "gpt-5.4",
16
- "github-copilot": "claude-sonnet-4.6",
15
+ "openai-codex": "gpt-5.5",
16
+ "github-copilot": "claude-opus-5.5",
17
17
  "openai-compatible": "glm-5.3-flash",
18
18
  "openai-compatible-gemini": "gemini-3.6-flash",
19
19
  };
@@ -63,8 +63,11 @@ function createGithubCopilotProviderRuntime(model, config = (0, config_1.getGith
63
63
  params.model = this.model;
64
64
  if (request.traceId)
65
65
  params.metadata = { trace_id: request.traceId };
66
+ // Copilot's Claude models think adaptively, and thinking only accepts
67
+ // tool_choice "auto" or "none"; "required" fails every turn with a 400.
68
+ // The engine already retries a turn that ends without a tool call.
66
69
  if (request.toolChoiceRequired)
67
- params.tool_choice = "required";
70
+ params.tool_choice = "auto";
68
71
  try {
69
72
  return await (0, streaming_1.streamChatCompletion)(this.client, params, request.callbacks, request.signal, request.eagerSettleStreaming);
70
73
  }