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 +47 -1
- package/package.json +1 -1
- package/src/config/settings.js +10 -5
- package/src/core/session.js +10 -1
- package/src/providers/anthropic.js +8 -3
- package/src/providers/nvidia.js +9 -0
- package/src/providers/openai.js +6 -3
- package/src/providers/tokenrouter.js +4 -1
- package/src/tui/components/SubagentPanel.tsx +1 -1
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]
|
|
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
package/src/config/settings.js
CHANGED
|
@@ -20,12 +20,17 @@ function configFile() {
|
|
|
20
20
|
const DEFAULTS = {
|
|
21
21
|
provider: 'anthropic',
|
|
22
22
|
model: {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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-
|
|
28
|
-
tokenrouter: '
|
|
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,
|
package/src/core/session.js
CHANGED
|
@@ -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
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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 };
|
package/src/providers/nvidia.js
CHANGED
|
@@ -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,
|
package/src/providers/openai.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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-
|
|
113
|
+
placeholder: 'e.g. "anthropic/claude-sonnet-5-5" — empty clears',
|
|
114
114
|
value: curModel,
|
|
115
115
|
onPick(val: string) {
|
|
116
116
|
closeModal();
|