amalgm 0.1.147 → 0.1.148

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amalgm",
3
- "version": "0.1.147",
3
+ "version": "0.1.148",
4
4
  "description": "Amalgm local computer runtime: login, MCP, chat, events, previews, and tunnels.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -32,11 +32,11 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@ai-sdk/gateway": "^3.0.131",
35
- "@anthropic-ai/claude-agent-sdk": "^0.3.177",
35
+ "@anthropic-ai/claude-agent-sdk": "^0.3.206",
36
36
  "@anthropic-ai/sdk": "^0.104.1",
37
37
  "@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
38
38
  "@modelcontextprotocol/sdk": "^1.29.0",
39
- "@openai/codex": "^0.139.0",
39
+ "@openai/codex": "^0.144.1",
40
40
  "@opencode-ai/sdk": "^1.17.6",
41
41
  "agent-browser": "^0.27.3",
42
42
  "ai": "^6.0.205",
@@ -57,7 +57,7 @@ function buildGatewayCliModel(gatewayId, harness) {
57
57
  // lib/modelNaming.ts
58
58
  var DEFAULT_MODEL_IDS = {
59
59
  claude_code: "anthropic/claude-opus-4.8",
60
- codex: "openai/gpt-5.5",
60
+ codex: "openai/gpt-5.6-sol",
61
61
  opencode: "opencode-deepseek-deepseek-v4-pro",
62
62
  pi: "pi-anthropic-claude-sonnet-4.6",
63
63
  amp: "amp-default",
@@ -84,19 +84,21 @@ var CLAUDE_LEGACY_ALIASES = {
84
84
  "claude-code-opus-4-8-1m": CLAUDE_OPUS_4_8_1M_MODEL_ID,
85
85
  "claude-code-opus-4.7-1m": CLAUDE_OPUS_4_8_1M_MODEL_ID,
86
86
  "claude-code-opus-4-7-1m": CLAUDE_OPUS_4_8_1M_MODEL_ID,
87
- "claude-code-sonnet": "anthropic/claude-sonnet-4.6",
88
- "claude-code-sonnet-45": "anthropic/claude-sonnet-4.6",
89
- "claude-code-sonnet-4.6": "anthropic/claude-sonnet-4.6",
90
- "claude-code-sonnet-4-6": "anthropic/claude-sonnet-4.6",
91
- "claude-code-sonnet-4.5": "anthropic/claude-sonnet-4.6",
92
- "claude-code-sonnet-4-5": "anthropic/claude-sonnet-4.6",
87
+ "claude-code-sonnet": "anthropic/claude-sonnet-5",
88
+ "claude-code-sonnet-5": "anthropic/claude-sonnet-5",
89
+ "claude-code-sonnet-45": "anthropic/claude-sonnet-5",
90
+ "claude-code-sonnet-4.6": "anthropic/claude-sonnet-5",
91
+ "claude-code-sonnet-4-6": "anthropic/claude-sonnet-5",
92
+ "claude-code-sonnet-4.5": "anthropic/claude-sonnet-5",
93
+ "claude-code-sonnet-4-5": "anthropic/claude-sonnet-5",
93
94
  "claude-code-haiku": "anthropic/claude-haiku-4.5",
94
95
  "claude-code-haiku-4.5": "anthropic/claude-haiku-4.5",
95
96
  "claude-code-haiku-4-5": "anthropic/claude-haiku-4.5",
96
97
  "anthropic/claude-opus-4.7": "anthropic/claude-opus-4.8",
97
98
  "anthropic/claude-opus-4.6": "anthropic/claude-opus-4.8",
98
99
  "anthropic/claude-opus-4.5": "anthropic/claude-opus-4.8",
99
- "anthropic/claude-sonnet-4.5": "anthropic/claude-sonnet-4.6",
100
+ "anthropic/claude-sonnet-4.6": "anthropic/claude-sonnet-5",
101
+ "anthropic/claude-sonnet-4.5": "anthropic/claude-sonnet-5",
100
102
  "claude-opus-4.8-1m": CLAUDE_OPUS_4_8_1M_MODEL_ID,
101
103
  "claude-opus-4-8-1m": CLAUDE_OPUS_4_8_1M_MODEL_ID,
102
104
  "claude-opus-4.7-1m": CLAUDE_OPUS_4_8_1M_MODEL_ID,
@@ -104,8 +106,9 @@ var CLAUDE_LEGACY_ALIASES = {
104
106
  opus: "anthropic/claude-opus-4.8",
105
107
  opus1m: CLAUDE_OPUS_4_8_1M_MODEL_ID,
106
108
  "opus[1m]": CLAUDE_OPUS_4_8_1M_MODEL_ID,
107
- sonnet: "anthropic/claude-sonnet-4.6",
108
- "sonnet[1m]": "anthropic/claude-sonnet-4.6",
109
+ sonnet: "anthropic/claude-sonnet-5",
110
+ "sonnet[1m]": "anthropic/claude-sonnet-5",
111
+ "sonnet-5": "anthropic/claude-sonnet-5",
109
112
  haiku: "anthropic/claude-haiku-4.5",
110
113
  fable: "anthropic/claude-fable-5",
111
114
  "claude-code-fable": "anthropic/claude-fable-5",
@@ -117,6 +120,7 @@ var CLAUDE_HARNESS_MODELS = {
117
120
  "anthropic/claude-opus-4.7": "opus",
118
121
  "anthropic/claude-opus-4.6": "opus",
119
122
  "anthropic/claude-opus-4.5": "opus",
123
+ "anthropic/claude-sonnet-5": "sonnet",
120
124
  "anthropic/claude-sonnet-4.6": "sonnet",
121
125
  "anthropic/claude-sonnet-4.5": "sonnet",
122
126
  "anthropic/claude-haiku-4.5": "haiku",
@@ -202,8 +206,8 @@ var CURSOR_CLI_ALIASES = {
202
206
  "composer-2": "composer-2.5",
203
207
  "composer-2-fast": "composer-2.5-fast"
204
208
  };
205
- var CODEX_THINKING_SUFFIX_RE = /:thinking-(low|medium|high|xhigh)$/i;
206
- var CODEX_LEGACY_THINKING_SUFFIX_RE = /-thinking-(low|medium|high|xhigh)$/i;
209
+ var CODEX_THINKING_SUFFIX_RE = /:thinking-(low|medium|high|xhigh|max|ultra)$/i;
210
+ var CODEX_LEGACY_THINKING_SUFFIX_RE = /-thinking-(low|medium|high|xhigh|max|ultra)$/i;
207
211
  function cleanModelId(value) {
208
212
  return value.trim().replace(/^vercel\//i, "").toLowerCase();
209
213
  }
@@ -214,7 +218,8 @@ function normalizeClaudeModelPart(modelPart) {
214
218
  "claude-opus-4.7": "claude-opus-4.8",
215
219
  "claude-opus-4.6": "claude-opus-4.8",
216
220
  "claude-opus-4.5": "claude-opus-4.8",
217
- "claude-sonnet-4.5": "claude-sonnet-4.6"
221
+ "claude-sonnet-4.6": "claude-sonnet-5",
222
+ "claude-sonnet-4.5": "claude-sonnet-5"
218
223
  }[base] ?? base;
219
224
  return hasOneMillionContext && currentBase === "claude-opus-4.8" ? `${currentBase}-1m` : currentBase;
220
225
  }
@@ -244,7 +249,7 @@ function codexGatewayModelId(modelId) {
244
249
  }
245
250
  function codexHarnessModelId(modelId, effort) {
246
251
  const baseModel = codexGatewayModelId(modelId).replace(/^openai\//, "");
247
- if (effort && /^gpt-5\.[45](?:-mini)?$/i.test(baseModel)) {
252
+ if (effort && /^gpt-5\.(?:[45](?:-mini)?|6-(?:sol|terra|luna))$/i.test(baseModel)) {
248
253
  return `${baseModel}/${effort}`;
249
254
  }
250
255
  return baseModel;
@@ -252,7 +257,7 @@ function codexHarnessModelId(modelId, effort) {
252
257
  function normalizeCodexModelSelection(value) {
253
258
  const cleaned = cleanModelId(value);
254
259
  const legacyThinkingMatch = cleaned.match(
255
- /^(codex-[a-z0-9.-]+(?:-[a-z0-9.-]+)*)-thinking-(low|medium|high|xhigh)$/i
260
+ /^(codex-[a-z0-9.-]+(?:-[a-z0-9.-]+)*)-thinking-(low|medium|high|xhigh|max|ultra)$/i
256
261
  );
257
262
  if (legacyThinkingMatch) {
258
263
  const effort = legacyThinkingMatch[2].toLowerCase();
@@ -262,7 +267,7 @@ function normalizeCodexModelSelection(value) {
262
267
  };
263
268
  }
264
269
  const canonicalThinkingMatch = cleaned.match(
265
- /^((?:openai\/)?(?:gpt|o)[a-z0-9.-]+(?:-[a-z0-9.-]+)*)(?::thinking-|-thinking-)(low|medium|high|xhigh)$/i
270
+ /^((?:openai\/)?(?:gpt|o)[a-z0-9.-]+(?:-[a-z0-9.-]+)*)(?::thinking-|-thinking-)(low|medium|high|xhigh|max|ultra)$/i
266
271
  );
267
272
  if (canonicalThinkingMatch) {
268
273
  const effort = canonicalThinkingMatch[2].toLowerCase();
@@ -272,7 +277,7 @@ function normalizeCodexModelSelection(value) {
272
277
  };
273
278
  }
274
279
  const slashThinkingMatch = cleaned.match(
275
- /^((?:openai\/)?(?:gpt|o)[a-z0-9.-]+(?:-[a-z0-9.-]+)*)\/(low|medium|high|xhigh)$/i
280
+ /^((?:openai\/)?(?:gpt|o)[a-z0-9.-]+(?:-[a-z0-9.-]+)*)\/(low|medium|high|xhigh|max|ultra)$/i
276
281
  );
277
282
  if (slashThinkingMatch) {
278
283
  const effort = slashThinkingMatch[2].toLowerCase();
@@ -495,11 +500,11 @@ var CLAUDE_MODELS = [
495
500
  providerGroup: "anthropic"
496
501
  },
497
502
  {
498
- id: "anthropic/claude-sonnet-4.6",
499
- name: "Sonnet 4.6",
503
+ id: "anthropic/claude-sonnet-5",
504
+ name: "Sonnet 5",
500
505
  description: "Balanced Claude Code model",
501
- gatewayModelId: "anthropic/claude-sonnet-4.6",
502
- cliModel: modelIdToHarnessModel("anthropic/claude-sonnet-4.6", "claude_code"),
506
+ gatewayModelId: "anthropic/claude-sonnet-5",
507
+ cliModel: modelIdToHarnessModel("anthropic/claude-sonnet-5", "claude_code"),
503
508
  provider: "claude",
504
509
  providerGroup: "anthropic"
505
510
  },
@@ -747,7 +752,7 @@ var CURSOR_MODELS = CURSOR_MODEL_ROWS.map(
747
752
  };
748
753
  }
749
754
  );
750
- function codexModel(id, name, description, reasoningEffort, gatewayModelId = id.replace(/(?::thinking-|-thinking-)(low|medium|high|xhigh)$/i, ""), providerGroup = id.includes("gpt-5.5") ? "gpt-5.5" : "gpt-5.4") {
755
+ function codexModel(id, name, description, reasoningEffort, gatewayModelId = id.replace(/(?::thinking-|-thinking-)(low|medium|high|xhigh|max|ultra)$/i, ""), providerGroup = id.includes("gpt-5.6") ? "gpt-5.6" : id.includes("gpt-5.5") ? "gpt-5.5" : "gpt-5.4") {
751
756
  return {
752
757
  id,
753
758
  name,
@@ -760,6 +765,21 @@ function codexModel(id, name, description, reasoningEffort, gatewayModelId = id.
760
765
  };
761
766
  }
762
767
  var CODEX_MODELS = [
768
+ codexModel(
769
+ "openai/gpt-5.6-sol",
770
+ "GPT-5.6 Sol",
771
+ "Flagship GPT-5.6 tier for complex coding and agentic work"
772
+ ),
773
+ codexModel(
774
+ "openai/gpt-5.6-terra",
775
+ "GPT-5.6 Terra",
776
+ "Balanced GPT-5.6 tier for everyday work"
777
+ ),
778
+ codexModel(
779
+ "openai/gpt-5.6-luna",
780
+ "GPT-5.6 Luna",
781
+ "Fastest, lowest-cost GPT-5.6 tier"
782
+ ),
763
783
  codexModel(
764
784
  "openai/gpt-5.5",
765
785
  "GPT-5.5",
@@ -184,6 +184,7 @@ function normalizeEffort(value) {
184
184
  if (normalized === 'high') return 'high';
185
185
  if (normalized === 'xhigh' || normalized === 'extra-high' || normalized === 'extra high') return 'xhigh';
186
186
  if (normalized === 'max') return 'max';
187
+ if (normalized === 'ultra') return 'ultra';
187
188
  return null;
188
189
  }
189
190
 
@@ -195,11 +196,11 @@ function normalizeModelSettings(value, fallback = null, harnessId = null) {
195
196
  harnessId === 'claude_code'
196
197
  ? new Set(['low', 'medium', 'high', 'xhigh', 'max'])
197
198
  : harnessId === 'codex'
198
- ? new Set(['low', 'medium', 'high', 'xhigh'])
199
+ ? new Set(['low', 'medium', 'high', 'xhigh', 'max', 'ultra'])
199
200
  : null;
200
201
  const normalized = {
201
202
  ...(effort && (!allowedEfforts || allowedEfforts.has(effort)) ? { effort } : {}),
202
- ...((harnessId === 'claude_code' || harnessId === 'codex' || !harnessId)
203
+ ...((harnessId === 'codex' || !harnessId)
203
204
  && (raw.fastMode === true || raw.speed === 'fast')
204
205
  ? { fastMode: true }
205
206
  : {}),
@@ -361,6 +361,7 @@ function normalizeEffort(value) {
361
361
  if (normalized === 'high') return 'high';
362
362
  if (normalized === 'xhigh' || normalized === 'extra-high' || normalized === 'extra high') return 'xhigh';
363
363
  if (normalized === 'max') return 'max';
364
+ if (normalized === 'ultra') return 'ultra';
364
365
  return null;
365
366
  }
366
367
 
@@ -371,19 +372,19 @@ function sanitizeAgentModelSettings(settings, harness) {
371
372
  harness === 'claude_code'
372
373
  ? new Set(['low', 'medium', 'high', 'xhigh', 'max'])
373
374
  : harness === 'codex'
374
- ? new Set(['low', 'medium', 'high', 'xhigh'])
375
+ ? new Set(['low', 'medium', 'high', 'xhigh', 'max', 'ultra'])
375
376
  : new Set();
376
377
  return {
377
378
  ...(effort && allowedEfforts.has(effort) ? { effort } : {}),
378
- ...((harness === 'claude_code' || harness === 'codex') && settings.fastMode === true ? { fastMode: true } : {}),
379
+ ...(harness === 'codex' && settings.fastMode === true ? { fastMode: true } : {}),
379
380
  };
380
381
  }
381
382
 
382
383
  function modelIdForAgentSettings(modelId, harness, modelSettings) {
383
384
  if (harness !== 'codex' || !modelSettings.effort || typeof modelId !== 'string') return modelId;
384
385
  return modelId
385
- .replace(/(?::thinking-|-thinking-)(low|medium|high|xhigh)$/i, '')
386
- .replace(/\/(low|medium|high|xhigh)$/i, '') + '/' + modelSettings.effort;
386
+ .replace(/(?::thinking-|-thinking-)(low|medium|high|xhigh|max|ultra)$/i, '')
387
+ .replace(/\/(low|medium|high|xhigh|max|ultra)$/i, '') + '/' + modelSettings.effort;
387
388
  }
388
389
 
389
390
  async function appendAsyncCompletionToCallerSession({
@@ -15,7 +15,7 @@ const {
15
15
 
16
16
  const DEFAULT_SELECTED_MODELS = {
17
17
  claude_code: 'anthropic/claude-opus-4.8',
18
- codex: 'openai/gpt-5.5',
18
+ codex: 'openai/gpt-5.6-sol',
19
19
  opencode: 'opencode-deepseek-deepseek-v4-pro',
20
20
  pi: 'pi-anthropic-claude-sonnet-4.6',
21
21
  amp: 'amp-default',
@@ -70,19 +70,21 @@ const CLAUDE_LEGACY_ALIASES = {
70
70
  'claude-code-opus-4-8-1m': CLAUDE_OPUS_4_8_1M_MODEL_ID,
71
71
  'claude-code-opus-4.7-1m': CLAUDE_OPUS_4_8_1M_MODEL_ID,
72
72
  'claude-code-opus-4-7-1m': CLAUDE_OPUS_4_8_1M_MODEL_ID,
73
- 'claude-code-sonnet': 'anthropic/claude-sonnet-4.6',
74
- 'claude-code-sonnet-45': 'anthropic/claude-sonnet-4.6',
75
- 'claude-code-sonnet-4.6': 'anthropic/claude-sonnet-4.6',
76
- 'claude-code-sonnet-4-6': 'anthropic/claude-sonnet-4.6',
77
- 'claude-code-sonnet-4.5': 'anthropic/claude-sonnet-4.6',
78
- 'claude-code-sonnet-4-5': 'anthropic/claude-sonnet-4.6',
73
+ 'claude-code-sonnet': 'anthropic/claude-sonnet-5',
74
+ 'claude-code-sonnet-5': 'anthropic/claude-sonnet-5',
75
+ 'claude-code-sonnet-45': 'anthropic/claude-sonnet-5',
76
+ 'claude-code-sonnet-4.6': 'anthropic/claude-sonnet-5',
77
+ 'claude-code-sonnet-4-6': 'anthropic/claude-sonnet-5',
78
+ 'claude-code-sonnet-4.5': 'anthropic/claude-sonnet-5',
79
+ 'claude-code-sonnet-4-5': 'anthropic/claude-sonnet-5',
79
80
  'claude-code-haiku': 'anthropic/claude-haiku-4.5',
80
81
  'claude-code-haiku-4.5': 'anthropic/claude-haiku-4.5',
81
82
  'claude-code-haiku-4-5': 'anthropic/claude-haiku-4.5',
82
83
  'anthropic/claude-opus-4.7': 'anthropic/claude-opus-4.8',
83
84
  'anthropic/claude-opus-4.6': 'anthropic/claude-opus-4.8',
84
85
  'anthropic/claude-opus-4.5': 'anthropic/claude-opus-4.8',
85
- 'anthropic/claude-sonnet-4.5': 'anthropic/claude-sonnet-4.6',
86
+ 'anthropic/claude-sonnet-4.6': 'anthropic/claude-sonnet-5',
87
+ 'anthropic/claude-sonnet-4.5': 'anthropic/claude-sonnet-5',
86
88
  'claude-opus-4.8-1m': CLAUDE_OPUS_4_8_1M_MODEL_ID,
87
89
  'claude-opus-4-8-1m': CLAUDE_OPUS_4_8_1M_MODEL_ID,
88
90
  'claude-opus-4.7-1m': CLAUDE_OPUS_4_8_1M_MODEL_ID,
@@ -90,8 +92,9 @@ const CLAUDE_LEGACY_ALIASES = {
90
92
  opus: 'anthropic/claude-opus-4.8',
91
93
  opus1m: CLAUDE_OPUS_4_8_1M_MODEL_ID,
92
94
  'opus[1m]': CLAUDE_OPUS_4_8_1M_MODEL_ID,
93
- sonnet: 'anthropic/claude-sonnet-4.6',
94
- 'sonnet[1m]': 'anthropic/claude-sonnet-4.6',
95
+ sonnet: 'anthropic/claude-sonnet-5',
96
+ 'sonnet[1m]': 'anthropic/claude-sonnet-5',
97
+ 'sonnet-5': 'anthropic/claude-sonnet-5',
95
98
  haiku: 'anthropic/claude-haiku-4.5',
96
99
  fable: 'anthropic/claude-fable-5',
97
100
  'claude-code-fable': 'anthropic/claude-fable-5',
@@ -104,14 +107,15 @@ const CLAUDE_HARNESS_MODELS = {
104
107
  'anthropic/claude-opus-4.7': 'opus',
105
108
  'anthropic/claude-opus-4.6': 'opus',
106
109
  'anthropic/claude-opus-4.5': 'opus',
110
+ 'anthropic/claude-sonnet-5': 'sonnet',
107
111
  'anthropic/claude-sonnet-4.6': 'sonnet',
108
112
  'anthropic/claude-sonnet-4.5': 'sonnet',
109
113
  'anthropic/claude-haiku-4.5': 'haiku',
110
114
  'anthropic/claude-fable-5': 'claude-fable-5',
111
115
  };
112
116
 
113
- const CODEX_THINKING_SUFFIX_RE = /:thinking-(low|medium|high|xhigh)$/i;
114
- const CODEX_LEGACY_THINKING_SUFFIX_RE = /-thinking-(low|medium|high|xhigh)$/i;
117
+ const CODEX_THINKING_SUFFIX_RE = /:thinking-(low|medium|high|xhigh|max|ultra)$/i;
118
+ const CODEX_LEGACY_THINKING_SUFFIX_RE = /-thinking-(low|medium|high|xhigh|max|ultra)$/i;
115
119
 
116
120
  const CURSOR_MODEL_ALIASES = {
117
121
  'cursor-opus-4.6-thinking': 'anthropic/claude-opus-4.6-high-thinking',
@@ -178,7 +182,8 @@ function normalizeClaudeModelPart(modelPart) {
178
182
  'claude-opus-4.7': 'claude-opus-4.8',
179
183
  'claude-opus-4.6': 'claude-opus-4.8',
180
184
  'claude-opus-4.5': 'claude-opus-4.8',
181
- 'claude-sonnet-4.5': 'claude-sonnet-4.6',
185
+ 'claude-sonnet-4.6': 'claude-sonnet-5',
186
+ 'claude-sonnet-4.5': 'claude-sonnet-5',
182
187
  }[base] || base;
183
188
  return hasOneMillionContext && currentBase === 'claude-opus-4.8'
184
189
  ? currentBase + '-1m'
@@ -215,7 +220,7 @@ function codexGatewayModelId(modelId) {
215
220
 
216
221
  function codexHarnessModelId(modelId, effort) {
217
222
  const baseModel = codexGatewayModelId(modelId).replace(/^openai\//, '');
218
- if (effort && /^gpt-5\.[45](?:-mini)?$/i.test(baseModel)) {
223
+ if (effort && /^gpt-5\.(?:[45](?:-mini)?|6-(?:sol|terra|luna))$/i.test(baseModel)) {
219
224
  return `${baseModel}/${effort}`;
220
225
  }
221
226
  return baseModel;
@@ -285,7 +290,7 @@ function normalizeModelSelection(harnessId, modelId) {
285
290
  }
286
291
 
287
292
  if (harnessId === 'codex') {
288
- const legacyThinkingMatch = cleaned.match(/^(codex-[a-z0-9.-]+(?:-[a-z0-9.-]+)*)-thinking-(low|medium|high|xhigh)$/i);
293
+ const legacyThinkingMatch = cleaned.match(/^(codex-[a-z0-9.-]+(?:-[a-z0-9.-]+)*)-thinking-(low|medium|high|xhigh|max|ultra)$/i);
289
294
  if (legacyThinkingMatch) {
290
295
  const effort = legacyThinkingMatch[2].toLowerCase();
291
296
  return {
@@ -293,7 +298,7 @@ function normalizeModelSelection(harnessId, modelId) {
293
298
  reasoningEffort: effort,
294
299
  };
295
300
  }
296
- const canonicalThinkingMatch = cleaned.match(/^((?:openai\/)?(?:gpt|o)[a-z0-9.-]+(?:-[a-z0-9.-]+)*)(?::thinking-|-thinking-)(low|medium|high|xhigh)$/i);
301
+ const canonicalThinkingMatch = cleaned.match(/^((?:openai\/)?(?:gpt|o)[a-z0-9.-]+(?:-[a-z0-9.-]+)*)(?::thinking-|-thinking-)(low|medium|high|xhigh|max|ultra)$/i);
297
302
  if (canonicalThinkingMatch) {
298
303
  const effort = canonicalThinkingMatch[2].toLowerCase();
299
304
  return {
@@ -301,7 +306,7 @@ function normalizeModelSelection(harnessId, modelId) {
301
306
  reasoningEffort: effort,
302
307
  };
303
308
  }
304
- const slashThinkingMatch = cleaned.match(/^((?:openai\/)?(?:gpt|o)[a-z0-9.-]+(?:-[a-z0-9.-]+)*)\/(low|medium|high|xhigh)$/i);
309
+ const slashThinkingMatch = cleaned.match(/^((?:openai\/)?(?:gpt|o)[a-z0-9.-]+(?:-[a-z0-9.-]+)*)\/(low|medium|high|xhigh|max|ultra)$/i);
305
310
  if (slashThinkingMatch) {
306
311
  const effort = slashThinkingMatch[2].toLowerCase();
307
312
  return {
@@ -369,6 +374,8 @@ function normalizeReasoningEffort(value) {
369
374
  if (normalized === 'xhigh' || normalized === 'extra-high' || normalized === 'extra high') {
370
375
  return 'xhigh';
371
376
  }
377
+ if (normalized === 'max') return 'max';
378
+ if (normalized === 'ultra') return 'ultra';
372
379
  return null;
373
380
  }
374
381
 
@@ -59,6 +59,7 @@ function normalizeEffort(value) {
59
59
  if (normalized === 'high') return 'high';
60
60
  if (normalized === 'xhigh' || normalized === 'extra-high' || normalized === 'extra high') return 'xhigh';
61
61
  if (normalized === 'max') return 'max';
62
+ if (normalized === 'ultra') return 'ultra';
62
63
  return null;
63
64
  }
64
65
 
@@ -69,19 +70,19 @@ function sanitizeRunModelSettings(settings, harness) {
69
70
  harness === 'claude_code'
70
71
  ? new Set(['low', 'medium', 'high', 'xhigh', 'max'])
71
72
  : harness === 'codex'
72
- ? new Set(['low', 'medium', 'high', 'xhigh'])
73
+ ? new Set(['low', 'medium', 'high', 'xhigh', 'max', 'ultra'])
73
74
  : new Set();
74
75
  return {
75
76
  ...(effort && allowedEfforts.has(effort) ? { effort } : {}),
76
- ...((harness === 'claude_code' || harness === 'codex') && settings.fastMode === true ? { fastMode: true } : {}),
77
+ ...(harness === 'codex' && settings.fastMode === true ? { fastMode: true } : {}),
77
78
  };
78
79
  }
79
80
 
80
81
  function modelIdForSettings(modelId, harness, modelSettings) {
81
82
  if (harness !== 'codex' || !modelSettings.effort || typeof modelId !== 'string') return modelId;
82
83
  return modelId
83
- .replace(/(?::thinking-|-thinking-)(low|medium|high|xhigh)$/i, '')
84
- .replace(/\/(low|medium|high|xhigh)$/i, '');
84
+ .replace(/(?::thinking-|-thinking-)(low|medium|high|xhigh|max|ultra)$/i, '')
85
+ .replace(/\/(low|medium|high|xhigh|max|ultra)$/i, '');
85
86
  }
86
87
 
87
88
  function disableTerminalScheduleIfNeeded(task) {
@@ -37,7 +37,6 @@ class ClaudeAdapter {
37
37
  const pathToClaudeCodeExecutable = process.env.CLAUDE_CODE_BINARY || bundledClaudeBinary();
38
38
  const settings = {
39
39
  ...toClaudeSettings(contract.agentConfig),
40
- ...(contract.fastMode ? { fastMode: true, fastModePerSessionOptIn: true } : {}),
41
40
  };
42
41
  return {
43
42
  cwd: contract.cwd,
@@ -552,7 +552,7 @@ class CodexAdapter {
552
552
  threadId: session.providerSessionId,
553
553
  input: [{ type: 'text', text: prompt }],
554
554
  cwd: contract.cwd,
555
- model: contract.cliModel.replace(/\/(?:low|medium|high|xhigh)$/i, ''),
555
+ model: contract.cliModel.replace(/\/(?:low|medium|high|xhigh|max|ultra)$/i, ''),
556
556
  effort: contract.reasoningEffort || undefined,
557
557
  serviceTier: serviceTierForContract(contract),
558
558
  approvalPolicy: 'never',
@@ -263,6 +263,7 @@ function cliModelFor({ harness, modelId, cliModel, reasoningEffort }) {
263
263
  const canonical = canonicalModel(clean, harness);
264
264
  const aliases = {
265
265
  'anthropic/claude-haiku-4.5': 'haiku',
266
+ 'anthropic/claude-sonnet-5': 'sonnet',
266
267
  'anthropic/claude-sonnet-4.6': 'sonnet',
267
268
  'anthropic/claude-opus-4.8': 'opus',
268
269
  'anthropic/claude-opus-4.8-1m': 'opus[1m]',
@@ -271,6 +272,8 @@ function cliModelFor({ harness, modelId, cliModel, reasoningEffort }) {
271
272
  'anthropic/claude-fable-5': 'claude-fable-5',
272
273
  'haiku': 'haiku',
273
274
  'sonnet': 'sonnet',
275
+ 'sonnet-5': 'sonnet',
276
+ 'claude-sonnet-5': 'sonnet',
274
277
  'opus': 'opus',
275
278
  'opus1m': 'opus[1m]',
276
279
  'opus[1m]': 'opus[1m]',
@@ -284,12 +287,12 @@ function cliModelFor({ harness, modelId, cliModel, reasoningEffort }) {
284
287
  if (harness === 'codex') {
285
288
  let base = clean.replace(/^openai\//, '');
286
289
  let effort = reasoningEffort;
287
- const slashEffort = base.match(/\/(low|medium|high|xhigh)$/i);
290
+ const slashEffort = base.match(/\/(low|medium|high|xhigh|max|ultra)$/i);
288
291
  if (slashEffort) {
289
292
  effort ||= slashEffort[1].toLowerCase();
290
293
  base = base.slice(0, -slashEffort[0].length);
291
294
  }
292
- const thinkingEffort = base.match(/-thinking-(low|medium|high|xhigh)$/i);
295
+ const thinkingEffort = base.match(/-thinking-(low|medium|high|xhigh|max|ultra)$/i);
293
296
  if (!cliModel && thinkingEffort) {
294
297
  effort ||= thinkingEffort[1].toLowerCase();
295
298
  base = base.slice(0, -thinkingEffort[0].length);
@@ -55,6 +55,7 @@ const MODEL_CATALOG = [
55
55
  { id: "anthropic/claude-sonnet-4", name: "Claude Sonnet 4", provider: "anthropic", contextWindow: 1000000, maxOutput: 64000, inputPrice: 3, outputPrice: 15, cacheRead: 0.3, cacheWrite: 3.75, tags: ["file-input", "reasoning", "tool-use", "vision", "explicit-caching"], released: "2025-05-22" },
56
56
  { id: "anthropic/claude-sonnet-4.5", name: "Claude Sonnet 4.5", provider: "anthropic", contextWindow: 1000000, maxOutput: 64000, inputPrice: 3, outputPrice: 15, cacheRead: 0.3, cacheWrite: 3.75, tags: ["file-input", "reasoning", "tool-use", "vision", "explicit-caching"], released: "2025-09-29" },
57
57
  { id: "anthropic/claude-sonnet-4.6", name: "Claude Sonnet 4.6", provider: "anthropic", contextWindow: 1000000, maxOutput: 128000, inputPrice: 3, outputPrice: 15, cacheRead: 0.3, cacheWrite: 3.75, tags: ["file-input", "reasoning", "tool-use", "vision", "explicit-caching", "web-search"], released: "2026-02-17" },
58
+ { id: "anthropic/claude-sonnet-5", name: "Claude Sonnet 5", provider: "anthropic", contextWindow: 1000000, maxOutput: 128000, inputPrice: 3, outputPrice: 15, cacheRead: 0.3, cacheWrite: 3.75, tags: ["file-input", "reasoning", "tool-use", "vision", "explicit-caching", "web-search"], released: "2026-06-30" },
58
59
  // ── arcee-ai (3) ──────────────────────────────────────────
59
60
  { id: "arcee-ai/trinity-large-preview", name: "Trinity Large Preview", provider: "arcee-ai", contextWindow: 131000, maxOutput: 131000, inputPrice: 0.25, outputPrice: 1, cacheRead: null, cacheWrite: null, tags: ["tool-use"], released: "2025-01-01" },
60
61
  { id: "arcee-ai/trinity-large-thinking", name: "Trinity Large Thinking", provider: "arcee-ai", contextWindow: 262100, maxOutput: 80000, inputPrice: 0.25, outputPrice: 0.9, cacheRead: null, cacheWrite: null, tags: ["reasoning", "tool-use", "implicit-caching"], released: "2026-04-01" },
@@ -182,6 +183,9 @@ const MODEL_CATALOG = [
182
183
  { id: "openai/gpt-5.4-pro", name: "GPT 5.4 Pro", provider: "openai", contextWindow: 1050000, maxOutput: 128000, inputPrice: 30, outputPrice: 180, cacheRead: null, cacheWrite: null, tags: ["reasoning", "tool-use", "vision", "file-input", "implicit-caching", "web-search"], released: "2026-03-05" },
183
184
  { id: "openai/gpt-5.5", name: "GPT 5.5", provider: "openai", contextWindow: 1000000, maxOutput: 128000, inputPrice: 5, outputPrice: 30, cacheRead: 0.5, cacheWrite: null, tags: ["reasoning", "tool-use", "web-search", "implicit-caching", "file-input", "vision"], released: "2026-04-24" },
184
185
  { id: "openai/gpt-5.5-pro", name: "GPT 5.5 Pro", provider: "openai", contextWindow: 1000000, maxOutput: 128000, inputPrice: 30, outputPrice: 180, cacheRead: null, cacheWrite: null, tags: ["reasoning", "tool-use", "implicit-caching", "file-input", "web-search", "vision"], released: "2026-04-24" },
186
+ { id: "openai/gpt-5.6-sol", name: "GPT 5.6 Sol", provider: "openai", contextWindow: 1050000, maxOutput: 128000, inputPrice: 5, outputPrice: 30, cacheRead: 0.5, cacheWrite: 6.25, tags: ["reasoning", "tool-use", "web-search", "implicit-caching", "file-input", "vision"], released: "2026-06-26" },
187
+ { id: "openai/gpt-5.6-terra", name: "GPT 5.6 Terra", provider: "openai", contextWindow: 1050000, maxOutput: 128000, inputPrice: 2.5, outputPrice: 15, cacheRead: 0.25, cacheWrite: 3.125, tags: ["reasoning", "tool-use", "web-search", "implicit-caching", "file-input", "vision"], released: "2026-06-26" },
188
+ { id: "openai/gpt-5.6-luna", name: "GPT 5.6 Luna", provider: "openai", contextWindow: 1050000, maxOutput: 128000, inputPrice: 1, outputPrice: 6, cacheRead: 0.1, cacheWrite: 1.25, tags: ["reasoning", "tool-use", "web-search", "implicit-caching", "file-input", "vision"], released: "2026-06-26" },
185
189
  { id: "openai/gpt-oss-120b", name: "GPT OSS 120B", provider: "openai", contextWindow: 131072, maxOutput: 131000, inputPrice: 0.35, outputPrice: 0.75, cacheRead: 0.25, cacheWrite: null, tags: ["implicit-caching"], released: "2025-08-05" },
186
190
  { id: "openai/gpt-oss-20b", name: "GPT OSS 120B", provider: "openai", contextWindow: 131072, maxOutput: 8192, inputPrice: 0.05, outputPrice: 0.2, cacheRead: null, cacheWrite: null, tags: ["reasoning", "tool-use"], released: "2025-08-05" },
187
191
  { id: "openai/gpt-oss-safeguard-20b", name: "GPT OSS Safeguard 20B", provider: "openai", contextWindow: 131072, maxOutput: 65536, inputPrice: 0.075, outputPrice: 0.3, cacheRead: 0.037, cacheWrite: null, tags: ["reasoning", "tool-use"], released: "2024-12-01" },
@@ -95,7 +95,7 @@ If the user wants a public, highly shared, or hyperscaler-hosted service, think
95
95
 
96
96
  ## Primitive 3: Notifications — Keep the User Informed
97
97
 
98
- - `notify_user` — Send an email notification to the user (from concierge@amalgm.ai). Supports `level` (info, warning, error, success) and an optional `link`.
98
+ - `notify_user` — Send an email notification to the user (from emails@amalgm.ai). Supports `level` (info, warning, error, success) and an optional `link`.
99
99
 
100
100
  **When to use notifications:**
101
101
  - **Usually** at the end of automation runs when the result matters to the user.
@@ -178,7 +178,7 @@ Do not force scaffolding, wrappers, or opinionated project layouts unless the us
178
178
 
179
179
  ## Tile Entity References
180
180
 
181
- When you mention a chat session, automation, app, or preview that exists on the platform, render it as an inline tile using markdown link syntax. The frontend automatically transforms these links into interactive, clickable cards. Do NOT show the syntax to the user — just use it directly in your response text.
181
+ When you mention a chat session, automation, app, or preview that exists on the platform, render it as a tile using markdown link syntax. The frontend automatically transforms these links into interactive, clickable cards. Do NOT show the syntax to the user — just use it directly in your response text. Tiles and expanded references are block-level: they take up the whole line, so put each one on its own line rather than mid-sentence. The compact tile is the DEFAULT for entity references; only switch to the expanded form (next section) when a full in-chat preview is worth the space.
182
182
 
183
183
  Tile format: [label](tile:TYPE:ID)
184
184
 
@@ -188,15 +188,19 @@ Types:
188
188
  - App: [label](tile:app:APP_ID)
189
189
  - Preview: [label](tile:preview:PORT)
190
190
 
191
- IMPORTANT: Never wrap these in backticks or code blocks. Never explain the syntax to the user. Just emit the markdown link naturally in your prose. The UI handles the rest — the user sees a rich card, not a raw link.
191
+ IMPORTANT: Never wrap these in backticks or code blocks. Never explain the syntax to the user. Just emit the markdown link on its own line. The UI handles the rest — the user sees a rich card, not a raw link.
192
192
 
193
- Example response (what you output): "Here's the automation I set up for you: [API Health Monitor](tile:automation:abc123). It runs every hour and will notify you if anything breaks."
193
+ Example response (what you output):
194
+
195
+ "Here's the automation I set up for you:
196
+ [API Health Monitor](tile:automation:abc123)
197
+ It runs every hour and will notify you if anything breaks."
194
198
 
195
199
  The user sees "API Health Monitor" as a clickable card — not a link.
196
200
 
197
201
  ## Expanded Entity References
198
202
 
199
- When a full in-chat preview is useful, render the entity with the expanded form. Expanded references use the message width, have a capped height, and include top-right actions for opening the entity in a tab.
203
+ When a full in-chat preview is useful, render the entity with the expanded form. Expanded references use the message width, have a capped height, and include top-right actions for opening the entity in a tab. Use this sparingly — for the one entity the response is actually about; everything else stays a compact tile.
200
204
 
201
205
  Expanded format: [label](full:TYPE:ID)
202
206
 
@@ -221,7 +225,7 @@ Rules:
221
225
 
222
226
  ## Citing Files, Folders, Skills, and Agents
223
227
 
224
- When you reference a file, folder, skill, or agent that exists on the user's local volume, emit it as an `amalgm://` markdown link. The frontend renders these as inline citation chips by default, with a hover card showing the path and (for skills) description. Skills are files too: if you only have the `SKILL.md` path, a normal file citation is valid. This is the same format the user's `@`-menu produces, and it's how agents talk to each other about local resources.
228
+ When you reference a file, folder, skill, or agent that exists on the user's local volume, emit it as an `amalgm://` markdown link. The frontend renders these as inline citation chips by default, with a hover card showing the path and (for skills) description. Citations are for *referring to* a resource mid-sentence; to *show* a file's content (a screenshot, clip, or document preview), use the embed syntax from the previous section (`![label](...)` on its own line) instead. Skills are files too: if you only have the `SKILL.md` path, a normal file citation is valid. This is the same format the user's `@`-menu produces, and it's how agents talk to each other about local resources.
225
229
 
226
230
  Render format: `[label](amalgm://KIND/ENCODED_PATH_OR_ID)`
227
231