Compare commits

..

110 Commits

Author SHA1 Message Date
Aiden Cline f2bce90b67 fix(core): return content-only Code Mode results 2026-08-12 06:00:54 +00:00
opencode-agent[bot] 01cbdcb8e4 fix(ai): batch Anthropic parallel tool results (#41948)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-08-12 00:18:50 -05:00
opencode-agent[bot] bf751a907d fix(core): jitter session retry delays (#41942)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-08-11 23:58:20 -05:00
opencode-agent[bot] 9d63ca8f90 chore: generate 2026-08-12 04:19:09 +00:00
opencode-agent[bot] e3bd82013c fix(ai): preserve stream transport failures (#41779)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-08-11 23:17:48 -05:00
Kit Langton 90b6fa0eab fix(core): expose local attachment paths (#41789) 2026-08-11 23:32:49 -04:00
Kit Langton 5b7b1830d2 refactor(server): resume suspended sessions unconditionally in the fetch entry (#41938) 2026-08-12 03:31:30 +00:00
Kit Langton a8fc664b6d fix(tui): pad markdown table cells (#41937) 2026-08-11 23:21:00 -04:00
Kit Langton d853ff8848 fix(tui): configure new session location (#41929) 2026-08-11 22:55:48 -04:00
opencode-agent[bot] 94bc0fc6fa chore: generate 2026-08-12 02:40:33 +00:00
Kit Langton d3eecf7ba2 feat(tui): compact turn token usage with expandable steps (#41922) 2026-08-12 02:39:19 +00:00
Kit Langton 99166f7c17 feat(tui): add plus button to session tab bar (#41887) 2026-08-11 22:38:08 -04:00
opencode-agent[bot] 08dcf7d731 chore: generate 2026-08-12 02:23:16 +00:00
Kit Langton caae28e0d4 fix(tui): render instruction updates as compact notices (#41900) 2026-08-11 22:21:24 -04:00
Kit Langton c83933d1d4 fix(core): gate tool snapshot on initial MCP registration (#41884) 2026-08-11 22:21:21 -04:00
Kit Langton c86f1c41ff fix(tui): show completed write output (#41883) 2026-08-11 22:20:55 -04:00
Kit Langton 5c0cc8e617 fix(tui): align running shell output (#41880) 2026-08-11 22:20:52 -04:00
Kit Langton 1b45061afb feat(tui): experiments via devtools bar, drafts stay put (#41917) 2026-08-12 02:08:06 +00:00
opencode-agent[bot] 07bcd290c2 chore: generate 2026-08-12 02:06:08 +00:00
Luke Parker 04ad06e2e3 fix(desktop): align local development identity (#41889) 2026-08-12 12:04:57 +10:00
Dax 93965df860 feat(session): record location switches (#41899) 2026-08-11 19:03:57 -07:00
Kit Langton f0333e0eea chore(tui): remove leftover discovery smoke plugin (#41897) 2026-08-11 21:56:55 -04:00
Kit Langton 452335a78d fix(tui): truncate fractional mtimes in fresh plugin specifiers (#41891) 2026-08-11 21:56:44 -04:00
Kit Langton 9322f5d2c9 fix(client): surface managed startup stderr (#41793) 2026-08-11 21:55:43 -04:00
opencode-agent[bot] d6ed520c25 chore: generate 2026-08-12 01:38:26 +00:00
Kit Langton 96a74ffcc6 chore(core): drop obsolete StreamSse hunk from effect patch (#41892) 2026-08-11 21:37:09 -04:00
Kit Langton c858986b08 feat(server): web-standard fetch handler entry (#41896) 2026-08-11 21:37:06 -04:00
Dax Raad f6611a1f56 refactor(core): internalize effect sqlite adapter 2026-08-11 21:33:23 -04:00
Kit Langton 57b636df00 test(tui): resolve autocomplete paths per platform (#41893) 2026-08-11 21:28:23 -04:00
opencode-agent[bot] 3489abedc0 chore: generate 2026-08-12 01:12:18 +00:00
Dax Raad 49a4175a34 fix: make workspace imports NodeNext compatible 2026-08-11 21:09:46 -04:00
Dax Raad b50b8268f2 feat(codemode): configure package publishing 2026-08-11 21:09:46 -04:00
Dax Raad 51512862a5 feat: add V2 curl installer 2026-08-11 21:03:15 -04:00
Kit Langton 3d23c907eb fix(core): restore bundler resolution for source-imported deps (#41885) 2026-08-11 21:01:24 -04:00
opencode-agent[bot] 9c4e6b500e chore: generate 2026-08-12 00:58:51 +00:00
Dax 5da7eaa6eb feat(api): continue pending work after interrupt (#41888) 2026-08-11 17:56:54 -07:00
Kit Langton c254ba8a7f core: embed models.dev snapshot instead of compile-time define (#41838) 2026-08-11 20:55:09 -04:00
Kit Langton d8e126b817 feat(tui): hidden experiments section with per-tab prompt drafts (#41862) 2026-08-11 20:52:56 -04:00
James Long 7987aed8f3 feat(tui): autocomplete cd directories (#41870) 2026-08-11 20:52:16 -04:00
Kit Langton 0df3070d6d test(client): accelerate service lifecycle tests (#41879) 2026-08-11 20:50:25 -04:00
Luke Parker c217ebe2ad fix(desktop): skip web ui build in dev (#41881) 2026-08-12 10:25:32 +10:00
Dax Raad 4acdeffbe9 refactor(core): require explicit import extensions 2026-08-11 20:22:50 -04:00
Kit Langton dc82a446b9 fix(core): guard Deferred waiter cleanup in vendored effect patch (#41858) 2026-08-11 20:16:21 -04:00
Luke Parker c4bea9d558 fix(app): stabilize markdown worker startup (#41487) 2026-08-12 10:05:32 +10:00
Luke Parker 1190ef3818 feat(desktop): support local server builds (#41486) 2026-08-12 09:56:47 +10:00
opencode-agent[bot] 055a380e66 fix(core): parameterize v1 migration messages (#41877)
Co-authored-by: Dax <826656+thdxr@users.noreply.github.com>
2026-08-11 19:51:37 -04:00
Dax Raad 456c26a012 feat(tui): show localhost on pair screen 2026-08-11 19:49:33 -04:00
opencode-agent[bot] 6072fc5c1b chore: generate 2026-08-11 22:44:47 +00:00
Brendan Allan 20df2fdba6 feat(cli): embed web ui (#41525)
Co-authored-by: Dax Raad <d@ironbay.co>
2026-08-11 15:43:07 -07:00
opencode-agent[bot] f1399dcb65 fix(desktop): orchestrate update restarts (#41865)
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
2026-08-12 08:38:18 +10:00
Dax Raad 3507bd10b6 fix(www): match OG images to docs theme 2026-08-11 18:28:51 -04:00
Dax Raad 492ae1fdfa feat(www): match legacy docs theme 2026-08-11 18:20:58 -04:00
Kit Langton b00d8d65fe feat(tui): hierarchical slot tree for plugin UI placement (#41189) 2026-08-11 22:00:04 +00:00
Kit Langton f1366d80c8 fix(core): default #sqlite resolution to the node driver (#41834) 2026-08-11 17:50:09 -04:00
opencode-agent[bot] 549a8f826b fix(core): log Plan reminder failures (#41856)
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
2026-08-11 16:39:26 -05:00
Kit Langton 59970699d0 test(core): narrow plugin test layer (#41852) 2026-08-11 17:23:47 -04:00
Aiden Cline b35c5fc985 fix(core): detect copilot PDF input support (#41854) 2026-08-11 16:05:36 -05:00
Kit Langton 627e67323c docs: remove ideal-pseudocode project skill (#41851) 2026-08-11 17:03:05 -04:00
opencode-agent[bot] b97d964e5c chore: generate 2026-08-11 20:53:50 +00:00
Aiden Cline 3fd3e28690 fix(core): classify copilot utility requests (#41840) 2026-08-11 15:51:55 -05:00
Kit Langton b4abeb4788 test(core): narrow effect flock harness (#41837) 2026-08-11 16:51:42 -04:00
Kit Langton 14deb6baf7 docs: clarify skill source precedence (#41844) 2026-08-11 20:46:14 +00:00
Aiden Cline ab6e18e4ff fix(core): route Vertex Anthropic natively (#41836) 2026-08-11 15:29:02 -05:00
Kit Langton 2b6dd2559c fix(core): prefer nearest skill source (#41788) 2026-08-11 16:13:32 -04:00
Kit Langton 2b7bd84867 test(core): speed up subagent tool suite (#41835) 2026-08-11 16:13:04 -04:00
Kit Langton baa54a5150 test(core): speed up shell tool suite (#41831) 2026-08-11 16:03:50 -04:00
Kit Langton c5704d3e3b feat(core): sqlite driver for durable object storage (#41659) 2026-08-11 15:45:23 -04:00
Kit Langton e3336725db fix(core): normalize provider endpoint templates (#41816) 2026-08-11 15:42:54 -04:00
opencode-agent[bot] ff3ecefd24 fix(cli): sign macOS preview binaries (#40662)
Co-authored-by: Ryan Vogel <89211796+R44VC0RP@users.noreply.github.com>
2026-08-11 15:37:44 -04:00
Kit Langton 8486bbcdc1 refactor(core): unify fff runtime adapters (#41827) 2026-08-11 15:22:03 -04:00
Kit Langton 2621dde1c9 refactor(core): unify config collection decoding (#41826) 2026-08-11 15:21:52 -04:00
Kit Langton a253c0437e test(core): await shell tool registration (#41825) 2026-08-11 15:21:35 -04:00
opencode-agent[bot] d8b3e528e8 fix(core): use standard web search key dialogs (#41821)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-08-11 14:13:58 -05:00
Aiden Cline a5d6969f6f feat(core): extract plan agent into a plugin (#41665) 2026-08-11 13:49:24 -05:00
opencode-agent[bot] 3954d7979d chore: generate 2026-08-11 18:11:13 +00:00
Kit Langton a69a372f27 fix(util): defer module-scope randomness and import.meta path derivation (#41765) 2026-08-11 14:09:18 -04:00
Kit Langton 7300e7e10f core: write-ahead execution claims replace shutdown-hook suspension (#41800) 2026-08-11 14:09:04 -04:00
James Long eeb870b0cc feat(sdk): configure embedded logging (#41809) 2026-08-11 14:03:55 -04:00
Kit Langton 136bad9f17 feat(core): discover AGENTS.md up to the home directory (#41652) 2026-08-11 13:57:10 -04:00
Kit Langton 17536a9237 fix(core): discover local plugin packages (#41784) 2026-08-11 13:14:46 -04:00
Kit Langton 315bc6ac2e fix(acp): avoid implicit model variant (#41782) 2026-08-11 13:09:59 -04:00
Kit Langton a183fb5615 refactor(core): share SQLite client adapter (#41797) 2026-08-11 13:07:22 -04:00
Kit Langton 2c1596ca80 refactor(core): share AI SDK provider factory (#41796) 2026-08-11 13:07:14 -04:00
Kit Langton 9e082c2d43 refactor(core): centralize project upsert (#41795) 2026-08-11 13:07:05 -04:00
Kit Langton fa5ca85e30 refactor(core): reuse plugin source discovery (#41794) 2026-08-11 13:06:58 -04:00
Kit Langton 37a8c6c916 fix(ai): merge Bedrock tool result messages (#41780) 2026-08-11 13:03:31 -04:00
Kit Langton 23b0688a7f fix(server): await models before listing (#41783) 2026-08-11 12:18:07 -04:00
opencode-agent[bot] d0dd49bd84 chore: generate 2026-08-11 16:12:58 +00:00
Kit Langton db9a3b6c41 refactor(core): compact question tool schema (#41772) 2026-08-11 12:09:37 -04:00
opencode-agent[bot] 961b51b509 fix(core): yield while clearing migration events (#41775)
Co-authored-by: Dax Raad <d@ironbay.co>
2026-08-11 16:02:30 +00:00
opencode-agent[bot] 964f7f4254 chore: generate 2026-08-11 15:53:52 +00:00
Aiden Cline 8c27c8485e feat(session): persist previous selections (#41771) 2026-08-11 10:52:14 -05:00
opencode-agent[bot] 6721ff5328 fix(core): omit deprecated models.dev models (#41769)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-08-11 10:17:04 -05:00
Kit Langton 026e0c634f refactor(core): reuse plugin directory names (#41754) 2026-08-11 10:40:36 -04:00
Kit Langton c581b59b7f refactor(merman): simplify spatial span assembly (#41757) 2026-08-11 10:40:22 -04:00
Kit Langton 5cc7811ec2 refactor(core): defer database global lookup (#41755) 2026-08-11 10:40:03 -04:00
Kit Langton 5d32845b02 refactor(tui): simplify marquee reset (#41758) 2026-08-11 10:39:51 -04:00
Kit Langton e9f5842f29 refactor: simplify attachment identity tracking (#41756) 2026-08-11 10:39:42 -04:00
Kit Langton 7b9734593a refactor(core): generate static imports for the migration manifest (#41657) 2026-08-11 10:35:19 -04:00
opencode-agent[bot] 1dbfc7cfab chore: generate 2026-08-11 14:12:14 +00:00
Kit Langton 3441b95afc fix(core): models.dev catalog population must survive KV cache write failures (#41735) 2026-08-11 10:09:37 -04:00
opencode-agent[bot] 306204bad8 fix(app): handle untitled session tab info (#41700)
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
2026-08-11 18:02:10 +10:00
Aiden Cline 47c8d85904 feat(plugin): allow tool hooks to fail with tool errors (#41668) 2026-08-11 00:36:59 -05:00
Aiden Cline c401076b6f fix(core): preserve AI SDK tool media (#41672) 2026-08-11 00:33:33 -05:00
Luke Parker 1aef4de853 chore(desktop): skip unused beta CLI builds (#41673) 2026-08-11 15:07:21 +10:00
opencode-agent[bot] 9c94634515 fix(tui): use active model for compaction (#41608)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
2026-08-10 23:50:51 -05:00
Luke Parker c2b754bb03 feat(desktop): publish v2 beta desktop (#41626) 2026-08-11 14:33:31 +10:00
Aiden Cline 2372edd5eb feat(tui): show previous agent in switch notices (#41661) 2026-08-10 23:09:26 -05:00
Kit Langton a5f7f8d3b5 fix(tui): deduplicate repeated image attachments (#41651) 2026-08-10 23:39:38 -04:00
Aiden Cline 4df276b9e8 feat(session): persist previous agent on switch (#41621) 2026-08-10 22:35:16 -05:00
691 changed files with 10724 additions and 4751 deletions
+1
View File
@@ -1,3 +1,4 @@
packages/core/migration/**/snapshot.json linguist-generated
packages/core/src/database/migration.gen.ts linguist-generated
packages/core/src/models-dev/snapshot.txt linguist-generated
packages/core/src/**/*.txt text eol=lf
+69 -11
View File
@@ -75,7 +75,7 @@ jobs:
build-cli:
needs: version
runs-on: blacksmith-4vcpu-ubuntu-2404
if: github.repository == 'anomalyco/opencode'
if: github.repository == 'anomalyco/opencode' && github.ref_name != 'beta'
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
@@ -91,7 +91,7 @@ jobs:
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}
- name: Build legacy CLI
if: github.ref_name != 'v2'
if: github.ref_name != 'v2' && github.ref_name != 'beta'
run: ./packages/opencode/script/build.ts ${{ (github.ref_name == 'beta' && '--sourcemaps') || '' }}
env:
OPENCODE_VERSION: ${{ needs.version.outputs.version }}
@@ -109,7 +109,7 @@ jobs:
GH_TOKEN: ${{ steps.committer.outputs.token }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: github.ref_name != 'v2'
if: github.ref_name != 'v2' && github.ref_name != 'beta'
with:
name: opencode-cli
path: |
@@ -117,22 +117,76 @@ jobs:
packages/opencode/dist/opencode-linux*
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: github.ref_name != 'v2'
if: github.ref_name != 'v2' && github.ref_name != 'beta'
with:
name: opencode-cli-windows
path: packages/opencode/dist/opencode-windows*
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-preview-cli
name: opencode-preview-cli-unsigned
path: packages/cli/dist/cli-*
outputs:
version: ${{ needs.version.outputs.version }}
sign-cli-macos:
needs: build-cli
runs-on: macos-26
if: github.repository == 'anomalyco/opencode'
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- uses: apple-actions/import-codesign-certs@8f3fb608891dd2244cdab3d69cd68c0d37a7fe93 # v2.0.0
with:
keychain: build
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: opencode-preview-cli-unsigned
path: packages/cli/dist
- name: Sign macOS CLI binaries
run: |
identity=$(security find-identity -v -p codesigning build.keychain | sed -n 's/.*"\(Developer ID Application:.*\)"/\1/p' | head -n 1)
if [ -z "$identity" ]; then
echo "Developer ID Application identity not found"
exit 1
fi
found=0
for file in packages/cli/dist/cli-darwin-*/bin/opencode2; do
if [ ! -f "$file" ]; then
continue
fi
found=1
codesign \
--force \
--timestamp \
--options runtime \
--entitlements packages/cli/script/entitlements.plist \
--sign "$identity" \
"$file"
codesign --verify --deep --strict --verbose=4 "$file"
codesign --display --requirements - "$file"
done
if [ "$found" -eq 0 ]; then
echo "No macOS CLI binaries found"
exit 1
fi
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: opencode-preview-cli
path: packages/cli/dist/cli-*
if-no-files-found: error
build-node-cli:
needs: version
if: github.repository == 'anomalyco/opencode'
if: github.repository == 'anomalyco/opencode' && github.ref_name != 'beta'
strategy:
fail-fast: false
matrix:
@@ -184,7 +238,7 @@ jobs:
- build-cli
- version
runs-on: blacksmith-4vcpu-windows-2025
if: github.repository == 'anomalyco/opencode' && github.ref_name != 'v2'
if: github.repository == 'anomalyco/opencode' && github.ref_name != 'v2' && github.ref_name != 'beta'
env:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
@@ -377,7 +431,7 @@ jobs:
env:
OPENCODE_VERSION: ${{ needs.version.outputs.version }}
OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
RUST_TARGET: ${{ matrix.settings.target }}
OPENCODE_CLI_TARGET: ${{ matrix.settings.target }}
- name: Build
run: bun run build
@@ -393,6 +447,7 @@ jobs:
VITE_SENTRY_DSN: ${{ vars.WEB_SENTRY_DSN }}
VITE_SENTRY_ENVIRONMENT: ${{ (github.ref_name == 'beta' && 'beta') || 'production' }}
VITE_SENTRY_RELEASE: desktop@${{ needs.version.outputs.version }}
OPENCODE_CLI_TARGET: ${{ matrix.settings.target }}
- name: Package
if: needs.version.outputs.release
@@ -467,6 +522,7 @@ jobs:
needs:
- version
- build-cli
- sign-cli-macos
- build-node-cli
- sign-cli-windows
- build-electron
@@ -496,29 +552,31 @@ jobs:
registry-url: "https://registry.npmjs.org"
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
if: github.ref_name != 'v2'
if: github.ref_name != 'v2' && github.ref_name != 'beta'
with:
name: opencode-cli
path: packages/opencode/dist
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
if: github.ref_name != 'v2'
if: github.ref_name != 'v2' && github.ref_name != 'beta'
with:
name: opencode-cli-windows
path: packages/opencode/dist
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
if: github.ref_name != 'v2'
if: github.ref_name != 'v2' && github.ref_name != 'beta'
with:
name: opencode-cli-signed-windows
path: packages/opencode/dist
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
if: github.ref_name != 'beta'
with:
name: opencode-preview-cli
path: packages/cli/dist
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
if: github.ref_name != 'beta'
with:
pattern: opencode-node-cli-*
path: packages/cli/dist/node
-13
View File
@@ -1,13 +0,0 @@
import type { Context } from "../../../packages/plugin/src/tui/context"
export default {
id: "test.tui-discovery-smoke",
setup(_context: Context) {
// context.ui.toast.show({
// title: "TUI plugin discovery works",
// message: "Loaded .opencode/plugins/tui/discovery-smoke.ts",
// variant: "success",
// duration: 30_000,
// })
},
}
@@ -1,68 +0,0 @@
---
name: ideal-pseudocode
description: Function-by-function refactoring loop driven by ideal pseudocode. Use when the user says "ideal pseudocode", asks to make a function read like its pseudocode, or wants a dense module cleaned up one function at a time.
---
# Ideal Pseudocode
Clean up one function at a time by writing the pseudocode it _should_ read as, naming every delta between that and the real code, and closing only the gaps the user approves.
## Loop
One function per round. Never touch code before the user picks a direction.
1. **Pick the target** with the user — usually the next function up or down the call chain from the last round.
2. **Read the current code** fresh from disk. It may have unsaved or parallel edits; ask before overwriting anything unexpected.
3. **Distill.** Write the function's ideal pseudocode in a `ts`-fenced code block — TypeScript-flavored for syntax highlighting, but pseudocode: comments over mechanics, one line per idea, every arm of a loop visible as an arm. For a dense or unfamiliar function, first show the _current_ structure as pseudocode, then the ideal.
4. **Name the deltas.** A numbered list; each delta is one concrete gap: control flow smuggled through combinators, a flag-typed parameter, colliding names, side-effect plumbing drowning a loop body, twin functions differing only by a filter. For each, give an honest cost/benefit and a decisive recommendation — including "leave it" when the density has reasons (state the reasons).
5. **Verify before proposing.** Any API the proposal builds on (a combinator, schedule, matcher) gets checked against the installed version's source, not memory.
6. **Get buy-in, then apply.** Minimal edits. Quarantine irreducible ugliness inside a small helper whose name is the pseudocode line it implements. Collapse shallow sibling functions into one deep function only when the distinguishing argument is a domain noun, not a behavior switch.
7. **Validate.** Typecheck and the focused test suites from the package directory; rerun timing-sensitive tests repeatedly. Flag any semantic change the restructure introduced, even when tests pass.
8. **Offer the next target** and stop.
## Style
- Keep each round tight: pseudocode block, deltas, recommendation, one question.
- State mutation belongs in one visible place (usually the loop tail), never spread across error channels or callback closures.
- Prefer early return and `if` chains for control flow; matchers are for producing values.
- Compare names against the question each caller is actually asking; rename toward the domain noun.
## Example round
Every round should read like this (abridged from a real one, on an Effect step-runner):
> `runStep` it is. The ideal pseudocode:
>
> ```ts
> // One logical step: one settled model call, however many attempts it takes.
> // An attempt can end without settling in two ways:
> // transient provider failure -> retry the same call, same assistant message
> // compaction rewrote history -> rebuild the request and call again
> function runStep(session, promotable, step) {
> while (true) {
> const result = callModel(session, promotable, step)
>
> if (result.completed) return result
>
> if (result.retryable) {
> wait(retrySchedule) // exhausted -> publish Step.Failed, fail drain
> promotable = none // never re-promote on a second attempt
> continue
> }
>
> // compaction restarted the step: fresh request from rewritten history
> promotable = none
> step = result.step
> }
> }
> ```
>
> Comparing against the real thing, three deltas:
>
> 1. **The retry arm doesn't live in the loop.** In the pseudocode, retry is just another loop arm. In the real code it's smuggled through the error channel: `Effect.tapError` mutating loop variables via `Effect.sync` closures, then `Effect.retryOrElse` re-running a suspended call. Four mutable variables mutated from three different places — the state flow is invisible unless you already know the trick.
> 2. **`recoverOverflow: typeof compaction.compact | undefined`** — a function-typed parameter used as a one-shot armed/disarmed flag. The callee already closes over `compaction`; a boolean says what it is.
> 3. **`assistantMessageID`** exists solely to resume the same durable message across retries — fine, but only legible once the retry arm is visible in the loop.
>
> The unifying move for (1): a schedule driver, so a retryable failure becomes a caught value handled in the loop body exactly like the compaction arm. One honest trade: it's more manual than the blessed combinator — but the manual version is the loop the combinator was hiding, and the loop already exists for restarts. Two restart mechanisms, one control structure.
>
> Want me to apply it — unified loop, simplified schedule input, boolean `recoverOverflow`?
+3 -18
View File
@@ -375,7 +375,6 @@
"@modelcontextprotocol/sdk": "1.29.0",
"@opencode-ai/ai": "workspace:*",
"@opencode-ai/codemode": "workspace:*",
"@opencode-ai/effect-drizzle-sqlite": "workspace:*",
"@opencode-ai/plugin": "workspace:*",
"@opencode-ai/schema": "workspace:*",
"@opencode-ai/util": "workspace:*",
@@ -439,6 +438,7 @@
"@actions/artifact": "4.0.0",
"@lydell/node-pty": "catalog:",
"@opencode-ai/app": "workspace:*",
"@opencode-ai/client": "workspace:*",
"@opencode-ai/ui": "workspace:*",
"@sentry/solid": "catalog:",
"@sentry/vite-plugin": "catalog:",
@@ -476,20 +476,6 @@
"@parcel/watcher-win32-x64": "2.5.1",
},
},
"packages/effect-drizzle-sqlite": {
"name": "@opencode-ai/effect-drizzle-sqlite",
"version": "1.18.15",
"dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:",
},
"devDependencies": {
"@effect/sql-sqlite-bun": "catalog:",
"@tsconfig/bun": "catalog:",
"@types/bun": "catalog:",
"@typescript/native-preview": "catalog:",
},
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.18.15",
@@ -1080,8 +1066,9 @@
"@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch",
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
"@ai-sdk/mistral@3.0.51": "patches/@ai-sdk%2Fmistral@3.0.51.patch",
"@npmcli/agent@4.0.2": "patches/@npmcli%2Fagent@4.0.2.patch",
"@ff-labs/fff-bun@0.10.1": "patches/@ff-labs%2Ffff-bun@0.10.1.patch",
"@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch",
"@npmcli/agent@4.0.2": "patches/@npmcli%2Fagent@4.0.2.patch",
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch",
"@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch",
"@dnd-kit/dom@0.5.0": "patches/@dnd-kit%2Fdom@0.5.0.patch",
@@ -2086,8 +2073,6 @@
"@opencode-ai/desktop": ["@opencode-ai/desktop@workspace:packages/desktop"],
"@opencode-ai/effect-drizzle-sqlite": ["@opencode-ai/effect-drizzle-sqlite@workspace:packages/effect-drizzle-sqlite"],
"@opencode-ai/enterprise": ["@opencode-ai/enterprise@workspace:packages/enterprise"],
"@opencode-ai/function": ["@opencode-ai/function@workspace:packages/function"],
+45 -53
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
APP=opencode
APP=opencode2
MUTED='\033[0;2m'
RED='\033[0;31m'
@@ -15,14 +15,14 @@ Usage: install.sh [options]
Options:
-h, --help Display this help message
-v, --version <version> Install a specific version (e.g., 1.0.180)
-v, --version <version> Install a specific version (e.g., 0.0.0-next-17236)
-b, --binary <path> Install from a local binary instead of downloading
--no-modify-path Don't modify shell config files (.zshrc, .bashrc, etc.)
Examples:
curl -fsSL https://opencode.ai/install | bash
curl -fsSL https://opencode.ai/install | bash -s -- --version 1.0.180
./install --binary /path/to/opencode
curl -fsSL https://raw.githubusercontent.com/anomalyco/opencode/v2/install | bash
curl -fsSL https://raw.githubusercontent.com/anomalyco/opencode/v2/install | bash -s -- --version 0.0.0-next-17236
./install --binary /path/to/opencode2
EOF
}
@@ -109,11 +109,6 @@ else
;;
esac
archive_ext=".zip"
if [ "$os" = "linux" ]; then
archive_ext=".tar.gz"
fi
is_musl=false
if [ "$os" = "linux" ]; then
if [ -f /etc/alpine-release ]; then
@@ -165,42 +160,42 @@ else
target="$target-musl"
fi
filename="$APP-$target$archive_ext"
if [ "$os" = "linux" ]; then
if ! command -v tar >/dev/null 2>&1; then
echo -e "${RED}Error: 'tar' is required but not installed.${NC}"
exit 1
fi
else
if ! command -v unzip >/dev/null 2>&1; then
echo -e "${RED}Error: 'unzip' is required but not installed.${NC}"
exit 1
fi
if ! command -v tar >/dev/null 2>&1; then
echo -e "${RED}Error: 'tar' is required but not installed.${NC}"
exit 1
fi
if [ -z "$requested_version" ]; then
url="https://github.com/anomalyco/opencode/releases/latest/download/$filename"
specific_version=$(curl -s https://api.github.com/repos/anomalyco/opencode/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
metadata=$(curl -fsSL https://registry.npmjs.org/@opencode-ai%2fcli/next || true)
specific_version=$(echo "$metadata" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p')
if [[ $? -ne 0 || -z "$specific_version" ]]; then
if [ -z "$specific_version" ]; then
echo -e "${RED}Failed to fetch version information${NC}"
exit 1
fi
else
# Strip leading 'v' if present
requested_version="${requested_version#v}"
url="https://github.com/anomalyco/opencode/releases/download/v${requested_version}/$filename"
specific_version=$requested_version
fi
# Verify the release exists before downloading
http_status=$(curl -sI -o /dev/null -w "%{http_code}" "https://github.com/anomalyco/opencode/releases/tag/v${requested_version}")
if [ "$http_status" = "404" ]; then
echo -e "${RED}Error: Release v${requested_version} not found${NC}"
echo -e "${MUTED}Available releases: https://github.com/anomalyco/opencode/releases${NC}"
exit 1
fi
package_name="@opencode-ai/cli-$target"
http_status=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/@opencode-ai%2fcli-$target/$specific_version" || true)
if [ "$http_status" = "404" ]; then
echo -e "${RED}Error: Version ${specific_version} is not available for $target${NC}"
echo -e "${MUTED}Available versions: https://www.npmjs.com/package/$package_name?activeTab=versions${NC}"
exit 1
fi
if [ "$http_status" != "200" ]; then
echo -e "${RED}Failed to fetch package information${NC}"
exit 1
fi
filename="cli-$target-$specific_version.tgz"
url="https://registry.npmjs.org/$package_name/-/$filename"
binary_name="$APP"
if [ "$os" = "windows" ]; then
binary_name="$APP.exe"
fi
fi
@@ -219,11 +214,13 @@ print_message() {
}
check_version() {
if command -v opencode >/dev/null 2>&1; then
opencode_path=$(which opencode)
if command -v "$APP" >/dev/null 2>&1; then
opencode_path=$(which "$APP")
## Check the installed version
installed_version=$(opencode --version 2>/dev/null || echo "")
installed_version=$("$APP" --version 2>/dev/null || echo "")
installed_version="${installed_version##* }"
installed_version="${installed_version#v}"
if [[ "$installed_version" != "$specific_version" ]]; then
print_message info "${MUTED}Installed version: ${NC}$installed_version."
@@ -287,7 +284,7 @@ download_with_progress() {
trap "trap - RETURN; rm -f \"$tracefile\"; printf '\033[?25h' >&4; exec 4>&-" RETURN
(
curl --trace-ascii "$tracefile" -s -L -o "$output" "$url"
curl --trace-ascii "$tracefile" -fsL -o "$output" "$url"
) &
local curl_pid=$!
@@ -325,30 +322,25 @@ download_with_progress() {
}
download_and_install() {
print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version"
print_message info "\n${MUTED}Installing ${NC}$APP ${MUTED}version: ${NC}$specific_version"
local tmp_dir="${TMPDIR:-/tmp}/opencode_install_$$"
mkdir -p "$tmp_dir"
if [[ "$os" == "windows" ]] || ! [ -t 2 ] || ! download_with_progress "$url" "$tmp_dir/$filename"; then
# Fallback to standard curl on Windows, non-TTY environments, or if custom progress fails
curl -# -L -o "$tmp_dir/$filename" "$url"
curl -f -# -L -o "$tmp_dir/$filename" "$url"
fi
if [ "$os" = "linux" ]; then
tar -xzf "$tmp_dir/$filename" -C "$tmp_dir"
else
unzip -q "$tmp_dir/$filename" -d "$tmp_dir"
fi
mv "$tmp_dir/opencode" "$INSTALL_DIR"
chmod 755 "${INSTALL_DIR}/opencode"
tar -xzf "$tmp_dir/$filename" -C "$tmp_dir"
mv "$tmp_dir/package/bin/$binary_name" "$INSTALL_DIR"
chmod 755 "${INSTALL_DIR}/$binary_name"
rm -rf "$tmp_dir"
}
install_from_binary() {
print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}from: ${NC}$binary_path"
cp "$binary_path" "${INSTALL_DIR}/opencode"
chmod 755 "${INSTALL_DIR}/opencode"
print_message info "\n${MUTED}Installing ${NC}$APP ${MUTED}from: ${NC}$binary_path"
cp "$binary_path" "${INSTALL_DIR}/$APP"
chmod 755 "${INSTALL_DIR}/$APP"
}
if [ -n "$binary_path" ]; then
@@ -453,8 +445,8 @@ echo -e ""
echo -e "${MUTED}OpenCode includes free models, to start:${NC}"
echo -e ""
echo -e "cd <project> ${MUTED}# Open directory${NC}"
echo -e "opencode ${MUTED}# Run command${NC}"
echo -e "opencode2 ${MUTED}# Run command${NC}"
echo -e ""
echo -e "${MUTED}For more information visit ${NC}https://opencode.ai/docs"
echo -e "${MUTED}For more information visit ${NC}https://opencode.ai/v2/docs"
echo -e ""
echo -e ""
+2 -1
View File
@@ -171,6 +171,7 @@
"@pierre/trees@1.0.0-beta.4": "patches/@pierre%2Ftrees@1.0.0-beta.4.patch",
"@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
"effect@4.0.0-beta.101": "patches/effect@4.0.0-beta.101.patch",
"@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch"
"@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch",
"@ff-labs/fff-bun@0.10.1": "patches/@ff-labs%2Ffff-bun@0.10.1.patch"
}
}
+2 -2
View File
@@ -10,8 +10,8 @@
//
// Manual `cache: CacheHint` placements on individual parts are preserved and
// count against the four-breakpoint budget; auto only fills remaining slots.
import { CacheHint, type CachePolicy, type CachePolicyObject } from "./schema/options"
import { LLMRequest, Message, ToolDefinition, type ContentPart } from "./schema/messages"
import { CacheHint, type CachePolicy, type CachePolicyObject } from "./schema/options.js"
import { LLMRequest, Message, ToolDefinition, type ContentPart } from "./schema/messages.js"
const AUTO: CachePolicyObject = {
tools: true,
+3 -3
View File
@@ -1,7 +1,7 @@
import { Context, Effect, Layer } from "effect"
import { RequestExecutor } from "./route/executor"
import type { ImageOptions, ImageRequest, ImageRequestFor, ImageResponse } from "./image"
import type { AIError } from "./schema"
import { RequestExecutor } from "./route/executor.js"
import type { ImageOptions, ImageRequest, ImageRequestFor, ImageResponse } from "./image.js"
import type { AIError } from "./schema/index.js"
export type Execute = RequestExecutor.Interface["execute"]
+10 -2
View File
@@ -1,6 +1,14 @@
import { Effect, Schema } from "effect"
import { HttpOptions, InvalidRequestReason, AIError, ModelID, ProviderID, ProviderMetadata, Usage } from "./schema"
import { ImageClient, Service, type Execute as ImageExecute } from "./image-client"
import {
HttpOptions,
InvalidRequestReason,
AIError,
ModelID,
ProviderID,
ProviderMetadata,
Usage,
} from "./schema/index.js"
import { ImageClient, Service, type Execute as ImageExecute } from "./image-client.js"
export interface ImageRoute<Options extends ImageOptions = ImageOptions> {
readonly id: string
+21 -18
View File
@@ -1,22 +1,22 @@
export { LLMClient } from "./route/client"
export { ImageClient } from "./image-client"
export { Auth } from "./route/auth"
export { Provider } from "./provider"
export { ProviderPackage } from "./provider-package"
export { isContextOverflow, isContextOverflowFailure } from "./provider-error"
export { LLMClient } from "./route/client.js"
export { ImageClient } from "./image-client.js"
export { Auth } from "./route/auth.js"
export { Provider } from "./provider.js"
export { ProviderPackage } from "./provider-package.js"
export { isContextOverflow, isContextOverflowFailure } from "./provider-error.js"
export type {
RouteLanguageModelInput,
RouteRoutedLanguageModelInput,
Interface as LLMClientShape,
Service as LLMClientService,
} from "./route/client"
export * from "./schema"
export { GeneratedImage, ImageInput, ImageInputSchema, ImageModel, ImageRequest, ImageResponse } from "./image"
export type { ImageModelOptions, ImageOptions, ImageRequestFor, ImageRequestInput, ImageRoute } from "./image"
export { Image } from "./image"
export { Tool, ToolFailure, toDefinitions } from "./tool"
export { ToolRuntime } from "./tool-runtime"
export type { DispatchResult as ToolDispatchResult, ToolSettlement } from "./tool-runtime"
} from "./route/client.js"
export * from "./schema/index.js"
export { GeneratedImage, ImageInput, ImageInputSchema, ImageModel, ImageRequest, ImageResponse } from "./image.js"
export type { ImageModelOptions, ImageOptions, ImageRequestFor, ImageRequestInput, ImageRoute } from "./image.js"
export { Image } from "./image.js"
export { Tool, ToolFailure, toDefinitions } from "./tool.js"
export { ToolRuntime } from "./tool-runtime.js"
export type { DispatchResult as ToolDispatchResult, ToolSettlement } from "./tool-runtime.js"
export type {
AnyExecutableTool,
AnyTool,
@@ -29,11 +29,14 @@ export type {
Tools,
ToolSchema,
ToolToModelOutput,
} from "./tool"
export * as LLM from "./llm"
} from "./tool.js"
export * as LLM from "./llm.js"
export type {
Definition as ProviderDefinition,
LanguageModelFactory as ProviderLanguageModelFactory,
LanguageModelOptions as ProviderLanguageModelOptions,
} from "./provider"
export type { Definition as ProviderPackageDefinition, Settings as ProviderPackageSettings } from "./provider-package"
} from "./provider.js"
export type {
Definition as ProviderPackageDefinition,
Settings as ProviderPackageSettings,
} from "./provider-package.js"
+3 -3
View File
@@ -1,5 +1,5 @@
import { Effect, JsonSchema, Schema } from "effect"
import { LLMClient, Service } from "./route/client"
import { LLMClient, Service } from "./route/client.js"
import {
GenerationOptions,
HttpOptions,
@@ -15,8 +15,8 @@ import {
ToolDefinition,
type ContentPart,
type LanguageModelProviderOptions,
} from "./schema"
import { make as makeTool, toDefinitions, type ToolSchema } from "./tool"
} from "./schema/index.js"
import { make as makeTool, toDefinitions, type ToolSchema } from "./tool.js"
/** Input accepted by `LLM.request`, normalized into the canonical `LLMRequest` class. */
export type RequestInput<SelectedLanguageModel extends LanguageModel = LanguageModel> = Omit<
+1 -1
View File
@@ -1 +1 @@
export * from "./protocols/index"
export * from "./protocols/index.js"
+17 -14
View File
@@ -1,10 +1,10 @@
import { Effect, Schema } from "effect"
import { Tool } from "@opencode-ai/schema/tool"
import { Route } from "../route/client"
import { Auth } from "../route/auth"
import { Endpoint } from "../route/endpoint"
import { Framing } from "../route/framing"
import { Protocol } from "../route/protocol"
import { Route } from "../route/client.js"
import { Auth } from "../route/auth.js"
import { Endpoint } from "../route/endpoint.js"
import { Framing } from "../route/framing.js"
import { Protocol } from "../route/protocol.js"
import {
AIError,
LLMEvent,
@@ -21,13 +21,13 @@ import {
type ToolCallPart,
type ToolDefinition,
type ToolResultPart,
} from "../schema"
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared"
import { classifyProviderFailure } from "../provider-error"
import * as Cache from "./utils/cache"
import { Lifecycle } from "./utils/lifecycle"
import { ToolSchemaProjection } from "./utils/tool-schema"
import { ToolStream } from "./utils/tool-stream"
} from "../schema/index.js"
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js"
import { classifyProviderFailure } from "../provider-error.js"
import * as Cache from "./utils/cache.js"
import { Lifecycle } from "./utils/lifecycle.js"
import { ToolSchemaProjection } from "./utils/tool-schema.js"
import { ToolStream } from "./utils/tool-stream.js"
const ADAPTER = "anthropic-messages"
const MEDIA_MIMES = new Set<string>([...ProviderShared.IMAGE_MIMES, ...ProviderShared.PDF_MIMES])
@@ -573,7 +573,10 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (
cache_control: cacheControl(breakpoints, part.cache),
})
}
messages.push({ role: "user", content })
const previous = messages.at(-1)
if (previous?.role === "user" && previous.content.every((block) => block.type === "tool_result"))
messages[messages.length - 1] = { role: "user", content: [...previous.content, ...content] }
else messages.push({ role: "user", content })
}
return messages
@@ -1029,4 +1032,4 @@ export const route = Route.make({
headers: () => ({ "anthropic-version": "2023-06-01" }),
})
export * as AnthropicMessages from "./anthropic-messages"
export * as AnthropicMessages from "./anthropic-messages.js"
+23 -17
View File
@@ -1,7 +1,7 @@
import { Effect, Schema } from "effect"
import { Route } from "../route/client"
import { Endpoint } from "../route/endpoint"
import { Protocol } from "../route/protocol"
import { Route } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Protocol } from "../route/protocol.js"
import {
AIError,
LLMEvent,
@@ -17,20 +17,20 @@ import {
type ToolCallPart,
type ToolDefinition,
type ToolResultPart,
} from "../schema"
import { BedrockEventStream } from "./bedrock-event-stream"
import { classifyProviderFailure } from "../provider-error"
import { JsonObject, optionalArray, ProviderShared } from "./shared"
import { BedrockAuth } from "./utils/bedrock-auth"
import { BedrockCache } from "./utils/bedrock-cache"
import { BedrockMedia } from "./utils/bedrock-media"
import { Lifecycle } from "./utils/lifecycle"
import { ToolSchemaProjection } from "./utils/tool-schema"
import { ToolStream } from "./utils/tool-stream"
} from "../schema/index.js"
import { BedrockEventStream } from "./bedrock-event-stream.js"
import { classifyProviderFailure } from "../provider-error.js"
import { JsonObject, optionalArray, ProviderShared } from "./shared.js"
import { BedrockAuth } from "./utils/bedrock-auth.js"
import { BedrockCache } from "./utils/bedrock-cache.js"
import { BedrockMedia } from "./utils/bedrock-media.js"
import { Lifecycle } from "./utils/lifecycle.js"
import { ToolSchemaProjection } from "./utils/tool-schema.js"
import { ToolStream } from "./utils/tool-stream.js"
const ADAPTER = "bedrock-converse"
export type { Credentials as BedrockCredentials } from "./utils/bedrock-auth"
export type { Credentials as BedrockCredentials } from "./utils/bedrock-auth.js"
// =============================================================================
// Request Body Schema
@@ -348,7 +348,10 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (
continue
}
}
messages.push({ role: "user", content })
const previous = messages.at(-1)
if (previous?.role === "user")
messages[messages.length - 1] = { role: "user", content: [...previous.content, ...content] }
else messages.push({ role: "user", content })
continue
}
@@ -392,7 +395,10 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (
const cachePoint = BedrockCache.block(breakpoints, part.cache)
if (cachePoint) content.push(cachePoint)
}
messages.push({ role: "user", content })
const previous = messages.at(-1)
if (previous?.role === "user")
messages[messages.length - 1] = { role: "user", content: [...previous.content, ...content] }
else messages.push({ role: "user", content })
}
return messages
@@ -731,4 +737,4 @@ export const route = Route.make({
export const sigV4Auth = BedrockAuth.sigV4
export * as BedrockConverse from "./bedrock-converse"
export * as BedrockConverse from "./bedrock-converse.js"
@@ -1,8 +1,8 @@
import { EventStreamCodec } from "@smithy/eventstream-codec"
import { fromUtf8, toUtf8 } from "@smithy/util-utf8"
import { Effect, Stream } from "effect"
import { Framing } from "../route/framing"
import { ProviderShared } from "./shared"
import { Framing } from "../route/framing.js"
import { ProviderShared } from "./shared.js"
// Bedrock streams responses using the AWS event stream binary protocol — each
// frame is `[length:4][headers-length:4][prelude-crc:4][headers][payload][crc:4]`.
@@ -98,4 +98,4 @@ export const framing = (route: string): Framing.Definition<object> => ({
frame: (bytes) => bytes.pipe(Stream.mapAccumEffect(() => initialFrameBuffer, consumeFrames(route))),
})
export * as BedrockEventStream from "./bedrock-event-stream"
export * as BedrockEventStream from "./bedrock-event-stream.js"
+11 -11
View File
@@ -1,10 +1,10 @@
import { Effect, Schema } from "effect"
import { Tool } from "@opencode-ai/schema/tool"
import { Route } from "../route/client"
import { Auth } from "../route/auth"
import { Endpoint } from "../route/endpoint"
import { Framing } from "../route/framing"
import { Protocol } from "../route/protocol"
import { Route } from "../route/client.js"
import { Auth } from "../route/auth.js"
import { Endpoint } from "../route/endpoint.js"
import { Framing } from "../route/framing.js"
import { Protocol } from "../route/protocol.js"
import {
LLMEvent,
Usage,
@@ -17,11 +17,11 @@ import {
type TextPart,
type ToolCallPart,
type ToolDefinition,
} from "../schema"
import { JsonObject, optionalArray, ProviderShared } from "./shared"
import { GeminiToolSchema } from "./utils/gemini-tool-schema"
import { Lifecycle } from "./utils/lifecycle"
import { ToolSchemaProjection } from "./utils/tool-schema"
} from "../schema/index.js"
import { JsonObject, optionalArray, ProviderShared } from "./shared.js"
import { GeminiToolSchema } from "./utils/gemini-tool-schema.js"
import { Lifecycle } from "./utils/lifecycle.js"
import { ToolSchemaProjection } from "./utils/tool-schema.js"
const ADAPTER = "gemini"
const MEDIA_MIMES = new Set<string>(ProviderShared.MEDIA_MIMES)
@@ -643,4 +643,4 @@ export const route = Route.make({
framing: Framing.sse,
})
export * as Gemini from "./gemini"
export * as Gemini from "./gemini.js"
+5 -5
View File
@@ -7,8 +7,8 @@ import {
type ImageInput,
type ImageRequestFor,
type ImageRoute,
} from "../image"
import { Auth, type Definition as AuthDefinition } from "../route/auth"
} from "../image.js"
import { Auth, type Definition as AuthDefinition } from "../route/auth.js"
import {
InvalidProviderOutputReason,
AIError,
@@ -17,9 +17,9 @@ import {
mergeJsonRecords,
type HttpOptions,
type ProviderMetadata,
} from "../schema"
import { ProviderShared } from "./shared"
import { ImageInputs } from "./utils/image-input"
} from "../schema/index.js"
import { ProviderShared } from "./shared.js"
import { ImageInputs } from "./utils/image-input.js"
const ADAPTER = "google-images"
export const DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com/v1beta"
+9 -9
View File
@@ -1,9 +1,9 @@
export * as AnthropicMessages from "./anthropic-messages"
export * as BedrockConverse from "./bedrock-converse"
export * as Gemini from "./gemini"
export * as OpenAIChat from "./openai-chat"
export * as OpenAIImages from "./openai-images"
export * as OpenAICompatibleChat from "./openai-compatible-chat"
export * as OpenAICompatibleResponses from "./openai-compatible-responses"
export * as OpenAIResponses from "./openai-responses"
export * as OpenResponses from "./open-responses"
export * as AnthropicMessages from "./anthropic-messages.js"
export * as BedrockConverse from "./bedrock-converse.js"
export * as Gemini from "./gemini.js"
export * as OpenAIChat from "./openai-chat.js"
export * as OpenAIImages from "./openai-images.js"
export * as OpenAICompatibleChat from "./openai-compatible-chat.js"
export * as OpenAICompatibleResponses from "./openai-compatible-responses.js"
export * as OpenAIResponses from "./openai-responses.js"
export * as OpenResponses from "./open-responses.js"
+10 -10
View File
@@ -1,7 +1,7 @@
import { Effect, Schema } from "effect"
import type { Content } from "@opencode-ai/schema/tool"
import { HttpTransport } from "../route/transport"
import { Protocol } from "../route/protocol"
import { HttpTransport } from "../route/transport/index.js"
import { Protocol } from "../route/protocol.js"
import {
AIError,
LLMEvent,
@@ -16,13 +16,13 @@ import {
type ToolCallPart,
type ToolDefinition,
type ToolResultPart,
} from "../schema"
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared"
import { classifyProviderFailure } from "../provider-error"
import { OpenResponsesOptions } from "./utils/open-responses-options"
import { Lifecycle } from "./utils/lifecycle"
import { ToolSchemaProjection } from "./utils/tool-schema"
import { ToolStream } from "./utils/tool-stream"
} from "../schema/index.js"
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js"
import { classifyProviderFailure } from "../provider-error.js"
import { OpenResponsesOptions } from "./utils/open-responses-options.js"
import { Lifecycle } from "./utils/lifecycle.js"
import { ToolSchemaProjection } from "./utils/tool-schema.js"
import { ToolStream } from "./utils/tool-stream.js"
const ADAPTER = "open-responses"
const NAME = "Open Responses"
@@ -1061,4 +1061,4 @@ export const protocol = Protocol.make({
export const httpTransport = HttpTransport.sseJson.with<OpenResponsesBody>()
export * as OpenResponses from "./open-responses"
export * as OpenResponses from "./open-responses.js"
+13 -13
View File
@@ -1,10 +1,10 @@
import { Effect, Schema } from "effect"
import { Tool } from "@opencode-ai/schema/tool"
import { Route } from "../route/client"
import { Auth } from "../route/auth"
import { Endpoint } from "../route/endpoint"
import { HttpTransport } from "../route/transport"
import { Protocol } from "../route/protocol"
import { Route } from "../route/client.js"
import { Auth } from "../route/auth.js"
import { Endpoint } from "../route/endpoint.js"
import { HttpTransport } from "../route/transport/index.js"
import { Protocol } from "../route/protocol.js"
import {
AIError,
LLMEvent,
@@ -19,13 +19,13 @@ import {
type TextPart,
type ToolCallPart,
type ToolDefinition,
} from "../schema"
import { classifyProviderFailure } from "../provider-error"
import { isRecord, JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared"
import { OpenAIOptions } from "./utils/openai-options"
import { Lifecycle } from "./utils/lifecycle"
import { ToolSchemaProjection } from "./utils/tool-schema"
import { ToolStream } from "./utils/tool-stream"
} from "../schema/index.js"
import { classifyProviderFailure } from "../provider-error.js"
import { isRecord, JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js"
import { OpenAIOptions } from "./utils/openai-options.js"
import { Lifecycle } from "./utils/lifecycle.js"
import { ToolSchemaProjection } from "./utils/tool-schema.js"
import { ToolStream } from "./utils/tool-stream.js"
const ADAPTER = "openai-chat"
const IMAGE_MIMES = new Set<string>(ProviderShared.IMAGE_MIMES)
@@ -884,4 +884,4 @@ export const route = Route.make({
transport: httpTransport,
})
export * as OpenAIChat from "./openai-chat"
export * as OpenAIChat from "./openai-chat.js"
@@ -1,7 +1,7 @@
import { Route, type RouteRoutedLanguageModelInput } from "../route/client"
import { Endpoint } from "../route/endpoint"
import { Framing } from "../route/framing"
import * as OpenAIChat from "./openai-chat"
import { Route, type RouteRoutedLanguageModelInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Framing } from "../route/framing.js"
import * as OpenAIChat from "./openai-chat.js"
const ADAPTER = "openai-compatible-chat"
@@ -22,4 +22,4 @@ export const route = Route.make({
framing: Framing.sse,
})
export * as OpenAICompatibleChat from "./openai-compatible-chat"
export * as OpenAICompatibleChat from "./openai-compatible-chat.js"
@@ -1,6 +1,6 @@
import { Route, type RouteRoutedLanguageModelInput } from "../route/client"
import { Endpoint } from "../route/endpoint"
import { OpenResponses } from "./open-responses"
import { Route, type RouteRoutedLanguageModelInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { OpenResponses } from "./open-responses.js"
const ADAPTER = "openai-compatible-responses"
@@ -19,4 +19,4 @@ export const route = Route.make({
transport: OpenResponses.httpTransport,
})
export * as OpenAICompatibleResponses from "./openai-compatible-responses"
export * as OpenAICompatibleResponses from "./openai-compatible-responses.js"
+6 -6
View File
@@ -7,8 +7,8 @@ import {
type ImageInput,
type ImageRequestFor,
type ImageRoute,
} from "../image"
import { Auth, type Definition as AuthDefinition } from "../route/auth"
} from "../image.js"
import { Auth, type Definition as AuthDefinition } from "../route/auth.js"
import {
InvalidProviderOutputReason,
AIError,
@@ -16,10 +16,10 @@ import {
mergeHttpOptions,
mergeJsonRecords,
type HttpOptions,
} from "../schema"
import { ProviderShared } from "./shared"
import { ImageInputs } from "./utils/image-input"
import { OpenAIImage } from "./utils/openai-image"
} from "../schema/index.js"
import { ProviderShared } from "./shared.js"
import { ImageInputs } from "./utils/image-input.js"
import { OpenAIImage } from "./utils/openai-image.js"
const ADAPTER = "openai-images"
export const DEFAULT_BASE_URL = "https://api.openai.com/v1"
+12 -12
View File
@@ -1,15 +1,15 @@
import { Effect, Encoding, Schema } from "effect"
import { Route } from "../route/client"
import { Auth } from "../route/auth"
import { Endpoint } from "../route/endpoint"
import { Protocol } from "../route/protocol"
import { HttpTransport, WebSocketTransport } from "../route/transport"
import { LLMEvent, LLMRequest, type JsonSchema, type ToolDefinition } from "../schema"
import { OpenResponses } from "./open-responses"
import { optionalArray, ProviderShared } from "./shared"
import { Lifecycle } from "./utils/lifecycle"
import { OpenAIImage } from "./utils/openai-image"
import { ToolSchemaProjection } from "./utils/tool-schema"
import { Route } from "../route/client.js"
import { Auth } from "../route/auth.js"
import { Endpoint } from "../route/endpoint.js"
import { Protocol } from "../route/protocol.js"
import { HttpTransport, WebSocketTransport } from "../route/transport/index.js"
import { LLMEvent, LLMRequest, type JsonSchema, type ToolDefinition } from "../schema/index.js"
import { OpenResponses } from "./open-responses.js"
import { optionalArray, ProviderShared } from "./shared.js"
import { Lifecycle } from "./utils/lifecycle.js"
import { OpenAIImage } from "./utils/openai-image.js"
import { ToolSchemaProjection } from "./utils/tool-schema.js"
const ADAPTER = "openai-responses"
const NAME = "OpenAI Responses"
@@ -290,4 +290,4 @@ export const webSocketRoute = Route.make({
defaults: { providerOptions: { openai: { store: false } } },
})
export * as OpenAIResponses from "./openai-responses"
export * as OpenAIResponses from "./openai-responses.js"
+3 -3
View File
@@ -12,8 +12,8 @@ import {
type MediaPart,
type TextPart,
type ToolResultPart,
} from "../schema"
import { isRecord } from "../utils/record"
} from "../schema/index.js"
import { isRecord } from "../utils/record.js"
export { isRecord }
export const Json = Schema.fromJsonString(Schema.Unknown)
@@ -324,4 +324,4 @@ export const jsonPost = (input: { readonly url: string; readonly body: string; r
HttpClientRequest.bodyText(input.body, "application/json"),
)
export * as ProviderShared from "./shared"
export * as ProviderShared from "./shared.js"
@@ -1,8 +1,8 @@
import { AwsV4Signer } from "aws4fetch"
import { Effect } from "effect"
import { Headers } from "effect/unstable/http"
import { Auth, type AuthInput } from "../../route/auth"
import { ProviderShared } from "../shared"
import { Auth, type AuthInput } from "../../route/auth.js"
import { ProviderShared } from "../shared.js"
/**
* AWS credentials for SigV4 signing. Bedrock also supports Bearer API key auth,
@@ -74,4 +74,4 @@ export const sigV4 = (
/** Bedrock route auth defaults to SigV4 and expects credentials from route configuration. */
export const auth = sigV4(undefined)
export * as BedrockAuth from "./bedrock-auth"
export * as BedrockAuth from "./bedrock-auth.js"
@@ -1,6 +1,6 @@
import { Schema } from "effect"
import type { CacheHint } from "../../schema"
import { newBreakpoints, ttlBucket, type Breakpoints } from "./cache"
import type { CacheHint } from "../../schema/index.js"
import { newBreakpoints, ttlBucket, type Breakpoints } from "./cache.js"
// Bedrock cache markers are positional: emit a `cachePoint` block immediately
// after the content the caller wants treated as a cacheable prefix. Bedrock
@@ -18,7 +18,7 @@ export type CachePointBlock = Schema.Schema.Type<typeof CachePointBlock>
// budget is respected across `system`, `messages`, and `tools`.
export const BEDROCK_BREAKPOINT_CAP = 4
export type { Breakpoints } from "./cache"
export type { Breakpoints } from "./cache.js"
export const breakpoints = () => newBreakpoints(BEDROCK_BREAKPOINT_CAP)
const DEFAULT_5M: CachePointBlock = { cachePoint: { type: "default" } }
@@ -34,4 +34,4 @@ export const block = (breakpoints: Breakpoints, cache: CacheHint | undefined): C
return ttlBucket(cache.ttlSeconds) === "1h" ? DEFAULT_1H : DEFAULT_5M
}
export * as BedrockCache from "./bedrock-cache"
export * as BedrockCache from "./bedrock-cache.js"
@@ -1,6 +1,6 @@
import { Effect, Schema } from "effect"
import type { MediaPart } from "../../schema"
import { ProviderShared } from "../shared"
import type { MediaPart } from "../../schema/index.js"
import { ProviderShared } from "../shared.js"
// Bedrock Converse accepts image `format` as the file extension and
// `source.bytes` as base64 in the JSON wire format.
@@ -89,4 +89,4 @@ export const lower = Effect.fn("BedrockMedia.lower")(function* (part: MediaPart)
return yield* ProviderShared.invalidRequest(`Bedrock Converse does not support media type ${part.mediaType}`)
})
export * as BedrockMedia from "./bedrock-media"
export * as BedrockMedia from "./bedrock-media.js"
@@ -1,4 +1,4 @@
import { isRecord } from "../../utils/record"
import { isRecord } from "../../utils/record.js"
// Gemini accepts a JSON Schema-like dialect for tool parameters, but rejects a
// handful of common JSON Schema shapes. Keep this projection isolated so the
@@ -116,4 +116,4 @@ const projectNode = (schema: unknown, nested = false): Record<string, unknown> |
export const convert = (schema: unknown) => projectNode(sanitizeNode(schema))
export * as GeminiToolSchema from "./gemini-tool-schema"
export * as GeminiToolSchema from "./gemini-tool-schema.js"
@@ -1,6 +1,6 @@
import { Effect, Encoding } from "effect"
import type { ImageInput } from "../../image"
import { InvalidRequestReason, AIError } from "../../schema"
import type { ImageInput } from "../../image.js"
import { InvalidRequestReason, AIError } from "../../schema/index.js"
const invalid = (module: string, message: string) =>
new AIError({
+2 -2
View File
@@ -1,4 +1,4 @@
import { LLMEvent, type FinishReasonDetails, type ProviderMetadata, type Usage } from "../../schema"
import { LLMEvent, type FinishReasonDetails, type ProviderMetadata, type Usage } from "../../schema/index.js"
export interface State {
readonly stepStarted: boolean
@@ -102,4 +102,4 @@ export const finish = (
return { ...stepped, stepStarted: false }
}
export * as Lifecycle from "./lifecycle"
export * as Lifecycle from "./lifecycle.js"
@@ -1,5 +1,5 @@
import { Schema } from "effect"
import { TextVerbosity, type LLMRequest } from "../../schema"
import { TextVerbosity, type LLMRequest } from "../../schema/index.js"
export const ResponseIncludables = [
"file_search_call.results",
@@ -60,4 +60,4 @@ export const resolve = (request: LLMRequest): Resolved => {
}
}
export * as OpenResponsesOptions from "./open-responses-options"
export * as OpenResponsesOptions from "./open-responses-options.js"
@@ -1,5 +1,5 @@
import { ReasoningEfforts } from "../../schema"
import { OpenResponsesOptions } from "./open-responses-options"
import { ReasoningEfforts } from "../../schema/index.js"
import { OpenResponsesOptions } from "./open-responses-options.js"
export const OpenAIReasoningEfforts = ReasoningEfforts
export type OpenAIReasoningEffort = string
@@ -20,4 +20,4 @@ export const isReasoningEffort = (effort: unknown): effort is OpenAIReasoningEff
export const resolve = OpenResponsesOptions.resolve
export * as OpenAIOptions from "./openai-options"
export * as OpenAIOptions from "./openai-options.js"
@@ -1,6 +1,6 @@
import type { JsonSchema, LanguageModelToolSchemaCompatibility } from "../../schema"
import { isRecord } from "../../utils/record"
import { GeminiToolSchema } from "./gemini-tool-schema"
import type { JsonSchema, LanguageModelToolSchemaCompatibility } from "../../schema/index.js"
import { isRecord } from "../../utils/record.js"
import { GeminiToolSchema } from "./gemini-tool-schema.js"
const removeNullSchemas = (value: unknown): unknown => {
if (Array.isArray(value)) return value.map(removeNullSchemas)
@@ -1,6 +1,6 @@
import { Effect } from "effect"
import { AIError, LLMEvent, type ProviderMetadata, type ToolCall, type ToolInputError } from "../../schema"
import { eventError, parseToolInput, type ToolAccumulator } from "../shared"
import { AIError, LLMEvent, type ProviderMetadata, type ToolCall, type ToolInputError } from "../../schema/index.js"
import { eventError, parseToolInput, type ToolAccumulator } from "../shared.js"
type StreamKey = string | number
@@ -223,4 +223,4 @@ export const finishAll = <K extends StreamKey>(route: string, tools: State<K>) =
}
})
export * as ToolStream from "./tool-stream"
export * as ToolStream from "./tool-stream.js"
+5 -5
View File
@@ -1,7 +1,7 @@
import { Effect, Encoding, Schema } from "effect"
import { Headers, HttpClientRequest } from "effect/unstable/http"
import { GeneratedImage, ImageModel, ImageResponse, type ImageRequestFor, type ImageRoute } from "../image"
import { Auth, type Definition as AuthDefinition } from "../route/auth"
import { GeneratedImage, ImageModel, ImageResponse, type ImageRequestFor, type ImageRoute } from "../image.js"
import { Auth, type Definition as AuthDefinition } from "../route/auth.js"
import {
InvalidProviderOutputReason,
AIError,
@@ -9,9 +9,9 @@ import {
mergeHttpOptions,
mergeJsonRecords,
type HttpOptions,
} from "../schema"
import { ProviderShared, optionalNull } from "./shared"
import { ImageInputs } from "./utils/image-input"
} from "../schema/index.js"
import { ProviderShared, optionalNull } from "./shared.js"
import { ImageInputs } from "./utils/image-input.js"
const ADAPTER = "xai-images"
export const DEFAULT_BASE_URL = "https://api.x.ai/v1"
+11 -5
View File
@@ -1,10 +1,16 @@
import { Effect, Schema } from "effect"
import { Headers, HttpClientRequest } from "effect/unstable/http"
import { GeneratedImage, ImageModel, ImageResponse, type ImageRequestFor, type ImageRoute } from "../image"
import { Auth, type Definition as AuthDefinition } from "../route/auth"
import { InvalidProviderOutputReason, AIError, mergeHttpOptions, mergeJsonRecords, type HttpOptions } from "../schema"
import { ProviderShared } from "./shared"
import { ImageInputs } from "./utils/image-input"
import { GeneratedImage, ImageModel, ImageResponse, type ImageRequestFor, type ImageRoute } from "../image.js"
import { Auth, type Definition as AuthDefinition } from "../route/auth.js"
import {
InvalidProviderOutputReason,
AIError,
mergeHttpOptions,
mergeJsonRecords,
type HttpOptions,
} from "../schema/index.js"
import { ProviderShared } from "./shared.js"
import { ImageInputs } from "./utils/image-input.js"
const ADAPTER = "zai-images"
export const DEFAULT_BASE_URL = "https://api.z.ai/api/paas/v4"
+1 -1
View File
@@ -12,7 +12,7 @@ import {
type HttpContext,
type HttpRateLimitDetails,
type ProviderMetadata,
} from "./schema"
} from "./schema/index.js"
const patterns = [
/prompt is too long/i,
+2 -2
View File
@@ -1,4 +1,4 @@
import type { LanguageModel, ProviderOptions } from "./schema"
import type { LanguageModel, ProviderOptions } from "./schema/index.js"
export interface Settings extends Readonly<Record<string, unknown>> {
readonly baseURL?: string
@@ -18,4 +18,4 @@ export interface Definition<
readonly model: (modelID: string, settings: ProviderSettings) => LanguageModel<Options>
}
export * as ProviderPackage from "./provider-package"
export * as ProviderPackage from "./provider-package.js"
+2 -2
View File
@@ -1,4 +1,4 @@
import type { LanguageModel, ModelID, ProviderID } from "./schema"
import type { LanguageModel, ModelID, ProviderID } from "./schema/index.js"
export type LanguageModelOptions = Pick<LanguageModel.Input, "defaults" | "compatibility">
@@ -33,4 +33,4 @@ export const make = <DefinitionType extends DefinitionShape>(
definition: NoExtraFields<DefinitionType, DefinitionShape>,
) => definition
export * as Provider from "./provider"
export * as Provider from "./provider.js"
+1 -1
View File
@@ -1 +1 @@
export * from "./providers/index"
export * from "./providers/index.js"
@@ -1,11 +1,11 @@
import { Auth } from "../route/auth"
import type { Route as RouteDef, RouteDefaultsInput } from "../route/client"
import type { ProviderPackage } from "../provider-package"
import { OpenAIChat } from "../protocols/openai-chat"
import { OpenAIResponses } from "../protocols/openai-responses"
import { BedrockAuth, type Credentials } from "../protocols/utils/bedrock-auth"
import { ProviderID, type ModelID } from "../schema"
import { withOpenAIOptions, type OpenAIProviderOptionsInput } from "./openai-options"
import { Auth } from "../route/auth.js"
import type { Route as RouteDef, RouteDefaultsInput } from "../route/client.js"
import type { ProviderPackage } from "../provider-package.js"
import { OpenAIChat } from "../protocols/openai-chat.js"
import { OpenAIResponses } from "../protocols/openai-responses.js"
import { BedrockAuth, type Credentials } from "../protocols/utils/bedrock-auth.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { withOpenAIOptions, type OpenAIProviderOptionsInput } from "./openai-options.js"
export const id = ProviderID.make("amazon-bedrock")
+6 -6
View File
@@ -1,9 +1,9 @@
import type { RouteDefaultsInput } from "../route/client"
import { Auth } from "../route/auth"
import type { ProviderPackage } from "../provider-package"
import { ProviderID, type ModelID } from "../schema"
import * as BedrockConverse from "../protocols/bedrock-converse"
import type { BedrockCredentials } from "../protocols/bedrock-converse"
import type { RouteDefaultsInput } from "../route/client.js"
import { Auth } from "../route/auth.js"
import type { ProviderPackage } from "../provider-package.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import * as BedrockConverse from "../protocols/bedrock-converse.js"
import type { BedrockCredentials } from "../protocols/bedrock-converse.js"
export const id = ProviderID.make("amazon-bedrock")
@@ -1,2 +1,2 @@
export { chatModel as model } from "../amazon-bedrock-mantle"
export type { Settings } from "../amazon-bedrock-mantle"
export { chatModel as model } from "../amazon-bedrock-mantle.js"
export type { Settings } from "../amazon-bedrock-mantle.js"
@@ -1,2 +1,2 @@
export { chatModel as model } from "../../amazon-bedrock-mantle"
export type { Settings } from "../../amazon-bedrock-mantle"
export { chatModel as model } from "../../amazon-bedrock-mantle.js"
export type { Settings } from "../../amazon-bedrock-mantle.js"
@@ -1,2 +1,2 @@
export { responsesModel as model } from "../../amazon-bedrock-mantle"
export type { Settings } from "../../amazon-bedrock-mantle"
export { responsesModel as model } from "../../amazon-bedrock-mantle.js"
export type { Settings } from "../../amazon-bedrock-mantle.js"
@@ -1,9 +1,9 @@
import type { ProviderPackage } from "../provider-package"
import { AnthropicMessages } from "../protocols/anthropic-messages"
import { Auth } from "../route/auth"
import type { ProviderAuthOption } from "../route/auth-options"
import type { RouteDefaultsInput } from "../route/client"
import { ProviderID, type ModelID } from "../schema"
import type { ProviderPackage } from "../provider-package.js"
import { AnthropicMessages } from "../protocols/anthropic-messages.js"
import { Auth } from "../route/auth.js"
import type { ProviderAuthOption } from "../route/auth-options.js"
import type { RouteDefaultsInput } from "../route/client.js"
import { ProviderID, type ModelID } from "../schema/index.js"
export type AnthropicOptionsInput = AnthropicMessages.OptionsInput
export type AnthropicProviderOptionsInput = AnthropicMessages.ProviderOptionsInput
@@ -74,4 +74,4 @@ export const model: ProviderPackage.Definition<Settings, AnthropicMessages.Provi
}).model(modelID)
}
export * as AnthropicCompatible from "./anthropic-compatible"
export * as AnthropicCompatible from "./anthropic-compatible.js"
+7 -7
View File
@@ -1,10 +1,10 @@
import type { RouteDefaultsInput } from "../route/client"
import { Auth } from "../route/auth"
import type { ProviderAuthOption } from "../route/auth-options"
import type { ProviderPackage } from "../provider-package"
import { ProviderID, type ModelID } from "../schema"
import { AnthropicMessages } from "../protocols/anthropic-messages"
import { AnthropicCompatible } from "./anthropic-compatible"
import type { RouteDefaultsInput } from "../route/client.js"
import { Auth } from "../route/auth.js"
import type { ProviderAuthOption } from "../route/auth-options.js"
import type { ProviderPackage } from "../provider-package.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { AnthropicMessages } from "../protocols/anthropic-messages.js"
import { AnthropicCompatible } from "./anthropic-compatible.js"
export type AnthropicOptionsInput = AnthropicMessages.OptionsInput
export type AnthropicProviderOptionsInput = AnthropicMessages.ProviderOptionsInput
+9 -9
View File
@@ -1,12 +1,12 @@
import { Auth } from "../route/auth"
import { type AtLeastOne, type ProviderAuthOption } from "../route/auth-options"
import type { Route as RouteDef, RouteDefaultsInput } from "../route/client"
import type { ProviderPackage } from "../provider-package"
import { ProviderID, type ModelID } from "../schema"
import * as OpenAIChat from "../protocols/openai-chat"
import * as OpenAIResponses from "../protocols/openai-responses"
import { ProviderShared } from "../protocols/shared"
import { withOpenAIOptions, type OpenAIProviderOptionsInput } from "./openai-options"
import { Auth } from "../route/auth.js"
import { type AtLeastOne, type ProviderAuthOption } from "../route/auth-options.js"
import type { Route as RouteDef, RouteDefaultsInput } from "../route/client.js"
import type { ProviderPackage } from "../provider-package.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import * as OpenAIChat from "../protocols/openai-chat.js"
import * as OpenAIResponses from "../protocols/openai-responses.js"
import { ProviderShared } from "../protocols/shared.js"
import { withOpenAIOptions, type OpenAIProviderOptionsInput } from "./openai-options.js"
export const id = ProviderID.make("azure")
const routeAuth = Auth.remove("authorization")
+2 -2
View File
@@ -1,2 +1,2 @@
export { chatModel as model } from "../azure"
export type { Settings } from "../azure"
export { chatModel as model } from "../azure.js"
export type { Settings } from "../azure.js"
+2 -2
View File
@@ -1,2 +1,2 @@
export { responsesModel as model } from "../azure"
export type { Settings } from "../azure"
export { responsesModel as model } from "../azure.js"
export type { Settings } from "../azure.js"
+6 -6
View File
@@ -1,10 +1,10 @@
import type { Config, Redacted } from "effect"
import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat"
import { Auth } from "../route/auth"
import { AuthOptions, type AtLeastOne, type ProviderAuthOption } from "../route/auth-options"
import type { RouteDefaultsInput } from "../route/client"
import { ProviderID, type ModelID } from "../schema"
import type { OpenAIProviderOptionsInput } from "./openai-options"
import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat.js"
import { Auth } from "../route/auth.js"
import { AuthOptions, type AtLeastOne, type ProviderAuthOption } from "../route/auth-options.js"
import type { RouteDefaultsInput } from "../route/client.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import type { OpenAIProviderOptionsInput } from "./openai-options.js"
export const aiGatewayID = ProviderID.make("cloudflare-ai-gateway")
export const workersAIID = ProviderID.make("cloudflare-workers-ai")
@@ -1,9 +1,9 @@
import type { ProviderPackage } from "../provider-package"
import { OpenAICompatibleChat } from "../protocols/openai-compatible-chat"
import type { RouteDefaultsInput } from "../route/client"
import { ProviderID, type ModelID } from "../schema"
import { GoogleVertexShared } from "./google-vertex-shared"
import type { OpenAIProviderOptionsInput } from "./openai-options"
import type { ProviderPackage } from "../provider-package.js"
import { OpenAICompatibleChat } from "../protocols/openai-compatible-chat.js"
import type { RouteDefaultsInput } from "../route/client.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { GoogleVertexShared } from "./google-vertex-shared.js"
import type { OpenAIProviderOptionsInput } from "./openai-options.js"
export const id = ProviderID.make("google-vertex")
@@ -1,13 +1,13 @@
import { Effect, Schema, Struct } from "effect"
import type { ProviderPackage } from "../provider-package"
import { AnthropicMessages } from "../protocols/anthropic-messages"
import { Auth } from "../route/auth"
import { Route, type RouteDefaultsInput } from "../route/client"
import { Endpoint } from "../route/endpoint"
import { Framing } from "../route/framing"
import { Protocol } from "../route/protocol"
import { ProviderID, type ModelID } from "../schema"
import { GoogleVertexShared } from "./google-vertex-shared"
import type { ProviderPackage } from "../provider-package.js"
import { AnthropicMessages } from "../protocols/anthropic-messages.js"
import { Auth } from "../route/auth.js"
import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Framing } from "../route/framing.js"
import { Protocol } from "../route/protocol.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { GoogleVertexShared } from "./google-vertex-shared.js"
export type AnthropicOptionsInput = AnthropicMessages.OptionsInput
export type AnthropicProviderOptionsInput = AnthropicMessages.ProviderOptionsInput
@@ -1,9 +1,9 @@
import type { ProviderPackage } from "../provider-package"
import { OpenAICompatibleResponses } from "../protocols/openai-compatible-responses"
import type { RouteDefaultsInput } from "../route/client"
import { ProviderID, type ModelID } from "../schema"
import { GoogleVertexShared } from "./google-vertex-shared"
import type { OpenResponsesProviderOptionsInput } from "./open-responses-options"
import type { ProviderPackage } from "../provider-package.js"
import { OpenAICompatibleResponses } from "../protocols/openai-compatible-responses.js"
import type { RouteDefaultsInput } from "../route/client.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { GoogleVertexShared } from "./google-vertex-shared.js"
import type { OpenResponsesProviderOptionsInput } from "./open-responses-options.js"
export const id = ProviderID.make("google-vertex")
@@ -1,6 +1,6 @@
import type { AnyAuthClient } from "google-auth-library"
import { Effect, Redacted } from "effect"
import { Auth, MissingCredentialError } from "../route/auth"
import { Auth, MissingCredentialError } from "../route/auth.js"
const SCOPE = "https://www.googleapis.com/auth/cloud-platform"
@@ -74,4 +74,4 @@ export const oauth = (input: OAuthOptions, project?: string) => {
return adc(project)
}
export * as GoogleVertexShared from "./google-vertex-shared"
export * as GoogleVertexShared from "./google-vertex-shared.js"
+8 -8
View File
@@ -1,11 +1,11 @@
import type { ProviderPackage } from "../provider-package"
import { Gemini } from "../protocols/gemini"
import { Auth } from "../route/auth"
import { Route, type RouteDefaultsInput } from "../route/client"
import { Endpoint } from "../route/endpoint"
import { Framing } from "../route/framing"
import { ProviderID, type ModelID } from "../schema"
import { GoogleVertexShared } from "./google-vertex-shared"
import type { ProviderPackage } from "../provider-package.js"
import { Gemini } from "../protocols/gemini.js"
import { Auth } from "../route/auth.js"
import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Framing } from "../route/framing.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import { GoogleVertexShared } from "./google-vertex-shared.js"
export type GeminiOptionsInput = Gemini.OptionsInput
export type GeminiProviderOptionsInput = Gemini.ProviderOptionsInput
@@ -1,2 +1,2 @@
export { model } from "../google-vertex-chat"
export type { Settings } from "../google-vertex-chat"
export { model } from "../google-vertex-chat.js"
export type { Settings } from "../google-vertex-chat.js"
@@ -1,2 +1,2 @@
export { model } from "../google-vertex"
export type { Settings } from "../google-vertex"
export { model } from "../google-vertex.js"
export type { Settings } from "../google-vertex.js"
@@ -1,2 +1,2 @@
export { model } from "../google-vertex-messages"
export type { Settings } from "../google-vertex-messages"
export { model } from "../google-vertex-messages.js"
export type { Settings } from "../google-vertex-messages.js"
@@ -1,2 +1,2 @@
export { model } from "../google-vertex-responses"
export type { Settings } from "../google-vertex-responses"
export { model } from "../google-vertex-responses.js"
export type { Settings } from "../google-vertex-responses.js"
+8 -8
View File
@@ -1,12 +1,12 @@
import type { RouteDefaultsInput } from "../route/client"
import { Auth } from "../route/auth"
import type { ProviderAuthOption } from "../route/auth-options"
import type { ProviderPackage } from "../provider-package"
import { HttpOptions, ProviderID, mergeHttpOptions, type ModelID } from "../schema"
import { Gemini } from "../protocols/gemini"
import { GoogleImages } from "../protocols/google-images"
import type { RouteDefaultsInput } from "../route/client.js"
import { Auth } from "../route/auth.js"
import type { ProviderAuthOption } from "../route/auth-options.js"
import type { ProviderPackage } from "../provider-package.js"
import { HttpOptions, ProviderID, mergeHttpOptions, type ModelID } from "../schema/index.js"
import { Gemini } from "../protocols/gemini.js"
import { GoogleImages } from "../protocols/google-images.js"
export type { GoogleImageOptions } from "../protocols/google-images"
export type { GoogleImageOptions } from "../protocols/google-images.js"
export type GeminiOptionsInput = Gemini.OptionsInput
export type GeminiProviderOptionsInput = Gemini.ProviderOptionsInput
+18 -18
View File
@@ -1,18 +1,18 @@
export * as Anthropic from "./anthropic"
export * as AnthropicCompatible from "./anthropic-compatible"
export * as AmazonBedrock from "./amazon-bedrock"
export * as AmazonBedrockMantle from "./amazon-bedrock-mantle"
export * as Azure from "./azure"
export * as Cloudflare from "./cloudflare"
export { CloudflareAIGateway, CloudflareWorkersAI } from "./cloudflare"
export * as Google from "./google"
export * as GoogleVertex from "./google-vertex"
export * as GoogleVertexChat from "./google-vertex-chat"
export * as GoogleVertexMessages from "./google-vertex-messages"
export * as GoogleVertexResponses from "./google-vertex-responses"
export * as OpenAI from "./openai"
export * as OpenAICompatible from "./openai-compatible"
export * as OpenAICompatibleResponses from "./openai-compatible-responses"
export * as OpenRouter from "./openrouter"
export * as XAI from "./xai"
export * as ZAI from "./zai"
export * as Anthropic from "./anthropic.js"
export * as AnthropicCompatible from "./anthropic-compatible.js"
export * as AmazonBedrock from "./amazon-bedrock.js"
export * as AmazonBedrockMantle from "./amazon-bedrock-mantle.js"
export * as Azure from "./azure.js"
export * as Cloudflare from "./cloudflare.js"
export { CloudflareAIGateway, CloudflareWorkersAI } from "./cloudflare.js"
export * as Google from "./google.js"
export * as GoogleVertex from "./google-vertex.js"
export * as GoogleVertexChat from "./google-vertex-chat.js"
export * as GoogleVertexMessages from "./google-vertex-messages.js"
export * as GoogleVertexResponses from "./google-vertex-responses.js"
export * as OpenAI from "./openai.js"
export * as OpenAICompatible from "./openai-compatible.js"
export * as OpenAICompatibleResponses from "./openai-compatible-responses.js"
export * as OpenRouter from "./openrouter.js"
export * as XAI from "./xai.js"
export * as ZAI from "./zai.js"
@@ -1,5 +1,5 @@
import type { ResponseIncludable, ServiceTier } from "../protocols/utils/open-responses-options"
import type { ProviderOptions, ReasoningEffort, TextVerbosity } from "../schema"
import type { ResponseIncludable, ServiceTier } from "../protocols/utils/open-responses-options.js"
import type { ProviderOptions, ReasoningEffort, TextVerbosity } from "../schema/index.js"
export interface OpenResponsesOptionsInput {
readonly [key: string]: unknown
@@ -16,4 +16,4 @@ export type OpenResponsesProviderOptionsInput = ProviderOptions & {
readonly openresponses?: OpenResponsesOptionsInput
}
export * as OpenResponsesProviderOptions from "./open-responses-options"
export * as OpenResponsesProviderOptions from "./open-responses-options.js"
@@ -1,11 +1,11 @@
import type { ProviderPackage } from "../provider-package"
import { OpenAICompatibleResponses } from "../protocols/openai-compatible-responses"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options"
import type { RouteDefaultsInput } from "../route/client"
import { ProviderID, type ModelID } from "../schema"
import type { OpenResponsesProviderOptionsInput } from "./open-responses-options"
import type { ProviderPackage } from "../provider-package.js"
import { OpenAICompatibleResponses } from "../protocols/openai-compatible-responses.js"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.js"
import type { RouteDefaultsInput } from "../route/client.js"
import { ProviderID, type ModelID } from "../schema/index.js"
import type { OpenResponsesProviderOptionsInput } from "./open-responses-options.js"
export type { OpenResponsesOptionsInput, OpenResponsesProviderOptionsInput } from "./open-responses-options"
export type { OpenResponsesOptionsInput, OpenResponsesProviderOptionsInput } from "./open-responses-options.js"
export const id = ProviderID.make("openai-compatible")
@@ -1,10 +1,10 @@
import { ProviderID, type ModelID } from "../schema"
import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat"
import type { RouteDefaultsInput } from "../route/client"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options"
import type { ProviderPackage } from "../provider-package"
import { profiles, type OpenAICompatibleProfile } from "./openai-compatible-profile"
import type { OpenAIProviderOptionsInput } from "./openai-options"
import { ProviderID, type ModelID } from "../schema/index.js"
import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat.js"
import type { RouteDefaultsInput } from "../route/client.js"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.js"
import type { ProviderPackage } from "../provider-package.js"
import { profiles, type OpenAICompatibleProfile } from "./openai-compatible-profile.js"
import type { OpenAIProviderOptionsInput } from "./openai-options.js"
export const id = ProviderID.make("openai-compatible")
@@ -1 +1 @@
export * from "../openai-compatible-responses"
export * from "../openai-compatible-responses.js"
+5 -5
View File
@@ -1,8 +1,8 @@
import type { ProviderOptions } from "../schema"
import { mergeProviderOptions } from "../schema"
import type { OpenResponsesOptionsInput } from "./open-responses-options"
import type { ProviderOptions } from "../schema/index.js"
import { mergeProviderOptions } from "../schema/index.js"
import type { OpenResponsesOptionsInput } from "./open-responses-options.js"
export type { OpenAIResponseIncludable, OpenAIServiceTier } from "../protocols/utils/openai-options"
export type { OpenAIResponseIncludable, OpenAIServiceTier } from "../protocols/utils/openai-options.js"
export type OpenAIOptionsInput = OpenResponsesOptionsInput
@@ -67,4 +67,4 @@ export const withOpenAIOptions = <Options extends { readonly providerOptions?: O
}
}
export * as OpenAIProviderOptions from "./openai-options"
export * as OpenAIProviderOptions from "./openai-options.js"
+10 -10
View File
@@ -1,14 +1,14 @@
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options"
import type { Route, RouteDefaultsInput } from "../route/client"
import type { ProviderPackage } from "../provider-package"
import { HttpOptions, ProviderID, ToolDefinition, mergeHttpOptions, type ModelID } from "../schema"
import * as OpenAIChat from "../protocols/openai-chat"
import * as OpenAIResponses from "../protocols/openai-responses"
import { withOpenAIOptions, type OpenAIProviderOptionsInput } from "./openai-options"
import { OpenAIImages, type OpenAIImageString } from "../protocols/openai-images"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.js"
import type { Route, RouteDefaultsInput } from "../route/client.js"
import type { ProviderPackage } from "../provider-package.js"
import { HttpOptions, ProviderID, ToolDefinition, mergeHttpOptions, type ModelID } from "../schema/index.js"
import * as OpenAIChat from "../protocols/openai-chat.js"
import * as OpenAIResponses from "../protocols/openai-responses.js"
import { withOpenAIOptions, type OpenAIProviderOptionsInput } from "./openai-options.js"
import { OpenAIImages, type OpenAIImageString } from "../protocols/openai-images.js"
export type { OpenAIOptionsInput, OpenAIResponseIncludable } from "./openai-options"
export type { OpenAIImageOptions } from "../protocols/openai-images"
export type { OpenAIOptionsInput, OpenAIResponseIncludable } from "./openai-options.js"
export type { OpenAIImageOptions } from "../protocols/openai-images.js"
export const id = ProviderID.make("openai")
+2 -2
View File
@@ -1,2 +1,2 @@
export { chatModel as model } from "../openai"
export type { Settings } from "../openai"
export { chatModel as model } from "../openai.js"
export type { Settings } from "../openai.js"
@@ -1,2 +1,2 @@
export { model } from "../openai"
export type { Settings } from "../openai"
export { model } from "../openai.js"
export type { Settings } from "../openai.js"
+11 -11
View File
@@ -1,15 +1,15 @@
import { Effect, Schema } from "effect"
import { Route, type RouteDefaultsInput } from "../route/client"
import { Endpoint } from "../route/endpoint"
import { Framing } from "../route/framing"
import { Protocol } from "../route/protocol"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options"
import { ProviderID, type CacheHint, type ModelID, type ProviderOptions } from "../schema"
import type { ProviderPackage } from "../provider-package"
import * as OpenAICompatibleProfiles from "./openai-compatible-profile"
import * as OpenAIChat from "../protocols/openai-chat"
import { newBreakpoints, ttlBucket } from "../protocols/utils/cache"
import { isRecord } from "../protocols/shared"
import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { Framing } from "../route/framing.js"
import { Protocol } from "../route/protocol.js"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.js"
import { ProviderID, type CacheHint, type ModelID, type ProviderOptions } from "../schema/index.js"
import type { ProviderPackage } from "../provider-package.js"
import * as OpenAICompatibleProfiles from "./openai-compatible-profile.js"
import * as OpenAIChat from "../protocols/openai-chat.js"
import { newBreakpoints, ttlBucket } from "../protocols/utils/cache.js"
import { isRecord } from "../protocols/shared.js"
export const profile = OpenAICompatibleProfiles.profiles.openrouter
export const id = ProviderID.make(profile.provider)
+12 -12
View File
@@ -1,14 +1,14 @@
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options"
import { Route, type RouteDefaultsInput } from "../route/client"
import { Endpoint } from "../route/endpoint"
import { HttpOptions, ProviderID, type ModelID, type ProviderOptions } from "../schema"
import * as OpenAICompatibleProfiles from "./openai-compatible-profile"
import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat"
import * as OpenAIChat from "../protocols/openai-chat"
import * as OpenAIResponses from "../protocols/openai-responses"
import { XAIImages } from "../protocols/xai-images"
import type { OpenAIOptionsInput } from "./openai-options"
import type { ProviderPackage } from "../provider-package"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.js"
import { Route, type RouteDefaultsInput } from "../route/client.js"
import { Endpoint } from "../route/endpoint.js"
import { HttpOptions, ProviderID, type ModelID, type ProviderOptions } from "../schema/index.js"
import * as OpenAICompatibleProfiles from "./openai-compatible-profile.js"
import * as OpenAICompatibleChat from "../protocols/openai-compatible-chat.js"
import * as OpenAIChat from "../protocols/openai-chat.js"
import * as OpenAIResponses from "../protocols/openai-responses.js"
import { XAIImages } from "../protocols/xai-images.js"
import type { OpenAIOptionsInput } from "./openai-options.js"
import type { ProviderPackage } from "../provider-package.js"
export const id = ProviderID.make("xai")
@@ -28,7 +28,7 @@ export interface Settings extends ProviderPackage.Settings {
readonly providerOptions?: XAIProviderOptionsInput
}
export type { XAIImageOptions } from "../protocols/xai-images"
export type { XAIImageOptions } from "../protocols/xai-images.js"
const responsesRoute = Route.make({
id: "openai-responses",
+4 -4
View File
@@ -1,6 +1,6 @@
import { ZAIImages } from "../protocols/zai-images"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options"
import { HttpOptions, ProviderID, type ModelID } from "../schema"
import { ZAIImages } from "../protocols/zai-images.js"
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.js"
import { HttpOptions, ProviderID, type ModelID } from "../schema/index.js"
export const id = ProviderID.make("zai")
@@ -10,7 +10,7 @@ export type Config = ProviderAuthOption<"optional"> & {
readonly http?: HttpOptions.Input
}
export type { ZAIImageOptions } from "../protocols/zai-images"
export type { ZAIImageOptions } from "../protocols/zai-images.js"
const auth = (options: ProviderAuthOption<"optional">) => AuthOptions.bearer(options, "ZAI_API_KEY")
+1 -1
View File
@@ -1 +1 @@
export * from "./route/index"
export * from "./route/index.js"
+2 -2
View File
@@ -1,5 +1,5 @@
import type { Config, Redacted } from "effect"
import { Auth } from "./auth"
import { Auth } from "./auth.js"
export type ApiKeyMode = "optional" | "required"
@@ -61,4 +61,4 @@ export const bearer = (
.bearer()
}
export * as AuthOptions from "./auth-options"
export * as AuthOptions from "./auth-options.js"
+2 -2
View File
@@ -1,6 +1,6 @@
import { Config, Effect, Redacted } from "effect"
import { Headers } from "effect/unstable/http"
import { AuthenticationReason, InvalidRequestReason, AIError, type HttpOptions } from "../schema"
import { AuthenticationReason, InvalidRequestReason, AIError, type HttpOptions } from "../schema/index.js"
export class MissingCredentialError extends Error {
readonly _tag = "MissingCredentialError"
@@ -153,4 +153,4 @@ export const toEffect =
(authInput: AuthInput): Effect.Effect<Headers.Headers, AIError> =>
input.apply(authInput).pipe(Effect.mapError(toAIError))
export * as Auth from "./auth"
export * as Auth from "./auth.js"
+12 -12
View File
@@ -1,16 +1,16 @@
import { Cause, Context, Effect, Layer, Schema, Stream } from "effect"
import * as Option from "effect/Option"
import { Auth } from "./auth"
import { Endpoint, type EndpointPatch } from "./endpoint"
import { RequestExecutor } from "./executor"
import { Framing } from "./framing"
import { HttpTransport } from "./transport"
import type { HttpMiddleware, Transport, TransportRuntime } from "./transport"
import { WebSocketExecutor } from "./transport"
import type { Protocol } from "./protocol"
import { applyCachePolicy } from "../cache-policy"
import * as ProviderShared from "../protocols/shared"
import type { ProtocolID, ProviderOptions } from "../schema"
import { Auth } from "./auth.js"
import { Endpoint, type EndpointPatch } from "./endpoint.js"
import { RequestExecutor } from "./executor.js"
import { Framing } from "./framing.js"
import { HttpTransport } from "./transport/index.js"
import type { HttpMiddleware, Transport, TransportRuntime } from "./transport/index.js"
import { WebSocketExecutor } from "./transport/index.js"
import type { Protocol } from "./protocol.js"
import { applyCachePolicy } from "../cache-policy.js"
import * as ProviderShared from "../protocols/shared.js"
import type { ProtocolID, ProviderOptions } from "../schema/index.js"
import {
AIError,
GenerationOptions,
@@ -25,7 +25,7 @@ import {
mergeGenerationOptions,
mergeHttpOptions,
mergeProviderOptions,
} from "../schema"
} from "../schema/index.js"
export interface RouteBody<Body> {
/** Schema for the validated provider-native body sent as the JSON request. */
+3 -3
View File
@@ -1,5 +1,5 @@
import type { LLMRequest } from "../schema"
import * as ProviderShared from "../protocols/shared"
import type { LLMRequest } from "../schema/index.js"
import * as ProviderShared from "../protocols/shared.js"
export interface EndpointInput<Body> {
readonly request: LLMRequest
@@ -53,4 +53,4 @@ export const render = <Body>(endpoint: Definition<Body>, input: EndpointInput<Bo
return url
}
export * as Endpoint from "./endpoint"
export * as Endpoint from "./endpoint.js"
+76 -33
View File
@@ -1,4 +1,4 @@
import { Cause, Context, Effect, Layer, Option, Schema } from "effect"
import { Cause, Context, Effect, Layer, Option, Schema, Stream } from "effect"
import {
FetchHttpClient,
Headers,
@@ -14,8 +14,8 @@ import {
HttpResponseDetails,
AIError,
TransportReason,
} from "../schema"
import { classifyProviderFailure } from "../provider-error"
} from "../schema/index.js"
import { classifyProviderFailure } from "../provider-error.js"
export interface Interface {
readonly execute: (
@@ -297,44 +297,86 @@ export const classifyHttpFailure = (input: {
})
}
const toHttpError = (redactedNames: ReadonlyArray<string | RegExp>) => (error: unknown) => {
const transportError = (input: {
readonly message: string
readonly kind?: string | undefined
readonly request?: HttpClientRequest.HttpClientRequest | undefined
}) =>
type HttpOperation = "request" | "read"
const NativeTransportFailure = Schema.Struct({
message: Schema.String,
code: Schema.optionalKey(Schema.String),
cause: Schema.optionalKey(Schema.Unknown),
})
const decodeNativeTransportFailure = Schema.decodeUnknownOption(NativeTransportFailure)
const nativeTransportFailure = (error: unknown) => {
const failure = Option.getOrUndefined(decodeNativeTransportFailure(error))
if (!failure) return undefined
if (failure.code !== undefined) return failure
const cause = Option.getOrUndefined(decodeNativeTransportFailure(failure.cause))
if (cause?.code !== undefined) return cause
return failure
}
const httpError = (input: {
readonly error: unknown
readonly request: HttpClientRequest.HttpClientRequest
readonly operation: HttpOperation
readonly redactedNames: ReadonlyArray<string | RegExp>
}) => {
const request = HttpClientError.isHttpClientError(input.error) ? input.error.request : input.request
const transportError = (failure: { readonly message: string; readonly code?: string | undefined }) =>
new AIError({
module: "RequestExecutor",
method: "execute",
method: input.operation,
reason: new TransportReason({
message: input.message,
kind: input.kind,
url: input.request ? redactUrl(input.request.url) : undefined,
http: input.request ? new HttpContext({ request: requestDetails(input.request, redactedNames) }) : undefined,
message: failure.message,
transport: "http",
operation: input.operation,
code: failure.code,
url: redactUrl(request.url),
http: new HttpContext({ request: requestDetails(request, input.redactedNames) }),
}),
})
if (Cause.isTimeoutError(error)) {
return transportError({ message: error.message, kind: "Timeout" })
}
if (!HttpClientError.isHttpClientError(error)) {
return transportError({ message: error instanceof Error ? error.message : "HTTP transport failed" })
}
const request = "request" in error ? error.request : undefined
if (error.reason._tag === "TransportError") {
const source =
HttpClientError.isHttpClientError(input.error) && "cause" in input.error.reason
? input.error.reason.cause
: input.error
const native = nativeTransportFailure(source)
const code = native?.code
const raw = native?.message ?? (input.error instanceof Error ? input.error.message : undefined)
const detail = raw ? redactBody(raw, secretValues(request)) : undefined
const message = code && detail && !detail.includes(code) ? `${code}: ${detail}` : detail
if (Cause.isTimeoutError(input.error) || Cause.isTimeoutError(source))
return transportError({ message: message ?? "HTTP transport timed out", code: code ?? "Timeout" })
if (!HttpClientError.isHttpClientError(input.error))
return transportError({ message: message ?? "HTTP transport failed", code })
if (input.error.reason._tag === "TransportError") {
return transportError({
message: error.reason.description ?? "HTTP transport failed",
kind: error.reason._tag,
request,
message: message ?? input.error.reason.description ?? "HTTP transport failed",
code: code ?? input.error.reason._tag,
})
}
return transportError({
message: `HTTP transport failed: ${error.reason._tag}`,
kind: error.reason._tag,
request,
message: message ?? `HTTP transport failed: ${input.error.reason._tag}`,
code: code ?? input.error.reason._tag,
})
}
export const stream = (
executor: Interface,
request: HttpClientRequest.HttpClientRequest,
middleware?: HttpMiddleware,
): Stream.Stream<Uint8Array, AIError> =>
Stream.unwrap(
Effect.gen(function* () {
const redactedNames = yield* Headers.CurrentRedactedNames
const response = yield* executor.execute(request, middleware)
return response.stream.pipe(
Stream.mapError((error) => httpError({ error, request: response.request, operation: "read", redactedNames })),
)
}),
)
export const layer: Layer.Layer<Service, never, HttpClient.HttpClient> = Layer.effect(
Service,
Effect.gen(function* () {
@@ -343,15 +385,16 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient> = Layer.e
Effect.gen(function* () {
const redactedNames = yield* Headers.CurrentRedactedNames
if (!middleware)
return yield* http
.execute(request)
.pipe(Effect.mapError(toHttpError(redactedNames)), Effect.flatMap(statusError(request, redactedNames)))
return yield* http.execute(request).pipe(
Effect.mapError((error) => httpError({ error, request, operation: "request", redactedNames })),
Effect.flatMap(statusError(request, redactedNames)),
)
const response = yield* middleware(request, (input) =>
http
.execute(input)
.pipe(Effect.mapError((cause) => (cause instanceof Error ? cause : new Error(String(cause))))),
).pipe(Effect.mapError(toHttpError(redactedNames)))
).pipe(Effect.mapError((error) => httpError({ error, request, operation: "request", redactedNames })))
return yield* statusError(response.request, redactedNames)(response)
})
return Service.of({
@@ -362,4 +405,4 @@ export const layer: Layer.Layer<Service, never, HttpClient.HttpClient> = Layer.e
export const fetchLayer = layer.pipe(Layer.provide(FetchHttpClient.layer))
export * as RequestExecutor from "./executor"
export * as RequestExecutor from "./executor.js"
+3 -3
View File
@@ -1,6 +1,6 @@
import type { Stream } from "effect"
import * as ProviderShared from "../protocols/shared"
import type { AIError } from "../schema"
import * as ProviderShared from "../protocols/shared.js"
import type { AIError } from "../schema/index.js"
/**
* Decode a streaming HTTP response body into provider-protocol frames.
@@ -24,4 +24,4 @@ export interface Definition<Frame> {
/** Server-Sent Events framing. Used by every JSON-streaming HTTP provider. */
export const sse: Definition<string> = { id: "sse", frame: ProviderShared.sseFraming }
export * as Framing from "./framing"
export * as Framing from "./framing.js"
+16 -16
View File
@@ -1,4 +1,4 @@
export { Route, LLMClient } from "./client"
export { Route, LLMClient } from "./client.js"
export type {
Route as RouteShape,
RouteLanguageModelInput,
@@ -9,18 +9,18 @@ export type {
Interface as LLMClientShape,
Service as LLMClientService,
StreamOptions,
} from "./client"
export * from "./executor"
export { Auth } from "./auth"
export { AuthOptions } from "./auth-options"
export { Endpoint } from "./endpoint"
export { Framing } from "./framing"
export { Protocol } from "./protocol"
export { HttpTransport, WebSocketExecutor, WebSocketTransport } from "./transport"
export * as Transport from "./transport"
export type { Definition as AuthShape, AuthInput, Credential, CredentialError } from "./auth"
export type { ApiKeyMode, AuthOverride, ProviderAuthOption } from "./auth-options"
export type { Definition as EndpointFn, EndpointInput } from "./endpoint"
export type { Definition as FramingDef } from "./framing"
export type { Protocol as ProtocolDef } from "./protocol"
export type { HttpHandler, HttpMiddleware, Transport as TransportDef, TransportRuntime } from "./transport"
} from "./client.js"
export * from "./executor.js"
export { Auth } from "./auth.js"
export { AuthOptions } from "./auth-options.js"
export { Endpoint } from "./endpoint.js"
export { Framing } from "./framing.js"
export { Protocol } from "./protocol.js"
export { HttpTransport, WebSocketExecutor, WebSocketTransport } from "./transport/index.js"
export * as Transport from "./transport/index.js"
export type { Definition as AuthShape, AuthInput, Credential, CredentialError } from "./auth.js"
export type { ApiKeyMode, AuthOverride, ProviderAuthOption } from "./auth-options.js"
export type { Definition as EndpointFn, EndpointInput } from "./endpoint.js"
export type { Definition as FramingDef } from "./framing.js"
export type { Protocol as ProtocolDef } from "./protocol.js"
export type { HttpHandler, HttpMiddleware, Transport as TransportDef, TransportRuntime } from "./transport/index.js"
+2 -2
View File
@@ -1,5 +1,5 @@
import { Schema, type Effect } from "effect"
import type { AIError, LLMEvent, LLMRequest, ProtocolID } from "../schema"
import type { AIError, LLMEvent, LLMRequest, ProtocolID } from "../schema/index.js"
/**
* The semantic API contract of one model server family.
@@ -82,4 +82,4 @@ export const make = <Body, Frame, Event, State>(
export const jsonEvent = <const S extends Schema.Top>(schema: S) => Schema.fromJsonString(schema)
export * as Protocol from "./protocol"
export * as Protocol from "./protocol.js"
+10 -27
View File
@@ -1,11 +1,12 @@
import { Effect, Stream } from "effect"
import { Effect } from "effect"
import { Headers, HttpClientRequest } from "effect/unstable/http"
import { Auth } from "../auth"
import { render as renderEndpoint } from "../endpoint"
import { Framing } from "../framing"
import type { HttpMiddleware, Transport, TransportPrepareInput } from "./index"
import * as ProviderShared from "../../protocols/shared"
import { mergeJsonRecords, type LLMRequest } from "../../schema"
import { Auth } from "../auth.js"
import { render as renderEndpoint } from "../endpoint.js"
import { Framing } from "../framing.js"
import type { HttpMiddleware, Transport, TransportPrepareInput } from "./index.js"
import * as ProviderShared from "../../protocols/shared.js"
import { mergeJsonRecords, type LLMRequest } from "../../schema/index.js"
import { RequestExecutor } from "../executor.js"
export type JsonRequestInput<Body> = TransportPrepareInput<Body>
@@ -86,26 +87,8 @@ export const httpJson = <Body, Frame>(input: HttpJsonInput<Body, Frame>): HttpJs
middleware: prepareInput.middleware,
}
}),
frames: (prepared, request, runtime) =>
Stream.unwrap(
runtime.http
.execute(prepared.request, prepared.middleware)
.pipe(
Effect.map((response) =>
prepared.framing.frame(
response.stream.pipe(
Stream.mapError((error) =>
ProviderShared.eventError(
`${request.model.provider}/${request.model.route.id}`,
`Failed to read ${request.model.provider}/${request.model.route.id} stream`,
ProviderShared.errorText(error),
),
),
),
),
),
),
),
frames: (prepared, _request, runtime) =>
prepared.framing.frame(RequestExecutor.stream(runtime.http, prepared.request, prepared.middleware)),
})
export const sseJson = {
+8 -8
View File
@@ -1,9 +1,9 @@
import type { Effect, Stream } from "effect"
import { Endpoint } from "../endpoint"
import { Auth } from "../auth"
import type { HttpMiddleware, Interface as RequestExecutorInterface } from "../executor"
import type { Interface as WebSocketExecutorInterface } from "./websocket"
import type { AIError, LLMRequest } from "../../schema"
import { Endpoint } from "../endpoint.js"
import { Auth } from "../auth.js"
import type { HttpMiddleware, Interface as RequestExecutorInterface } from "../executor.js"
import type { Interface as WebSocketExecutorInterface } from "./websocket.js"
import type { AIError, LLMRequest } from "../../schema/index.js"
export interface TransportRuntime {
readonly http: RequestExecutorInterface
@@ -26,6 +26,6 @@ export interface TransportPrepareInput<Body> {
readonly middleware?: HttpMiddleware
}
export * as HttpTransport from "./http"
export type { HttpHandler, HttpMiddleware } from "../executor"
export { WebSocketExecutor, WebSocketTransport } from "./websocket"
export * as HttpTransport from "./http.js"
export type { HttpHandler, HttpMiddleware } from "../executor.js"
export { WebSocketExecutor, WebSocketTransport } from "./websocket.js"
+38 -15
View File
@@ -1,8 +1,8 @@
import { Cause, Context, Effect, Layer, Queue, Stream } from "effect"
import { Headers } from "effect/unstable/http"
import { AIError, TransportReason } from "../../schema"
import * as HttpTransport from "./http"
import type { Transport } from "./index"
import { AIError, TransportReason, type TransportOperation } from "../../schema/index.js"
import * as HttpTransport from "./http.js"
import type { Transport } from "./index.js"
export interface WebSocketRequest {
readonly url: string
@@ -29,12 +29,18 @@ export class Service extends Context.Service<Service, Interface>()("@opencode/AI
const transportError = (
method: string,
message: string,
input: { readonly url?: string; readonly kind?: string } = {},
input: { readonly operation: TransportOperation; readonly url?: string; readonly code?: string },
) =>
new AIError({
module: "WebSocketExecutor",
method,
reason: new TransportReason({ message, url: input.url, kind: input.kind }),
reason: new TransportReason({
message,
transport: "websocket",
operation: input.operation,
url: input.url,
code: input.code,
}),
})
const eventMessage = (event: Event) => {
@@ -55,7 +61,8 @@ const waitOpen = (ws: globalThis.WebSocket, input: WebSocketRequest) => {
return Effect.fail(
transportError("open", `WebSocket closed before opening (state ${ws.readyState})`, {
url: input.url,
kind: "open",
operation: "request",
code: "closed",
}),
)
}
@@ -79,7 +86,10 @@ const waitOpen = (ws: globalThis.WebSocket, input: WebSocketRequest) => {
cleanup()
resume(
Effect.fail(
transportError("open", `Failed to open WebSocket: ${eventMessage(event)}`, { url: input.url, kind: "open" }),
transportError("open", `Failed to open WebSocket: ${eventMessage(event)}`, {
url: input.url,
operation: "request",
}),
),
)
}
@@ -89,7 +99,8 @@ const waitOpen = (ws: globalThis.WebSocket, input: WebSocketRequest) => {
Effect.fail(
transportError("open", `WebSocket closed before opening with code ${event.code}`, {
url: input.url,
kind: "open",
operation: "request",
code: String(event.code),
}),
),
)
@@ -118,7 +129,8 @@ const webSocketUrl = (value: string) =>
catch: (error) =>
transportError("prepare", error instanceof Error ? error.message : "Invalid WebSocket URL", {
url: value,
kind: "websocket",
operation: "request",
code: "invalid-url",
}),
})
@@ -129,7 +141,7 @@ export const open = (input: WebSocketRequest) =>
catch: (error) =>
transportError("open", error instanceof Error ? error.message : "Failed to construct WebSocket", {
url: input.url,
kind: "open",
operation: "request",
}),
}).pipe(Effect.flatMap((ws) => fromWebSocket(ws, input)))
@@ -150,7 +162,10 @@ export const fromWebSocket = (
Queue.failCauseUnsafe(
messages,
Cause.fail(
transportError("message", "Unsupported WebSocket message payload", { url: input.url, kind: "message" }),
transportError("message", "Unsupported WebSocket message payload", {
url: input.url,
operation: "read",
}),
),
)
}
@@ -158,7 +173,10 @@ export const fromWebSocket = (
Queue.failCauseUnsafe(
messages,
Cause.fail(
transportError("message", `WebSocket error: ${eventMessage(event)}`, { url: input.url, kind: "message" }),
transportError("message", `WebSocket error: ${eventMessage(event)}`, {
url: input.url,
operation: "read",
}),
),
)
}
@@ -167,7 +185,11 @@ export const fromWebSocket = (
Queue.failCauseUnsafe(
messages,
Cause.fail(
transportError("message", `WebSocket closed with code ${event.code}`, { url: input.url, kind: "close" }),
transportError("message", `WebSocket closed with code ${event.code}`, {
url: input.url,
operation: "read",
code: String(event.code),
}),
),
)
}
@@ -188,7 +210,7 @@ export const fromWebSocket = (
catch: (error) =>
transportError("sendText", error instanceof Error ? error.message : "Failed to send WebSocket message", {
url: input.url,
kind: "write",
operation: "write",
}),
}),
messages: Stream.fromQueue(messages),
@@ -243,7 +265,8 @@ export const json = <Body, Message>(input: JsonInput<Body, Message>): JsonTransp
return Stream.fail(
transportError("json", "WebSocket JSON transport requires WebSocketExecutor.Service", {
url: prepared.url,
kind: "websocket",
operation: "request",
code: "unavailable",
}),
)
}
+10 -2
View File
@@ -1,6 +1,6 @@
import { Schema } from "effect"
import { Tool } from "@opencode-ai/schema/tool"
import { ModelID, ProviderID, ProviderMetadata, RouteID } from "./ids"
import { ModelID, ProviderID, ProviderMetadata, RouteID } from "./ids.js"
export const ProviderFailureClassification = Schema.Literals(["context-overflow", "payload-too-large"])
export type ProviderFailureClassification = typeof ProviderFailureClassification.Type
@@ -92,10 +92,18 @@ export class ProviderInternalReason extends Schema.Class<ProviderInternalReason>
http: Schema.optional(HttpContext),
}) {}
export const TransportType = Schema.Literals(["http", "websocket"])
export type TransportType = typeof TransportType.Type
export const TransportOperation = Schema.Literals(["request", "read", "write"])
export type TransportOperation = typeof TransportOperation.Type
export class TransportReason extends Schema.Class<TransportReason>("AI.Error.Transport")({
_tag: Schema.tag("Transport"),
message: Schema.String,
kind: Schema.optional(Schema.String),
transport: TransportType,
operation: TransportOperation,
code: Schema.optional(Schema.String),
url: Schema.optional(Schema.String),
http: Schema.optional(HttpContext),
}) {}
+3 -3
View File
@@ -1,7 +1,7 @@
import { Schema } from "effect"
import { ContentBlockID, FinishReason, ProviderMetadata, ToolCallID } from "./ids"
import { Message, ToolCallPart, ToolOutput, ToolResultPart, ToolResultValue, type ContentPart } from "./messages"
import { ProviderFailureClassification } from "./errors"
import { ContentBlockID, FinishReason, ProviderMetadata, ToolCallID } from "./ids.js"
import { Message, ToolCallPart, ToolOutput, ToolResultPart, ToolResultValue, type ContentPart } from "./messages.js"
import { ProviderFailureClassification } from "./errors.js"
/**
* Token usage reported by an LLM provider.
+5 -5
View File
@@ -1,5 +1,5 @@
export * from "./ids"
export * from "./options"
export * from "./messages"
export * from "./events"
export * from "./errors"
export * from "./ids.js"
export * from "./options.js"
export * from "./messages.js"
export * from "./events.js"
export * from "./errors.js"
+10 -3
View File
@@ -1,8 +1,15 @@
import { Schema } from "effect"
import { Tool } from "@opencode-ai/schema/tool"
import { JsonSchema, MessageRole, ProviderMetadata } from "./ids"
import { CacheHint, CachePolicy, GenerationOptions, HttpOptions, LanguageModelSchema, ProviderOptions } from "./options"
import { isRecord } from "../utils/record"
import { JsonSchema, MessageRole, ProviderMetadata } from "./ids.js"
import {
CacheHint,
CachePolicy,
GenerationOptions,
HttpOptions,
LanguageModelSchema,
ProviderOptions,
} from "./options.js"
import { isRecord } from "../utils/record.js"
const systemPartSchema = Schema.Struct({
type: Schema.Literal("text"),
+3 -3
View File
@@ -1,7 +1,7 @@
import { Schema } from "effect"
import { JsonSchema, ModelID, ProviderID } from "./ids"
import type { AnyRoute } from "../route/client"
import { isRecord } from "../utils/record"
import { JsonSchema, ModelID, ProviderID } from "./ids.js"
import type { AnyRoute } from "../route/client.js"
import { isRecord } from "../utils/record.js"
export const mergeJsonRecords = (
...items: ReadonlyArray<Record<string, unknown> | undefined>
+3 -3
View File
@@ -1,6 +1,6 @@
export * as TestLLM from "./testing"
export * as TestLLM from "./testing.js"
import { LLMClient, type Interface as LLMClientShape } from "./route/client"
import { LLMClient, type Interface as LLMClientShape } from "./route/client.js"
import {
LLMEvent,
LLMResponse,
@@ -8,7 +8,7 @@ import {
type AIError,
type LLMRequest,
type UsageInput,
} from "./schema"
} from "./schema/index.js"
import { Context, Deferred, Effect, Latch, Layer, Queue, Scope, Stream } from "effect"
export type Response = readonly LLMEvent[] | Stream.Stream<LLMEvent, AIError>
+2 -2
View File
@@ -7,8 +7,8 @@ import {
ToolResultValue,
type ToolOutput as ToolOutputType,
type ToolResultValue as ToolResultValueType,
} from "./schema"
import { type AnyTool, type Tools } from "./tool"
} from "./schema/index.js"
import { type AnyTool, type Tools } from "./tool.js"
export interface ToolSettlement {
readonly result: ToolResultValueType
+7 -3
View File
@@ -1,7 +1,11 @@
import { Effect, JsonSchema, Schema } from "effect"
import { Tool } from "@opencode-ai/schema/tool"
import type { ToolCallPart, ToolDefinition as ToolDefinitionClass, ToolOutput as ToolOutputType } from "./schema"
import { ToolDefinition, ToolFailure, ToolOutput } from "./schema"
import type {
ToolCallPart,
ToolDefinition as ToolDefinitionClass,
ToolOutput as ToolOutputType,
} from "./schema/index.js"
import { ToolDefinition, ToolFailure, ToolOutput } from "./schema/index.js"
/**
* Schema constraint for tool parameters / success values: no decoding or
@@ -245,4 +249,4 @@ const project = (
export { ToolFailure }
export * as Tool from "./tool"
export * as Tool from "./tool.js"
+6 -6
View File
@@ -1,11 +1,11 @@
import { describe, expect } from "bun:test"
import { Effect, Schema, Stream } from "effect"
import { LLM, LLMRequest, LLMResponse } from "../src"
import { Route, Endpoint, LLMClient, Protocol, type FramingDef } from "../src/route"
import { compileRequest } from "../src/route/client"
import { LanguageModel } from "../src/schema"
import { testEffect } from "./lib/effect"
import { dynamicResponse } from "./lib/http"
import { LLM, LLMRequest, LLMResponse } from "../src/index.js"
import { Route, Endpoint, LLMClient, Protocol, type FramingDef } from "../src/route.js"
import { compileRequest } from "../src/route/client.js"
import { LanguageModel } from "../src/schema/index.js"
import { testEffect } from "./lib/effect.js"
import { dynamicResponse } from "./lib/http.js"
const updateModel = (model: LanguageModel, patch: Partial<LanguageModel.Input>) => LanguageModel.update(model, patch)
+17 -17
View File
@@ -1,21 +1,21 @@
import { Config } from "effect"
import { Auth } from "../src/route"
import type { LanguageModelFactory } from "../src/route/auth-options"
import * as OpenAIChat from "../src/protocols/openai-chat"
import * as AmazonBedrock from "../src/providers/amazon-bedrock"
import * as Anthropic from "../src/providers/anthropic"
import * as AnthropicCompatible from "../src/providers/anthropic-compatible"
import * as Azure from "../src/providers/azure"
import * as Cloudflare from "../src/providers/cloudflare"
import * as Google from "../src/providers/google"
import * as GoogleVertex from "../src/providers/google-vertex"
import * as GoogleVertexChat from "../src/providers/google-vertex-chat"
import * as GoogleVertexMessages from "../src/providers/google-vertex-messages"
import * as GoogleVertexResponses from "../src/providers/google-vertex-responses"
import * as OpenAI from "../src/providers/openai"
import * as OpenAICompatible from "../src/providers/openai-compatible"
import * as OpenRouter from "../src/providers/openrouter"
import * as XAI from "../src/providers/xai"
import { Auth } from "../src/route.js"
import type { LanguageModelFactory } from "../src/route/auth-options.js"
import * as OpenAIChat from "../src/protocols/openai-chat.js"
import * as AmazonBedrock from "../src/providers/amazon-bedrock.js"
import * as Anthropic from "../src/providers/anthropic.js"
import * as AnthropicCompatible from "../src/providers/anthropic-compatible.js"
import * as Azure from "../src/providers/azure.js"
import * as Cloudflare from "../src/providers/cloudflare.js"
import * as Google from "../src/providers/google.js"
import * as GoogleVertex from "../src/providers/google-vertex.js"
import * as GoogleVertexChat from "../src/providers/google-vertex-chat.js"
import * as GoogleVertexMessages from "../src/providers/google-vertex-messages.js"
import * as GoogleVertexResponses from "../src/providers/google-vertex-responses.js"
import * as OpenAI from "../src/providers/openai.js"
import * as OpenAICompatible from "../src/providers/openai-compatible.js"
import * as OpenRouter from "../src/providers/openrouter.js"
import * as XAI from "../src/providers/xai.js"
type BaseOptions = {
readonly baseURL?: string
+5 -5
View File
@@ -1,11 +1,11 @@
import { describe, expect } from "bun:test"
import { ConfigProvider, Effect } from "effect"
import { Headers } from "effect/unstable/http"
import { LLM } from "../src"
import { Auth } from "../src/route/auth"
import * as OpenAIChat from "../src/protocols/openai-chat"
import { LanguageModel } from "../src/schema"
import { it } from "./lib/effect"
import { LLM } from "../src/index.js"
import { Auth } from "../src/route/auth.js"
import * as OpenAIChat from "../src/protocols/openai-chat.js"
import { LanguageModel } from "../src/schema/index.js"
import { it } from "./lib/effect.js"
const request = LLM.request({
id: "req_auth",
+9 -9
View File
@@ -1,14 +1,14 @@
import { describe, expect, test } from "bun:test"
import { Effect } from "effect"
import { CacheHint, LLM, Message } from "../src"
import { Auth } from "../src/route"
import { compileRequest } from "../src/route/client"
import { AmazonBedrock } from "../src/providers"
import * as AnthropicMessages from "../src/protocols/anthropic-messages"
import * as Gemini from "../src/protocols/gemini"
import * as OpenAIChat from "../src/protocols/openai-chat"
import { applyCachePolicy } from "../src/cache-policy"
import { it } from "./lib/effect"
import { CacheHint, LLM, Message } from "../src/index.js"
import { Auth } from "../src/route.js"
import { compileRequest } from "../src/route/client.js"
import { AmazonBedrock } from "../src/providers.js"
import * as AnthropicMessages from "../src/protocols/anthropic-messages.js"
import * as Gemini from "../src/protocols/gemini.js"
import * as OpenAIChat from "../src/protocols/openai-chat.js"
import { applyCachePolicy } from "../src/cache-policy.js"
import { it } from "./lib/effect.js"
const anthropicModel = AnthropicMessages.route
.with({ endpoint: { baseURL: "https://api.anthropic.test/v1/" }, auth: Auth.header("x-api-key", "test") })
+8 -8
View File
@@ -1,14 +1,14 @@
import { describe, expect, test } from "bun:test"
import { Effect, Ref, Schema } from "effect"
import { HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
import { LLM, mergeProviderOptions } from "../src"
import { AnthropicMessages, OpenAIChat } from "../src/protocols"
import { Auth, LLMClient } from "../src/route"
import { compileRequest } from "../src/route/client"
import { it } from "./lib/effect"
import { dynamicResponse } from "./lib/http"
import { deltaChunk } from "./lib/openai-chunks"
import { sseEvents } from "./lib/sse"
import { LLM, mergeProviderOptions } from "../src/index.js"
import { AnthropicMessages, OpenAIChat } from "../src/protocols.js"
import { Auth, LLMClient } from "../src/route.js"
import { compileRequest } from "../src/route/client.js"
import { it } from "./lib/effect.js"
import { dynamicResponse } from "./lib/http.js"
import { deltaChunk } from "./lib/openai-chunks.js"
import { sseEvents } from "./lib/sse.js"
const TargetJson = Schema.fromJsonString(Schema.Unknown)
const decodeJson = Schema.decodeUnknownSync(TargetJson)

Some files were not shown because too many files have changed in this diff Show More