loom-agent 1.5.0 → 1.6.0

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.md CHANGED
@@ -4,7 +4,9 @@ All notable changes to **Loom Code** are documented here.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased] — completion harness, specialist agents, headless browser, TUI refresh
7
+ ## [Unreleased]
8
+
9
+ ## [1.6.0] — 2026-10-17
8
10
 
9
11
  ### Added
10
12
  - **Transcript undo / redo (`/undo`, `/redo`, `/undo-files`).** The
@@ -38,6 +40,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
38
40
  `<leader>x` keybind, which previously resolved to a slash command with no
39
41
  handler.
40
42
 
43
+ ### Fixed
44
+ - **Model catalogs verified against live provider APIs.** Every model ID the
45
+ picker ships was checked against the authoritative source (OpenAI,
46
+ NVIDIA, OpenRouter and Groq `/v1/models`; Anthropic's official pricing +
47
+ deprecation pages; the models.dev cache for registry providers), and every
48
+ dead ID was removed or repointed:
49
+ - **NVIDIA** (the reported failure): the default active model
50
+ `nvidia/llama-3.3-nemotron-super-49b-v1.5` did not exist and 404'd on
51
+ every request — repointed to `nvidia/nemotron-3-super-120b-a12b`
52
+ (54/54 catalog models live).
53
+ - **OpenAI:** dropped phantom `gpt-5.6`, `gpt-5.3-codex-spark`, `o3-pro`;
54
+ added live `gpt-5-codex`, `gpt-5.1-codex`, `gpt-5.1-codex-max`,
55
+ `gpt-5.1-codex-mini`, `gpt-5.2-codex`, `gpt-5.2-pro` (34/34 live).
56
+ - **Anthropic:** dropped models Anthropic retired in 2026
57
+ (`claude-sonnet-4-20250514`, `claude-opus-4-20250514`,
58
+ `claude-3-5-haiku-20241022`); added live `claude-fable-5`,
59
+ `claude-opus-4-7`, `claude-opus-4-6` (14 models, all prices matched to
60
+ the official pricing table; Mythos 5/5.1 omitted — verification-program
61
+ accounts only).
62
+ - **Defaults:** `settings.js` DEFAULTS and the shipped model map no longer
63
+ name dead IDs (`gpt-5-fast`, `meta/llama-3.1-8b-instruct`,
64
+ `anthropic/claude-sonnet-4`, `moonshotai/kimi-k3-free` → `gpt-5`,
65
+ `nemotron-3-super-120b-a12b`, `claude-sonnet-5-5`,
66
+ `z-ai/glm-5.3-free`); OpenRouter 42/42 and TokenRouter (models.dev's
67
+ single `z-ai/glm-5.3-free`) verified live.
68
+ - Usage/context tests now pin a deterministic model/window so future
69
+ default-model changes can't shift their expectations.
70
+ - **Speed telemetry now ticks during the thinking phase.** Reasoning deltas
71
+ count as first-token + generation tokens, so the sidebar latency gauge
72
+ starts when the model starts *thinking* instead of reading "waiting…"
73
+ through the entire thinking phase (measured on nemotron-3-super: ~7s to
74
+ the first thinking token, then +16s of thought before any visible text —
75
+ the response looked hung while the model was working). `last.latencyMs`
76
+ and `last.tokensPerSec` now reflect true time-to-first-model-output and
77
+ full generation throughput, including reasoning tokens. Regression test
78
+ in `session.test.js`.
79
+ - **NVIDIA catalog note: `/v1/models` is not account availability.** The
80
+ endpoint lists NVIDIA's global catalog, but chat POSTs can return
81
+ `Function '…': Not found for account '…'` when the key's account hasn't
82
+ enabled that model (probed 2026-10-17: 9/54 curated IDs answered chat on
83
+ one key — 37 account-gated 404s, ~6 hung to timeout, 2 returned 503).
84
+ Availability is per-account, so the curated list stays; the caveat is
85
+ now documented in `nvidia.js`.
86
+
41
87
  ### Changed
42
88
  - **Orchestrator now delegates by default.** The build agent's standing
43
89
  instructions were rewritten to make fan-out the first move on any broad
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loom-agent",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/toshalkumbhar8979-design/loomcode.git"
@@ -20,12 +20,17 @@ function configFile() {
20
20
  const DEFAULTS = {
21
21
  provider: 'anthropic',
22
22
  model: {
23
- anthropic: 'claude-sonnet-4-20250514',
24
- openai: 'gpt-5-fast',
25
- nvidia: 'meta/llama-3.1-8b-instruct',
23
+ // claude-sonnet-4-20250514 was retired 2026-06-15 (404); Anthropic's
24
+ // recommended replacement is claude-sonnet-5-5.
25
+ anthropic: 'claude-sonnet-5-5',
26
+ // Defaults must be IDs that exist on the LIVE provider APIs (verified
27
+ // 2026-10-17): gpt-5-fast and meta/llama-3.1-8b-instruct returned 404,
28
+ // anthropic/claude-sonnet-4 and moonshotai/kimi-k3-free are gone too.
29
+ openai: 'gpt-5',
30
+ nvidia: 'nvidia/nemotron-3-super-120b-a12b',
26
31
  google: 'gemini-2.5-flash',
27
- openrouter: 'anthropic/claude-sonnet-4',
28
- tokenrouter: 'moonshotai/kimi-k3-free',
32
+ openrouter: 'anthropic/claude-sonnet-5.5',
33
+ tokenrouter: 'z-ai/glm-5.3-free',
29
34
  local: 'llama3.2',
30
35
  },
31
36
  maxTokens: 16384,
@@ -696,7 +696,16 @@ ${this.mode === 'build' ? `- You have all tools available: read, write, edit, ba
696
696
  if (!speed._firstTokenAt) speed._firstTokenAt = now;
697
697
  if (callbacks.onDelta) callbacks.onDelta(txt);
698
698
  }, onReasoning: (txt) => {
699
+ const now = Date.now();
699
700
  reasoning += txt;
701
+ // Thinking tokens are still model output: count them toward the
702
+ // live gauge so first-token latency ticks from the first THINKING
703
+ // token. Otherwise the sidebar reads "waiting…" for the entire
704
+ // thinking phase (measured: ~7s to first thinking delta, then +16s
705
+ // of thought before any visible text on nemotron-3-super) and the
706
+ // response looks hung while the model is actually working.
707
+ speed._liveTokens += txt.length / 4;
708
+ if (!speed._firstTokenAt) speed._firstTokenAt = now;
700
709
  if (callbacks.onReasoning) callbacks.onReasoning(txt);
701
710
  } }
702
711
  : callbacks;
@@ -838,7 +847,7 @@ ${this.mode === 'build' ? `- You have all tools available: read, write, edit, ba
838
847
  // Finalize the speed snapshot for this model call (or tool step).
839
848
  if (resp && !resp.interrupted) {
840
849
  const dur = Date.now() - speed._turnStart;
841
- const tokens = (streamed.length || String(resp.content || '').length) / 4;
850
+ const tokens = ((streamed + reasoning).length || String(resp.content || '').length) / 4;
842
851
  speed.lastDurationMs = dur;
843
852
  speed.lastTokens = Math.round(tokens);
844
853
  speed.lastTokensPerSec = dur > 0 ? Math.round((tokens / dur) * 1000) : 0;
@@ -328,6 +328,9 @@ const models = [
328
328
  { id: 'claude-opus-4-8', name: 'Claude Opus 4.8', provider: 'anthropic', context: 1000000, priceIn: 5, priceOut: 25, tags: ['frontier', 'reasoning'] },
329
329
  { id: 'claude-opus-4-5', name: 'Claude Opus 4.5', provider: 'anthropic', context: 200000, priceIn: 5, priceOut: 25, tags: ['frontier', 'reasoning'] },
330
330
  { id: 'claude-fable-5-1', name: 'Claude Fable 5.1', provider: 'anthropic', context: 1000000, priceIn: 10, priceOut: 50, tags: ['frontier', 'reasoning'] },
331
+ { id: 'claude-fable-5', name: 'Claude Fable 5', provider: 'anthropic', context: 1000000, priceIn: 10, priceOut: 50, tags: ['frontier', 'reasoning'] },
332
+ { id: 'claude-opus-4-7', name: 'Claude Opus 4.7', provider: 'anthropic', context: 1000000, priceIn: 5, priceOut: 25, tags: ['frontier', 'reasoning'] },
333
+ { id: 'claude-opus-4-6', name: 'Claude Opus 4.6', provider: 'anthropic', context: 1000000, priceIn: 5, priceOut: 25, tags: ['frontier', 'reasoning'] },
331
334
  // ── Sonnet ──
332
335
  { id: 'claude-sonnet-5-5', name: 'Claude Sonnet 5.5', provider: 'anthropic', context: 1000000, priceIn: 2, priceOut: 10, tags: ['reasoning'] },
333
336
  { id: 'claude-sonnet-5', name: 'Claude Sonnet 5', provider: 'anthropic', context: 1000000, priceIn: 2, priceOut: 10, tags: ['reasoning'] },
@@ -337,9 +340,11 @@ const models = [
337
340
  { id: 'claude-haiku-5-5', name: 'Claude Haiku 5.5', provider: 'anthropic', context: 1000000, priceIn: 0.1, priceOut: 0.5, tags: ['fast', 'cheap', 'reasoning'] },
338
341
  { id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5', provider: 'anthropic', context: 200000, priceIn: 1, priceOut: 5, tags: ['fast', 'reasoning'] },
339
342
  // ── Legacy snapshots ──
340
- { id: 'claude-sonnet-4-20250514', name: 'Claude Sonnet 4', provider: 'anthropic', context: 200000, priceIn: 3, priceOut: 15, tags: ['reasoning', 'legacy'] },
341
- { id: 'claude-opus-4-20250514', name: 'Claude Opus 4', provider: 'anthropic', context: 200000, priceIn: 15, priceOut: 75, tags: ['reasoning', 'legacy'] },
342
- { id: 'claude-3-5-haiku-20241022', name: 'Claude 3.5 Haiku', provider: 'anthropic', context: 200000, priceIn: 0.8, priceOut: 4, tags: ['legacy'] },
343
+ // Retired models verified against Anthropic's model-deprecations page
344
+ // (2026-10-17): claude-sonnet-4-20250514 and claude-opus-4-20250514 were
345
+ // retired 2026-06-15, claude-3-5-haiku-20241022 retired 2026-02-19 — they
346
+ // 404 and are no longer listed. claude-mythos-5/5.1 exist but are limited
347
+ // to verified organizations, so they are not offered in the picker.
343
348
  ];
344
349
 
345
350
  module.exports = { chat, stream, models, buildBody, normalizeBlocks };
@@ -13,6 +13,15 @@ function getKey() {
13
13
  // deepseek-ai/deepseek-v4-flash-0731, z-ai/glm-5.2, openai/gpt-oss-120b —
14
14
  // return 404/410 and were removed. Re-verify against /v1/models before
15
15
  // adding any ID.
16
+ //
17
+ // NOTE (probed 2026-10-17): GET /v1/models is the GLOBAL catalog — a chat
18
+ // POST can still fail with `Function '<id>': Not found for account '<key>'`,
19
+ // i.e. the model exists but the key's account hasn't enabled it. On one
20
+ // sample key only 9/54 of these IDs answered a chat call (37 account-gated
21
+ // 404s, ~6 hang to timeout, 2 return 503 capacity errors), so the picker
22
+ // may offer models that 404 for a given account. Availability is
23
+ // per-account, so the full curated list stays; NVIDIA's own errors carry
24
+ // the account hint.
16
25
  const provider = {
17
26
  ...createOpenAICompatProvider({
18
27
  getKey,
@@ -18,7 +18,6 @@ const provider = {
18
18
  { id: 'gpt-6-luna', name: 'GPT-6 Luna', provider: 'openai', tags: ['fast', 'cheap', 'reasoning'], context: 1050000, priceIn: 0.1, priceOut: 0.5 },
19
19
 
20
20
  // ── GPT-5.6 / 5.5 / 5.4 ──
21
- { id: 'gpt-5.6', name: 'GPT-5.6', provider: 'openai', tags: ['frontier', 'reasoning'], context: 1050000, priceIn: 4, priceOut: 20 },
22
21
  { id: 'gpt-5.6-sol', name: 'GPT-5.6 Sol', provider: 'openai', tags: ['reasoning'], context: 1050000, priceIn: 4, priceOut: 20 },
23
22
  { id: 'gpt-5.6-terra', name: 'GPT-5.6 Terra', provider: 'openai', tags: ['reasoning'], context: 1050000, priceIn: 2, priceOut: 12 },
24
23
  { id: 'gpt-5.6-luna', name: 'GPT-5.6 Luna', provider: 'openai', tags: ['fast', 'cheap', 'reasoning'], context: 1050000, priceIn: 0.2, priceOut: 1.2 },
@@ -31,10 +30,15 @@ const provider = {
31
30
 
32
31
  // ── GPT-5 Codex (coding) ──
33
32
  { id: 'gpt-5.3-codex', name: 'GPT-5.3 Codex', provider: 'openai', tags: ['coding', 'reasoning'], context: 400000, priceIn: 1.75, priceOut: 14 },
34
- { id: 'gpt-5.3-codex-spark', name: 'GPT-5.3 Codex Spark', provider: 'openai', tags: ['coding', 'fast', 'reasoning'], context: 128000, priceIn: 1.75, priceOut: 14 },
33
+ { id: 'gpt-5.2-codex', name: 'GPT-5.2 Codex', provider: 'openai', tags: ['coding', 'reasoning'], context: 400000, priceIn: 1.75, priceOut: 14 },
34
+ { id: 'gpt-5.1-codex-max', name: 'GPT-5.1 Codex Max', provider: 'openai', tags: ['coding', 'reasoning'], context: 400000, priceIn: 1.75, priceOut: 14 },
35
+ { id: 'gpt-5.1-codex', name: 'GPT-5.1 Codex', provider: 'openai', tags: ['coding', 'reasoning'], context: 400000, priceIn: 1.25, priceOut: 10 },
36
+ { id: 'gpt-5.1-codex-mini', name: 'GPT-5.1 Codex Mini', provider: 'openai', tags: ['coding', 'fast', 'reasoning'], context: 400000, priceIn: 0.25, priceOut: 2 },
37
+ { id: 'gpt-5-codex', name: 'GPT-5 Codex', provider: 'openai', tags: ['coding', 'reasoning'], context: 400000, priceIn: 1.25, priceOut: 10 },
35
38
 
36
39
  // ── GPT-5 Series ──
37
40
  { id: 'gpt-5.2', name: 'GPT-5.2', provider: 'openai', tags: ['reasoning'], context: 400000, priceIn: 1.75, priceOut: 14 },
41
+ { id: 'gpt-5.2-pro', name: 'GPT-5.2 Pro', provider: 'openai', tags: ['reasoning', 'pro'], context: 400000, priceIn: 21, priceOut: 168 },
38
42
  { id: 'gpt-5.1', name: 'GPT-5.1', provider: 'openai', tags: ['reasoning'], context: 400000, priceIn: 1.25, priceOut: 10 },
39
43
  { id: 'gpt-5', name: 'GPT-5', provider: 'openai', tags: ['frontier', 'reasoning'], context: 400000, priceIn: 1.25, priceOut: 10 },
40
44
  { id: 'gpt-5-mini', name: 'GPT-5 Mini', provider: 'openai', tags: ['fast', 'reasoning'], context: 400000, priceIn: 0.25, priceOut: 2 },
@@ -43,7 +47,6 @@ const provider = {
43
47
 
44
48
  // ── O-Series (Reasoning, legacy) ──
45
49
  { id: 'o3', name: 'o3', provider: 'openai', tags: ['reasoning', 'legacy'], context: 200000, priceIn: 2, priceOut: 8 },
46
- { id: 'o3-pro', name: 'o3 Pro', provider: 'openai', tags: ['reasoning', 'pro', 'legacy'], context: 200000, priceIn: 20, priceOut: 80 },
47
50
  { id: 'o3-mini', name: 'o3 Mini', provider: 'openai', tags: ['reasoning', 'fast', 'legacy'], context: 200000, priceIn: 1.1, priceOut: 4.4 },
48
51
  { id: 'o4-mini', name: 'o4 Mini', provider: 'openai', tags: ['reasoning', 'fast', 'legacy'], context: 200000, priceIn: 1.1, priceOut: 4.4 },
49
52
 
@@ -12,7 +12,10 @@ const provider = {
12
12
  envKeyHint: 'TOKENROUTER',
13
13
  }),
14
14
  models: [
15
- { id: 'moonshotai/kimi-k3-free', name: 'Kimi K3 Free', provider: 'tokenrouter', tags: ['free'], context: 128000, priceIn: 0, priceOut: 0 },
15
+ // models.dev (2026-10-17): TokenRouter's only listed model is the free
16
+ // GLM-5.3 endpoint; the earlier moonshotai/kimi-k3-free ID is gone and
17
+ // returns an error. Verified against the models.dev registry cache.
18
+ { id: 'z-ai/glm-5.3-free', name: 'GLM 5.3 Free', provider: 'tokenrouter', tags: ['free'], context: 1000000, priceIn: 0, priceOut: 0 },
16
19
  ],
17
20
  };
18
21
 
@@ -110,7 +110,7 @@ export function SubagentPanel() {
110
110
  const curModel = (cfg.agents[cur.agentId] && cfg.agents[cur.agentId].model) || "";
111
111
  openModal({
112
112
  type: "input", title: "Default model for " + cur.agent,
113
- placeholder: 'e.g. "anthropic/claude-sonnet-4-20250514" — empty clears',
113
+ placeholder: 'e.g. "anthropic/claude-sonnet-5-5" — empty clears',
114
114
  value: curModel,
115
115
  onPick(val: string) {
116
116
  closeModal();