Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions AMICODE-PATCHES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -265,16 +265,14 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
if something else (e.g. the harmoniqs website dev server) holds 3000.
- Checks: `tsgo -b` clean; `bun run test:unit` 376 pass / 0 fail.

15. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).
10. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).

> ⚠️ **LICENSE-PENDING — release blocker.** "Aero" by Nirmal Biswas (Picatype) is donationware, USD 25+ to nirmalbiswas@gmail.com. Bundled at `packages/app/public/assets/Aero-Regular.ttf` for PREVIEW ONLY; not locked as the official face. Before any release: pay the license and record proof here, or drop `'Aero'` from both `font-family` chains + remove its `@font-face` (index.css) + the asset.

- index.css: new `@font-face` for "Aero" (truetype, weight 400, `font-display: swap`), inserted immediately before the existing Racing Sans One face; carries the license-pending comment inline.
- New asset (git-added): `public/assets/Aero-Regular.ttf` (44,464 B).
- Verify: `bun run typecheck` green in both `packages/ui` and `packages/app` (tsgo, no errors). Visual/glyph confirmation is manual-only (see build note under #16, which builds and vendors this alongside the paste fix).

16. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.

11. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.
- platform.tsx: new optional capability `readClipboardText?(): Promise<string | null>`, alongside the existing `readClipboardImage?`.
- entry.tsx: implements it — no-op (`null`) when not framed (`window.parent === window`, i.e. plain browser/opencode.ai/desktop — zero behavior change there); when framed, posts `{source:"amicode", kind:"clipboard-request", nonce}` to `window.parent` and resolves on the matching `{kind:"clipboard", nonce}` reply or a 1500 ms timeout — same nonce/timeout/listener shape as the proven `readClipboardViaBridge`, just exposed as a platform capability instead of a component-local closure (this file already hosts the analogous `readClipboardImage`).
- attachments.ts: `handlePaste` no longer bails out when `event.clipboardData` is null (only when it's ALSO missing `readClipboardText`, i.e. non-amicode contexts are untouched); after the existing file/image-bridge attempts, falls back to `readClipboardText()` when there's still no plain text.
Expand All@@ -288,7 +286,7 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Tests: same 376/376 pass (app suite), typecheck green — no regressions. No unit coverage added, same house-precedent reasoning as above (DOM/postMessage bridge code, build+manual verified here).
- **Final build sha256 (covers #15 + #16 + this addendum together):** `115216e82a6db15843fca46d5b32b587ba9a1e542297501cf2b45c394f745ea9`. Verify: smoke test `--version` → `1.17.3`; string-literal checks confirm the underlying protocol compiled in (`Aero` ×5, `clipboard-request` ×2, `readClipboardText` ×3 — note: the new `installGlobalPasteFallback`/`isFormField` are local identifiers, not string literals, so they're minifier-renamed and don't grep-match; absence there is expected, not a failure signal); channel gate ON (`newLayoutDesigns` sentinel `=!0`). **Interactive Cmd/Ctrl+V confirmation (composer AND the generalized fallback) is live-VS-Code-only, NOT yet human-verified past Aaron's one negative report on the pre-addendum build** — same deferred-to-dev-host-acceptance caveat as patches #12/#13.

17. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.
12. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.

- Trigger: amicode's mark was redesigned (PR #99) without a corresponding update here — the fork still rendered the OLD "digi" pixel-accented H-robot everywhere. PR #99 went through several iterations before landing on its final geometry; this entry tracks that FINAL state (square viewBox `0 0 3600 3600`), not the intermediate "hackathon mark" (viewBox `116 287 3377 3035`) an earlier draft of this fork PR had copied — that intermediate geometry is now itself stale and was replaced here.
- Two copies of near-identical geometry lived in THIS repo (logo.tsx's `Robot` used by `Mark`/`Splash`, and spinner.tsx's `AmicoSpinner`), plus a third in favicon/amico.svg. Consolidated to a single `MARK_PATH` exported from logo.tsx.
Expand DownExpand Up@@ -340,3 +338,18 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Service account (`client_credentials`) is the documented exit condition (retires the password entirely, ADR-clean); request is with Pasqal (Baptiste Peyras). Browser/device/token/refresh paths are evidence-ruled-out (see #194); the scaffold's tolerant method model harmlessly still parses `auth_methods` if a future server ever advertises them.
- CAVEAT (cannot be verified here): the real @napi-rs/keyring backend + its load inside the bun-compiled binary needs a real-machine smoke test before trusted, and the dep must be added to packages/opencode/package.json (node-pty/tree-sitter precedent). All LOGIC is tested behind the injected in-memory store.
- Tests: pasqal-secret.test.ts +5; amicode-connections.test.ts +6 silent-reauth (store-on-submit / re-mint / reject-wipes / unreachable-stands / disconnect-wipes / secret-free-response) + hermetic secret-store isolation in setup; existing expiry test made explicit about the no-password fallback. opencode `bun test test/server/amicode-connections.test.ts test/server/pasqal-secret.test.ts test/server/amicode-connections-routes.test.ts` → 105 pass. typecheck (tsgo) green. (15 unrelated `built-in widget sources` failures are a pre-existing missing-build-artifact issue, not this diff.)

24. (upstream provider/model port — Jack, 2026-07-27) — **first deliberate partial upstream sync.** Our base is sst/opencode `v1.17.3` (2026-06-10); upstream was 1,150 commits ahead at v1.18.7. Rather than a full merge (54 fork-touched files overlap), only the provider/model bucket was ported, because Claude 5 was silently broken at our base.
- THE BUG: `anthropicOpus47OrLater()` matched `/opus-(\d+)[.-](\d+)/` — requires BOTH major and minor. `claude-opus-5` has no minor and `claude-sonnet-5` isn't "opus", so neither matched. Both fell through to the legacy `thinking:{type:"enabled",budgetTokens:16000}` path with only `high`/`max` tiers, instead of the 5-tier `type:"adaptive"` path. Sonnet 5 released 2026-06-29 and Opus 5 on 2026-07-24 — both AFTER our fork point. Upstream fixed this in #38757 (generalize Claude adaptive thinking): the version regex now tolerates a missing minor and defaults unversioned Claude IDs to modern.
- NOT a "new models" problem: the catalog is fetched live from models.dev at BUILD time (`script/generate.ts`; `amicode-release.yml` pins no snapshot), so Opus 5 already appeared in the picker — just hobbled. QA-ing "can I select Opus 5?" gives a false negative on the need to sync.
- WHAT WAS PORTED (deliberately minimal — the END STATE of files, not 112 commits of history):
- `packages/opencode/src/provider/transform.ts` — replaced wholesale with upstream/dev. Fork had never touched it → 0 conflicts. Also carries #38424 (prompt cache keys by SDK), #36624/#36543 (derive variants from reasoning metadata), and the Grok/GLM/Bedrock-Mantle variant fixes.
- `packages/opencode/test/provider/transform.test.ts` — replaced wholesale with upstream/dev (our copy asserted 6 now-superseded behaviors).
- `packages/core/src/models-dev.ts` — ADDITIVE only: upstream's `ReasoningOption` union + optional `reasoning_options` field on `Model`. transform.ts reads it; without it the port is 4 type errors.
- `packages/opencode/src/session/llm/request.ts` — 3-way merged (`git merge-file` ours/v1.17.3/upstream), 0 conflicts. Brings upstream #33392 (`strict: false` on tools for `@ai-sdk/openai`, `@ai-sdk/azure`, `@ai-sdk/amazon-bedrock/mantle`). **amicode patch #18 (PROMPT_COMMUNICATING) is preserved** — different region of the file.
- WHAT WAS DELIBERATELY NOT PORTED: the Effect `layer-node → app-node` refactor and the `@opencode-ai/schema` extraction (upstream gutted `core/src/model.ts` 127→41 and `core/src/provider.ts` 85→25 into a new package). Cherry-picking the bucket's 112 commits would drag both in. Take file end-states, not history.
- MEASURED BLAST RADIUS: ran both transform versions over all 454 reasoning models in the live models.dev catalog — **418 identical, 36 changed, 0 errors**. The 36: Claude 5 (opus/sonnet, across `anthropic` + all `amazon-bedrock` regions + `opencode` zen) goes `high,max` → `low,medium,high,xhigh,max` with `type:"adaptive"`; xAI Grok 4.3/4.5/4.20/build and GLM-5.2 gain effort variants where they previously had NONE; `claude-opus-4-5` keeps its `low,medium,high` keys but now also sends `budgetTokens:16000` alongside `effort`. Claude 4.8/4.6/4.1 unchanged.
- VERIFICATION: `tsgo --noEmit` green on packages/opencode AND packages/core. `bun test test/provider/` → 503 pass / 0 fail. `bun test test/session/ test/server/` → identical results before and after the port (3 pre-existing `llm-native-recorded` failures + a pre-existing Bun 1.3.14 teardown segfault, both reproduced byte-for-byte on the unported tree).
- STILL UNVERIFIED (needs live API creds): whether the OLD legacy `thinking:{type:"enabled",budgetTokens}` form actually 400s against Opus 5 or merely degrades — i.e. whether this was "hobbled" or "unusable". Also unexercised by CI: the Grok/GLM effort variants and the opus-4-5 `budgetTokens`+`effort` combination.
- FUTURE SYNC COST: this is a knowing trade — porting file end-states now makes a future clean upstream merge harder on these 4 files. Accepted. NOTE the bug class recurs every model generation (version-regex parsing of model IDs will break again at Opus 6), which argues for a standing narrow sync lane on `transform.ts` rather than one-off unfreezes.
- SEPARATE RISK SPOTTED (not fixed here): the release build does a bare `fetch(models.dev/api.json)` with no fallback, so a models.dev outage hard-fails the build. Consider pinning `MODELS_DEV_API_JSON` for the hackathon build.
19 changes: 19 additions & 0 deletions packages/core/src/models-dev.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,6 +43,24 @@ const Cost = Schema.Struct({
),
})

// How a model exposes its reasoning control in the models.dev catalog. Ported
// from upstream alongside provider/transform.ts — the transform derives thinking
// variants from this instead of pattern-matching model IDs. See AMICODE-PATCHES.md.
const ReasoningOption = Schema.Union([
Schema.Struct({
type: Schema.Literal("effort"),
values: Schema.Array(Schema.NullOr(Schema.String)),
}),
Schema.Struct({
type: Schema.Literal("toggle"),
}),
Schema.Struct({
type: Schema.Literal("budget_tokens"),
min: Schema.optional(Schema.Finite),
max: Schema.optional(Schema.Finite),
}),
])

export const Model = Schema.Struct({
id: Schema.String,
name: Schema.String,
Expand All@@ -52,6 +70,7 @@ export const Model = Schema.Struct({
reasoning: Schema.Boolean,
temperature: Schema.Boolean,
tool_call: Schema.Boolean,
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions AMICODE-PATCHES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -265,16 +265,14 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
if something else (e.g. the harmoniqs website dev server) holds 3000.
- Checks: `tsgo -b` clean; `bun run test:unit` 376 pass / 0 fail.

15. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).
10. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).

> ⚠️ **LICENSE-PENDING — release blocker.** "Aero" by Nirmal Biswas (Picatype) is donationware, USD 25+ to nirmalbiswas@gmail.com. Bundled at `packages/app/public/assets/Aero-Regular.ttf` for PREVIEW ONLY; not locked as the official face. Before any release: pay the license and record proof here, or drop `'Aero'` from both `font-family` chains + remove its `@font-face` (index.css) + the asset.

- index.css: new `@font-face` for "Aero" (truetype, weight 400, `font-display: swap`), inserted immediately before the existing Racing Sans One face; carries the license-pending comment inline.
- New asset (git-added): `public/assets/Aero-Regular.ttf` (44,464 B).
- Verify: `bun run typecheck` green in both `packages/ui` and `packages/app` (tsgo, no errors). Visual/glyph confirmation is manual-only (see build note under #16, which builds and vendors this alongside the paste fix).

16. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.

11. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.
- platform.tsx: new optional capability `readClipboardText?(): Promise<string | null>`, alongside the existing `readClipboardImage?`.
- entry.tsx: implements it — no-op (`null`) when not framed (`window.parent === window`, i.e. plain browser/opencode.ai/desktop — zero behavior change there); when framed, posts `{source:"amicode", kind:"clipboard-request", nonce}` to `window.parent` and resolves on the matching `{kind:"clipboard", nonce}` reply or a 1500 ms timeout — same nonce/timeout/listener shape as the proven `readClipboardViaBridge`, just exposed as a platform capability instead of a component-local closure (this file already hosts the analogous `readClipboardImage`).
- attachments.ts: `handlePaste` no longer bails out when `event.clipboardData` is null (only when it's ALSO missing `readClipboardText`, i.e. non-amicode contexts are untouched); after the existing file/image-bridge attempts, falls back to `readClipboardText()` when there's still no plain text.
Expand All@@ -288,7 +286,7 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Tests: same 376/376 pass (app suite), typecheck green — no regressions. No unit coverage added, same house-precedent reasoning as above (DOM/postMessage bridge code, build+manual verified here).
- **Final build sha256 (covers #15 + #16 + this addendum together):** `115216e82a6db15843fca46d5b32b587ba9a1e542297501cf2b45c394f745ea9`. Verify: smoke test `--version` → `1.17.3`; string-literal checks confirm the underlying protocol compiled in (`Aero` ×5, `clipboard-request` ×2, `readClipboardText` ×3 — note: the new `installGlobalPasteFallback`/`isFormField` are local identifiers, not string literals, so they're minifier-renamed and don't grep-match; absence there is expected, not a failure signal); channel gate ON (`newLayoutDesigns` sentinel `=!0`). **Interactive Cmd/Ctrl+V confirmation (composer AND the generalized fallback) is live-VS-Code-only, NOT yet human-verified past Aaron's one negative report on the pre-addendum build** — same deferred-to-dev-host-acceptance caveat as patches #12/#13.

17. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.
12. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.

- Trigger: amicode's mark was redesigned (PR #99) without a corresponding update here — the fork still rendered the OLD "digi" pixel-accented H-robot everywhere. PR #99 went through several iterations before landing on its final geometry; this entry tracks that FINAL state (square viewBox `0 0 3600 3600`), not the intermediate "hackathon mark" (viewBox `116 287 3377 3035`) an earlier draft of this fork PR had copied — that intermediate geometry is now itself stale and was replaced here.
- Two copies of near-identical geometry lived in THIS repo (logo.tsx's `Robot` used by `Mark`/`Splash`, and spinner.tsx's `AmicoSpinner`), plus a third in favicon/amico.svg. Consolidated to a single `MARK_PATH` exported from logo.tsx.
Expand DownExpand Up@@ -340,3 +338,18 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Service account (`client_credentials`) is the documented exit condition (retires the password entirely, ADR-clean); request is with Pasqal (Baptiste Peyras). Browser/device/token/refresh paths are evidence-ruled-out (see #194); the scaffold's tolerant method model harmlessly still parses `auth_methods` if a future server ever advertises them.
- CAVEAT (cannot be verified here): the real @napi-rs/keyring backend + its load inside the bun-compiled binary needs a real-machine smoke test before trusted, and the dep must be added to packages/opencode/package.json (node-pty/tree-sitter precedent). All LOGIC is tested behind the injected in-memory store.
- Tests: pasqal-secret.test.ts +5; amicode-connections.test.ts +6 silent-reauth (store-on-submit / re-mint / reject-wipes / unreachable-stands / disconnect-wipes / secret-free-response) + hermetic secret-store isolation in setup; existing expiry test made explicit about the no-password fallback. opencode `bun test test/server/amicode-connections.test.ts test/server/pasqal-secret.test.ts test/server/amicode-connections-routes.test.ts` → 105 pass. typecheck (tsgo) green. (15 unrelated `built-in widget sources` failures are a pre-existing missing-build-artifact issue, not this diff.)

24. (upstream provider/model port — Jack, 2026-07-27) — **first deliberate partial upstream sync.** Our base is sst/opencode `v1.17.3` (2026-06-10); upstream was 1,150 commits ahead at v1.18.7. Rather than a full merge (54 fork-touched files overlap), only the provider/model bucket was ported, because Claude 5 was silently broken at our base.
- THE BUG: `anthropicOpus47OrLater()` matched `/opus-(\d+)[.-](\d+)/` — requires BOTH major and minor. `claude-opus-5` has no minor and `claude-sonnet-5` isn't "opus", so neither matched. Both fell through to the legacy `thinking:{type:"enabled",budgetTokens:16000}` path with only `high`/`max` tiers, instead of the 5-tier `type:"adaptive"` path. Sonnet 5 released 2026-06-29 and Opus 5 on 2026-07-24 — both AFTER our fork point. Upstream fixed this in #38757 (generalize Claude adaptive thinking): the version regex now tolerates a missing minor and defaults unversioned Claude IDs to modern.
- NOT a "new models" problem: the catalog is fetched live from models.dev at BUILD time (`script/generate.ts`; `amicode-release.yml` pins no snapshot), so Opus 5 already appeared in the picker — just hobbled. QA-ing "can I select Opus 5?" gives a false negative on the need to sync.
- WHAT WAS PORTED (deliberately minimal — the END STATE of files, not 112 commits of history):
- `packages/opencode/src/provider/transform.ts` — replaced wholesale with upstream/dev. Fork had never touched it → 0 conflicts. Also carries #38424 (prompt cache keys by SDK), #36624/#36543 (derive variants from reasoning metadata), and the Grok/GLM/Bedrock-Mantle variant fixes.
- `packages/opencode/test/provider/transform.test.ts` — replaced wholesale with upstream/dev (our copy asserted 6 now-superseded behaviors).
- `packages/core/src/models-dev.ts` — ADDITIVE only: upstream's `ReasoningOption` union + optional `reasoning_options` field on `Model`. transform.ts reads it; without it the port is 4 type errors.
- `packages/opencode/src/session/llm/request.ts` — 3-way merged (`git merge-file` ours/v1.17.3/upstream), 0 conflicts. Brings upstream #33392 (`strict: false` on tools for `@ai-sdk/openai`, `@ai-sdk/azure`, `@ai-sdk/amazon-bedrock/mantle`). **amicode patch #18 (PROMPT_COMMUNICATING) is preserved** — different region of the file.
- WHAT WAS DELIBERATELY NOT PORTED: the Effect `layer-node → app-node` refactor and the `@opencode-ai/schema` extraction (upstream gutted `core/src/model.ts` 127→41 and `core/src/provider.ts` 85→25 into a new package). Cherry-picking the bucket's 112 commits would drag both in. Take file end-states, not history.
- MEASURED BLAST RADIUS: ran both transform versions over all 454 reasoning models in the live models.dev catalog — **418 identical, 36 changed, 0 errors**. The 36: Claude 5 (opus/sonnet, across `anthropic` + all `amazon-bedrock` regions + `opencode` zen) goes `high,max` → `low,medium,high,xhigh,max` with `type:"adaptive"`; xAI Grok 4.3/4.5/4.20/build and GLM-5.2 gain effort variants where they previously had NONE; `claude-opus-4-5` keeps its `low,medium,high` keys but now also sends `budgetTokens:16000` alongside `effort`. Claude 4.8/4.6/4.1 unchanged.
- VERIFICATION: `tsgo --noEmit` green on packages/opencode AND packages/core. `bun test test/provider/` → 503 pass / 0 fail. `bun test test/session/ test/server/` → identical results before and after the port (3 pre-existing `llm-native-recorded` failures + a pre-existing Bun 1.3.14 teardown segfault, both reproduced byte-for-byte on the unported tree).
- STILL UNVERIFIED (needs live API creds): whether the OLD legacy `thinking:{type:"enabled",budgetTokens}` form actually 400s against Opus 5 or merely degrades — i.e. whether this was "hobbled" or "unusable". Also unexercised by CI: the Grok/GLM effort variants and the opus-4-5 `budgetTokens`+`effort` combination.
- FUTURE SYNC COST: this is a knowing trade — porting file end-states now makes a future clean upstream merge harder on these 4 files. Accepted. NOTE the bug class recurs every model generation (version-regex parsing of model IDs will break again at Opus 6), which argues for a standing narrow sync lane on `transform.ts` rather than one-off unfreezes.
- SEPARATE RISK SPOTTED (not fixed here): the release build does a bare `fetch(models.dev/api.json)` with no fallback, so a models.dev outage hard-fails the build. Consider pinning `MODELS_DEV_API_JSON` for the hackathon build.
19 changes: 19 additions & 0 deletions packages/core/src/models-dev.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,6 +43,24 @@ const Cost = Schema.Struct({
),
})

// How a model exposes its reasoning control in the models.dev catalog. Ported
// from upstream alongside provider/transform.ts — the transform derives thinking
// variants from this instead of pattern-matching model IDs. See AMICODE-PATCHES.md.
const ReasoningOption = Schema.Union([
Schema.Struct({
type: Schema.Literal("effort"),
values: Schema.Array(Schema.NullOr(Schema.String)),
}),
Schema.Struct({
type: Schema.Literal("toggle"),
}),
Schema.Struct({
type: Schema.Literal("budget_tokens"),
min: Schema.optional(Schema.Finite),
max: Schema.optional(Schema.Finite),
}),
])

export const Model = Schema.Struct({
id: Schema.String,
name: Schema.String,
Expand All@@ -52,6 +70,7 @@ export const Model = Schema.Struct({
reasoning: Schema.Boolean,
temperature: Schema.Boolean,
tool_call: Schema.Boolean,
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions AMICODE-PATCHES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -265,16 +265,14 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
if something else (e.g. the harmoniqs website dev server) holds 3000.
- Checks: `tsgo -b` clean; `bun run test:unit` 376 pass / 0 fail.

15. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).
10. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).

> ⚠️ **LICENSE-PENDING — release blocker.** "Aero" by Nirmal Biswas (Picatype) is donationware, USD 25+ to nirmalbiswas@gmail.com. Bundled at `packages/app/public/assets/Aero-Regular.ttf` for PREVIEW ONLY; not locked as the official face. Before any release: pay the license and record proof here, or drop `'Aero'` from both `font-family` chains + remove its `@font-face` (index.css) + the asset.

- index.css: new `@font-face` for "Aero" (truetype, weight 400, `font-display: swap`), inserted immediately before the existing Racing Sans One face; carries the license-pending comment inline.
- New asset (git-added): `public/assets/Aero-Regular.ttf` (44,464 B).
- Verify: `bun run typecheck` green in both `packages/ui` and `packages/app` (tsgo, no errors). Visual/glyph confirmation is manual-only (see build note under #16, which builds and vendors this alongside the paste fix).

16. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.

11. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.
- platform.tsx: new optional capability `readClipboardText?(): Promise<string | null>`, alongside the existing `readClipboardImage?`.
- entry.tsx: implements it — no-op (`null`) when not framed (`window.parent === window`, i.e. plain browser/opencode.ai/desktop — zero behavior change there); when framed, posts `{source:"amicode", kind:"clipboard-request", nonce}` to `window.parent` and resolves on the matching `{kind:"clipboard", nonce}` reply or a 1500 ms timeout — same nonce/timeout/listener shape as the proven `readClipboardViaBridge`, just exposed as a platform capability instead of a component-local closure (this file already hosts the analogous `readClipboardImage`).
- attachments.ts: `handlePaste` no longer bails out when `event.clipboardData` is null (only when it's ALSO missing `readClipboardText`, i.e. non-amicode contexts are untouched); after the existing file/image-bridge attempts, falls back to `readClipboardText()` when there's still no plain text.
Expand All@@ -288,7 +286,7 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Tests: same 376/376 pass (app suite), typecheck green — no regressions. No unit coverage added, same house-precedent reasoning as above (DOM/postMessage bridge code, build+manual verified here).
- **Final build sha256 (covers #15 + #16 + this addendum together):** `115216e82a6db15843fca46d5b32b587ba9a1e542297501cf2b45c394f745ea9`. Verify: smoke test `--version` → `1.17.3`; string-literal checks confirm the underlying protocol compiled in (`Aero` ×5, `clipboard-request` ×2, `readClipboardText` ×3 — note: the new `installGlobalPasteFallback`/`isFormField` are local identifiers, not string literals, so they're minifier-renamed and don't grep-match; absence there is expected, not a failure signal); channel gate ON (`newLayoutDesigns` sentinel `=!0`). **Interactive Cmd/Ctrl+V confirmation (composer AND the generalized fallback) is live-VS-Code-only, NOT yet human-verified past Aaron's one negative report on the pre-addendum build** — same deferred-to-dev-host-acceptance caveat as patches #12/#13.

17. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.
12. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.

- Trigger: amicode's mark was redesigned (PR #99) without a corresponding update here — the fork still rendered the OLD "digi" pixel-accented H-robot everywhere. PR #99 went through several iterations before landing on its final geometry; this entry tracks that FINAL state (square viewBox `0 0 3600 3600`), not the intermediate "hackathon mark" (viewBox `116 287 3377 3035`) an earlier draft of this fork PR had copied — that intermediate geometry is now itself stale and was replaced here.
- Two copies of near-identical geometry lived in THIS repo (logo.tsx's `Robot` used by `Mark`/`Splash`, and spinner.tsx's `AmicoSpinner`), plus a third in favicon/amico.svg. Consolidated to a single `MARK_PATH` exported from logo.tsx.
Expand DownExpand Up@@ -340,3 +338,18 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Service account (`client_credentials`) is the documented exit condition (retires the password entirely, ADR-clean); request is with Pasqal (Baptiste Peyras). Browser/device/token/refresh paths are evidence-ruled-out (see #194); the scaffold's tolerant method model harmlessly still parses `auth_methods` if a future server ever advertises them.
- CAVEAT (cannot be verified here): the real @napi-rs/keyring backend + its load inside the bun-compiled binary needs a real-machine smoke test before trusted, and the dep must be added to packages/opencode/package.json (node-pty/tree-sitter precedent). All LOGIC is tested behind the injected in-memory store.
- Tests: pasqal-secret.test.ts +5; amicode-connections.test.ts +6 silent-reauth (store-on-submit / re-mint / reject-wipes / unreachable-stands / disconnect-wipes / secret-free-response) + hermetic secret-store isolation in setup; existing expiry test made explicit about the no-password fallback. opencode `bun test test/server/amicode-connections.test.ts test/server/pasqal-secret.test.ts test/server/amicode-connections-routes.test.ts` → 105 pass. typecheck (tsgo) green. (15 unrelated `built-in widget sources` failures are a pre-existing missing-build-artifact issue, not this diff.)

24. (upstream provider/model port — Jack, 2026-07-27) — **first deliberate partial upstream sync.** Our base is sst/opencode `v1.17.3` (2026-06-10); upstream was 1,150 commits ahead at v1.18.7. Rather than a full merge (54 fork-touched files overlap), only the provider/model bucket was ported, because Claude 5 was silently broken at our base.
- THE BUG: `anthropicOpus47OrLater()` matched `/opus-(\d+)[.-](\d+)/` — requires BOTH major and minor. `claude-opus-5` has no minor and `claude-sonnet-5` isn't "opus", so neither matched. Both fell through to the legacy `thinking:{type:"enabled",budgetTokens:16000}` path with only `high`/`max` tiers, instead of the 5-tier `type:"adaptive"` path. Sonnet 5 released 2026-06-29 and Opus 5 on 2026-07-24 — both AFTER our fork point. Upstream fixed this in #38757 (generalize Claude adaptive thinking): the version regex now tolerates a missing minor and defaults unversioned Claude IDs to modern.
- NOT a "new models" problem: the catalog is fetched live from models.dev at BUILD time (`script/generate.ts`; `amicode-release.yml` pins no snapshot), so Opus 5 already appeared in the picker — just hobbled. QA-ing "can I select Opus 5?" gives a false negative on the need to sync.
- WHAT WAS PORTED (deliberately minimal — the END STATE of files, not 112 commits of history):
- `packages/opencode/src/provider/transform.ts` — replaced wholesale with upstream/dev. Fork had never touched it → 0 conflicts. Also carries #38424 (prompt cache keys by SDK), #36624/#36543 (derive variants from reasoning metadata), and the Grok/GLM/Bedrock-Mantle variant fixes.
- `packages/opencode/test/provider/transform.test.ts` — replaced wholesale with upstream/dev (our copy asserted 6 now-superseded behaviors).
- `packages/core/src/models-dev.ts` — ADDITIVE only: upstream's `ReasoningOption` union + optional `reasoning_options` field on `Model`. transform.ts reads it; without it the port is 4 type errors.
- `packages/opencode/src/session/llm/request.ts` — 3-way merged (`git merge-file` ours/v1.17.3/upstream), 0 conflicts. Brings upstream #33392 (`strict: false` on tools for `@ai-sdk/openai`, `@ai-sdk/azure`, `@ai-sdk/amazon-bedrock/mantle`). **amicode patch #18 (PROMPT_COMMUNICATING) is preserved** — different region of the file.
- WHAT WAS DELIBERATELY NOT PORTED: the Effect `layer-node → app-node` refactor and the `@opencode-ai/schema` extraction (upstream gutted `core/src/model.ts` 127→41 and `core/src/provider.ts` 85→25 into a new package). Cherry-picking the bucket's 112 commits would drag both in. Take file end-states, not history.
- MEASURED BLAST RADIUS: ran both transform versions over all 454 reasoning models in the live models.dev catalog — **418 identical, 36 changed, 0 errors**. The 36: Claude 5 (opus/sonnet, across `anthropic` + all `amazon-bedrock` regions + `opencode` zen) goes `high,max` → `low,medium,high,xhigh,max` with `type:"adaptive"`; xAI Grok 4.3/4.5/4.20/build and GLM-5.2 gain effort variants where they previously had NONE; `claude-opus-4-5` keeps its `low,medium,high` keys but now also sends `budgetTokens:16000` alongside `effort`. Claude 4.8/4.6/4.1 unchanged.
- VERIFICATION: `tsgo --noEmit` green on packages/opencode AND packages/core. `bun test test/provider/` → 503 pass / 0 fail. `bun test test/session/ test/server/` → identical results before and after the port (3 pre-existing `llm-native-recorded` failures + a pre-existing Bun 1.3.14 teardown segfault, both reproduced byte-for-byte on the unported tree).
- STILL UNVERIFIED (needs live API creds): whether the OLD legacy `thinking:{type:"enabled",budgetTokens}` form actually 400s against Opus 5 or merely degrades — i.e. whether this was "hobbled" or "unusable". Also unexercised by CI: the Grok/GLM effort variants and the opus-4-5 `budgetTokens`+`effort` combination.
- FUTURE SYNC COST: this is a knowing trade — porting file end-states now makes a future clean upstream merge harder on these 4 files. Accepted. NOTE the bug class recurs every model generation (version-regex parsing of model IDs will break again at Opus 6), which argues for a standing narrow sync lane on `transform.ts` rather than one-off unfreezes.
- SEPARATE RISK SPOTTED (not fixed here): the release build does a bare `fetch(models.dev/api.json)` with no fallback, so a models.dev outage hard-fails the build. Consider pinning `MODELS_DEV_API_JSON` for the hackathon build.
19 changes: 19 additions & 0 deletions packages/core/src/models-dev.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,6 +43,24 @@ const Cost = Schema.Struct({
),
})

// How a model exposes its reasoning control in the models.dev catalog. Ported
// from upstream alongside provider/transform.ts — the transform derives thinking
// variants from this instead of pattern-matching model IDs. See AMICODE-PATCHES.md.
const ReasoningOption = Schema.Union([
Schema.Struct({
type: Schema.Literal("effort"),
values: Schema.Array(Schema.NullOr(Schema.String)),
}),
Schema.Struct({
type: Schema.Literal("toggle"),
}),
Schema.Struct({
type: Schema.Literal("budget_tokens"),
min: Schema.optional(Schema.Finite),
max: Schema.optional(Schema.Finite),
}),
])

export const Model = Schema.Struct({
id: Schema.String,
name: Schema.String,
Expand All@@ -52,6 +70,7 @@ export const Model = Schema.Struct({
reasoning: Schema.Boolean,
temperature: Schema.Boolean,
tool_call: Schema.Boolean,
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions AMICODE-PATCHES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -265,16 +265,14 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
if something else (e.g. the harmoniqs website dev server) holds 3000.
- Checks: `tsgo -b` clean; `bun run test:unit` 376 pass / 0 fail.

15. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).
10. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).

> ⚠️ **LICENSE-PENDING — release blocker.** "Aero" by Nirmal Biswas (Picatype) is donationware, USD 25+ to nirmalbiswas@gmail.com. Bundled at `packages/app/public/assets/Aero-Regular.ttf` for PREVIEW ONLY; not locked as the official face. Before any release: pay the license and record proof here, or drop `'Aero'` from both `font-family` chains + remove its `@font-face` (index.css) + the asset.

- index.css: new `@font-face` for "Aero" (truetype, weight 400, `font-display: swap`), inserted immediately before the existing Racing Sans One face; carries the license-pending comment inline.
- New asset (git-added): `public/assets/Aero-Regular.ttf` (44,464 B).
- Verify: `bun run typecheck` green in both `packages/ui` and `packages/app` (tsgo, no errors). Visual/glyph confirmation is manual-only (see build note under #16, which builds and vendors this alongside the paste fix).

16. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.

11. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.
- platform.tsx: new optional capability `readClipboardText?(): Promise<string | null>`, alongside the existing `readClipboardImage?`.
- entry.tsx: implements it — no-op (`null`) when not framed (`window.parent === window`, i.e. plain browser/opencode.ai/desktop — zero behavior change there); when framed, posts `{source:"amicode", kind:"clipboard-request", nonce}` to `window.parent` and resolves on the matching `{kind:"clipboard", nonce}` reply or a 1500 ms timeout — same nonce/timeout/listener shape as the proven `readClipboardViaBridge`, just exposed as a platform capability instead of a component-local closure (this file already hosts the analogous `readClipboardImage`).
- attachments.ts: `handlePaste` no longer bails out when `event.clipboardData` is null (only when it's ALSO missing `readClipboardText`, i.e. non-amicode contexts are untouched); after the existing file/image-bridge attempts, falls back to `readClipboardText()` when there's still no plain text.
Expand All@@ -288,7 +286,7 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Tests: same 376/376 pass (app suite), typecheck green — no regressions. No unit coverage added, same house-precedent reasoning as above (DOM/postMessage bridge code, build+manual verified here).
- **Final build sha256 (covers #15 + #16 + this addendum together):** `115216e82a6db15843fca46d5b32b587ba9a1e542297501cf2b45c394f745ea9`. Verify: smoke test `--version` → `1.17.3`; string-literal checks confirm the underlying protocol compiled in (`Aero` ×5, `clipboard-request` ×2, `readClipboardText` ×3 — note: the new `installGlobalPasteFallback`/`isFormField` are local identifiers, not string literals, so they're minifier-renamed and don't grep-match; absence there is expected, not a failure signal); channel gate ON (`newLayoutDesigns` sentinel `=!0`). **Interactive Cmd/Ctrl+V confirmation (composer AND the generalized fallback) is live-VS-Code-only, NOT yet human-verified past Aaron's one negative report on the pre-addendum build** — same deferred-to-dev-host-acceptance caveat as patches #12/#13.

17. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.
12. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.

- Trigger: amicode's mark was redesigned (PR #99) without a corresponding update here — the fork still rendered the OLD "digi" pixel-accented H-robot everywhere. PR #99 went through several iterations before landing on its final geometry; this entry tracks that FINAL state (square viewBox `0 0 3600 3600`), not the intermediate "hackathon mark" (viewBox `116 287 3377 3035`) an earlier draft of this fork PR had copied — that intermediate geometry is now itself stale and was replaced here.
- Two copies of near-identical geometry lived in THIS repo (logo.tsx's `Robot` used by `Mark`/`Splash`, and spinner.tsx's `AmicoSpinner`), plus a third in favicon/amico.svg. Consolidated to a single `MARK_PATH` exported from logo.tsx.
Expand DownExpand Up@@ -340,3 +338,18 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Service account (`client_credentials`) is the documented exit condition (retires the password entirely, ADR-clean); request is with Pasqal (Baptiste Peyras). Browser/device/token/refresh paths are evidence-ruled-out (see #194); the scaffold's tolerant method model harmlessly still parses `auth_methods` if a future server ever advertises them.
- CAVEAT (cannot be verified here): the real @napi-rs/keyring backend + its load inside the bun-compiled binary needs a real-machine smoke test before trusted, and the dep must be added to packages/opencode/package.json (node-pty/tree-sitter precedent). All LOGIC is tested behind the injected in-memory store.
- Tests: pasqal-secret.test.ts +5; amicode-connections.test.ts +6 silent-reauth (store-on-submit / re-mint / reject-wipes / unreachable-stands / disconnect-wipes / secret-free-response) + hermetic secret-store isolation in setup; existing expiry test made explicit about the no-password fallback. opencode `bun test test/server/amicode-connections.test.ts test/server/pasqal-secret.test.ts test/server/amicode-connections-routes.test.ts` → 105 pass. typecheck (tsgo) green. (15 unrelated `built-in widget sources` failures are a pre-existing missing-build-artifact issue, not this diff.)

24. (upstream provider/model port — Jack, 2026-07-27) — **first deliberate partial upstream sync.** Our base is sst/opencode `v1.17.3` (2026-06-10); upstream was 1,150 commits ahead at v1.18.7. Rather than a full merge (54 fork-touched files overlap), only the provider/model bucket was ported, because Claude 5 was silently broken at our base.
- THE BUG: `anthropicOpus47OrLater()` matched `/opus-(\d+)[.-](\d+)/` — requires BOTH major and minor. `claude-opus-5` has no minor and `claude-sonnet-5` isn't "opus", so neither matched. Both fell through to the legacy `thinking:{type:"enabled",budgetTokens:16000}` path with only `high`/`max` tiers, instead of the 5-tier `type:"adaptive"` path. Sonnet 5 released 2026-06-29 and Opus 5 on 2026-07-24 — both AFTER our fork point. Upstream fixed this in #38757 (generalize Claude adaptive thinking): the version regex now tolerates a missing minor and defaults unversioned Claude IDs to modern.
- NOT a "new models" problem: the catalog is fetched live from models.dev at BUILD time (`script/generate.ts`; `amicode-release.yml` pins no snapshot), so Opus 5 already appeared in the picker — just hobbled. QA-ing "can I select Opus 5?" gives a false negative on the need to sync.
- WHAT WAS PORTED (deliberately minimal — the END STATE of files, not 112 commits of history):
- `packages/opencode/src/provider/transform.ts` — replaced wholesale with upstream/dev. Fork had never touched it → 0 conflicts. Also carries #38424 (prompt cache keys by SDK), #36624/#36543 (derive variants from reasoning metadata), and the Grok/GLM/Bedrock-Mantle variant fixes.
- `packages/opencode/test/provider/transform.test.ts` — replaced wholesale with upstream/dev (our copy asserted 6 now-superseded behaviors).
- `packages/core/src/models-dev.ts` — ADDITIVE only: upstream's `ReasoningOption` union + optional `reasoning_options` field on `Model`. transform.ts reads it; without it the port is 4 type errors.
- `packages/opencode/src/session/llm/request.ts` — 3-way merged (`git merge-file` ours/v1.17.3/upstream), 0 conflicts. Brings upstream #33392 (`strict: false` on tools for `@ai-sdk/openai`, `@ai-sdk/azure`, `@ai-sdk/amazon-bedrock/mantle`). **amicode patch #18 (PROMPT_COMMUNICATING) is preserved** — different region of the file.
- WHAT WAS DELIBERATELY NOT PORTED: the Effect `layer-node → app-node` refactor and the `@opencode-ai/schema` extraction (upstream gutted `core/src/model.ts` 127→41 and `core/src/provider.ts` 85→25 into a new package). Cherry-picking the bucket's 112 commits would drag both in. Take file end-states, not history.
- MEASURED BLAST RADIUS: ran both transform versions over all 454 reasoning models in the live models.dev catalog — **418 identical, 36 changed, 0 errors**. The 36: Claude 5 (opus/sonnet, across `anthropic` + all `amazon-bedrock` regions + `opencode` zen) goes `high,max` → `low,medium,high,xhigh,max` with `type:"adaptive"`; xAI Grok 4.3/4.5/4.20/build and GLM-5.2 gain effort variants where they previously had NONE; `claude-opus-4-5` keeps its `low,medium,high` keys but now also sends `budgetTokens:16000` alongside `effort`. Claude 4.8/4.6/4.1 unchanged.
- VERIFICATION: `tsgo --noEmit` green on packages/opencode AND packages/core. `bun test test/provider/` → 503 pass / 0 fail. `bun test test/session/ test/server/` → identical results before and after the port (3 pre-existing `llm-native-recorded` failures + a pre-existing Bun 1.3.14 teardown segfault, both reproduced byte-for-byte on the unported tree).
- STILL UNVERIFIED (needs live API creds): whether the OLD legacy `thinking:{type:"enabled",budgetTokens}` form actually 400s against Opus 5 or merely degrades — i.e. whether this was "hobbled" or "unusable". Also unexercised by CI: the Grok/GLM effort variants and the opus-4-5 `budgetTokens`+`effort` combination.
- FUTURE SYNC COST: this is a knowing trade — porting file end-states now makes a future clean upstream merge harder on these 4 files. Accepted. NOTE the bug class recurs every model generation (version-regex parsing of model IDs will break again at Opus 6), which argues for a standing narrow sync lane on `transform.ts` rather than one-off unfreezes.
- SEPARATE RISK SPOTTED (not fixed here): the release build does a bare `fetch(models.dev/api.json)` with no fallback, so a models.dev outage hard-fails the build. Consider pinning `MODELS_DEV_API_JSON` for the hackathon build.
19 changes: 19 additions & 0 deletions packages/core/src/models-dev.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,6 +43,24 @@ const Cost = Schema.Struct({
),
})

// How a model exposes its reasoning control in the models.dev catalog. Ported
// from upstream alongside provider/transform.ts — the transform derives thinking
// variants from this instead of pattern-matching model IDs. See AMICODE-PATCHES.md.
const ReasoningOption = Schema.Union([
Schema.Struct({
type: Schema.Literal("effort"),
values: Schema.Array(Schema.NullOr(Schema.String)),
}),
Schema.Struct({
type: Schema.Literal("toggle"),
}),
Schema.Struct({
type: Schema.Literal("budget_tokens"),
min: Schema.optional(Schema.Finite),
max: Schema.optional(Schema.Finite),
}),
])

export const Model = Schema.Struct({
id: Schema.String,
name: Schema.String,
Expand All@@ -52,6 +70,7 @@ export const Model = Schema.Struct({
reasoning: Schema.Boolean,
temperature: Schema.Boolean,
tool_call: Schema.Boolean,
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions AMICODE-PATCHES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -265,16 +265,14 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
if something else (e.g. the harmoniqs website dev server) holds 3000.
- Checks: `tsgo -b` clean; `bun run test:unit` 376 pass / 0 fail.

15. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).
10. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).

> ⚠️ **LICENSE-PENDING — release blocker.** "Aero" by Nirmal Biswas (Picatype) is donationware, USD 25+ to nirmalbiswas@gmail.com. Bundled at `packages/app/public/assets/Aero-Regular.ttf` for PREVIEW ONLY; not locked as the official face. Before any release: pay the license and record proof here, or drop `'Aero'` from both `font-family` chains + remove its `@font-face` (index.css) + the asset.

- index.css: new `@font-face` for "Aero" (truetype, weight 400, `font-display: swap`), inserted immediately before the existing Racing Sans One face; carries the license-pending comment inline.
- New asset (git-added): `public/assets/Aero-Regular.ttf` (44,464 B).
- Verify: `bun run typecheck` green in both `packages/ui` and `packages/app` (tsgo, no errors). Visual/glyph confirmation is manual-only (see build note under #16, which builds and vendors this alongside the paste fix).

16. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.

11. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.
- platform.tsx: new optional capability `readClipboardText?(): Promise<string | null>`, alongside the existing `readClipboardImage?`.
- entry.tsx: implements it — no-op (`null`) when not framed (`window.parent === window`, i.e. plain browser/opencode.ai/desktop — zero behavior change there); when framed, posts `{source:"amicode", kind:"clipboard-request", nonce}` to `window.parent` and resolves on the matching `{kind:"clipboard", nonce}` reply or a 1500 ms timeout — same nonce/timeout/listener shape as the proven `readClipboardViaBridge`, just exposed as a platform capability instead of a component-local closure (this file already hosts the analogous `readClipboardImage`).
- attachments.ts: `handlePaste` no longer bails out when `event.clipboardData` is null (only when it's ALSO missing `readClipboardText`, i.e. non-amicode contexts are untouched); after the existing file/image-bridge attempts, falls back to `readClipboardText()` when there's still no plain text.
Expand All@@ -288,7 +286,7 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Tests: same 376/376 pass (app suite), typecheck green — no regressions. No unit coverage added, same house-precedent reasoning as above (DOM/postMessage bridge code, build+manual verified here).
- **Final build sha256 (covers #15 + #16 + this addendum together):** `115216e82a6db15843fca46d5b32b587ba9a1e542297501cf2b45c394f745ea9`. Verify: smoke test `--version` → `1.17.3`; string-literal checks confirm the underlying protocol compiled in (`Aero` ×5, `clipboard-request` ×2, `readClipboardText` ×3 — note: the new `installGlobalPasteFallback`/`isFormField` are local identifiers, not string literals, so they're minifier-renamed and don't grep-match; absence there is expected, not a failure signal); channel gate ON (`newLayoutDesigns` sentinel `=!0`). **Interactive Cmd/Ctrl+V confirmation (composer AND the generalized fallback) is live-VS-Code-only, NOT yet human-verified past Aaron's one negative report on the pre-addendum build** — same deferred-to-dev-host-acceptance caveat as patches #12/#13.

17. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.
12. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.

- Trigger: amicode's mark was redesigned (PR #99) without a corresponding update here — the fork still rendered the OLD "digi" pixel-accented H-robot everywhere. PR #99 went through several iterations before landing on its final geometry; this entry tracks that FINAL state (square viewBox `0 0 3600 3600`), not the intermediate "hackathon mark" (viewBox `116 287 3377 3035`) an earlier draft of this fork PR had copied — that intermediate geometry is now itself stale and was replaced here.
- Two copies of near-identical geometry lived in THIS repo (logo.tsx's `Robot` used by `Mark`/`Splash`, and spinner.tsx's `AmicoSpinner`), plus a third in favicon/amico.svg. Consolidated to a single `MARK_PATH` exported from logo.tsx.
Expand DownExpand Up@@ -340,3 +338,18 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Service account (`client_credentials`) is the documented exit condition (retires the password entirely, ADR-clean); request is with Pasqal (Baptiste Peyras). Browser/device/token/refresh paths are evidence-ruled-out (see #194); the scaffold's tolerant method model harmlessly still parses `auth_methods` if a future server ever advertises them.
- CAVEAT (cannot be verified here): the real @napi-rs/keyring backend + its load inside the bun-compiled binary needs a real-machine smoke test before trusted, and the dep must be added to packages/opencode/package.json (node-pty/tree-sitter precedent). All LOGIC is tested behind the injected in-memory store.
- Tests: pasqal-secret.test.ts +5; amicode-connections.test.ts +6 silent-reauth (store-on-submit / re-mint / reject-wipes / unreachable-stands / disconnect-wipes / secret-free-response) + hermetic secret-store isolation in setup; existing expiry test made explicit about the no-password fallback. opencode `bun test test/server/amicode-connections.test.ts test/server/pasqal-secret.test.ts test/server/amicode-connections-routes.test.ts` → 105 pass. typecheck (tsgo) green. (15 unrelated `built-in widget sources` failures are a pre-existing missing-build-artifact issue, not this diff.)

24. (upstream provider/model port — Jack, 2026-07-27) — **first deliberate partial upstream sync.** Our base is sst/opencode `v1.17.3` (2026-06-10); upstream was 1,150 commits ahead at v1.18.7. Rather than a full merge (54 fork-touched files overlap), only the provider/model bucket was ported, because Claude 5 was silently broken at our base.
- THE BUG: `anthropicOpus47OrLater()` matched `/opus-(\d+)[.-](\d+)/` — requires BOTH major and minor. `claude-opus-5` has no minor and `claude-sonnet-5` isn't "opus", so neither matched. Both fell through to the legacy `thinking:{type:"enabled",budgetTokens:16000}` path with only `high`/`max` tiers, instead of the 5-tier `type:"adaptive"` path. Sonnet 5 released 2026-06-29 and Opus 5 on 2026-07-24 — both AFTER our fork point. Upstream fixed this in #38757 (generalize Claude adaptive thinking): the version regex now tolerates a missing minor and defaults unversioned Claude IDs to modern.
- NOT a "new models" problem: the catalog is fetched live from models.dev at BUILD time (`script/generate.ts`; `amicode-release.yml` pins no snapshot), so Opus 5 already appeared in the picker — just hobbled. QA-ing "can I select Opus 5?" gives a false negative on the need to sync.
- WHAT WAS PORTED (deliberately minimal — the END STATE of files, not 112 commits of history):
- `packages/opencode/src/provider/transform.ts` — replaced wholesale with upstream/dev. Fork had never touched it → 0 conflicts. Also carries #38424 (prompt cache keys by SDK), #36624/#36543 (derive variants from reasoning metadata), and the Grok/GLM/Bedrock-Mantle variant fixes.
- `packages/opencode/test/provider/transform.test.ts` — replaced wholesale with upstream/dev (our copy asserted 6 now-superseded behaviors).
- `packages/core/src/models-dev.ts` — ADDITIVE only: upstream's `ReasoningOption` union + optional `reasoning_options` field on `Model`. transform.ts reads it; without it the port is 4 type errors.
- `packages/opencode/src/session/llm/request.ts` — 3-way merged (`git merge-file` ours/v1.17.3/upstream), 0 conflicts. Brings upstream #33392 (`strict: false` on tools for `@ai-sdk/openai`, `@ai-sdk/azure`, `@ai-sdk/amazon-bedrock/mantle`). **amicode patch #18 (PROMPT_COMMUNICATING) is preserved** — different region of the file.
- WHAT WAS DELIBERATELY NOT PORTED: the Effect `layer-node → app-node` refactor and the `@opencode-ai/schema` extraction (upstream gutted `core/src/model.ts` 127→41 and `core/src/provider.ts` 85→25 into a new package). Cherry-picking the bucket's 112 commits would drag both in. Take file end-states, not history.
- MEASURED BLAST RADIUS: ran both transform versions over all 454 reasoning models in the live models.dev catalog — **418 identical, 36 changed, 0 errors**. The 36: Claude 5 (opus/sonnet, across `anthropic` + all `amazon-bedrock` regions + `opencode` zen) goes `high,max` → `low,medium,high,xhigh,max` with `type:"adaptive"`; xAI Grok 4.3/4.5/4.20/build and GLM-5.2 gain effort variants where they previously had NONE; `claude-opus-4-5` keeps its `low,medium,high` keys but now also sends `budgetTokens:16000` alongside `effort`. Claude 4.8/4.6/4.1 unchanged.
- VERIFICATION: `tsgo --noEmit` green on packages/opencode AND packages/core. `bun test test/provider/` → 503 pass / 0 fail. `bun test test/session/ test/server/` → identical results before and after the port (3 pre-existing `llm-native-recorded` failures + a pre-existing Bun 1.3.14 teardown segfault, both reproduced byte-for-byte on the unported tree).
- STILL UNVERIFIED (needs live API creds): whether the OLD legacy `thinking:{type:"enabled",budgetTokens}` form actually 400s against Opus 5 or merely degrades — i.e. whether this was "hobbled" or "unusable". Also unexercised by CI: the Grok/GLM effort variants and the opus-4-5 `budgetTokens`+`effort` combination.
- FUTURE SYNC COST: this is a knowing trade — porting file end-states now makes a future clean upstream merge harder on these 4 files. Accepted. NOTE the bug class recurs every model generation (version-regex parsing of model IDs will break again at Opus 6), which argues for a standing narrow sync lane on `transform.ts` rather than one-off unfreezes.
- SEPARATE RISK SPOTTED (not fixed here): the release build does a bare `fetch(models.dev/api.json)` with no fallback, so a models.dev outage hard-fails the build. Consider pinning `MODELS_DEV_API_JSON` for the hackathon build.
19 changes: 19 additions & 0 deletions packages/core/src/models-dev.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,6 +43,24 @@ const Cost = Schema.Struct({
),
})

// How a model exposes its reasoning control in the models.dev catalog. Ported
// from upstream alongside provider/transform.ts — the transform derives thinking
// variants from this instead of pattern-matching model IDs. See AMICODE-PATCHES.md.
const ReasoningOption = Schema.Union([
Schema.Struct({
type: Schema.Literal("effort"),
values: Schema.Array(Schema.NullOr(Schema.String)),
}),
Schema.Struct({
type: Schema.Literal("toggle"),
}),
Schema.Struct({
type: Schema.Literal("budget_tokens"),
min: Schema.optional(Schema.Finite),
max: Schema.optional(Schema.Finite),
}),
])

export const Model = Schema.Struct({
id: Schema.String,
name: Schema.String,
Expand All@@ -52,6 +70,7 @@ export const Model = Schema.Struct({
reasoning: Schema.Boolean,
temperature: Schema.Boolean,
tool_call: Schema.Boolean,
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions AMICODE-PATCHES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -265,16 +265,14 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
if something else (e.g. the harmoniqs website dev server) holds 3000.
- Checks: `tsgo -b` clean; `bun run test:unit` 376 pass / 0 fail.

15. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).
10. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).

> ⚠️ **LICENSE-PENDING — release blocker.** "Aero" by Nirmal Biswas (Picatype) is donationware, USD 25+ to nirmalbiswas@gmail.com. Bundled at `packages/app/public/assets/Aero-Regular.ttf` for PREVIEW ONLY; not locked as the official face. Before any release: pay the license and record proof here, or drop `'Aero'` from both `font-family` chains + remove its `@font-face` (index.css) + the asset.

- index.css: new `@font-face` for "Aero" (truetype, weight 400, `font-display: swap`), inserted immediately before the existing Racing Sans One face; carries the license-pending comment inline.
- New asset (git-added): `public/assets/Aero-Regular.ttf` (44,464 B).
- Verify: `bun run typecheck` green in both `packages/ui` and `packages/app` (tsgo, no errors). Visual/glyph confirmation is manual-only (see build note under #16, which builds and vendors this alongside the paste fix).

16. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.

11. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.
- platform.tsx: new optional capability `readClipboardText?(): Promise<string | null>`, alongside the existing `readClipboardImage?`.
- entry.tsx: implements it — no-op (`null`) when not framed (`window.parent === window`, i.e. plain browser/opencode.ai/desktop — zero behavior change there); when framed, posts `{source:"amicode", kind:"clipboard-request", nonce}` to `window.parent` and resolves on the matching `{kind:"clipboard", nonce}` reply or a 1500 ms timeout — same nonce/timeout/listener shape as the proven `readClipboardViaBridge`, just exposed as a platform capability instead of a component-local closure (this file already hosts the analogous `readClipboardImage`).
- attachments.ts: `handlePaste` no longer bails out when `event.clipboardData` is null (only when it's ALSO missing `readClipboardText`, i.e. non-amicode contexts are untouched); after the existing file/image-bridge attempts, falls back to `readClipboardText()` when there's still no plain text.
Expand All@@ -288,7 +286,7 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Tests: same 376/376 pass (app suite), typecheck green — no regressions. No unit coverage added, same house-precedent reasoning as above (DOM/postMessage bridge code, build+manual verified here).
- **Final build sha256 (covers #15 + #16 + this addendum together):** `115216e82a6db15843fca46d5b32b587ba9a1e542297501cf2b45c394f745ea9`. Verify: smoke test `--version` → `1.17.3`; string-literal checks confirm the underlying protocol compiled in (`Aero` ×5, `clipboard-request` ×2, `readClipboardText` ×3 — note: the new `installGlobalPasteFallback`/`isFormField` are local identifiers, not string literals, so they're minifier-renamed and don't grep-match; absence there is expected, not a failure signal); channel gate ON (`newLayoutDesigns` sentinel `=!0`). **Interactive Cmd/Ctrl+V confirmation (composer AND the generalized fallback) is live-VS-Code-only, NOT yet human-verified past Aaron's one negative report on the pre-addendum build** — same deferred-to-dev-host-acceptance caveat as patches #12/#13.

17. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.
12. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.

- Trigger: amicode's mark was redesigned (PR #99) without a corresponding update here — the fork still rendered the OLD "digi" pixel-accented H-robot everywhere. PR #99 went through several iterations before landing on its final geometry; this entry tracks that FINAL state (square viewBox `0 0 3600 3600`), not the intermediate "hackathon mark" (viewBox `116 287 3377 3035`) an earlier draft of this fork PR had copied — that intermediate geometry is now itself stale and was replaced here.
- Two copies of near-identical geometry lived in THIS repo (logo.tsx's `Robot` used by `Mark`/`Splash`, and spinner.tsx's `AmicoSpinner`), plus a third in favicon/amico.svg. Consolidated to a single `MARK_PATH` exported from logo.tsx.
Expand DownExpand Up@@ -340,3 +338,18 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Service account (`client_credentials`) is the documented exit condition (retires the password entirely, ADR-clean); request is with Pasqal (Baptiste Peyras). Browser/device/token/refresh paths are evidence-ruled-out (see #194); the scaffold's tolerant method model harmlessly still parses `auth_methods` if a future server ever advertises them.
- CAVEAT (cannot be verified here): the real @napi-rs/keyring backend + its load inside the bun-compiled binary needs a real-machine smoke test before trusted, and the dep must be added to packages/opencode/package.json (node-pty/tree-sitter precedent). All LOGIC is tested behind the injected in-memory store.
- Tests: pasqal-secret.test.ts +5; amicode-connections.test.ts +6 silent-reauth (store-on-submit / re-mint / reject-wipes / unreachable-stands / disconnect-wipes / secret-free-response) + hermetic secret-store isolation in setup; existing expiry test made explicit about the no-password fallback. opencode `bun test test/server/amicode-connections.test.ts test/server/pasqal-secret.test.ts test/server/amicode-connections-routes.test.ts` → 105 pass. typecheck (tsgo) green. (15 unrelated `built-in widget sources` failures are a pre-existing missing-build-artifact issue, not this diff.)

24. (upstream provider/model port — Jack, 2026-07-27) — **first deliberate partial upstream sync.** Our base is sst/opencode `v1.17.3` (2026-06-10); upstream was 1,150 commits ahead at v1.18.7. Rather than a full merge (54 fork-touched files overlap), only the provider/model bucket was ported, because Claude 5 was silently broken at our base.
- THE BUG: `anthropicOpus47OrLater()` matched `/opus-(\d+)[.-](\d+)/` — requires BOTH major and minor. `claude-opus-5` has no minor and `claude-sonnet-5` isn't "opus", so neither matched. Both fell through to the legacy `thinking:{type:"enabled",budgetTokens:16000}` path with only `high`/`max` tiers, instead of the 5-tier `type:"adaptive"` path. Sonnet 5 released 2026-06-29 and Opus 5 on 2026-07-24 — both AFTER our fork point. Upstream fixed this in #38757 (generalize Claude adaptive thinking): the version regex now tolerates a missing minor and defaults unversioned Claude IDs to modern.
- NOT a "new models" problem: the catalog is fetched live from models.dev at BUILD time (`script/generate.ts`; `amicode-release.yml` pins no snapshot), so Opus 5 already appeared in the picker — just hobbled. QA-ing "can I select Opus 5?" gives a false negative on the need to sync.
- WHAT WAS PORTED (deliberately minimal — the END STATE of files, not 112 commits of history):
- `packages/opencode/src/provider/transform.ts` — replaced wholesale with upstream/dev. Fork had never touched it → 0 conflicts. Also carries #38424 (prompt cache keys by SDK), #36624/#36543 (derive variants from reasoning metadata), and the Grok/GLM/Bedrock-Mantle variant fixes.
- `packages/opencode/test/provider/transform.test.ts` — replaced wholesale with upstream/dev (our copy asserted 6 now-superseded behaviors).
- `packages/core/src/models-dev.ts` — ADDITIVE only: upstream's `ReasoningOption` union + optional `reasoning_options` field on `Model`. transform.ts reads it; without it the port is 4 type errors.
- `packages/opencode/src/session/llm/request.ts` — 3-way merged (`git merge-file` ours/v1.17.3/upstream), 0 conflicts. Brings upstream #33392 (`strict: false` on tools for `@ai-sdk/openai`, `@ai-sdk/azure`, `@ai-sdk/amazon-bedrock/mantle`). **amicode patch #18 (PROMPT_COMMUNICATING) is preserved** — different region of the file.
- WHAT WAS DELIBERATELY NOT PORTED: the Effect `layer-node → app-node` refactor and the `@opencode-ai/schema` extraction (upstream gutted `core/src/model.ts` 127→41 and `core/src/provider.ts` 85→25 into a new package). Cherry-picking the bucket's 112 commits would drag both in. Take file end-states, not history.
- MEASURED BLAST RADIUS: ran both transform versions over all 454 reasoning models in the live models.dev catalog — **418 identical, 36 changed, 0 errors**. The 36: Claude 5 (opus/sonnet, across `anthropic` + all `amazon-bedrock` regions + `opencode` zen) goes `high,max` → `low,medium,high,xhigh,max` with `type:"adaptive"`; xAI Grok 4.3/4.5/4.20/build and GLM-5.2 gain effort variants where they previously had NONE; `claude-opus-4-5` keeps its `low,medium,high` keys but now also sends `budgetTokens:16000` alongside `effort`. Claude 4.8/4.6/4.1 unchanged.
- VERIFICATION: `tsgo --noEmit` green on packages/opencode AND packages/core. `bun test test/provider/` → 503 pass / 0 fail. `bun test test/session/ test/server/` → identical results before and after the port (3 pre-existing `llm-native-recorded` failures + a pre-existing Bun 1.3.14 teardown segfault, both reproduced byte-for-byte on the unported tree).
- STILL UNVERIFIED (needs live API creds): whether the OLD legacy `thinking:{type:"enabled",budgetTokens}` form actually 400s against Opus 5 or merely degrades — i.e. whether this was "hobbled" or "unusable". Also unexercised by CI: the Grok/GLM effort variants and the opus-4-5 `budgetTokens`+`effort` combination.
- FUTURE SYNC COST: this is a knowing trade — porting file end-states now makes a future clean upstream merge harder on these 4 files. Accepted. NOTE the bug class recurs every model generation (version-regex parsing of model IDs will break again at Opus 6), which argues for a standing narrow sync lane on `transform.ts` rather than one-off unfreezes.
- SEPARATE RISK SPOTTED (not fixed here): the release build does a bare `fetch(models.dev/api.json)` with no fallback, so a models.dev outage hard-fails the build. Consider pinning `MODELS_DEV_API_JSON` for the hackathon build.
19 changes: 19 additions & 0 deletions packages/core/src/models-dev.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,6 +43,24 @@ const Cost = Schema.Struct({
),
})

// How a model exposes its reasoning control in the models.dev catalog. Ported
// from upstream alongside provider/transform.ts — the transform derives thinking
// variants from this instead of pattern-matching model IDs. See AMICODE-PATCHES.md.
const ReasoningOption = Schema.Union([
Schema.Struct({
type: Schema.Literal("effort"),
values: Schema.Array(Schema.NullOr(Schema.String)),
}),
Schema.Struct({
type: Schema.Literal("toggle"),
}),
Schema.Struct({
type: Schema.Literal("budget_tokens"),
min: Schema.optional(Schema.Finite),
max: Schema.optional(Schema.Finite),
}),
])

export const Model = Schema.Struct({
id: Schema.String,
name: Schema.String,
Expand All@@ -52,6 +70,7 @@ export const Model = Schema.Struct({
reasoning: Schema.Boolean,
temperature: Schema.Boolean,
tool_call: Schema.Boolean,
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions AMICODE-PATCHES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -265,16 +265,14 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
if something else (e.g. the harmoniqs website dev server) holds 3000.
- Checks: `tsgo -b` clean; `bun run test:unit` 376 pass / 0 fail.

15. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).
10. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).

> ⚠️ **LICENSE-PENDING — release blocker.** "Aero" by Nirmal Biswas (Picatype) is donationware, USD 25+ to nirmalbiswas@gmail.com. Bundled at `packages/app/public/assets/Aero-Regular.ttf` for PREVIEW ONLY; not locked as the official face. Before any release: pay the license and record proof here, or drop `'Aero'` from both `font-family` chains + remove its `@font-face` (index.css) + the asset.

- index.css: new `@font-face` for "Aero" (truetype, weight 400, `font-display: swap`), inserted immediately before the existing Racing Sans One face; carries the license-pending comment inline.
- New asset (git-added): `public/assets/Aero-Regular.ttf` (44,464 B).
- Verify: `bun run typecheck` green in both `packages/ui` and `packages/app` (tsgo, no errors). Visual/glyph confirmation is manual-only (see build note under #16, which builds and vendors this alongside the paste fix).

16. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.

11. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.
- platform.tsx: new optional capability `readClipboardText?(): Promise<string | null>`, alongside the existing `readClipboardImage?`.
- entry.tsx: implements it — no-op (`null`) when not framed (`window.parent === window`, i.e. plain browser/opencode.ai/desktop — zero behavior change there); when framed, posts `{source:"amicode", kind:"clipboard-request", nonce}` to `window.parent` and resolves on the matching `{kind:"clipboard", nonce}` reply or a 1500 ms timeout — same nonce/timeout/listener shape as the proven `readClipboardViaBridge`, just exposed as a platform capability instead of a component-local closure (this file already hosts the analogous `readClipboardImage`).
- attachments.ts: `handlePaste` no longer bails out when `event.clipboardData` is null (only when it's ALSO missing `readClipboardText`, i.e. non-amicode contexts are untouched); after the existing file/image-bridge attempts, falls back to `readClipboardText()` when there's still no plain text.
Expand All@@ -288,7 +286,7 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Tests: same 376/376 pass (app suite), typecheck green — no regressions. No unit coverage added, same house-precedent reasoning as above (DOM/postMessage bridge code, build+manual verified here).
- **Final build sha256 (covers #15 + #16 + this addendum together):** `115216e82a6db15843fca46d5b32b587ba9a1e542297501cf2b45c394f745ea9`. Verify: smoke test `--version` → `1.17.3`; string-literal checks confirm the underlying protocol compiled in (`Aero` ×5, `clipboard-request` ×2, `readClipboardText` ×3 — note: the new `installGlobalPasteFallback`/`isFormField` are local identifiers, not string literals, so they're minifier-renamed and don't grep-match; absence there is expected, not a failure signal); channel gate ON (`newLayoutDesigns` sentinel `=!0`). **Interactive Cmd/Ctrl+V confirmation (composer AND the generalized fallback) is live-VS-Code-only, NOT yet human-verified past Aaron's one negative report on the pre-addendum build** — same deferred-to-dev-host-acceptance caveat as patches #12/#13.

17. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.
12. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.

- Trigger: amicode's mark was redesigned (PR #99) without a corresponding update here — the fork still rendered the OLD "digi" pixel-accented H-robot everywhere. PR #99 went through several iterations before landing on its final geometry; this entry tracks that FINAL state (square viewBox `0 0 3600 3600`), not the intermediate "hackathon mark" (viewBox `116 287 3377 3035`) an earlier draft of this fork PR had copied — that intermediate geometry is now itself stale and was replaced here.
- Two copies of near-identical geometry lived in THIS repo (logo.tsx's `Robot` used by `Mark`/`Splash`, and spinner.tsx's `AmicoSpinner`), plus a third in favicon/amico.svg. Consolidated to a single `MARK_PATH` exported from logo.tsx.
Expand DownExpand Up@@ -340,3 +338,18 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Service account (`client_credentials`) is the documented exit condition (retires the password entirely, ADR-clean); request is with Pasqal (Baptiste Peyras). Browser/device/token/refresh paths are evidence-ruled-out (see #194); the scaffold's tolerant method model harmlessly still parses `auth_methods` if a future server ever advertises them.
- CAVEAT (cannot be verified here): the real @napi-rs/keyring backend + its load inside the bun-compiled binary needs a real-machine smoke test before trusted, and the dep must be added to packages/opencode/package.json (node-pty/tree-sitter precedent). All LOGIC is tested behind the injected in-memory store.
- Tests: pasqal-secret.test.ts +5; amicode-connections.test.ts +6 silent-reauth (store-on-submit / re-mint / reject-wipes / unreachable-stands / disconnect-wipes / secret-free-response) + hermetic secret-store isolation in setup; existing expiry test made explicit about the no-password fallback. opencode `bun test test/server/amicode-connections.test.ts test/server/pasqal-secret.test.ts test/server/amicode-connections-routes.test.ts` → 105 pass. typecheck (tsgo) green. (15 unrelated `built-in widget sources` failures are a pre-existing missing-build-artifact issue, not this diff.)

24. (upstream provider/model port — Jack, 2026-07-27) — **first deliberate partial upstream sync.** Our base is sst/opencode `v1.17.3` (2026-06-10); upstream was 1,150 commits ahead at v1.18.7. Rather than a full merge (54 fork-touched files overlap), only the provider/model bucket was ported, because Claude 5 was silently broken at our base.
- THE BUG: `anthropicOpus47OrLater()` matched `/opus-(\d+)[.-](\d+)/` — requires BOTH major and minor. `claude-opus-5` has no minor and `claude-sonnet-5` isn't "opus", so neither matched. Both fell through to the legacy `thinking:{type:"enabled",budgetTokens:16000}` path with only `high`/`max` tiers, instead of the 5-tier `type:"adaptive"` path. Sonnet 5 released 2026-06-29 and Opus 5 on 2026-07-24 — both AFTER our fork point. Upstream fixed this in #38757 (generalize Claude adaptive thinking): the version regex now tolerates a missing minor and defaults unversioned Claude IDs to modern.
- NOT a "new models" problem: the catalog is fetched live from models.dev at BUILD time (`script/generate.ts`; `amicode-release.yml` pins no snapshot), so Opus 5 already appeared in the picker — just hobbled. QA-ing "can I select Opus 5?" gives a false negative on the need to sync.
- WHAT WAS PORTED (deliberately minimal — the END STATE of files, not 112 commits of history):
- `packages/opencode/src/provider/transform.ts` — replaced wholesale with upstream/dev. Fork had never touched it → 0 conflicts. Also carries #38424 (prompt cache keys by SDK), #36624/#36543 (derive variants from reasoning metadata), and the Grok/GLM/Bedrock-Mantle variant fixes.
- `packages/opencode/test/provider/transform.test.ts` — replaced wholesale with upstream/dev (our copy asserted 6 now-superseded behaviors).
- `packages/core/src/models-dev.ts` — ADDITIVE only: upstream's `ReasoningOption` union + optional `reasoning_options` field on `Model`. transform.ts reads it; without it the port is 4 type errors.
- `packages/opencode/src/session/llm/request.ts` — 3-way merged (`git merge-file` ours/v1.17.3/upstream), 0 conflicts. Brings upstream #33392 (`strict: false` on tools for `@ai-sdk/openai`, `@ai-sdk/azure`, `@ai-sdk/amazon-bedrock/mantle`). **amicode patch #18 (PROMPT_COMMUNICATING) is preserved** — different region of the file.
- WHAT WAS DELIBERATELY NOT PORTED: the Effect `layer-node → app-node` refactor and the `@opencode-ai/schema` extraction (upstream gutted `core/src/model.ts` 127→41 and `core/src/provider.ts` 85→25 into a new package). Cherry-picking the bucket's 112 commits would drag both in. Take file end-states, not history.
- MEASURED BLAST RADIUS: ran both transform versions over all 454 reasoning models in the live models.dev catalog — **418 identical, 36 changed, 0 errors**. The 36: Claude 5 (opus/sonnet, across `anthropic` + all `amazon-bedrock` regions + `opencode` zen) goes `high,max` → `low,medium,high,xhigh,max` with `type:"adaptive"`; xAI Grok 4.3/4.5/4.20/build and GLM-5.2 gain effort variants where they previously had NONE; `claude-opus-4-5` keeps its `low,medium,high` keys but now also sends `budgetTokens:16000` alongside `effort`. Claude 4.8/4.6/4.1 unchanged.
- VERIFICATION: `tsgo --noEmit` green on packages/opencode AND packages/core. `bun test test/provider/` → 503 pass / 0 fail. `bun test test/session/ test/server/` → identical results before and after the port (3 pre-existing `llm-native-recorded` failures + a pre-existing Bun 1.3.14 teardown segfault, both reproduced byte-for-byte on the unported tree).
- STILL UNVERIFIED (needs live API creds): whether the OLD legacy `thinking:{type:"enabled",budgetTokens}` form actually 400s against Opus 5 or merely degrades — i.e. whether this was "hobbled" or "unusable". Also unexercised by CI: the Grok/GLM effort variants and the opus-4-5 `budgetTokens`+`effort` combination.
- FUTURE SYNC COST: this is a knowing trade — porting file end-states now makes a future clean upstream merge harder on these 4 files. Accepted. NOTE the bug class recurs every model generation (version-regex parsing of model IDs will break again at Opus 6), which argues for a standing narrow sync lane on `transform.ts` rather than one-off unfreezes.
- SEPARATE RISK SPOTTED (not fixed here): the release build does a bare `fetch(models.dev/api.json)` with no fallback, so a models.dev outage hard-fails the build. Consider pinning `MODELS_DEV_API_JSON` for the hackathon build.
19 changes: 19 additions & 0 deletions packages/core/src/models-dev.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,6 +43,24 @@ const Cost = Schema.Struct({
),
})

// How a model exposes its reasoning control in the models.dev catalog. Ported
// from upstream alongside provider/transform.ts — the transform derives thinking
// variants from this instead of pattern-matching model IDs. See AMICODE-PATCHES.md.
const ReasoningOption = Schema.Union([
Schema.Struct({
type: Schema.Literal("effort"),
values: Schema.Array(Schema.NullOr(Schema.String)),
}),
Schema.Struct({
type: Schema.Literal("toggle"),
}),
Schema.Struct({
type: Schema.Literal("budget_tokens"),
min: Schema.optional(Schema.Finite),
max: Schema.optional(Schema.Finite),
}),
])

export const Model = Schema.Struct({
id: Schema.String,
name: Schema.String,
Expand All@@ -52,6 +70,7 @@ export const Model = Schema.Struct({
reasoning: Schema.Boolean,
temperature: Schema.Boolean,
tool_call: Schema.Boolean,
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions AMICODE-PATCHES.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -265,16 +265,14 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
if something else (e.g. the harmoniqs website dev server) holds 3000.
- Checks: `tsgo -b` clean; `bun run test:unit` 376 pass / 0 fail.

15. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).
10. (Aero wordmark, re-added) — amicode: AMICODE wordmark/logo font-family gains `'Aero'` ahead of the existing fallback chain, both call sites: logo.tsx (`'Aero', var(--font-family-sans, ...)`) and wordmark-v2.tsx (`'Aero', 'Racing Sans One', var(--font-family-mono, ...)`). Additive only — no fallback removed, no sizing/weight/spacing touched. This had been iterated as uncommitted working-tree WIP before the branch fast-forwarded 57 commits to current `origin/local/amicode` (e9b695191); re-applied fresh against the current font stacks (logo.tsx's had independently moved to a sans-serif stack + weight 750/letter-spacing 4 in the interim — preserved as-is, only the family list changed).

> ⚠️ **LICENSE-PENDING — release blocker.** "Aero" by Nirmal Biswas (Picatype) is donationware, USD 25+ to nirmalbiswas@gmail.com. Bundled at `packages/app/public/assets/Aero-Regular.ttf` for PREVIEW ONLY; not locked as the official face. Before any release: pay the license and record proof here, or drop `'Aero'` from both `font-family` chains + remove its `@font-face` (index.css) + the asset.

- index.css: new `@font-face` for "Aero" (truetype, weight 400, `font-display: swap`), inserted immediately before the existing Racing Sans One face; carries the license-pending comment inline.
- New asset (git-added): `public/assets/Aero-Regular.ttf` (44,464 B).
- Verify: `bun run typecheck` green in both `packages/ui` and `packages/app` (tsgo, no errors). Visual/glyph confirmation is manual-only (see build note under #16, which builds and vendors this alongside the paste fix).

16. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.

11. (composer paste bridge) — amicode: wire the main chat composer's `handlePaste` (prompt-input/attachments.ts) to the extension-clipboard bridge that patch #14's PR already shipped for a different input (home-cards.tsx's `readClipboardViaBridge`/`pasteFallback`, commit `5a2f1dde44`) — that bridge answers `{source:"amicode", kind:"clipboard-request"}` on the extension side (`packages/extension/src/chat_panel.ts`, already on `main`), but nothing in the composer's own paste path ever sent it. Root cause matches home-cards.tsx's own comment verbatim: the chat iframe is sandboxed + cross-origin, so `navigator.clipboard` is denied and the native `paste` event's `clipboardData` arrives empty — Cmd/Ctrl+V into the composer was a silent no-op.
- platform.tsx: new optional capability `readClipboardText?(): Promise<string | null>`, alongside the existing `readClipboardImage?`.
- entry.tsx: implements it — no-op (`null`) when not framed (`window.parent === window`, i.e. plain browser/opencode.ai/desktop — zero behavior change there); when framed, posts `{source:"amicode", kind:"clipboard-request", nonce}` to `window.parent` and resolves on the matching `{kind:"clipboard", nonce}` reply or a 1500 ms timeout — same nonce/timeout/listener shape as the proven `readClipboardViaBridge`, just exposed as a platform capability instead of a component-local closure (this file already hosts the analogous `readClipboardImage`).
- attachments.ts: `handlePaste` no longer bails out when `event.clipboardData` is null (only when it's ALSO missing `readClipboardText`, i.e. non-amicode contexts are untouched); after the existing file/image-bridge attempts, falls back to `readClipboardText()` when there's still no plain text.
Expand All@@ -288,7 +286,7 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Tests: same 376/376 pass (app suite), typecheck green — no regressions. No unit coverage added, same house-precedent reasoning as above (DOM/postMessage bridge code, build+manual verified here).
- **Final build sha256 (covers #15 + #16 + this addendum together):** `115216e82a6db15843fca46d5b32b587ba9a1e542297501cf2b45c394f745ea9`. Verify: smoke test `--version` → `1.17.3`; string-literal checks confirm the underlying protocol compiled in (`Aero` ×5, `clipboard-request` ×2, `readClipboardText` ×3 — note: the new `installGlobalPasteFallback`/`isFormField` are local identifiers, not string literals, so they're minifier-renamed and don't grep-match; absence there is expected, not a failure signal); channel gate ON (`newLayoutDesigns` sentinel `=!0`). **Interactive Cmd/Ctrl+V confirmation (composer AND the generalized fallback) is live-VS-Code-only, NOT yet human-verified past Aaron's one negative report on the pre-addendum build** — same deferred-to-dev-host-acceptance caveat as patches #12/#13.

17. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.
12. (mark drift fix, synced to amicode PR #99 final) — amicode: consolidated the fork's brand mark to ONE geometry, matching amicode's redesigned mark. The "kept in sync manually" cross-repo promise from patch #8 had already silently failed.

- Trigger: amicode's mark was redesigned (PR #99) without a corresponding update here — the fork still rendered the OLD "digi" pixel-accented H-robot everywhere. PR #99 went through several iterations before landing on its final geometry; this entry tracks that FINAL state (square viewBox `0 0 3600 3600`), not the intermediate "hackathon mark" (viewBox `116 287 3377 3035`) an earlier draft of this fork PR had copied — that intermediate geometry is now itself stale and was replaced here.
- Two copies of near-identical geometry lived in THIS repo (logo.tsx's `Robot` used by `Mark`/`Splash`, and spinner.tsx's `AmicoSpinner`), plus a third in favicon/amico.svg. Consolidated to a single `MARK_PATH` exported from logo.tsx.
Expand DownExpand Up@@ -340,3 +338,18 @@ Rebuilt with the exact T3 recipe (`OPENCODE_VERSION=1.17.3 bun run script/build.
- Service account (`client_credentials`) is the documented exit condition (retires the password entirely, ADR-clean); request is with Pasqal (Baptiste Peyras). Browser/device/token/refresh paths are evidence-ruled-out (see #194); the scaffold's tolerant method model harmlessly still parses `auth_methods` if a future server ever advertises them.
- CAVEAT (cannot be verified here): the real @napi-rs/keyring backend + its load inside the bun-compiled binary needs a real-machine smoke test before trusted, and the dep must be added to packages/opencode/package.json (node-pty/tree-sitter precedent). All LOGIC is tested behind the injected in-memory store.
- Tests: pasqal-secret.test.ts +5; amicode-connections.test.ts +6 silent-reauth (store-on-submit / re-mint / reject-wipes / unreachable-stands / disconnect-wipes / secret-free-response) + hermetic secret-store isolation in setup; existing expiry test made explicit about the no-password fallback. opencode `bun test test/server/amicode-connections.test.ts test/server/pasqal-secret.test.ts test/server/amicode-connections-routes.test.ts` → 105 pass. typecheck (tsgo) green. (15 unrelated `built-in widget sources` failures are a pre-existing missing-build-artifact issue, not this diff.)

24. (upstream provider/model port — Jack, 2026-07-27) — **first deliberate partial upstream sync.** Our base is sst/opencode `v1.17.3` (2026-06-10); upstream was 1,150 commits ahead at v1.18.7. Rather than a full merge (54 fork-touched files overlap), only the provider/model bucket was ported, because Claude 5 was silently broken at our base.
- THE BUG: `anthropicOpus47OrLater()` matched `/opus-(\d+)[.-](\d+)/` — requires BOTH major and minor. `claude-opus-5` has no minor and `claude-sonnet-5` isn't "opus", so neither matched. Both fell through to the legacy `thinking:{type:"enabled",budgetTokens:16000}` path with only `high`/`max` tiers, instead of the 5-tier `type:"adaptive"` path. Sonnet 5 released 2026-06-29 and Opus 5 on 2026-07-24 — both AFTER our fork point. Upstream fixed this in #38757 (generalize Claude adaptive thinking): the version regex now tolerates a missing minor and defaults unversioned Claude IDs to modern.
- NOT a "new models" problem: the catalog is fetched live from models.dev at BUILD time (`script/generate.ts`; `amicode-release.yml` pins no snapshot), so Opus 5 already appeared in the picker — just hobbled. QA-ing "can I select Opus 5?" gives a false negative on the need to sync.
- WHAT WAS PORTED (deliberately minimal — the END STATE of files, not 112 commits of history):
- `packages/opencode/src/provider/transform.ts` — replaced wholesale with upstream/dev. Fork had never touched it → 0 conflicts. Also carries #38424 (prompt cache keys by SDK), #36624/#36543 (derive variants from reasoning metadata), and the Grok/GLM/Bedrock-Mantle variant fixes.
- `packages/opencode/test/provider/transform.test.ts` — replaced wholesale with upstream/dev (our copy asserted 6 now-superseded behaviors).
- `packages/core/src/models-dev.ts` — ADDITIVE only: upstream's `ReasoningOption` union + optional `reasoning_options` field on `Model`. transform.ts reads it; without it the port is 4 type errors.
- `packages/opencode/src/session/llm/request.ts` — 3-way merged (`git merge-file` ours/v1.17.3/upstream), 0 conflicts. Brings upstream #33392 (`strict: false` on tools for `@ai-sdk/openai`, `@ai-sdk/azure`, `@ai-sdk/amazon-bedrock/mantle`). **amicode patch #18 (PROMPT_COMMUNICATING) is preserved** — different region of the file.
- WHAT WAS DELIBERATELY NOT PORTED: the Effect `layer-node → app-node` refactor and the `@opencode-ai/schema` extraction (upstream gutted `core/src/model.ts` 127→41 and `core/src/provider.ts` 85→25 into a new package). Cherry-picking the bucket's 112 commits would drag both in. Take file end-states, not history.
- MEASURED BLAST RADIUS: ran both transform versions over all 454 reasoning models in the live models.dev catalog — **418 identical, 36 changed, 0 errors**. The 36: Claude 5 (opus/sonnet, across `anthropic` + all `amazon-bedrock` regions + `opencode` zen) goes `high,max` → `low,medium,high,xhigh,max` with `type:"adaptive"`; xAI Grok 4.3/4.5/4.20/build and GLM-5.2 gain effort variants where they previously had NONE; `claude-opus-4-5` keeps its `low,medium,high` keys but now also sends `budgetTokens:16000` alongside `effort`. Claude 4.8/4.6/4.1 unchanged.
- VERIFICATION: `tsgo --noEmit` green on packages/opencode AND packages/core. `bun test test/provider/` → 503 pass / 0 fail. `bun test test/session/ test/server/` → identical results before and after the port (3 pre-existing `llm-native-recorded` failures + a pre-existing Bun 1.3.14 teardown segfault, both reproduced byte-for-byte on the unported tree).
- STILL UNVERIFIED (needs live API creds): whether the OLD legacy `thinking:{type:"enabled",budgetTokens}` form actually 400s against Opus 5 or merely degrades — i.e. whether this was "hobbled" or "unusable". Also unexercised by CI: the Grok/GLM effort variants and the opus-4-5 `budgetTokens`+`effort` combination.
- FUTURE SYNC COST: this is a knowing trade — porting file end-states now makes a future clean upstream merge harder on these 4 files. Accepted. NOTE the bug class recurs every model generation (version-regex parsing of model IDs will break again at Opus 6), which argues for a standing narrow sync lane on `transform.ts` rather than one-off unfreezes.
- SEPARATE RISK SPOTTED (not fixed here): the release build does a bare `fetch(models.dev/api.json)` with no fallback, so a models.dev outage hard-fails the build. Consider pinning `MODELS_DEV_API_JSON` for the hackathon build.
19 changes: 19 additions & 0 deletions packages/core/src/models-dev.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,6 +43,24 @@ const Cost = Schema.Struct({
),
})

// How a model exposes its reasoning control in the models.dev catalog. Ported
// from upstream alongside provider/transform.ts — the transform derives thinking
// variants from this instead of pattern-matching model IDs. See AMICODE-PATCHES.md.
const ReasoningOption = Schema.Union([
Schema.Struct({
type: Schema.Literal("effort"),
values: Schema.Array(Schema.NullOr(Schema.String)),
}),
Schema.Struct({
type: Schema.Literal("toggle"),
}),
Schema.Struct({
type: Schema.Literal("budget_tokens"),
min: Schema.optional(Schema.Finite),
max: Schema.optional(Schema.Finite),
}),
])

export const Model = Schema.Struct({
id: Schema.String,
name: Schema.String,
Expand All@@ -52,6 +70,7 @@ export const Model = Schema.Struct({
reasoning: Schema.Boolean,
temperature: Schema.Boolean,
tool_call: Schema.Boolean,
reasoning_options: Schema.optional(Schema.Array(ReasoningOption)),
interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
Expand Down
Loading
Loading