Commit graph

602 commits

Author SHA1 Message Date
ace-pm
e5d655bdb3 chore: checkpoint workspace changes 2026-04-15 13:38:15 +02:00
ace-pm
c0de3538ec fix(retry-handler): classify 529/overloaded as rate_limit for fallback walk
Minimax and other Anthropic-protocol providers return HTTP 529 with
`overloaded_error` bodies under heavy load. The retryable regex (line 119)
matched `overloaded` so the error was retried, but the rate-limit
classifier (line 423) only matched `429`, so the error never triggered
credential rotation or cross-provider fallback — the handler looped on
the same provider forever.

Adds `529|overloaded` to the rate-limit classifier so 529 responses
route through the same backoff + fallback path as real rate limits.
2026-04-15 11:04:41 +02:00
ace-pm
1f1c029c74 fix(cli): invert persistModelChanges default to false (#4251)
Followup to 828c5edf6. Swarm review flagged default=true as a latent
footgun: any SDK consumer of createAgentSession() that forgets to pass
persistModelChanges would silently mutate ~/.gsd/agent/settings.json.

Flip the default to false so persistence is opt-in. Interactive CLI
entry points now explicitly pass persistModelChanges: true:
- src/cli.ts interactive createAgentSession call
- packages/pi-coding-agent/src/main.ts: persistModelChanges = isInteractive

Print/rpc/mcp stay at the safe default. Tests updated (9/9 green).
2026-04-15 10:45:26 +02:00
ace-pm
828c5edf62 fix(cli): don't persist --model override in print mode (#4251)
`gsd -p --model X "msg"` was silently overwriting defaultProvider/
defaultModel in settings.json. One-shot verification runs must use the
model for that invocation only.

Adds an AgentSessionConfig.persistModelChanges flag (default true so
interactive behavior is unchanged), forwards it through createAgentSession,
and sets it false in main.ts when !isInteractive and in src/cli.ts print
mode. The gsd wrapper also skips validateConfiguredModel when --model is
explicitly passed, so a CLI-provided model can't trigger a fallback repair
that writes the wrong default back.

Three settings.json write sinks audited: agent-session._applyModelChange
(gated on flag), model-selector.ts (interactive only, unreachable in
print), startup-model-validation (gated by !cliFlags.model in print).

Regression: 8 source-assertion tests in
agent-session-print-mode-persist.test.ts.
2026-04-15 10:12:32 +02:00
ace-pm
1fc62582ed feat(anthropic): support longcat as Bearer-auth Anthropic-compatible provider
LongCat (Meituan) ships an Anthropic-compatible endpoint at
https://api.longcat.chat/anthropic that authenticates via
`Authorization: Bearer $KEY` instead of Anthropic's native `x-api-key`
header. Without this change, pi sends x-api-key and LongCat replies
with 401 invalid_api_key / missing_api_key.

Same topology as the existing alibaba-coding-plan / minimax /
minimax-cn entries (#3783).

- Add "longcat" to usesAnthropicBearerAuth() so createClient routes
  the key through authToken.
- Add "longcat": "LONGCAT_API_KEY" to env-api-keys.ts envMap so
  getEnvApiKey() can resolve it when options.apiKey is absent.
- Add "longcat" to KnownProvider so the === literal check type-checks.
- Extend anthropic-auth.test.ts to assert usesAnthropicBearerAuth
  returns true for longcat.
2026-04-15 08:54:52 +02:00
Jeremy McSpadden
cb8ac79ce6 Merge pull request #4245 from jeremymcs/fix/claude-mcp-orphaned-subturn-text
fix(chat): preserve Claude MCP chat visibility during tool-only windows
2026-04-14 23:41:36 -05:00
Jeremy
bc98495cdd fix(chat): preserve claude MCP thinking visibility during tool windows 2026-04-14 23:09:20 -05:00
Jeremy
51fdd6e973 fix(chat): cap claude reasoning blocks to keep chat visible 2026-04-14 22:58:56 -05:00
Jeremy McSpadden
9cc66484a9 Merge pull request #4238 from jeremymcs/fix/claude-mcp-orphaned-subturn-text
fix(chat): prune orphaned Claude MCP sub-turn provisional text
2026-04-14 22:41:03 -05:00
Jeremy McSpadden
3fb1bef6d8 Merge pull request #4227 from NilsR0711/feat/gsd-extract-learnings
feat(gsd): add /gsd extract-learnings command
2026-04-14 22:33:37 -05:00
Jeremy
9a344ad6ca fix(chat): prune orphaned claude MCP provisional sub-turn text 2026-04-14 22:22:10 -05:00
Jeremy McSpadden
b803d6e023 Merge pull request #3878 from mastertyko/fix/3782-minimax-env-key-fallback
fix(pi-coding-agent): fall back to env keys for built-ins
2026-04-14 22:03:31 -05:00
Nils Reeh
73916a8c38 feat(graph): parse LEARNINGS.md into knowledge graph and rebuild after extraction 2026-04-15 04:52:52 +02:00
Jeremy
7208a6af36 fix(chat): prune claude MCP provisional text above tool output 2026-04-14 21:41:29 -05:00
Jeremy McSpadden
c63f801412 Merge pull request #4215 from gsd-build/fix/adr-009-rfc-and-build-fixes
fix(gsd): align ADR-009 integration with type-safe builds
2026-04-14 21:07:13 -05:00
Jeremy McSpadden
76a85300ae fix(gsd): align ADR-009 integration with type-safe builds
Add ADR-009 docs and resolve compile/runtime typing regressions in UOK and extension modules.

Refs #4214
2026-04-14 20:46:46 -05:00
Nils Reeh
3509107228 fix(pi-coding-agent): remove explanatory comment from agent_end handler 2026-04-15 03:12:17 +02:00
Nils Reeh
b721ec1445 fix(pi-coding-agent): finalize streaming component on agent_end instead of removing it
When message_end does not fire before agent_end (e.g. abort path), the
agent_end case was calling chatContainer.removeChild(streamingComponent),
which silently erased the last assistant message from the TUI chat history.

Fix: follow the message_end finalization pattern — call setShowMetadata(true)
and updateContent() before clearing the reference. Never call removeChild on
a component that was added to the persistent chat history.

Closes #4197
2026-04-15 03:01:11 +02:00
Nils Reeh
736e542304 test(pi-coding-agent): add regression tests for agent_end DOM destruction (issue #4197) 2026-04-15 03:01:11 +02:00
Jeremy McSpadden
16fa6f45c0 Merge pull request #4212 from NilsR0711/feat/4202-knowledge-graph
feat(graph): implement knowledge graph system
2026-04-14 19:51:04 -05:00
Jeremy
eec05b68a8 fix(release): sync all workspace versions and harden release scripts
Two bugs were causing version drift across the repo:

1. Root package.json was silently reverted from 2.74.0 → 2.73.1 during
   commit b03c9401c (a CI optimization rebase). Tag v2.74.0 is already
   published on npm, so the next release would have computed 2.73.2 —
   lower than what's already out — and shipped a broken version.

2. scripts/bump-version.mjs only touches pi-coding-agent + pkg + native
   platform shims. Other workspace packages drift independently:
   - @gsd-build/mcp-server: stuck at 2.52.0 (22 minor versions behind)
   - @gsd-build/rpc-client: stuck at 2.52.0
   - @gsd/pi-ai, pi-tui, pi-agent-core: stuck at 0.57.1
   - @gsd/native, @gsd-build/daemon: stuck at 0.1.0

Changes:

- Bump all non-private workspace packages to 2.74.0 to match the latest
  release tag. Update daemon + mcp-server's internal rpc-client dep
  from ^2.52.0 → ^2.74.0. Regenerate root lockfile.

- scripts/generate-changelog.mjs: compute newVersion from max(latest
  stable tag, package.json) instead of package.json alone. Prevents
  version regressions when package.json is accidentally clobbered by
  rebases or merges.

- scripts/bump-version.mjs: extend to sync all eight non-private
  workspace packages (daemon, mcp-server, native, pi-agent-core, pi-ai,
  pi-coding-agent, pi-tui, rpc-client) including their internal deps
  on each other. Private packages (studio, web) are left alone.

Studio and web remain on their own versioning (private: true, never
published). The native platform shims under native/npm/* are still
synced via native/scripts/sync-platform-versions.cjs from the root
version as before.
2026-04-14 19:35:28 -05:00
Nils Reeh
15bccca78f feat(graph): implement knowledge graph system (closes #4202)
Ports the v1 graphify system to v2 as a native TypeScript implementation.
The knowledge graph builds semantic relationships between milestones, slices,
tasks, and knowledge entries — and injects relevant subgraphs automatically
into every agent dispatch prompt.

## Core implementation (packages/mcp-server/src/readers/graph.ts)

- `buildGraph(projectDir)` — walks all .gsd/ artifacts (STATE.md,
  milestone PLANs, slice PLANs, KNOWLEDGE.md), extracts nodes and edges
  with confidence tiers (EXTRACTED / INFERRED / AMBIGUOUS). Parse errors
  skip the node rather than crashing.
- `writeGraph(gsdRoot, graph)` — atomic write via tmp file + rename.
- `writeSnapshot(gsdRoot)` — saves a diff baseline before each rebuild.
- `graphQuery(projectDir, term, budget?)` — BFS subgraph search with
  case-insensitive matching on label + description; trims AMBIGUOUS edges
  first, then INFERRED, respecting the token budget (default 4 000).
- `graphStatus(projectDir)` — freshness check; stale = older than 24 h.
- `graphDiff(projectDir)` — compares current graph to last snapshot,
  returns added / removed / changed counts for nodes and edges.

## MCP tool (packages/mcp-server/src/server.ts)

Registers `gsd_graph` immediately after `gsd_knowledge` with four modes:
build | query | status | diff. All errors returned as isError: true.

## CLI subcommand (src/cli.ts, src/help-text.ts)

`gsd graph build|status|query <term>|diff` — follows the established
`if (cliFlags.messages[0] === '...')` dispatch pattern. Uses
`resolveGsdRoot()` for git-root-aware path resolution (not a naive
`.gsd` append). Help text updated with correct positional argument format.

## Auto-rebuild after slice completion
(src/resources/extensions/gsd/tools/complete-slice.ts)

Fire-and-forget `buildGraph → writeGraph` triggered after every slice
completion. Uses `@gsd-build/mcp-server` package import (not a relative
src path) and `resolveGsdRoot()` for correct path resolution in monorepos.

## Graph-aware dispatch injection
(src/resources/extensions/gsd/graph-context.ts,
 src/resources/extensions/gsd/auto-prompts.ts)

`inlineGraphSubgraph(projectDir, term, { budget })` queries the graph and
formats the result as a `### Knowledge Graph Context` markdown block,
consistent with all other inlined context blocks. Adds a stale warning
annotation when the graph is older than 24 h. Returns null (graceful
skip) when graph.json is missing, the query returns zero nodes, or the
import fails — no agent dispatch is ever blocked by graph availability.

Injected into three prompt builders:
- `buildResearchSlicePrompt` — 3 000 token budget
- `buildPlanSlicePrompt`     — 3 000 token budget
- `buildExecuteTaskPrompt`   — 2 000 token budget

## Tests

- 22 tests for the core graph reader (graph.test.ts)
- 14 tests for the dispatch injection helper (graph-context.test.ts)
- All tests use real on-disk fixtures (no module mocking needed)
- Full suite: 6 318 passed, 0 failed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 02:20:49 +02:00
Jeremy
b03c9401c4 ci: optimize build workflows and caching 2026-04-14 11:16:47 -05:00
github-actions[bot]
2e53b3cbad release: v2.74.0 2026-04-14 15:59:28 +00:00
Jeremy
bc22ce95bc Cap thinking output for tool-bearing assistant turns 2026-04-14 10:15:43 -05:00
Jeremy McSpadden
7f77322fe2 Merge pull request #4182 from jeremymcs/claude/refactor-code-cleanup-078AQ
fix: keep assistant text visible when thinking traces are long
2026-04-14 09:17:49 -05:00
Jeremy
e78eacb40e fix: keep assistant text visible when thinking traces are long
Cap thinking trace render height when assistant text is present so interactive questions remain visible.\n\nFixes #4181.
2026-04-14 09:01:20 -05:00
deseltrus
064389146c test(tui): add regression tests for render debounce and spinner batching
- DynamicBorder: verify lastExternalRender tracking suppresses redundant
  renders during streaming, and standalone renders fire when idle
- TUI clearOnShrink: verify debounce flag lifecycle — deferred shrink
  preserves maxLinesRendered, flag resets when content grows back

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 06:22:22 +02:00
deseltrus
73f9434d11 fix(tui): eliminate pinned output duplication and reduce render overhead
rebuildChatFromMessages() called populatePinnedFromMessages() which
re-populated the pinned zone with text already present in the chat
history, causing visible duplication during session state changes.
Additionally, the spinner interval at 80ms generated ~12.5 renders/s
for a purely cosmetic animation, and clearOnShrink triggered
unnecessary full redraws during pinned-zone transitions.

- Remove populatePinnedFromMessages() from rebuildChatFromMessages()
  and add pinnedMessageContainer.clear() instead — the streaming
  lifecycle in chat-controller manages pinned content during active work
- Reduce spinner interval 80ms→200ms with render-batching that skips
  redundant renders when streaming already triggers requestRender()
- Debounce clearOnShrink: defer full redraw by one render tick so
  pinned-clear→new-streaming transitions avoid a wasted full redraw
- Increase notification widget safety-net timer 5s→30s since the
  store subscription already handles push-based updates

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 06:17:18 +02:00
Jeremy McSpadden
4ab053d9ba Merge pull request #4156 from jeremymcs/fix/4144-claude-code-subturn-regression
fix(tui): reset segment state on claude-code sub-turn shrink
2026-04-13 20:45:36 -05:00
Jeremy
2bf2313395 test(tui): finalize sub-turn regression tests to stop pinned spinner
The two new sub-turn shrink regression tests created a pinned
DynamicBorder (via message_update with pinnable text + tool) but never
emitted message_end, so the spinner's setInterval kept the test process
alive until CI timed out after 15 minutes. Append a message_end to
each test so the module-level pinnedBorder is torn down.
2026-04-13 20:36:52 -05:00
Jeremy
03b7142400 fix(tui): reset segment state on claude-code sub-turn shrink
Commit c8c416802 (#4144) introduced module-level renderedSegments state
to track interleaved text/tool components per assistant turn, but never
reset it when an adapter shrinks streamingMessage.content[] back to 0/1
at a provider sub-turn boundary within one assistant lifecycle (the
claude-code adapter does this). Consequence chain: the segment walker
finds the stale text-run entry at startIndex=0, calls updateContent on
it with the new (shrunk) message, and the in-place edit destroys the
prior sub-turn's visible text. New tool blocks at contentIndex=1 then
collide with stale registrations, causing visual ordering corruption.
hasToolsInTurn stays sticky-true and lastPinnedText never clears, so
the pinned "Working - Latest Output" mirror freezes on the pre-shrink
snapshot.

Track lastContentLength explicitly. On shrink, clear renderedSegments,
reset lastPinnedText, and reset lastProcessedContentIndex so the
walker treats the new sub-turn as fresh segments that append after
prior sub-turn children. Prior history stays rendered as frozen
components; pendingTools and the spinner border are untouched.

Adds two regression tests in chat-controller-ordering.test.ts: one
verifies prior sub-turn components are not overwritten and new tools
append in content[] order after a shrink, the other verifies the
pinned markdown updates from the first sub-turn's text to the second
sub-turn's text across a shrink boundary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 19:58:11 -05:00
Jeremy McSpadden
fc7d195e09 Merge pull request #4150 from jeremymcs/claude/debug-tui-auto-mode-vCnxA
Split Container.clear() into clear() and detachChildren()
2026-04-13 18:39:33 -05:00
Claude
33d9a26dd7 fix(tui): keep AUTO-mode widgets alive and drop duplicate health panel
InteractiveMode.renderWidgets() called Container.clear() on the
widgetContainerAbove/Below render mounts, which disposed every mounted
extension widget and then re-added the now-dead components. In AUTO mode
updateProgressWidget re-registers gsd-progress on every unit dispatch,
so gsd-notifications and gsd-health had their refresh timers and store
subscriptions killed after the first dispatch. Renders kept returning
the widgets' frozen cachedLines, making them look alive but never update
(/gsd notifications clear appeared to do nothing, belowEditor last-commit
went stale while the top-of-screen dashboard stayed correct).

Split detach from dispose: add Container.detachChildren() and use it from
the two widget-mount call sites. clear() still disposes for every other
caller (chat, editor, status, pinned-message containers). The
extensionWidgets* maps remain the single owner of widget disposal via
removeExisting() and clearExtensionWidgets().

While in AUTO, gsd-progress duplicates gsd-health on last commit, cost/
budget, and the health signal. Make gsd-progress the single source of
truth: hide gsd-health from auto-start and re-register it from every
exit point in auto.ts (lock-lost stop, cleanupAfterLoopExit !paused
guard, stopAuto, pauseAuto). gsd-notifications stays visible — it is
independent state and, with the detach fix, its subscription + 5s
refresh actually work again.

Tests: Container.detachChildren()/clear() contract guards added to
packages/pi-tui/src/__tests__/tui.test.ts. health-widget,
notification-{store,widget,overlay}, notifications-handler, notifications,
and auto-paused-ui-cleanup suites all pass.
2026-04-13 23:30:25 +00:00
Jeremy McSpadden
96f77d8ff8 Merge pull request #4037 from mastertyko/fix/3925-claude-code-overflow-detect
fix(pi-ai): detect claude-code overflow text
2026-04-13 18:21:36 -05:00
Jeremy McSpadden
cdd257e59a Merge pull request #4059 from mastertyko/fix/4054-compaction-safe-role-markers
fix(pi-coding-agent): use safe compaction role markers
2026-04-13 17:58:04 -05:00
Jeremy
c8c416802f fix(tui): render assistant tool calls inline with text instead of grouped at end
Previously the chat-controller created one AssistantMessageComponent per
assistant message and removed/re-appended it to the chat container's tail
on every tool block, forcing all narration after every tool execution
regardless of stream order. Users had to scroll up to read text that was
written before each tool call.

Replace the reorder hack with a stream-order segment walker that walks
content[] left-to-right, collapses contiguous text/thinking blocks into
text-run segments, emits one segment per tool block, and append-only adds
new segments to chatContainer. AssistantMessageComponent gains a
ContentRange API so a single message can spawn multiple text-run
components, plus a separate showMetadata flag so timestamp/error footers
render only on the trailing segment without duplicating earlier text.

Adds a regression test that streams [text, tool, text, tool, text] and
asserts both interleaved order and per-segment rendered text content.

Closes #4144
2026-04-13 17:23:17 -05:00
Jeremy McSpadden
1ec1a8c4c4 Merge pull request #4060 from mastertyko/fix/3917-claude-code-effort
feat(claude-code): pass thinking level as effort
2026-04-13 16:07:59 -05:00
github-actions[bot]
01df12f14d release: v2.73.1 2026-04-13 17:00:39 +00:00
mastertyko
5474e99ae2 feat(claude-code): pass thinking level as effort 2026-04-13 18:05:19 +02:00
Jeremy
cce3bc6828 fix(model-resolver): gate saved default restore on provider readiness
Restore the isProviderRequestReady() guard lost during the main merge.
Tests in model-resolver.test.ts and model-resolver-initial-model-auth.test.ts
require findInitialModel() to skip an unauth'd saved default and fall
through to the first available model.
2026-04-13 10:26:28 -05:00
Jeremy
bafa4e483d Merge remote-tracking branch 'upstream/main' into claude/model-agnostic-selection-rmDX3
# Conflicts:
#	packages/pi-coding-agent/src/core/model-resolver.ts
#	src/cli.ts
2026-04-13 10:22:16 -05:00
Jeremy McSpadden
4fcf5d6e6b Merge pull request #4117 from NilsR0711/fix/localhost-custom-provider-compaction-auth
fix(pi-coding-agent): skip localhost dummy key when fallback resolver provides a configured key
2026-04-13 09:12:17 -05:00
Claude
0ed576ac00 Make model selection model-agnostic
Remove hard-coded Anthropic/Claude defaults and silent provider swaps so
the app honors whatever model/provider the user has configured.

- src/cli.ts: drop the anthropic->claude-code auto-migration blocks that
  were rewriting the user's saved defaultProvider on every startup.
- packages/pi-coding-agent/src/core/model-resolver.ts: delete the
  defaultModelPerProvider table, drop the "recommended variant" swap
  that silently upgraded e.g. claude-opus-4-6 to -extended, and replace
  the provider-iteration first-available fallback with provider-sticky
  (user's saved provider first, then first registry entry).
- src/startup-model-validation.ts: replace the openai/anthropic-first
  fallback chain with Pi-default -> same-provider -> first-available.
- src/help-text.ts: use a generic provider/model-id example for --model
  instead of claude-opus-4-6.
- src/tests/startup-model-validation.test.ts: update the fallback test
  to assert provider stickiness rather than a specific Claude model id.

https://claude.ai/code/session_01CvuUuzuVjRcQN25263nG6V
2026-04-13 14:03:35 +00:00
Jeremy McSpadden
3adafde442 Merge pull request #4121 from jeremymcs/fix/4120-pinned-output-duplication
fix(tui): stop pinned latest-output from duplicating streaming text
2026-04-13 08:30:08 -05:00
Jeremy
9ffde91020 test(tui): regression test for pinned latest-output duplication
Extract the post-tool text-block selection logic into a small pure
helper (`findLatestPinnableText`) so the regression scenario can be
covered without standing up the full interactive controller harness.
The new test pins the bug from #4120: when content blocks are
`[text1, tool1, text2_streaming]`, the helper must return `text1`
(not `text2`), because `text2` is still streaming live into the chat
container and mirroring it would render the same tokens twice.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 08:20:24 -05:00
Jeremy
dc84694c65 fix(tui): stop pinned latest-output mirror from duplicating streaming text
The pinned `Working · Latest Output` border above the editor mirrors
the assistant's latest text block while tools run, so prose stays
visible after a tool's output scrolls it off-screen. The mirror walked
content blocks from the end and picked the last text block — but when
the assistant streams a *new* text block after a tool call (sequence
`[text1, tool1, text2_streaming]`), it picked `text2`, which was also
being streamed live into the chat container. Result: identical tokens
rendered in two places at once.

Restrict the search to text blocks whose index is strictly less than
the index of the most recent tool call. Text after the last tool call
stays in the chat container only; earlier prose (e.g. `text1`) remains
mirrored the entire time the new text streams, so context isn't lost
and the loading-animation handoff is undisturbed.

Fixes #4120

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 08:16:16 -05:00
github-actions[bot]
4733cf7bed release: v2.73.0 2026-04-13 13:04:12 +00:00
Nils Reeh
1ef6ba16f9 fix(pi-coding-agent): skip localhost dummy key when fallback resolver provides a configured key
Custom OpenAI-compatible providers running on localhost (e.g. a local proxy)
with an explicit apiKey in models.json received 'local-no-key-needed' during
compaction instead of their configured key, causing 401 errors.

The localhost shortcut in AuthStorage.getApiKey() was unconditional. Normal
dispatch calls getApiKeyForProvider() which skips the baseUrl check entirely,
so the fallback resolver was reached and the real key was used. Compaction
calls getApiKey(model) which passes baseUrl, hitting the shortcut first.

Closes #4106
2026-04-13 14:32:16 +02:00
NilsR0711
ae1bcc572d chore(pi-ai): regenerate model registry from upstream APIs (#3887)
* chore(pi-ai): regenerate model registry from upstream APIs

Regenerated models.generated.ts by running generate-models.ts against
live provider APIs. Last generated: 2026-04-09.

+48 models added, 19 removed across all providers.
Notable additions: z-ai/glm-5.1 via OpenRouter (closes #4069,
supersedes custom entry in #4055), zai-org/GLM-5.1, z-ai/glm-5v-turbo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(pi-ai): add structural and regression tests for models.generated.ts

- Regression #3582: pins qwen/qwen3.6-plus in openrouter
- Regression #4069: pins z-ai/glm-5.1 in openrouter
- Structural invariants across all 23 providers / all models
- Registry shape: exact provider list, model count lower bound
- Removed models guard: decommissioned models must stay absent
- Spot-checks for notable models added in this regeneration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 08:05:03 -04:00