mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-08 01:46:23 +00:00
Compare commits
34
Commits
turn-diffs
...
v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a912a6ee4f | ||
|
|
2ac698d65a | ||
|
|
c1c6ab593d | ||
|
|
d1d1c6f890 | ||
|
|
0ab661a9cc | ||
|
|
a55dc8c84a | ||
|
|
be41bc4e7d | ||
|
|
567f8b9743 | ||
|
|
6263a35b3f | ||
|
|
74ca560c75 | ||
|
|
a68d6f904d | ||
|
|
cc8c2f8810 | ||
|
|
ad31bff969 | ||
|
|
a5312e169b | ||
|
|
16aca14bc7 | ||
|
|
4aba093c98 | ||
|
|
a3bbcd5c73 | ||
|
|
c05d07cd73 | ||
|
|
ef34ada9fb | ||
|
|
e15fb426ec | ||
|
|
72433f2ed8 | ||
|
|
b32d8c3e58 | ||
|
|
6af8515f69 | ||
|
|
5c50edb9bb | ||
|
|
fcddc84225 | ||
|
|
582a2108ce | ||
|
|
9c65a69937 | ||
|
|
1d391908f4 | ||
|
|
596dca4dee | ||
|
|
1827832775 | ||
|
|
898692af26 | ||
|
|
5c3f2ddf8c | ||
|
|
1382cebe10 | ||
|
|
0732cdd8e1 |
@@ -1,5 +1,5 @@
|
||||
---
|
||||
"@opencode-ai/core": patch
|
||||
"@opencode/core": patch
|
||||
---
|
||||
|
||||
Correct directory page headings when the read offset is zero.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
name: deploy-files
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- v2
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-files-${{ github.ref_name }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
if: github.repository == 'anomalyco/opencode' && (github.ref_name == 'dev' || github.ref_name == 'v2')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- uses: ./.github/actions/setup-bun
|
||||
|
||||
- name: Typecheck
|
||||
working-directory: services/files
|
||||
run: bun typecheck
|
||||
|
||||
- name: Deploy
|
||||
working-directory: services/files
|
||||
run: bun run deploy --env ${{ github.ref_name == 'v2' && 'production' || 'dev' }}
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
@@ -24,13 +24,13 @@ jobs:
|
||||
- uses: ./.github/actions/setup-bun
|
||||
|
||||
- name: Build
|
||||
working-directory: packages/www
|
||||
working-directory: services/www
|
||||
run: bun run build
|
||||
env:
|
||||
CLOUDFLARE_ENV: ${{ github.ref_name == 'v2' && 'production' || 'dev' }}
|
||||
|
||||
- name: Deploy
|
||||
working-directory: packages/www
|
||||
working-directory: services/www
|
||||
run: bun run deploy
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
|
||||
@@ -11,6 +11,7 @@ on:
|
||||
- "bun.lock"
|
||||
- "package.json"
|
||||
- "packages/*/package.json"
|
||||
- "services/*/package.json"
|
||||
- "flake.lock"
|
||||
- "nix/node_modules.nix"
|
||||
- "nix/scripts/**"
|
||||
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
|
||||
- name: Deploy update service
|
||||
if: github.ref_name == 'v2'
|
||||
working-directory: packages/updates
|
||||
working-directory: services/updates
|
||||
run: bun run deploy
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
@@ -670,19 +670,6 @@ jobs:
|
||||
git config --global user.name "opencode"
|
||||
ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts || true
|
||||
|
||||
- name: Upload desktop release assets
|
||||
if: needs.version.outputs.release
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.committer.outputs.token }}
|
||||
run: |
|
||||
shopt -s nullglob
|
||||
files=(/tmp/desktop/*.{exe,blockmap,dmg,zip,AppImage,deb,rpm} /tmp/desktop/*.app.tar.gz)
|
||||
if (( ${#files[@]} == 0 )); then
|
||||
echo "No desktop release assets found"
|
||||
exit 1
|
||||
fi
|
||||
gh release upload "v${{ needs.version.outputs.version }}" "${files[@]}" --clobber --repo "${{ needs.version.outputs.repo }}"
|
||||
|
||||
- run: ./script/publish.ts
|
||||
env:
|
||||
OPENCODE_VERSION: ${{ needs.version.outputs.version }}
|
||||
@@ -694,3 +681,6 @@ jobs:
|
||||
LATEST_YML_DIR: /tmp/latest-yml
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
OPENCODE_DESKTOP_DIST: /tmp/desktop
|
||||
CLOUDFLARE_ACCOUNT_ID: 15d29c8639fd3733b1b5486a2acfd968
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
echo "app=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
bun x turbo@2.10.2 ls --affected --filter=@opencode-ai/app --output=json > affected.json
|
||||
bun x turbo@2.10.2 ls --affected --filter=@opencode/app --output=json > affected.json
|
||||
bun -e 'const result = await Bun.file("affected.json").json(); console.log(`app=${result.packages.count > 0}`)' >> "$GITHUB_OUTPUT"
|
||||
|
||||
unit:
|
||||
@@ -132,10 +132,10 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
bun turbo verify:package --filter=@opencode-ai/sdk
|
||||
bun turbo verify:package --filter=@opencode/sdk
|
||||
exit 0
|
||||
fi
|
||||
bun turbo verify:package --affected --filter=@opencode-ai/sdk
|
||||
bun turbo verify:package --affected --filter=@opencode/sdk
|
||||
env:
|
||||
TURBO_SCM_BASE: ${{ github.event_name == 'pull_request' && format('{0}^1', github.sha) || github.event.before }}
|
||||
TURBO_SCM_HEAD: ${{ github.sha }}
|
||||
@@ -173,7 +173,7 @@ jobs:
|
||||
|
||||
- name: Check generated documentation
|
||||
if: runner.os == 'Linux'
|
||||
working-directory: packages/www
|
||||
working-directory: services/www
|
||||
run: bun run check:generated
|
||||
|
||||
e2e:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/// <reference path="../env.d.ts" />
|
||||
import { tool } from "@opencode-ai/plugin"
|
||||
import { tool } from "@opencode/plugin"
|
||||
async function githubFetch(endpoint: string, options: RequestInit = {}) {
|
||||
const response = await fetch(`https://api.github.com${endpoint}`, {
|
||||
...options,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/// <reference path="../env.d.ts" />
|
||||
import { tool } from "@opencode-ai/plugin"
|
||||
import { tool } from "@opencode/plugin"
|
||||
|
||||
const TEAM = {
|
||||
tui: ["kommander", "simonklee"],
|
||||
|
||||
@@ -84,9 +84,9 @@ const { a, b } = obj
|
||||
### Imports
|
||||
|
||||
- Never alias imports. Do not use `import { foo as bar } from "..."` or renamed imports like `resolve as pathResolve`.
|
||||
- Never use type-position `import("...")` references such as `Schema.declare<import("@opencode-ai/plugin/effect/plugin").Plugin["effect"]>`. Only when two imports genuinely collide on a name and no other option exists, an aliased type import (`import type { Plugin as PluginDefinition } from "..."`) is permitted as a last resort — still strongly preferred not to.
|
||||
- Never use type-position `import("...")` references such as `Schema.declare<import("@opencode/plugin/effect/plugin").Plugin["effect"]>`. Only when two imports genuinely collide on a name and no other option exists, an aliased type import (`import type { Plugin as PluginDefinition } from "..."`) is permitted as a last resort — still strongly preferred not to.
|
||||
- Never use star imports. Do not use `import * as Foo from "..."` or `import type * as Foo from "..."`.
|
||||
- If a namespace-style value is needed, import the module's own exported namespace by name, for example `import { Project } from "@opencode-ai/core/project"`, then reference `Project.ID`.
|
||||
- If a namespace-style value is needed, import the module's own exported namespace by name, for example `import { Project } from "@opencode/core/project"`, then reference `Project.ID`.
|
||||
- Prefer dynamic imports for heavy modules that are only needed in selected code paths, especially in startup-sensitive entrypoints. Destructure dynamic import bindings near the top of the narrowest scope that needs them so they read like normal imports. Avoid inline chains such as `await import("./module").then((mod) => mod.value())` or `(await import("./module")).value()`. Keep branch-specific imports inside the branch that needs them to preserve lazy loading.
|
||||
|
||||
### Variables
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
exact = true
|
||||
# Only install newly resolved package versions published at least 3 days ago.
|
||||
minimumReleaseAge = 259200
|
||||
minimumReleaseAgeExcludes = ["@ai-sdk/amazon-bedrock", "@ai-sdk/anthropic", "@brendonovich/vite-plugin-opencode", "@opencode-ai/sdk", "@opencode-ai/pty", "@opencode-ai/pty-darwin-arm64", "@opencode-ai/pty-darwin-x64", "@opencode-ai/pty-linux-arm64-gnu", "@opencode-ai/pty-linux-arm64-musl", "@opencode-ai/pty-linux-x64-gnu", "@opencode-ai/pty-linux-x64-musl", "@opentui/core", "@opentui/core-darwin-arm64", "@opentui/core-darwin-x64", "@opentui/core-linux-arm64", "@opentui/core-linux-arm64-musl", "@opentui/core-linux-x64", "@opentui/core-linux-x64-musl", "@opentui/core-win32-arm64", "@opentui/core-win32-x64", "@opentui/keymap", "@opentui/solid", "opentui-spinner", "gitlab-ai-provider", "opencode-gitlab-auth", "@ff-labs/fff-node", "@ff-labs/fff-bun", "@ff-labs/fff-bin-darwin-arm64", "@ff-labs/fff-bin-darwin-x64", "@ff-labs/fff-bin-linux-arm64-gnu", "@ff-labs/fff-bin-linux-arm64-musl", "@ff-labs/fff-bin-linux-x64-gnu", "@ff-labs/fff-bin-linux-x64-musl", "@ff-labs/fff-bin-win32-arm64", "@ff-labs/fff-bin-win32-x64", "@pierre/diffs", "@pierre/theming", "app-builder-lib", "dmg-builder", "electron", "electron-builder", "electron-publish", "blume", "mermaid"]
|
||||
minimumReleaseAgeExcludes = ["@ai-sdk/amazon-bedrock", "@ai-sdk/anthropic", "@brendonovich/vite-plugin-opencode", "@opencode/sdk", "@opencode-ai/pty", "@opencode-ai/pty-darwin-arm64", "@opencode-ai/pty-darwin-x64", "@opencode-ai/pty-linux-arm64-gnu", "@opencode-ai/pty-linux-arm64-musl", "@opencode-ai/pty-linux-x64-gnu", "@opencode-ai/pty-linux-x64-musl", "@opentui/core", "@opentui/core-darwin-arm64", "@opentui/core-darwin-x64", "@opentui/core-linux-arm64", "@opentui/core-linux-arm64-musl", "@opentui/core-linux-x64", "@opentui/core-linux-x64-musl", "@opentui/core-win32-arm64", "@opentui/core-win32-x64", "@opentui/keymap", "@opentui/solid", "opentui-spinner", "gitlab-ai-provider", "opencode-gitlab-auth", "@ff-labs/fff-node", "@ff-labs/fff-bun", "@ff-labs/fff-bin-darwin-arm64", "@ff-labs/fff-bin-darwin-x64", "@ff-labs/fff-bin-linux-arm64-gnu", "@ff-labs/fff-bin-linux-arm64-musl", "@ff-labs/fff-bin-linux-x64-gnu", "@ff-labs/fff-bin-linux-x64-musl", "@ff-labs/fff-bin-win32-arm64", "@ff-labs/fff-bin-win32-x64", "@pierre/diffs", "@pierre/theming", "app-builder-lib", "dmg-builder", "electron", "electron-builder", "electron-publish", "blume", "mermaid"]
|
||||
|
||||
[test]
|
||||
root = "./do-not-run-tests-from-root"
|
||||
|
||||
@@ -165,22 +165,30 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
package_scope="@opencode"
|
||||
if [ -z "$requested_version" ]; then
|
||||
metadata=$(curl -fsSL https://registry.npmjs.org/@opencode-ai%2fcli/beta || true)
|
||||
metadata=$(curl -fsSL https://opencode.ai/update/api/beta/cli/npm || true)
|
||||
specific_version=$(echo "$metadata" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p')
|
||||
package=$(echo "$metadata" | sed -n 's/.*"package":"\([^"]*\)".*/\1/p')
|
||||
|
||||
if [ -z "$specific_version" ]; then
|
||||
if [ -z "$specific_version" ] || [ -z "$package" ]; then
|
||||
echo -e "${RED}Failed to fetch version information${NC}"
|
||||
exit 1
|
||||
fi
|
||||
package_scope="${package%/cli}"
|
||||
else
|
||||
# Strip leading 'v' if present
|
||||
requested_version="${requested_version#v}"
|
||||
specific_version=$requested_version
|
||||
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)
|
||||
package_name="$package_scope/cli-$target"
|
||||
http_status=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/$package_scope%2fcli-$target/$specific_version" || true)
|
||||
# Older clients install the minimum release before they can migrate package names.
|
||||
if [ "$http_status" = "404" ] && [ -n "$requested_version" ]; then
|
||||
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)
|
||||
fi
|
||||
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}"
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
cd packages/desktop
|
||||
|
||||
export OPENCODE_CLI_DIST="$TMPDIR/desktop-cli"
|
||||
cli_package=$(bun -e 'import { getCurrentCli } from "./scripts/utils.ts"; console.log(getCurrentCli().package.replace("@opencode-ai/", ""))')
|
||||
cli_package=$(bun -e 'import { getCurrentCli } from "./scripts/utils.ts"; console.log(getCurrentCli().package.replace("@opencode/", ""))')
|
||||
mkdir -p "$OPENCODE_CLI_DIST/$cli_package/bin"
|
||||
cp ${lib.getExe opencode} "$OPENCODE_CLI_DIST/$cli_package/bin/opencode2"
|
||||
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"nodeModules": {
|
||||
"x86_64-linux": "sha256-7NBjLAaZRbirLuBJdQO9iwlonqUFKOkU8u6rh/e8Ij0=",
|
||||
"aarch64-linux": "sha256-877mqEw+JGTTftYSWvHOsKnFRQ0B5umxY5xW31Rs+ms=",
|
||||
"aarch64-darwin": "sha256-eaWQZfyQMefy5kn+Q9dAzOnXcwjwx7EEtDuzpocgHOQ=",
|
||||
"x86_64-darwin": "sha256-mg+Sr8h7d2dmrnOfjiX/ktmA3wuBg/iGZv9ooFvlERc="
|
||||
"x86_64-linux": "sha256-gW+1JbPQnt+PZzHfGijjnwch6X6pyaBnPTxAc47yiQw=",
|
||||
"aarch64-linux": "sha256-qI6CtJkmh20ouWeiQRR1zp+YjHootkN23VFJCwqnf0A=",
|
||||
"aarch64-darwin": "sha256-oyEhVcjbKq3+BCCxVBl0TZYmKJv1BBLWPVs0Vw6Fbac=",
|
||||
"x86_64-darwin": "sha256-UhLZjG3NlkoXRWNn8SK/pLm5eDR3saU+TgEgfX592vQ="
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,12 @@ stdenvNoCC.mkDerivation {
|
||||
fileset = lib.fileset.intersection (lib.fileset.fromSource (lib.sources.cleanSource ../.)) (
|
||||
lib.fileset.unions [
|
||||
../packages
|
||||
../services
|
||||
../bun.lock
|
||||
../package.json
|
||||
../patches
|
||||
../install # required by desktop build (cli.rs include_str!)
|
||||
../.github/TEAM_MEMBERS # required by @opencode-ai/script
|
||||
../.github/TEAM_MEMBERS # required by @opencode/script
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
+4
-3
@@ -13,7 +13,7 @@
|
||||
"dev:web": "bun --cwd packages/app dev",
|
||||
"dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev",
|
||||
"dev:stats": "bun sst shell --stage=production -- bun run --cwd packages/stats/app dev",
|
||||
"dev:www": "bun run --cwd packages/www dev",
|
||||
"dev:www": "bun run --cwd services/www dev",
|
||||
"dev:storybook": "bun --cwd packages/storybook storybook",
|
||||
"bench:devex": "bun run --cwd packages/app test:bench:devex",
|
||||
"lint": "oxlint",
|
||||
@@ -34,6 +34,7 @@
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"packages/*",
|
||||
"services/*",
|
||||
"packages/console/*",
|
||||
"packages/stats/*"
|
||||
],
|
||||
@@ -128,8 +129,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.933.0",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/script": "workspace:*",
|
||||
"@opencode/plugin": "workspace:*",
|
||||
"@opencode/script": "workspace:*",
|
||||
"heap-snapshot-toolkit": "1.1.3",
|
||||
"typescript": "catalog:"
|
||||
},
|
||||
|
||||
@@ -121,10 +121,10 @@ Keep provider facades small and explicit:
|
||||
|
||||
### Provider Package Entrypoints
|
||||
|
||||
Catalog-selected native providers use package-like export paths from `@opencode-ai/ai`. They are internal entrypoints in one npm package, not separately published provider packages. Every entrypoint implements `ProviderPackage.Definition` and exposes `model(modelID, settings)`, where settings are serializable provider configuration plus common `headers`, `body`, and `limits` overlays.
|
||||
Catalog-selected native providers use package-like export paths from `@opencode/ai`. They are internal entrypoints in one npm package, not separately published provider packages. Every entrypoint implements `ProviderPackage.Definition` and exposes `model(modelID, settings)`, where settings are serializable provider configuration plus common `headers`, `body`, and `limits` overlays.
|
||||
|
||||
```ts
|
||||
import { model } from "@opencode-ai/ai/providers/openai/responses"
|
||||
import { model } from "@opencode/ai/providers/openai/responses"
|
||||
|
||||
const selected = model("gpt-5", {
|
||||
apiKey,
|
||||
|
||||
+204
-33
@@ -1,12 +1,12 @@
|
||||
# @opencode-ai/ai
|
||||
# @opencode/ai
|
||||
|
||||
Schema-first language model and image-generation APIs built with Effect.
|
||||
|
||||
```ts
|
||||
import { Effect, Layer } from "effect"
|
||||
import { LLM, LLMClient } from "@opencode-ai/ai"
|
||||
import { RequestExecutor } from "@opencode-ai/ai/route"
|
||||
import { OpenAI } from "@opencode-ai/ai/providers"
|
||||
import { LLM, LLMClient } from "@opencode/ai"
|
||||
import { RequestExecutor } from "@opencode/ai/route"
|
||||
import { OpenAI } from "@opencode/ai/providers"
|
||||
|
||||
const model = OpenAI.configure({ apiKey: process.env.OPENAI_API_KEY }).responses("gpt-4o-mini")
|
||||
|
||||
@@ -29,13 +29,184 @@ await Effect.runPromise(program.pipe(Effect.provide(llmLayer)))
|
||||
|
||||
Run `LLMClient.stream(request)` instead of `generate` when you want incremental `LLMEvent`s. The event stream is provider-neutral — same shape across OpenAI Chat, OpenAI Responses, Anthropic Messages, Gemini, Bedrock Converse, and any OpenAI-compatible deployment.
|
||||
|
||||
## Moonshot
|
||||
|
||||
Moonshot defaults to Chat Completions, with Messages and Responses selectors for Kimi K3:
|
||||
|
||||
```ts
|
||||
import { LLM } from "@opencode/ai"
|
||||
import { Moonshot } from "@opencode/ai/providers"
|
||||
|
||||
const moonshot = Moonshot.configure({ apiKey: process.env.MOONSHOT_API_KEY })
|
||||
|
||||
const request = LLM.request({
|
||||
model: moonshot.model("kimi-k3"), // also moonshot.chat("kimi-k3")
|
||||
prompt: "Explain the tradeoffs in this design.",
|
||||
providerOptions: { reasoningEffort: "high" },
|
||||
})
|
||||
|
||||
const messages = LLM.request({
|
||||
model: moonshot.messages("kimi-k3"),
|
||||
prompt: "Explain the tradeoffs in this design.",
|
||||
providerOptions: { effort: "high" },
|
||||
})
|
||||
|
||||
const responses = LLM.request({
|
||||
model: moonshot.responses("kimi-k3"),
|
||||
prompt: "Explain the tradeoffs in this design.",
|
||||
providerOptions: { reasoningEffort: "high" },
|
||||
})
|
||||
```
|
||||
|
||||
When `apiKey` is omitted, authentication reads `MOONSHOT_API_KEY`, then `MOONSHOTAI_API_KEY`.
|
||||
Chat and Responses use `https://api.moonshot.ai/v1`; Messages uses
|
||||
`https://api.moonshot.ai/anthropic/v1`. `baseURL` overrides the selected API's complete base,
|
||||
including the version prefix, for regional endpoints or gateways. Each endpoint requires its own valid credentials.
|
||||
All three routes use HTTP/SSE.
|
||||
|
||||
Reasoning options stay native to the selected API and model:
|
||||
|
||||
| Model/API | Provider options |
|
||||
| --------------------------- | --------------------------------------------------------------------------------------- |
|
||||
| K3 Chat / Responses | `reasoningEffort: "low" \| "high" \| "max"`; default is `max` |
|
||||
| K3 Messages | `effort: "low" \| "high" \| "max"`; default is `max` |
|
||||
| K2.6 Chat | `thinking: { type: "enabled" \| "disabled", keep?: "all" \| null }`; default is enabled |
|
||||
| K2.7 Code / high-speed Chat | Omit `thinking` to use always-on, preserved reasoning |
|
||||
|
||||
Omitting options preserves the model's defaults. K3 uses effort rather than the K2.x `thinking`
|
||||
parameter. Known effort values have autocomplete while future strings remain accepted.
|
||||
For K2.6, `thinking.keep: "all"` enables preservation of reasoning across user messages.
|
||||
K3 and both K2.7 Code variants always preserve reasoning. Continue with the returned
|
||||
`response.message` and matching tool results so reasoning content and any Messages signatures are retained.
|
||||
Leave sampling options such as `temperature` unset to use these models' fixed defaults.
|
||||
|
||||
The recorded suite covers all three K3 APIs, default and explicit efforts, K2.6 thinking modes,
|
||||
both K2.7 Code variants, generated tool loops with a subsequent user follow-up, required/disabled
|
||||
tool choice, image-byte input, and native structured output through `http.body` overlays.
|
||||
K3 Chat and Messages accept required and disabled tool choice. Responses supports automatic tool
|
||||
choice only; explicit `required` and `none` produce a provider `InvalidRequest` error, also covered by recordings.
|
||||
The provider targets the Moonshot Open Platform; Kimi Code is a separate product and endpoint.
|
||||
|
||||
Package entrypoints are `@opencode/ai/providers/moonshot`, `moonshot/chat`, `moonshot/messages`,
|
||||
and `moonshot/responses`; each exports `model(modelID, settings)`.
|
||||
|
||||
## MiniMax
|
||||
|
||||
MiniMax defaults to its Messages API and reads `MINIMAX_API_KEY` when `apiKey` is omitted:
|
||||
|
||||
```ts
|
||||
import { Effect, Layer } from "effect"
|
||||
import { LLM, LLMClient } from "@opencode/ai"
|
||||
import { MiniMax } from "@opencode/ai/providers"
|
||||
import { RequestExecutor } from "@opencode/ai/route"
|
||||
|
||||
const minimax = MiniMax.configure({ apiKey: process.env.MINIMAX_API_KEY })
|
||||
const request = LLM.request({
|
||||
model: minimax.model("MiniMax-M3"), // also minimax.messages("MiniMax-M3")
|
||||
prompt: "What is 173 multiplied by 219?",
|
||||
providerOptions: { thinking: { type: "adaptive" } },
|
||||
generation: { maxTokens: 1536 },
|
||||
})
|
||||
|
||||
const layer = LLMClient.layer.pipe(Layer.provide(RequestExecutor.fetchLayer))
|
||||
const response = await Effect.runPromise(LLMClient.generate(request).pipe(Effect.provide(layer)))
|
||||
console.log(response.text)
|
||||
```
|
||||
|
||||
Select `minimax.chat("MiniMax-M3")` or `minimax.responses("MiniMax-M3")` for MiniMax's native Chat Completions
|
||||
and Responses APIs. The matching package entrypoints are `@opencode/ai/providers/minimax/messages`,
|
||||
`@opencode/ai/providers/minimax/chat`, and `@opencode/ai/providers/minimax/responses`.
|
||||
|
||||
- **Messages:** M3 thinking defaults off. Set `thinking: { type: "adaptive" }` to enable it or
|
||||
`thinking: { type: "disabled" }` to disable it.
|
||||
- **Chat:** M3 thinking defaults on and uses the same `thinking` control. The provider enables `reasoning_split`
|
||||
by default so reasoning is separate from answer text; `reasoningSplit: false` selects native `<think>`-tagged text.
|
||||
- **Responses:** M3 reasoning defaults off. `reasoningEffort: "none"` disables it; `"minimal"`, `"low"`,
|
||||
`"medium"`, and `"high"` enable reasoning without changing its depth.
|
||||
|
||||
M2.x models always think, even when a disabling option is supplied. For tool continuations, retain the complete
|
||||
`response.message` in history before adding `Message.tool(...)` results; this preserves reasoning and any signatures.
|
||||
|
||||
The default API bases are `https://api.minimax.io/anthropic/v1` for Messages and `https://api.minimax.io/v1` for
|
||||
Chat and Responses. `configure({ baseURL })` replaces the selected API's base, including its version prefix.
|
||||
|
||||
## Meta
|
||||
|
||||
Use Meta's direct [Model API](https://dev.meta.ai/docs/overview) with `META_API_KEY`:
|
||||
|
||||
```ts
|
||||
import { Meta } from "@opencode/ai/providers"
|
||||
|
||||
const meta = Meta.configure() // or Meta.configure({ apiKey })
|
||||
const request = LLM.request({
|
||||
model: meta.responses("muse-spark-1.3"), // meta.model(...) also selects Responses
|
||||
prompt: "What is 173 multiplied by 219? Reply with the integer.",
|
||||
providerOptions: { reasoningEffort: "low" },
|
||||
generation: { maxTokens: 1024 },
|
||||
})
|
||||
```
|
||||
|
||||
`meta.chat("muse-spark-1.3")` selects Chat Completions; `meta.messages("muse-spark-1.3")` selects
|
||||
the Anthropic-compatible Messages API. All use `https://api.meta.ai/v1`. The package entrypoints
|
||||
`@opencode/ai/providers/meta/responses`, `meta/chat`, and `meta/messages` expose `model(modelID, settings)`.
|
||||
|
||||
[Muse Spark](https://dev.meta.ai/docs/models) supports `minimal`, `low`, `medium`, `high`, and
|
||||
`xhigh` reasoning effort; standard-tier 1.3 also supports `max`. Omitting effort uses the model's
|
||||
default. Muse Spark always reasons and rejects `none`. The output-token budget includes private reasoning.
|
||||
|
||||
Responses defaults to `store: false` and `include: ["reasoning.encrypted_content"]`. Preserve
|
||||
`response.message` along with matching `Message.tool(...)` results in subsequent requests to replay
|
||||
reasoning through tool loops. Optional `reasoningSummary: "auto"` requests a readable summary.
|
||||
For server-managed history, override `store: true, include: []` and send the response ID through
|
||||
`http: { body: { previous_response_id: responseID } }` with only the new input.
|
||||
Chat Completions redacts private reasoning and cannot carry it between calls.
|
||||
Responses and Chat support only `toolChoice: "auto"` (the default). Messages also accepts `"none"`;
|
||||
its documented forced `"any"` choice currently returns HTTP 400. Messages defaults to adaptive thinking
|
||||
with `display: "omitted"`, preserving encrypted `redacted_thinking` in `response.message`. Use
|
||||
`providerOptions: { effort: "low" }` for depth or `thinking: { type: "enabled", budgetTokens: 1024 }`
|
||||
for budget compatibility (with `generation.maxTokens > 1024`).
|
||||
|
||||
Add `tools: [Meta.webSearch()]` to a Spark Responses or Messages request for hosted web search.
|
||||
Responses exposes hosted results and URL citations in text-part `providerMetadata.meta.annotations`.
|
||||
To include search result lists, set `include: ["reasoning.encrypted_content", "web_search_call.results"]`.
|
||||
Messages exposes hosted search calls; the recorded Messages API stream does not supply structured
|
||||
citations or separate result blocks. Retain `response.message` for either API's continuation.
|
||||
|
||||
Use `Image.generate` for one-off generation or editing:
|
||||
|
||||
```ts
|
||||
import { Image, ImageInput } from "@opencode/ai"
|
||||
|
||||
const generation = Image.generate({
|
||||
model: meta.image("muse-image-1.0"),
|
||||
prompt: "A flat black square on a white background.",
|
||||
options: { n: 1, reasoningStrength: "low" },
|
||||
})
|
||||
|
||||
const edit = Image.generate({
|
||||
model: meta.image("muse-image-1.0"),
|
||||
prompt: "Make the square purple.",
|
||||
images: [ImageInput.bytes(imageBytes, "image/webp")],
|
||||
options: { outputFormat: "png", reasoningStrength: "low" },
|
||||
})
|
||||
```
|
||||
|
||||
The default image format is WEBP; `outputFormat` also accepts PNG/JPEG and `responseFormat: "url"`
|
||||
returns a signed URL. `size` is an aspect-ratio hint. For conversational images, select
|
||||
`meta.responses("muse-image-1.0")` with `tools: [Meta.imageGeneration({ reasoningStrength: "low" })]`.
|
||||
Generated images are provider-executed tool results with file content. Retain `response.message` to
|
||||
replay the signed image handle on the next request. Muse Image accepts only the `image_generation` tool.
|
||||
|
||||
Meta Responses is explicitly HTTP/SSE-only and does not use WebSockets, even when a caller supplies
|
||||
`StreamOptions.webSocket`. The public `/v1/responses` endpoint rejects WebSocket upgrades with HTTP 405 (`Allow: POST`).
|
||||
|
||||
## Image generation
|
||||
|
||||
Use `Image.generate` with an image model for direct asset generation:
|
||||
|
||||
```ts
|
||||
import { Image, ImageInput } from "@opencode-ai/ai"
|
||||
import { OpenAI } from "@opencode-ai/ai/providers"
|
||||
import { Image, ImageInput } from "@opencode/ai"
|
||||
import { OpenAI } from "@opencode/ai/providers"
|
||||
|
||||
const program = Effect.gen(function* () {
|
||||
const response = yield* Image.generate({
|
||||
@@ -131,7 +302,7 @@ yield *
|
||||
Google's current Gemini image models use the same direct API:
|
||||
|
||||
```ts
|
||||
import { Google } from "@opencode-ai/ai/providers"
|
||||
import { Google } from "@opencode/ai/providers"
|
||||
|
||||
const googleProgram = Effect.gen(function* () {
|
||||
const response = yield* Image.generate({
|
||||
@@ -207,12 +378,12 @@ The hosted result is represented as a provider-executed tool call and tool resul
|
||||
|
||||
## Testing
|
||||
|
||||
Use the deterministic test client from `@opencode-ai/ai/testing` to script provider-neutral responses and inspect
|
||||
Use the deterministic test client from `@opencode/ai/testing` to script provider-neutral responses and inspect
|
||||
the requests sent by code under test:
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
import { TestLLM } from "@opencode-ai/ai/testing"
|
||||
import { TestLLM } from "@opencode/ai/testing"
|
||||
|
||||
const programWithTestClient = Effect.gen(function* () {
|
||||
const test = yield* TestLLM.Test
|
||||
@@ -323,8 +494,8 @@ This capability describes protocol implementation, **not universal availability
|
||||
Inside an `Effect.gen`, enable OpenAI compaction with typed provider options:
|
||||
|
||||
```ts
|
||||
import { LLM, LLMClient, LLMRequest, Message } from "@opencode-ai/ai"
|
||||
import { OpenAI } from "@opencode-ai/ai/providers"
|
||||
import { LLM, LLMClient, LLMRequest, Message } from "@opencode/ai"
|
||||
import { OpenAI } from "@opencode/ai/providers"
|
||||
|
||||
const request = LLM.request({
|
||||
model: OpenAI.configure({ apiKey }).responses("gpt-5.3-codex"),
|
||||
@@ -344,7 +515,7 @@ const next = LLMRequest.update(request, {
|
||||
A compaction part has `provider` and exactly one representation: `encrypted` for Responses, or `text` for Anthropic. Responses also preserves the optional checkpoint `id`. These fields survive message serialization without becoming visible assistant text. Sending a checkpoint to another provider or an incompatible API fails rather than silently losing context.
|
||||
|
||||
```ts
|
||||
import { CompactionPart, ProviderID } from "@opencode-ai/ai"
|
||||
import { CompactionPart, ProviderID } from "@opencode/ai"
|
||||
|
||||
CompactionPart.make({ provider: ProviderID.make("openai"), id: "cmp_123", encrypted: "..." })
|
||||
CompactionPart.make({ provider: ProviderID.make("anthropic"), text: "Summary of the conversation..." })
|
||||
@@ -450,7 +621,7 @@ Normalized cache usage is read back into `response.usage.cacheReadInputTokens` a
|
||||
Provider facades configure endpoint/auth/deployment details first, then expose model selectors that take only a model or deployment id. The selected model carries the executable route value used at runtime.
|
||||
|
||||
```ts
|
||||
import { OpenAI, CloudflareAIGateway } from "@opencode-ai/ai/providers"
|
||||
import { OpenAI, CloudflareAIGateway } from "@opencode/ai/providers"
|
||||
|
||||
const openai = OpenAI.configure({ apiKey: process.env.OPENAI_API_KEY }).responses("gpt-4o-mini")
|
||||
const gateway = CloudflareAIGateway.configure({
|
||||
@@ -464,7 +635,7 @@ Included LLM providers: OpenAI, Anthropic, Google (Gemini), Google Vertex, Amazo
|
||||
Each named provider owns its module, endpoint, authentication, and route setup. Providers with the same wire format compose the shared protocol directly:
|
||||
|
||||
```ts
|
||||
import { DeepSeek, Fireworks } from "@opencode-ai/ai/providers"
|
||||
import { DeepSeek, Fireworks } from "@opencode/ai/providers"
|
||||
|
||||
const deepseek = DeepSeek.configure({ apiKey }).model("deepseek-chat")
|
||||
const fireworks = Fireworks.configure({ apiKey }).model("accounts/fireworks/models/my-model")
|
||||
@@ -474,10 +645,10 @@ The former `OpenAICompatible.baseten`, `.cerebras`, `.deepinfra`, `.deepseek`, `
|
||||
|
||||
### Provider entrypoints
|
||||
|
||||
Provider modules are available through dedicated exports from `@opencode-ai/ai`. Each LLM entrypoint exports `model(modelID, settings)`, where `settings` contains provider configuration plus common `headers` and `body` overlays.
|
||||
Provider modules are available through dedicated exports from `@opencode/ai`. Each LLM entrypoint exports `model(modelID, settings)`, where `settings` contains provider configuration plus common `headers` and `body` overlays.
|
||||
|
||||
```ts
|
||||
import { model } from "@opencode-ai/ai/providers/openai/responses"
|
||||
import { model } from "@opencode/ai/providers/openai/responses"
|
||||
|
||||
const selected = model("gpt-5", {
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
@@ -487,14 +658,14 @@ const selected = model("gpt-5", {
|
||||
|
||||
APIs have separate entrypoints:
|
||||
|
||||
- `@opencode-ai/ai/providers/openai/chat`
|
||||
- `@opencode-ai/ai/providers/openai/responses`
|
||||
- `@opencode-ai/ai/providers/openai-compatible/responses`
|
||||
- `@opencode-ai/ai/providers/anthropic-compatible`
|
||||
- `@opencode-ai/ai/providers/google-vertex/gemini`
|
||||
- `@opencode-ai/ai/providers/google-vertex/chat`
|
||||
- `@opencode-ai/ai/providers/google-vertex/responses`
|
||||
- `@opencode-ai/ai/providers/google-vertex/messages`
|
||||
- `@opencode/ai/providers/openai/chat`
|
||||
- `@opencode/ai/providers/openai/responses`
|
||||
- `@opencode/ai/providers/openai-compatible/responses`
|
||||
- `@opencode/ai/providers/anthropic-compatible`
|
||||
- `@opencode/ai/providers/google-vertex/gemini`
|
||||
- `@opencode/ai/providers/google-vertex/chat`
|
||||
- `@opencode/ai/providers/google-vertex/responses`
|
||||
- `@opencode/ai/providers/google-vertex/messages`
|
||||
|
||||
OpenAI Responses has one semantic route and uses HTTP by default. Advanced callers may supply a per-call WebSocket channel executor through `StreamOptions`; transport policy does not change provider settings, model identity, or route identity. The provider-neutral Open Responses implementation owns the reusable WebSocket request and event contract, while each provider opts in with its own handshake and connection policy. Azure follows the same Chat/Responses split at `providers/azure/chat` and `providers/azure/responses`. Generic OpenAI-compatible Chat remains at `providers/openai-compatible`; the Responses adapter at `providers/openai-compatible/responses` uses the provider-neutral Open Responses protocol. OpenAI Responses extends that baseline with OpenAI tools, event variants, metadata, and defaults. Generic Anthropic Messages-compatible providers use `providers/anthropic-compatible`, which the named Anthropic provider composes. Google Gemini and Amazon Bedrock expose their single native API through their existing provider paths.
|
||||
|
||||
@@ -503,36 +674,36 @@ Vertex Gemini, Vertex Chat, Vertex Responses, and Vertex Messages are separate A
|
||||
Tuned Vertex Gemini deployments use model ids shaped like `endpoints/1234567890` and require OAuth or ADC; Vertex express-mode API keys support publisher models only.
|
||||
|
||||
```ts
|
||||
import { model } from "@opencode-ai/ai/providers/google-vertex/gemini"
|
||||
import { model } from "@opencode/ai/providers/google-vertex/gemini"
|
||||
|
||||
model("gemini-3.5-flash", { project: "my-project", location: "global" })
|
||||
```
|
||||
|
||||
```ts
|
||||
import { model } from "@opencode-ai/ai/providers/google-vertex/chat"
|
||||
import { model } from "@opencode/ai/providers/google-vertex/chat"
|
||||
|
||||
model("deepseek-ai/deepseek-v3.2-maas", { project: "my-project", location: "global" })
|
||||
```
|
||||
|
||||
```ts
|
||||
import { model } from "@opencode-ai/ai/providers/google-vertex/responses"
|
||||
import { model } from "@opencode/ai/providers/google-vertex/responses"
|
||||
|
||||
model("xai/grok-4.20-reasoning", { project: "my-project", location: "global" })
|
||||
```
|
||||
|
||||
```ts
|
||||
import { model } from "@opencode-ai/ai/providers/google-vertex/messages"
|
||||
import { model } from "@opencode/ai/providers/google-vertex/messages"
|
||||
|
||||
model("claude-sonnet-4-6", { project: "my-project", location: "global" })
|
||||
```
|
||||
|
||||
Additional provider entrypoints include:
|
||||
|
||||
- `@opencode-ai/ai/providers/baseten`
|
||||
- `@opencode-ai/ai/providers/deepseek`
|
||||
- `@opencode-ai/ai/providers/fireworks`
|
||||
- `@opencode-ai/ai/providers/cloudflare-ai-gateway`
|
||||
- `@opencode-ai/ai/providers/cloudflare-workers-ai`
|
||||
- `@opencode/ai/providers/baseten`
|
||||
- `@opencode/ai/providers/deepseek`
|
||||
- `@opencode/ai/providers/fireworks`
|
||||
- `@opencode/ai/providers/cloudflare-ai-gateway`
|
||||
- `@opencode/ai/providers/cloudflare-workers-ai`
|
||||
|
||||
## Provider options & HTTP overlays
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Config, Effect, Formatter, Layer, Schema, Stream } from "effect"
|
||||
import { LLM, LLMClient, LLMRequest, Message, ProviderID, Tool, ToolRuntime } from "@opencode-ai/ai"
|
||||
import { Route, Auth, Endpoint, Framing, Protocol, RequestExecutor } from "@opencode-ai/ai/route"
|
||||
import { OpenAI } from "@opencode-ai/ai/providers"
|
||||
import { LLM, LLMClient, LLMRequest, Message, ProviderID, Tool, ToolRuntime } from "@opencode/ai"
|
||||
import { Route, Auth, Endpoint, Framing, Protocol, RequestExecutor } from "@opencode/ai/route"
|
||||
import { OpenAI } from "@opencode/ai/providers"
|
||||
|
||||
/**
|
||||
* A runnable walkthrough of the LLM package use-site API.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.17.20",
|
||||
"name": "@opencode-ai/ai",
|
||||
"name": "@opencode/ai",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
@@ -21,7 +21,7 @@
|
||||
"devDependencies": {
|
||||
"@clack/prompts": "1.0.0-alpha.1",
|
||||
"@effect/platform-node": "catalog:",
|
||||
"@opencode-ai/http-recorder": "workspace:*",
|
||||
"@opencode/http-recorder": "workspace:*",
|
||||
"@tsconfig/bun": "catalog:",
|
||||
"@types/bun": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
@@ -31,7 +31,7 @@
|
||||
"@aws-sdk/credential-providers": "3.1057.0",
|
||||
"@smithy/eventstream-codec": "4.2.14",
|
||||
"@smithy/util-utf8": "4.2.2",
|
||||
"@opencode-ai/schema": "workspace:*",
|
||||
"@opencode/schema": "workspace:*",
|
||||
"aws4fetch": "1.0.20",
|
||||
"effect": "catalog:",
|
||||
"google-auth-library": "10.5.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bun
|
||||
import { Script } from "@opencode-ai/script"
|
||||
import { Script } from "@opencode/script"
|
||||
import { $ } from "bun"
|
||||
import { fileURLToPath } from "url"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Buffer } from "node:buffer"
|
||||
import { Effect, Option, Schema } from "effect"
|
||||
import { Tool } from "@opencode-ai/schema/tool"
|
||||
import { Tool } from "@opencode/schema/tool"
|
||||
import { Route } from "../route/client.js"
|
||||
import { Auth } from "../route/auth.js"
|
||||
import { Endpoint } from "../route/endpoint.js"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect, Option, Schema } from "effect"
|
||||
import { Tool } from "@opencode-ai/schema/tool"
|
||||
import { Tool } from "@opencode/schema/tool"
|
||||
import { Route } from "../route/client.js"
|
||||
import { Auth } from "../route/auth.js"
|
||||
import { Endpoint } from "../route/endpoint.js"
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
import { Effect, Encoding, Schema } from "effect"
|
||||
import { Headers, HttpClientRequest } from "effect/unstable/http"
|
||||
import { GeneratedImage, ImageModel, ImageResponse, type ImageRequestFor, type ImageRoute } from "../image.js"
|
||||
import { Auth } from "../route/auth.js"
|
||||
import { Usage, mergeHttpOptions, mergeJsonRecords, type HttpOptions } from "../schema/index.js"
|
||||
import { JsonObject, ProviderShared, optionalNull } from "./shared.js"
|
||||
import { ImageInputs } from "./utils/image-input.js"
|
||||
|
||||
type OpenString<Known extends string> = Known | (string & {})
|
||||
export type ImageOptions = {
|
||||
readonly n?: number
|
||||
/** Aspect ratio hint, not an exact output resolution. */
|
||||
readonly size?: string
|
||||
readonly outputFormat?: OpenString<"webp" | "png" | "jpeg">
|
||||
readonly responseFormat?: OpenString<"b64_json" | "url">
|
||||
readonly reasoningStrength?: OpenString<"low" | "high">
|
||||
readonly toolEnablement?: {
|
||||
readonly enable_image_search?: boolean
|
||||
readonly enable_web_search?: boolean
|
||||
readonly enable_shell?: boolean
|
||||
}
|
||||
readonly [key: string]: unknown
|
||||
}
|
||||
|
||||
const Body = Schema.StructWithRest(
|
||||
Schema.Struct({
|
||||
model: Schema.String,
|
||||
prompt: Schema.String,
|
||||
images: Schema.optional(Schema.Array(JsonObject)),
|
||||
n: Schema.optional(Schema.Number),
|
||||
size: Schema.optional(Schema.String),
|
||||
output_format: Schema.optional(Schema.String),
|
||||
response_format: Schema.optional(Schema.String),
|
||||
reasoning_strength: Schema.optional(Schema.String),
|
||||
tool_enablement: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)),
|
||||
}),
|
||||
[JsonObject],
|
||||
)
|
||||
|
||||
const Response = Schema.Struct({
|
||||
data: Schema.Array(Schema.Struct({ b64_json: optionalNull(Schema.String), url: optionalNull(Schema.String) })),
|
||||
output_format: Schema.optional(Schema.String),
|
||||
usage: Schema.optional(
|
||||
Schema.Struct({
|
||||
input_tokens: Schema.optional(Schema.Number),
|
||||
output_tokens: Schema.optional(Schema.Number),
|
||||
total_tokens: Schema.optional(Schema.Number),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
export const model = (input: {
|
||||
readonly id: string
|
||||
readonly auth: Auth.Definition
|
||||
readonly baseURL: string
|
||||
readonly headers?: Record<string, string>
|
||||
readonly http?: HttpOptions
|
||||
}) => {
|
||||
const route: ImageRoute<ImageOptions> = {
|
||||
id: "meta-images",
|
||||
generate: Effect.fn("MetaImages.generate")(function* (request: ImageRequestFor<ImageOptions>, execute) {
|
||||
const http = mergeHttpOptions(request.model.http, request.http)
|
||||
const images = yield* Effect.forEach(request.images ?? [], (image) => {
|
||||
if (image.type === "bytes") return Effect.succeed({ image_url: ImageInputs.dataUrl(image) })
|
||||
if (image.type === "url") return Effect.succeed({ image_url: image.url })
|
||||
return ImageInputs.invalid("Meta Images accepts image bytes and URLs")
|
||||
})
|
||||
const { outputFormat, responseFormat, reasoningStrength, toolEnablement, ...native } = request.options ?? {}
|
||||
const payload = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Body))(
|
||||
mergeJsonRecords(
|
||||
{
|
||||
model: request.model.id,
|
||||
prompt: request.prompt,
|
||||
images: images.length === 0 ? undefined : images,
|
||||
output_format: outputFormat,
|
||||
response_format: responseFormat,
|
||||
reasoning_strength: reasoningStrength,
|
||||
tool_enablement: toolEnablement,
|
||||
},
|
||||
native,
|
||||
http?.body,
|
||||
),
|
||||
)
|
||||
const body = ProviderShared.encodeJson(payload)
|
||||
const url = new URL(`${input.baseURL.replace(/\/$/, "")}/images/${images.length === 0 ? "generations" : "edits"}`)
|
||||
Object.entries(http?.query ?? {}).forEach(([key, value]) => url.searchParams.set(key, value))
|
||||
const headers = yield* Auth.toEffect(input.auth)({
|
||||
request,
|
||||
method: "POST",
|
||||
url: url.toString(),
|
||||
body,
|
||||
headers: Headers.fromInput({ ...input.headers, ...http?.headers }),
|
||||
})
|
||||
const response = yield* execute(
|
||||
HttpClientRequest.post(url.toString()).pipe(
|
||||
HttpClientRequest.setHeaders(headers),
|
||||
HttpClientRequest.bodyText(body, "application/json"),
|
||||
),
|
||||
)
|
||||
const output = yield* ProviderShared.imageResponse("meta-images", "Meta Images", response)
|
||||
const decoded = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Response))(output.body).pipe(
|
||||
Effect.mapError((cause) => output.invalid("Meta Images returned an invalid response", cause)),
|
||||
)
|
||||
const format = decoded.output_format ?? payload.output_format ?? "webp"
|
||||
const generated = yield* Effect.forEach(decoded.data, (item, index) => {
|
||||
if (item.b64_json)
|
||||
return Effect.fromResult(Encoding.decodeBase64(item.b64_json)).pipe(
|
||||
Effect.mapError((cause) => output.invalid(`Meta Images result ${index} contains invalid base64`, cause)),
|
||||
Effect.map((data) => new GeneratedImage({ mediaType: `image/${format}`, data })),
|
||||
)
|
||||
if (item.url) return Effect.succeed(new GeneratedImage({ mediaType: `image/${format}`, data: item.url }))
|
||||
return output.invalid(`Meta Images result ${index} has neither image data nor a URL`)
|
||||
})
|
||||
if (generated.length === 0) return yield* output.invalid("Meta Images returned no images")
|
||||
return new ImageResponse({
|
||||
images: generated,
|
||||
usage:
|
||||
decoded.usage === undefined
|
||||
? undefined
|
||||
: new Usage({
|
||||
inputTokens: decoded.usage.input_tokens,
|
||||
outputTokens: decoded.usage.output_tokens,
|
||||
totalTokens: decoded.usage.total_tokens,
|
||||
providerMetadata: { meta: decoded.usage },
|
||||
}),
|
||||
providerMetadata: { meta: { outputFormat: format } },
|
||||
})
|
||||
}),
|
||||
}
|
||||
return ImageModel.make<ImageOptions>({ id: input.id, provider: "meta", route, http: input.http })
|
||||
}
|
||||
|
||||
export * as MetaImages from "./meta-images.js"
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Protocol } from "../route/protocol.js"
|
||||
import type { LLMRequest } from "../schema/index.js"
|
||||
import { AnthropicMessages } from "./anthropic-messages.js"
|
||||
import { MetaResponses } from "./meta-responses.js"
|
||||
import { JsonObject, optionalArray, ProviderShared } from "./shared.js"
|
||||
|
||||
const WebSearch = Schema.Struct({
|
||||
type: Schema.Literal("web_search"),
|
||||
name: Schema.Literal("web_search"),
|
||||
user_location: MetaResponses.WebSearch.fields.user_location,
|
||||
})
|
||||
const Body = Schema.Struct({
|
||||
...AnthropicMessages.AnthropicMessagesBody.fields,
|
||||
tools: optionalArray(
|
||||
Schema.Union([
|
||||
Schema.Struct({ name: Schema.String, description: Schema.String, input_schema: JsonObject }),
|
||||
WebSearch,
|
||||
]),
|
||||
),
|
||||
})
|
||||
|
||||
const fromRequest = Effect.fn("MetaMessages.fromRequest")(function* (request: LLMRequest) {
|
||||
const projected = ProviderShared.flattenToolRequest(request)
|
||||
const body = yield* AnthropicMessages.protocol.body.from(projected.request)
|
||||
return {
|
||||
...body,
|
||||
tools:
|
||||
body.tools === undefined
|
||||
? undefined
|
||||
: yield* Effect.forEach(body.tools, (tool, index) =>
|
||||
Effect.gen(function* () {
|
||||
const native = projected.tools[index]?.native
|
||||
if (native === undefined) return tool
|
||||
const search = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(MetaResponses.WebSearch))(
|
||||
native.meta,
|
||||
)
|
||||
if (search.search_context_size !== undefined)
|
||||
return yield* ProviderShared.invalidRequest("Meta Messages does not support searchContextSize")
|
||||
return { type: "web_search" as const, name: "web_search" as const, user_location: search.user_location }
|
||||
}),
|
||||
),
|
||||
}
|
||||
})
|
||||
|
||||
export const protocol = Protocol.make({
|
||||
id: "meta-messages",
|
||||
body: { schema: Body, from: fromRequest },
|
||||
stream: AnthropicMessages.protocol.stream,
|
||||
})
|
||||
|
||||
export * as MetaMessages from "./meta-messages.js"
|
||||
@@ -0,0 +1,238 @@
|
||||
import { Effect, Encoding, Schema } from "effect"
|
||||
import { Protocol } from "../route/protocol.js"
|
||||
import { HttpTransport } from "../route/transport/index.js"
|
||||
import { LLMEvent, LLMRequest, Message, ToolResultPart } from "../schema/index.js"
|
||||
import { OpenResponses } from "./open-responses.js"
|
||||
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js"
|
||||
import { ResponsesHostedTools } from "./utils/responses-hosted-tools.js"
|
||||
import { ToolSchemaProjection } from "./utils/tool-schema.js"
|
||||
import { MetaImage } from "./utils/meta-image.js"
|
||||
|
||||
const ADAPTER = "meta-responses"
|
||||
const NAME = "Meta Responses"
|
||||
|
||||
export const WebSearch = Schema.Struct({
|
||||
type: Schema.Literal("web_search"),
|
||||
search_context_size: Schema.optional(Schema.String),
|
||||
user_location: Schema.optional(
|
||||
Schema.Struct({
|
||||
type: Schema.Literal("approximate"),
|
||||
city: Schema.optional(Schema.String),
|
||||
region: Schema.optional(Schema.String),
|
||||
country: Schema.optional(Schema.String),
|
||||
timezone: Schema.optional(Schema.String),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
export const ImageGeneration = Schema.Struct({
|
||||
type: Schema.Literal("image_generation"),
|
||||
size: Schema.optional(Schema.String),
|
||||
output_format: Schema.optional(Schema.String),
|
||||
reasoning_strength: Schema.optional(Schema.String),
|
||||
enable_image_search: Schema.optional(Schema.Boolean),
|
||||
enable_web_search: Schema.optional(Schema.Boolean),
|
||||
enable_shell: Schema.optional(Schema.Boolean),
|
||||
})
|
||||
|
||||
const NativeTool = Schema.Union([WebSearch, ImageGeneration])
|
||||
const ImageItem = Schema.Struct({
|
||||
type: Schema.Literal("image_generation_call"),
|
||||
id: Schema.String,
|
||||
status: Schema.optional(Schema.String),
|
||||
result: optionalNull(Schema.String),
|
||||
output_format: Schema.optional(Schema.String),
|
||||
error: Schema.optional(Schema.Unknown),
|
||||
})
|
||||
|
||||
const Body = Schema.Struct({
|
||||
...OpenResponses.coreFields,
|
||||
input: Schema.Array(Schema.Union([OpenResponses.InputItem, ImageItem])),
|
||||
tools: optionalArray(Schema.Union([OpenResponses.Tool, NativeTool])),
|
||||
stream: Schema.Literal(true),
|
||||
})
|
||||
|
||||
const MessageAnnotations = Schema.Struct({
|
||||
content: Schema.Array(Schema.Struct({ annotations: optionalArray(JsonObject) })),
|
||||
})
|
||||
|
||||
interface ParserState extends OpenResponses.ParserState {
|
||||
readonly completedItems: ReadonlySet<string>
|
||||
}
|
||||
|
||||
const adapter = {
|
||||
id: ADAPTER,
|
||||
name: NAME,
|
||||
restoreHostedToolItem: (item: unknown) => (Schema.is(ImageItem)(item) ? item : undefined),
|
||||
} satisfies OpenResponses.ProviderAdapter
|
||||
|
||||
const fromRequest = Effect.fn("MetaResponses.fromRequest")(function* (request: LLMRequest) {
|
||||
const key = request.model.route.providerMetadataKey ?? String(request.model.provider)
|
||||
const projected = ProviderShared.flattenToolRequest(
|
||||
LLMRequest.update(request, {
|
||||
messages: request.messages.map((message) =>
|
||||
Message.make({
|
||||
...message,
|
||||
content: message.content.map((part) => {
|
||||
if (
|
||||
part.type !== "tool-result" ||
|
||||
!part.providerExecuted ||
|
||||
part.name !== "image_generation" ||
|
||||
part.result.type !== "content" ||
|
||||
part.providerMetadata?.[key]?.itemId !== part.id
|
||||
)
|
||||
return part
|
||||
// Meta's signed image ID carries edit state; replay the handle, not the image bytes as a user message.
|
||||
return ToolResultPart.make({
|
||||
...part,
|
||||
result: {
|
||||
type: "json",
|
||||
value: { type: "image_generation_call", id: part.id, status: "completed", result: null },
|
||||
},
|
||||
})
|
||||
}),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
)
|
||||
return yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Body))({
|
||||
...(yield* OpenResponses.lowerConversation(projected.request, adapter)),
|
||||
...OpenResponses.lowerGeneration(request),
|
||||
tools:
|
||||
projected.tools.length === 0
|
||||
? undefined
|
||||
: yield* Effect.forEach(projected.tools, (tool) =>
|
||||
Effect.gen(function* () {
|
||||
if (tool.native === undefined)
|
||||
return yield* OpenResponses.lowerTool(
|
||||
NAME,
|
||||
tool,
|
||||
ToolSchemaProjection.modelCompatibility(tool.inputSchema, request.model.compatibility?.toolSchema),
|
||||
)
|
||||
return yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(NativeTool))(tool.native.meta)
|
||||
}),
|
||||
),
|
||||
tool_choice:
|
||||
OpenResponses.allowedToolChoice(request) ??
|
||||
(request.toolChoice ? yield* OpenResponses.lowerToolChoice(NAME, request.toolChoice) : undefined),
|
||||
})
|
||||
})
|
||||
|
||||
const HOSTED_TOOLS = {
|
||||
web_search_call: { name: "web_search", input: (item) => item.action ?? {} },
|
||||
image_generation_call: {
|
||||
name: "image_generation",
|
||||
input: () => ({}),
|
||||
result: Effect.fn("MetaResponses.imageResult")(function* (raw: ResponsesHostedTools.Item) {
|
||||
const item = yield* Schema.decodeUnknownEffect(ImageItem)(raw).pipe(
|
||||
Effect.mapError((cause) =>
|
||||
ProviderShared.eventError(
|
||||
ADAPTER,
|
||||
"Meta returned an invalid image item",
|
||||
ProviderShared.encodeJson(raw),
|
||||
cause,
|
||||
),
|
||||
),
|
||||
)
|
||||
if (item.error !== undefined && item.error !== null) return { type: "error" as const, value: item.error }
|
||||
if (!item.result)
|
||||
return yield* ProviderShared.eventError(
|
||||
ADAPTER,
|
||||
"Meta returned an image without data",
|
||||
ProviderShared.encodeJson(raw),
|
||||
)
|
||||
const data = yield* Effect.fromResult(Encoding.decodeBase64(item.result)).pipe(
|
||||
Effect.mapError((cause) =>
|
||||
ProviderShared.eventError(
|
||||
ADAPTER,
|
||||
"Meta returned invalid image base64",
|
||||
ProviderShared.encodeJson(raw),
|
||||
cause,
|
||||
),
|
||||
),
|
||||
)
|
||||
const mime = MetaImage.mediaType(data, item.output_format)
|
||||
return {
|
||||
type: "content" as const,
|
||||
value: [{ type: "file" as const, uri: `data:${mime};base64,${item.result}`, mime }],
|
||||
}
|
||||
}),
|
||||
},
|
||||
} satisfies ResponsesHostedTools.Definitions
|
||||
|
||||
const onEvent = Effect.fn("MetaResponses.onEvent")(function* (
|
||||
state: OpenResponses.ParserState,
|
||||
input: OpenResponses.Event,
|
||||
) {
|
||||
const event = OpenResponses.normalize(state, input)
|
||||
if (event.type === "response.output_item.done" && event.item && ResponsesHostedTools.isItem(event.item, HOSTED_TOOLS))
|
||||
return yield* ResponsesHostedTools.onDone(state, event.item, HOSTED_TOOLS)
|
||||
const result = yield* OpenResponses.step(state, event)
|
||||
if (event.type !== "response.output_item.done" || event.item?.type !== "message") return result
|
||||
const message = yield* Schema.decodeUnknownEffect(MessageAnnotations)(event.item).pipe(
|
||||
Effect.mapError((cause) =>
|
||||
ProviderShared.eventError(
|
||||
ADAPTER,
|
||||
"Meta returned invalid message annotations",
|
||||
ProviderShared.encodeJson(event),
|
||||
cause,
|
||||
),
|
||||
),
|
||||
)
|
||||
const annotations = message.content.flatMap((part) => part.annotations ?? [])
|
||||
if (annotations.length === 0) return result
|
||||
return [
|
||||
result[0],
|
||||
result[1].map((item) =>
|
||||
LLMEvent.is.textEnd(item)
|
||||
? LLMEvent.textEnd({
|
||||
...item,
|
||||
providerMetadata: {
|
||||
...item.providerMetadata,
|
||||
[state.providerMetadataKey]: { ...item.providerMetadata?.[state.providerMetadataKey], annotations },
|
||||
},
|
||||
})
|
||||
: item,
|
||||
),
|
||||
] satisfies OpenResponses.StepResult
|
||||
})
|
||||
|
||||
const step = Effect.fn("MetaResponses.step")(function* (state: ParserState, input: OpenResponses.Event) {
|
||||
const completedItems = new Set(state.completedItems)
|
||||
const event = OpenResponses.normalize(state, input)
|
||||
if (event.type === "response.output_item.done" && event.item && completedItems.has(event.item.id))
|
||||
return [state, []] as const
|
||||
const events: LLMEvent[] = []
|
||||
let current: OpenResponses.ParserState = state
|
||||
// Muse Image delivers its image and optional summary only in response.completed.
|
||||
// Recover terminal-only items in order, without duplicating Spark's streamed items.
|
||||
if (event.type === "response.completed") {
|
||||
for (const [index, item] of (event.response?.output ?? []).entries()) {
|
||||
const done = OpenResponses.normalize(current, { type: "response.output_item.done", item, output_index: index })
|
||||
// Spark changes reasoning IDs in the terminal snapshot; output indices still identify the streamed items.
|
||||
if (!done.item || completedItems.has(done.item.id) || completedItems.has(state.outputItems[index] ?? "")) continue
|
||||
const result = yield* onEvent(current, done)
|
||||
current = result[0]
|
||||
events.push(...result[1])
|
||||
completedItems.add(done.item.id)
|
||||
}
|
||||
}
|
||||
const result = yield* onEvent(current, event)
|
||||
if (event.type === "response.output_item.done" && event.item) completedItems.add(event.item.id)
|
||||
return [{ ...result[0], completedItems }, [...events, ...result[1]]] as const
|
||||
})
|
||||
|
||||
export const protocol = Protocol.make({
|
||||
id: ADAPTER,
|
||||
body: { schema: Body, from: fromRequest },
|
||||
stream: {
|
||||
event: OpenResponses.protocol.stream.event,
|
||||
initial: (request): ParserState => ({ ...OpenResponses.initial(request, adapter), completedItems: new Set() }),
|
||||
step,
|
||||
terminal: OpenResponses.terminal,
|
||||
},
|
||||
})
|
||||
|
||||
export const httpTransport = HttpTransport.sseJson.with<Schema.Schema.Type<typeof Body>>()
|
||||
|
||||
export * as MetaResponses from "./meta-responses.js"
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect, Option, Schema } from "effect"
|
||||
import type { Content } from "@opencode-ai/schema/tool"
|
||||
import type { Content } from "@opencode/schema/tool"
|
||||
import { HttpTransport } from "../route/transport/index.js"
|
||||
import { Protocol } from "../route/protocol.js"
|
||||
import {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Tool } from "@opencode-ai/schema/tool"
|
||||
import { Tool } from "@opencode/schema/tool"
|
||||
import { Route } from "../route/client.js"
|
||||
import { Auth } from "../route/auth.js"
|
||||
import { Endpoint } from "../route/endpoint.js"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Buffer } from "node:buffer"
|
||||
import { Tool } from "@opencode-ai/schema/tool"
|
||||
import { Tool } from "@opencode/schema/tool"
|
||||
import { Effect, Schema, Stream } from "effect"
|
||||
import * as Sse from "effect/unstable/encoding/Sse"
|
||||
import { Headers, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Responses image items can omit output_format, including when PNG/JPEG was requested.
|
||||
export const mediaType = (data: Uint8Array, format?: string) => {
|
||||
if (format !== undefined) return `image/${format}`
|
||||
if (data[0] === 137 && data[1] === 80 && data[2] === 78 && data[3] === 71) return "image/png"
|
||||
if (data[0] === 255 && data[1] === 216 && data[2] === 255) return "image/jpeg"
|
||||
if (new TextDecoder().decode(data.slice(0, 4)) === "RIFF" && new TextDecoder().decode(data.slice(8, 12)) === "WEBP")
|
||||
return "image/webp"
|
||||
return "application/octet-stream"
|
||||
}
|
||||
|
||||
export * as MetaImage from "./meta-image.js"
|
||||
@@ -16,7 +16,10 @@ 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 Groq from "./groq.js"
|
||||
export * as Meta from "./meta.js"
|
||||
export * as MiniMax from "./minimax.js"
|
||||
export * as Mistral from "./mistral.js"
|
||||
export * as Moonshot from "./moonshot.js"
|
||||
export * as OpenAI from "./openai.js"
|
||||
export * as OpenAICompatible from "./openai-compatible.js"
|
||||
export * as OpenAICompatibleResponses from "./openai-compatible-responses.js"
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
import type { ProviderPackage } from "../provider-package.js"
|
||||
import { OpenAIChat } from "../protocols/openai-chat.js"
|
||||
import { AnthropicMessages } from "../protocols/anthropic-messages.js"
|
||||
import { MetaResponses } from "../protocols/meta-responses.js"
|
||||
import { MetaMessages } from "../protocols/meta-messages.js"
|
||||
import { MetaImages } from "../protocols/meta-images.js"
|
||||
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, ToolDefinition, type ModelID } from "../schema/index.js"
|
||||
import type { OpenResponsesProviderOptionsInput } from "./open-responses-options.js"
|
||||
|
||||
export const id = ProviderID.make("meta")
|
||||
const baseURL = "https://api.meta.ai/v1"
|
||||
|
||||
export type ProviderOptionsInput = OpenResponsesProviderOptionsInput &
|
||||
Pick<AnthropicMessages.OptionsInput, "thinking" | "effort">
|
||||
export type MessagesOptionsInput = Pick<
|
||||
AnthropicMessages.OptionsInput,
|
||||
"thinking" | "effort" | "outputConfig" | "output_config" | "serviceTier" | "service_tier" | "metadata"
|
||||
> & { readonly [key: string]: unknown }
|
||||
export type ImageOptions = MetaImages.ImageOptions
|
||||
|
||||
export interface WebSearchOptions {
|
||||
readonly searchContextSize?: "low" | "medium" | "high" | (string & {})
|
||||
readonly userLocation?: {
|
||||
readonly city?: string
|
||||
readonly region?: string
|
||||
readonly country?: string
|
||||
readonly timezone?: string
|
||||
}
|
||||
}
|
||||
|
||||
export const webSearch = (options: WebSearchOptions = {}) =>
|
||||
ToolDefinition.make({
|
||||
name: "web_search",
|
||||
description: "Search the web with Meta's hosted search tool.",
|
||||
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
||||
native: {
|
||||
meta: {
|
||||
type: "web_search",
|
||||
search_context_size: options.searchContextSize,
|
||||
user_location:
|
||||
options.userLocation === undefined ? undefined : { type: "approximate", ...options.userLocation },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export interface ImageGenerationOptions {
|
||||
readonly size?: string
|
||||
readonly outputFormat?: "webp" | "png" | "jpeg" | (string & {})
|
||||
readonly reasoningStrength?: "low" | "high" | (string & {})
|
||||
readonly enableImageSearch?: boolean
|
||||
readonly enableWebSearch?: boolean
|
||||
readonly enableShell?: boolean
|
||||
}
|
||||
|
||||
export const imageGeneration = (options: ImageGenerationOptions = {}) =>
|
||||
ToolDefinition.make({
|
||||
name: "image_generation",
|
||||
description: "Generate or edit an image with Muse Image.",
|
||||
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
||||
native: {
|
||||
meta: {
|
||||
type: "image_generation",
|
||||
size: options.size,
|
||||
output_format: options.outputFormat,
|
||||
reasoning_strength: options.reasoningStrength,
|
||||
enable_image_search: options.enableImageSearch,
|
||||
enable_web_search: options.enableWebSearch,
|
||||
enable_shell: options.enableShell,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export type LanguageModelOptions = Omit<RouteDefaultsInput, "providerOptions"> &
|
||||
ProviderAuthOption<"optional"> & {
|
||||
readonly baseURL?: string
|
||||
readonly providerOptions?: ProviderOptionsInput
|
||||
}
|
||||
|
||||
export interface Settings extends ProviderPackage.Settings {
|
||||
readonly apiKey?: string
|
||||
readonly baseURL?: string
|
||||
readonly providerOptions?: ProviderOptionsInput
|
||||
}
|
||||
|
||||
const responsesRoute = Route.make({
|
||||
id: "meta-responses",
|
||||
provider: id,
|
||||
providerMetadataKey: "meta",
|
||||
protocol: MetaResponses.protocol,
|
||||
endpoint: Endpoint.path("/responses", { baseURL }),
|
||||
// Meta Responses does not support WebSocket upgrades; always use HTTP/SSE.
|
||||
transport: MetaResponses.httpTransport,
|
||||
defaults: { providerOptions: { store: false, include: ["reasoning.encrypted_content"] } },
|
||||
})
|
||||
|
||||
const chatRoute = Route.make({
|
||||
id: "meta-chat",
|
||||
provider: id,
|
||||
providerMetadataKey: "meta",
|
||||
protocol: OpenAIChat.protocol,
|
||||
endpoint: Endpoint.path("/chat/completions", { baseURL }),
|
||||
framing: OpenAIChat.framing,
|
||||
})
|
||||
|
||||
const messagesRoute = Route.make({
|
||||
id: "meta-messages",
|
||||
provider: id,
|
||||
providerMetadataKey: "meta",
|
||||
protocol: MetaMessages.protocol,
|
||||
endpoint: Endpoint.path("/messages", { baseURL }),
|
||||
framing: AnthropicMessages.framing,
|
||||
defaults: { providerOptions: { thinking: { type: "adaptive", display: "omitted" } } },
|
||||
})
|
||||
|
||||
export const routes = [responsesRoute, chatRoute, messagesRoute]
|
||||
|
||||
export const configure = (input: LanguageModelOptions = {}) => {
|
||||
const { apiKey: _apiKey, auth: _auth, baseURL: endpoint, ...defaults } = input
|
||||
const options = {
|
||||
...defaults,
|
||||
endpoint: { baseURL: endpoint ?? baseURL },
|
||||
auth: AuthOptions.bearer(input, "META_API_KEY"),
|
||||
}
|
||||
const configuredResponses = responsesRoute.with(options)
|
||||
const configuredChat = chatRoute.with(options)
|
||||
const configuredMessages = messagesRoute.with(options)
|
||||
const responses = (modelID: string | ModelID) =>
|
||||
configuredResponses.model<OpenResponsesProviderOptionsInput>({ id: modelID })
|
||||
const chat = (modelID: string | ModelID) =>
|
||||
configuredChat.model<OpenResponsesProviderOptionsInput>({
|
||||
id: modelID,
|
||||
compatibility: { maxTokensField: "max_completion_tokens", supportsStore: false },
|
||||
})
|
||||
const messages = (modelID: string | ModelID) =>
|
||||
configuredMessages.model<MessagesOptionsInput>({
|
||||
id: modelID,
|
||||
compatibility: { requireSignature: false },
|
||||
})
|
||||
const image = (modelID: string | ModelID) =>
|
||||
MetaImages.model({
|
||||
id: modelID,
|
||||
baseURL: endpoint ?? baseURL,
|
||||
auth: options.auth,
|
||||
headers: input.headers,
|
||||
http: input.http === undefined ? undefined : HttpOptions.make(input.http),
|
||||
})
|
||||
return { id, model: responses, responses, chat, messages, image, configure }
|
||||
}
|
||||
|
||||
export const provider = configure()
|
||||
export const responses = provider.responses
|
||||
export const chat = provider.chat
|
||||
export const messages = provider.messages
|
||||
export const image = provider.image
|
||||
|
||||
export const model: ProviderPackage.Definition<Settings, OpenResponsesProviderOptionsInput>["model"] = (
|
||||
modelID,
|
||||
settings,
|
||||
) => fromSettings(settings).responses(modelID)
|
||||
|
||||
export const chatModel: ProviderPackage.Definition<Settings, OpenResponsesProviderOptionsInput>["model"] = (
|
||||
modelID,
|
||||
settings,
|
||||
) => fromSettings(settings).chat(modelID)
|
||||
|
||||
export const messagesModel: ProviderPackage.Definition<Settings, MessagesOptionsInput>["model"] = (modelID, settings) =>
|
||||
fromSettings(settings).messages(modelID)
|
||||
|
||||
function fromSettings(settings: Settings) {
|
||||
return configure({
|
||||
apiKey: settings.apiKey,
|
||||
baseURL: settings.baseURL,
|
||||
headers: settings.headers,
|
||||
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
||||
providerOptions: settings.providerOptions,
|
||||
})
|
||||
}
|
||||
|
||||
export * as Meta from "./meta.js"
|
||||
@@ -0,0 +1,2 @@
|
||||
export { chatModel as model } from "../meta.js"
|
||||
export type { Settings } from "../meta.js"
|
||||
@@ -0,0 +1,2 @@
|
||||
export { messagesModel as model } from "../meta.js"
|
||||
export type { Settings } from "../meta.js"
|
||||
@@ -0,0 +1,2 @@
|
||||
export { model } from "../meta.js"
|
||||
export type { Settings } from "../meta.js"
|
||||
@@ -0,0 +1,144 @@
|
||||
import { Effect, Schema } from "effect"
|
||||
import type { ProviderPackage } from "../provider-package.js"
|
||||
import { AnthropicMessages } from "../protocols/anthropic-messages.js"
|
||||
import { OpenAIChat } from "../protocols/openai-chat.js"
|
||||
import { OpenResponses } from "../protocols/open-responses.js"
|
||||
import { ProviderShared } from "../protocols/shared.js"
|
||||
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.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 LLMRequest, type ModelID } from "../schema/index.js"
|
||||
|
||||
export const id = ProviderID.make("minimax")
|
||||
|
||||
export type MessagesOptionsInput = {
|
||||
/** M3 defaults to disabled; M2.x always thinks. */
|
||||
readonly thinking?: { readonly type: "adaptive" | "disabled" }
|
||||
readonly metadata?: AnthropicMessages.OptionsInput["metadata"]
|
||||
}
|
||||
|
||||
export type ChatOptionsInput = {
|
||||
/** M3 defaults to adaptive; M2.x always thinks. */
|
||||
readonly thinking?: { readonly type: "adaptive" | "disabled" | (string & {}) }
|
||||
/** Separates reasoning from text. Defaults to true. */
|
||||
readonly reasoningSplit?: boolean
|
||||
}
|
||||
|
||||
export type ResponsesOptionsInput = {
|
||||
/** M3 defaults to none. Other supported values enable thinking without changing its depth. */
|
||||
readonly reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | (string & {})
|
||||
}
|
||||
|
||||
export type ProviderOptionsInput = MessagesOptionsInput | ChatOptionsInput | ResponsesOptionsInput
|
||||
|
||||
export type Config = Omit<RouteDefaultsInput, "providerOptions"> &
|
||||
ProviderAuthOption<"optional"> & {
|
||||
/** Overrides the selected API's base URL, including its version prefix. */
|
||||
readonly baseURL?: string
|
||||
readonly providerOptions?: ProviderOptionsInput
|
||||
}
|
||||
|
||||
export interface Settings<Options = MessagesOptionsInput> extends ProviderPackage.Settings {
|
||||
readonly apiKey?: string
|
||||
readonly baseURL?: string
|
||||
readonly providerOptions?: Options
|
||||
}
|
||||
|
||||
const ChatOptions = Schema.Struct({
|
||||
thinking: Schema.optional(Schema.Struct({ type: Schema.String })),
|
||||
reasoningSplit: Schema.optional(Schema.Boolean),
|
||||
})
|
||||
|
||||
const chatProtocol = Protocol.make({
|
||||
id: "minimax-chat",
|
||||
body: {
|
||||
schema: Schema.Struct({
|
||||
...OpenAIChat.bodyFields,
|
||||
thinking: ChatOptions.fields.thinking,
|
||||
reasoning_split: Schema.Boolean,
|
||||
}),
|
||||
from: Effect.fn("MiniMax.chatFromRequest")(function* (request: LLMRequest) {
|
||||
const options = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(ChatOptions))(
|
||||
request.providerOptions ?? {},
|
||||
)
|
||||
return {
|
||||
...(yield* OpenAIChat.protocol.body.from(request)),
|
||||
thinking: options.thinking,
|
||||
// MiniMax otherwise embeds <think> tags in ordinary assistant text.
|
||||
reasoning_split: options.reasoningSplit ?? true,
|
||||
}
|
||||
}),
|
||||
},
|
||||
stream: OpenAIChat.protocol.stream,
|
||||
})
|
||||
|
||||
const messagesRoute = Route.make({
|
||||
id: "minimax-messages",
|
||||
provider: id,
|
||||
providerMetadataKey: "minimax",
|
||||
protocol: AnthropicMessages.protocol,
|
||||
endpoint: Endpoint.path("/messages", { baseURL: "https://api.minimax.io/anthropic/v1" }),
|
||||
framing: AnthropicMessages.framing,
|
||||
headers: () => ({ "anthropic-version": "2023-06-01" }),
|
||||
})
|
||||
|
||||
const chatRoute = Route.make({
|
||||
id: "minimax-chat",
|
||||
provider: id,
|
||||
providerMetadataKey: "minimax",
|
||||
protocol: chatProtocol,
|
||||
endpoint: Endpoint.path("/chat/completions", { baseURL: "https://api.minimax.io/v1" }),
|
||||
framing: OpenAIChat.framing,
|
||||
})
|
||||
|
||||
const responsesRoute = Route.make({
|
||||
id: "minimax-responses",
|
||||
provider: id,
|
||||
providerMetadataKey: "minimax",
|
||||
protocol: OpenResponses.protocol,
|
||||
endpoint: Endpoint.path("/responses", { baseURL: "https://api.minimax.io/v1" }),
|
||||
framing: Framing.sse,
|
||||
})
|
||||
|
||||
export const routes = [messagesRoute, chatRoute, responsesRoute]
|
||||
|
||||
export const configure = (input: Config = {}) => {
|
||||
const { apiKey: _apiKey, auth: _auth, baseURL, ...rest } = input
|
||||
const defaults = {
|
||||
...rest,
|
||||
endpoint: baseURL === undefined ? undefined : { baseURL },
|
||||
auth: AuthOptions.bearer(input, "MINIMAX_API_KEY"),
|
||||
}
|
||||
const messages = (modelID: string | ModelID) =>
|
||||
messagesRoute.with(defaults).model<MessagesOptionsInput>({ id: modelID })
|
||||
const chat = (modelID: string | ModelID) =>
|
||||
chatRoute.with(defaults).model<ChatOptionsInput>({
|
||||
id: modelID,
|
||||
compatibility: { supportsStore: false, supportsStrictMode: false },
|
||||
})
|
||||
const responses = (modelID: string | ModelID) =>
|
||||
responsesRoute.with(defaults).model<ResponsesOptionsInput>({ id: modelID })
|
||||
return { id, model: messages, messages, chat, responses, configure }
|
||||
}
|
||||
|
||||
export const provider = configure()
|
||||
|
||||
export const model: ProviderPackage.Definition<Settings<MessagesOptionsInput>, MessagesOptionsInput>["model"] = (
|
||||
modelID,
|
||||
settings,
|
||||
) =>
|
||||
configure({
|
||||
apiKey: settings.apiKey,
|
||||
baseURL: settings.baseURL,
|
||||
headers: settings.headers,
|
||||
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
||||
providerOptions: settings.providerOptions,
|
||||
}).model(modelID)
|
||||
|
||||
export const messages = provider.messages
|
||||
export const chat = provider.chat
|
||||
export const responses = provider.responses
|
||||
|
||||
export * as MiniMax from "./minimax.js"
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { ProviderPackage } from "../../provider-package.js"
|
||||
import { MiniMax } from "../minimax.js"
|
||||
|
||||
export type Settings = MiniMax.Settings<MiniMax.ChatOptionsInput>
|
||||
|
||||
export const model: ProviderPackage.Definition<Settings, MiniMax.ChatOptionsInput>["model"] = (modelID, settings) =>
|
||||
MiniMax.configure({
|
||||
apiKey: settings.apiKey,
|
||||
baseURL: settings.baseURL,
|
||||
headers: settings.headers,
|
||||
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
||||
providerOptions: settings.providerOptions,
|
||||
}).chat(modelID)
|
||||
@@ -0,0 +1 @@
|
||||
export { model, type Settings, type MessagesOptionsInput } from "../minimax.js"
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { ProviderPackage } from "../../provider-package.js"
|
||||
import { MiniMax } from "../minimax.js"
|
||||
|
||||
export type Settings = MiniMax.Settings<MiniMax.ResponsesOptionsInput>
|
||||
|
||||
export const model: ProviderPackage.Definition<Settings, MiniMax.ResponsesOptionsInput>["model"] = (
|
||||
modelID,
|
||||
settings,
|
||||
) =>
|
||||
MiniMax.configure({
|
||||
apiKey: settings.apiKey,
|
||||
baseURL: settings.baseURL,
|
||||
headers: settings.headers,
|
||||
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
||||
providerOptions: settings.providerOptions,
|
||||
}).responses(modelID)
|
||||
@@ -0,0 +1,145 @@
|
||||
import { Effect, Schema } from "effect"
|
||||
import type { ProviderPackage } from "../provider-package.js"
|
||||
import { AnthropicMessages } from "../protocols/anthropic-messages.js"
|
||||
import { OpenAIChat } from "../protocols/openai-chat.js"
|
||||
import { OpenResponses } from "../protocols/open-responses.js"
|
||||
import { ProviderShared } from "../protocols/shared.js"
|
||||
import { AuthOptions, type ProviderAuthOption } from "../route/auth-options.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 LLMRequest, type ModelID } from "../schema/index.js"
|
||||
|
||||
export const id = ProviderID.make("moonshotai")
|
||||
|
||||
export type ReasoningEffort = "low" | "high" | "max" | (string & {})
|
||||
|
||||
export type ChatOptionsInput = {
|
||||
/** K3 always reasons; omitted effort uses the model's default. */
|
||||
readonly reasoningEffort?: ReasoningEffort
|
||||
/** K2.6 supports disabling thinking; K2.7 Code always thinks and preserves reasoning. */
|
||||
readonly thinking?: {
|
||||
readonly type: "enabled" | "disabled" | (string & {})
|
||||
readonly keep?: "all" | (string & {}) | null
|
||||
}
|
||||
}
|
||||
|
||||
export type MessagesOptionsInput = {
|
||||
readonly effort?: ReasoningEffort
|
||||
readonly metadata?: AnthropicMessages.OptionsInput["metadata"]
|
||||
}
|
||||
|
||||
export type ResponsesOptionsInput = {
|
||||
readonly reasoningEffort?: ReasoningEffort
|
||||
readonly safetyIdentifier?: string
|
||||
}
|
||||
|
||||
export type Config = Omit<RouteDefaultsInput, "providerOptions"> &
|
||||
ProviderAuthOption<"optional"> & {
|
||||
/** Overrides the selected API's base URL, including its version prefix. */
|
||||
readonly baseURL?: string
|
||||
readonly providerOptions?: ChatOptionsInput | MessagesOptionsInput | ResponsesOptionsInput
|
||||
}
|
||||
|
||||
export interface Settings<Options = ChatOptionsInput> extends ProviderPackage.Settings {
|
||||
readonly apiKey?: string
|
||||
readonly baseURL?: string
|
||||
readonly providerOptions?: Options
|
||||
}
|
||||
|
||||
const ChatOptions = Schema.Struct({
|
||||
reasoningEffort: Schema.optional(Schema.String),
|
||||
thinking: Schema.optional(
|
||||
Schema.Struct({ type: Schema.String, keep: Schema.optional(Schema.NullOr(Schema.String)) }),
|
||||
),
|
||||
})
|
||||
|
||||
const chatProtocol = Protocol.make({
|
||||
id: "moonshot-chat",
|
||||
body: {
|
||||
schema: Schema.Struct({ ...OpenAIChat.bodyFields, thinking: ChatOptions.fields.thinking }),
|
||||
from: Effect.fn("Moonshot.chatFromRequest")(function* (request: LLMRequest) {
|
||||
const options = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(ChatOptions))(
|
||||
request.providerOptions ?? {},
|
||||
)
|
||||
return { ...(yield* OpenAIChat.protocol.body.from(request)), thinking: options.thinking }
|
||||
}),
|
||||
},
|
||||
stream: OpenAIChat.protocol.stream,
|
||||
})
|
||||
|
||||
const chatRoute = Route.make({
|
||||
id: "moonshot-chat",
|
||||
provider: id,
|
||||
providerMetadataKey: "moonshot",
|
||||
protocol: chatProtocol,
|
||||
endpoint: Endpoint.path("/chat/completions", { baseURL: "https://api.moonshot.ai/v1" }),
|
||||
framing: OpenAIChat.framing,
|
||||
})
|
||||
|
||||
const messagesRoute = Route.make({
|
||||
id: "moonshot-messages",
|
||||
provider: id,
|
||||
providerMetadataKey: "moonshot",
|
||||
protocol: AnthropicMessages.protocol,
|
||||
endpoint: Endpoint.path("/messages", { baseURL: "https://api.moonshot.ai/anthropic/v1" }),
|
||||
framing: AnthropicMessages.framing,
|
||||
})
|
||||
|
||||
const responsesRoute = Route.make({
|
||||
id: "moonshot-responses",
|
||||
provider: id,
|
||||
providerMetadataKey: "moonshot",
|
||||
protocol: OpenResponses.protocol,
|
||||
endpoint: Endpoint.path("/responses", { baseURL: "https://api.moonshot.ai/v1" }),
|
||||
framing: Framing.sse,
|
||||
})
|
||||
|
||||
export const routes = [chatRoute, messagesRoute, responsesRoute]
|
||||
|
||||
export const configure = (input: Config = {}) => {
|
||||
const { apiKey: _apiKey, auth: _auth, baseURL, ...rest } = input
|
||||
const defaults = {
|
||||
...rest,
|
||||
endpoint: baseURL === undefined ? undefined : { baseURL },
|
||||
auth: AuthOptions.bearer(input, ["MOONSHOT_API_KEY", "MOONSHOTAI_API_KEY"]),
|
||||
}
|
||||
const chat = (modelID: string | ModelID) =>
|
||||
chatRoute.with(defaults).model<ChatOptionsInput>({
|
||||
id: modelID,
|
||||
compatibility: {
|
||||
maxTokensField: "max_tokens",
|
||||
supportsStore: false,
|
||||
supportsStrictMode: false,
|
||||
toolSchema: "moonshot",
|
||||
reasoningField: "reasoning_content",
|
||||
},
|
||||
})
|
||||
const messages = (modelID: string | ModelID) =>
|
||||
messagesRoute.with(defaults).model<MessagesOptionsInput>({
|
||||
id: modelID,
|
||||
compatibility: { requireSignature: false, toolSchema: "moonshot" },
|
||||
})
|
||||
const responses = (modelID: string | ModelID) =>
|
||||
responsesRoute
|
||||
.with(defaults)
|
||||
.model<ResponsesOptionsInput>({ id: modelID, compatibility: { toolSchema: "moonshot" } })
|
||||
return { id, model: chat, chat, messages, responses, configure }
|
||||
}
|
||||
|
||||
export const provider = configure()
|
||||
export const chat = provider.chat
|
||||
export const messages = provider.messages
|
||||
export const responses = provider.responses
|
||||
|
||||
export const model: ProviderPackage.Definition<Settings, ChatOptionsInput>["model"] = (modelID, settings) =>
|
||||
configure({
|
||||
apiKey: settings.apiKey,
|
||||
baseURL: settings.baseURL,
|
||||
headers: settings.headers,
|
||||
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
||||
providerOptions: settings.providerOptions,
|
||||
}).model(modelID)
|
||||
|
||||
export * as Moonshot from "./moonshot.js"
|
||||
@@ -0,0 +1 @@
|
||||
export { model, type Settings } from "../moonshot.js"
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { ProviderPackage } from "../../provider-package.js"
|
||||
import { Moonshot } from "../moonshot.js"
|
||||
|
||||
export type Settings = Moonshot.Settings<Moonshot.MessagesOptionsInput>
|
||||
|
||||
export const model: ProviderPackage.Definition<Settings, Moonshot.MessagesOptionsInput>["model"] = (
|
||||
modelID,
|
||||
settings,
|
||||
) =>
|
||||
Moonshot.configure({
|
||||
apiKey: settings.apiKey,
|
||||
baseURL: settings.baseURL,
|
||||
headers: settings.headers,
|
||||
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
||||
providerOptions: settings.providerOptions,
|
||||
}).messages(modelID)
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { ProviderPackage } from "../../provider-package.js"
|
||||
import { Moonshot } from "../moonshot.js"
|
||||
|
||||
export type Settings = Moonshot.Settings<Moonshot.ResponsesOptionsInput>
|
||||
|
||||
export const model: ProviderPackage.Definition<Settings, Moonshot.ResponsesOptionsInput>["model"] = (
|
||||
modelID,
|
||||
settings,
|
||||
) =>
|
||||
Moonshot.configure({
|
||||
apiKey: settings.apiKey,
|
||||
baseURL: settings.baseURL,
|
||||
headers: settings.headers,
|
||||
http: settings.body === undefined ? undefined : { body: { ...settings.body } },
|
||||
providerOptions: settings.providerOptions,
|
||||
}).responses(modelID)
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Schema } from "effect"
|
||||
import { Tool } from "@opencode-ai/schema/tool"
|
||||
import { Tool } from "@opencode/schema/tool"
|
||||
import { ModelID, ProviderID, RouteID } from "./ids.js"
|
||||
|
||||
export const ProviderFailureClassification = Schema.Literals(["context-overflow", "payload-too-large"])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Schema } from "effect"
|
||||
import { LLM } from "@opencode-ai/schema/llm"
|
||||
import { LLM } from "@opencode/schema/llm"
|
||||
import { ContentBlockID, ToolCallID } from "./ids.js"
|
||||
import {
|
||||
Message,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Schema } from "effect"
|
||||
import { Tool } from "@opencode-ai/schema/tool"
|
||||
import { Tool } from "@opencode/schema/tool"
|
||||
import {
|
||||
CacheHint,
|
||||
CachePolicy,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect, JsonSchema, Schema } from "effect"
|
||||
import { Tool } from "@opencode-ai/schema/tool"
|
||||
import { Tool } from "@opencode/schema/tool"
|
||||
import type {
|
||||
ToolCallPart,
|
||||
ToolDefinition as ToolDefinitionClass,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { AIError, ImageInput, LanguageModel, LLM, LLMClient, Provider } from "@opencode-ai/ai"
|
||||
import { Route, Protocol, WebSocketTransport } from "@opencode-ai/ai/route"
|
||||
import { Provider as ProviderSubpath } from "@opencode-ai/ai/provider"
|
||||
import { AIError, ImageInput, LanguageModel, LLM, LLMClient, Provider } from "@opencode/ai"
|
||||
import { Route, Protocol, WebSocketTransport } from "@opencode/ai/route"
|
||||
import { Provider as ProviderSubpath } from "@opencode/ai/provider"
|
||||
import {
|
||||
Baseten,
|
||||
CloudflareAIGateway,
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
OpenAICompatible,
|
||||
OpenRouter,
|
||||
XAI,
|
||||
} from "@opencode-ai/ai/providers"
|
||||
} from "@opencode/ai/providers"
|
||||
import {
|
||||
OpenAIChat,
|
||||
OpenAICompatibleChat,
|
||||
@@ -20,9 +20,9 @@ import {
|
||||
OpenAIResponses,
|
||||
OpenResponses,
|
||||
OpenResponsesChannel,
|
||||
} from "@opencode-ai/ai/protocols"
|
||||
import * as AnthropicMessages from "@opencode-ai/ai/protocols/anthropic-messages"
|
||||
import { TestLLM } from "@opencode-ai/ai/testing"
|
||||
} from "@opencode/ai/protocols"
|
||||
import * as AnthropicMessages from "@opencode/ai/protocols/anthropic-messages"
|
||||
import { TestLLM } from "@opencode/ai/testing"
|
||||
|
||||
describe("public exports", () => {
|
||||
test("root exposes app-facing runtime APIs", () => {
|
||||
@@ -46,7 +46,7 @@ describe("public exports", () => {
|
||||
})
|
||||
|
||||
test("provider barrels expose user-facing facades", async () => {
|
||||
const { OpenAICompatibleResponses } = await import("@opencode-ai/ai/providers")
|
||||
const { OpenAICompatibleResponses } = await import("@opencode/ai/providers")
|
||||
|
||||
expect(OpenAI.model).toBeFunction()
|
||||
expect(OpenAI.provider.responses).toBe(OpenAI.responses)
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": [
|
||||
"prefix:meta-chat",
|
||||
"provider:meta",
|
||||
"protocol:openai-chat",
|
||||
"tool",
|
||||
"tool-loop",
|
||||
"reasoning",
|
||||
"usage",
|
||||
"effort:low"
|
||||
],
|
||||
"name": "meta-chat/continues-a-generated-tool-call",
|
||||
"recordedAt": "2026-09-07T16:54:19.772Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":\"Look up the current weather in Paris using lookup_weather before answering. After receiving the result, report Paris's weather in one short sentence.\"}],\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"lookup_weather\",\"description\":\"Look up the current weather for a city\",\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false},\"strict\":false}}],\"tool_choice\":\"auto\",\"stream\":true,\"stream_options\":{\"include_usage\":true},\"reasoning_effort\":\"low\",\"max_completion_tokens\":1024}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-01a07cca-c092-7423-880d-204c05dc6645\",\"choices\":[{\"delta\":{\"content\":\"I'll look up the current weather in Paris now.\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800057,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cca-c092-7423-880d-204c05dc6645\",\"choices\":[{\"delta\":{\"tool_calls\":[{\"index\":0,\"id\":\"call_01a07ccac34671129bd9ef9a66fd3266\",\"type\":\"function\",\"function\":{\"name\":\"lookup_weather\",\"arguments\":\"\"}}]},\"finish_reason\":null,\"index\":0}],\"created\":1788800057,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cca-c092-7423-880d-204c05dc6645\",\"choices\":[{\"delta\":{\"tool_calls\":[{\"index\":0,\"function\":{\"arguments\":\"{\\\"city\\\":\\\"Paris\\\"}\"}}]},\"finish_reason\":null,\"index\":0}],\"created\":1788800057,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cca-c092-7423-880d-204c05dc6645\",\"choices\":[{\"delta\":{},\"finish_reason\":\"tool_calls\",\"index\":0}],\"created\":1788800057,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"completion_tokens\":139,\"prompt_tokens\":570,\"total_tokens\":709,\"completion_tokens_details\":{\"reasoning_tokens\":70},\"prompt_tokens_details\":{\"cached_tokens\":497}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":\"Look up the current weather in Paris using lookup_weather before answering. After receiving the result, report Paris's weather in one short sentence.\"},{\"role\":\"assistant\",\"content\":\"I'll look up the current weather in Paris now.\",\"tool_calls\":[{\"id\":\"call_01a07ccac34671129bd9ef9a66fd3266\",\"type\":\"function\",\"function\":{\"name\":\"lookup_weather\",\"arguments\":\"{\\\"city\\\":\\\"Paris\\\"}\"}}]},{\"role\":\"tool\",\"tool_call_id\":\"call_01a07ccac34671129bd9ef9a66fd3266\",\"content\":\"{\\\"condition\\\":\\\"sunny\\\",\\\"temperature\\\":\\\"18C\\\"}\"}],\"tools\":[{\"type\":\"function\",\"function\":{\"name\":\"lookup_weather\",\"description\":\"Look up the current weather for a city\",\"parameters\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false},\"strict\":false}}],\"tool_choice\":\"auto\",\"stream\":true,\"stream_options\":{\"include_usage\":true},\"reasoning_effort\":\"low\",\"max_completion_tokens\":1024}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-01a07cca-c622-77e3-8e2c-9c52bac9acb5\",\"choices\":[{\"delta\":{\"content\":\"Paris is currently sunny with a\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800058,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cca-c622-77e3-8e2c-9c52bac9acb5\",\"choices\":[{\"delta\":{\"content\":\" temperature of 18°C\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800058,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cca-c622-77e3-8e2c-9c52bac9acb5\",\"choices\":[{\"delta\":{\"content\":\".\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800058,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cca-c622-77e3-8e2c-9c52bac9acb5\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\",\"index\":0}],\"created\":1788800058,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"completion_tokens\":91,\"prompt_tokens\":666,\"total_tokens\":757,\"completion_tokens_details\":{\"reasoning_tokens\":69},\"prompt_tokens_details\":{\"cached_tokens\":497}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": [
|
||||
"prefix:meta-chat",
|
||||
"provider:meta",
|
||||
"protocol:openai-chat",
|
||||
"text",
|
||||
"reasoning",
|
||||
"usage",
|
||||
"effort:default"
|
||||
],
|
||||
"name": "meta-chat/streams-text-with-default-reasoning",
|
||||
"recordedAt": "2026-09-07T16:55:12.540Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"max_completion_tokens\":1024}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-01a07ccb-8ae3-72b3-b321-b5163dda0714\",\"choices\":[{\"delta\":{\"content\":\"37887\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800109,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07ccb-8ae3-72b3-b321-b5163dda0714\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\",\"index\":0}],\"created\":1788800109,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"completion_tokens\":363,\"prompt_tokens\":23,\"total_tokens\":386,\"completion_tokens_details\":{\"reasoning_tokens\":351},\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": ["prefix:meta-chat", "provider:meta", "protocol:openai-chat", "text", "reasoning", "usage", "effort:high"],
|
||||
"name": "meta-chat/streams-text-with-high-reasoning",
|
||||
"recordedAt": "2026-09-07T16:53:30.276Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"reasoning_effort\":\"high\",\"max_completion_tokens\":1024}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-01a07cc9-fe49-7773-b7f3-0be27454d3c3\",\"choices\":[{\"delta\":{\"content\":\"37887\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800007,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cc9-fe49-7773-b7f3-0be27454d3c3\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\",\"index\":0}],\"created\":1788800007,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"completion_tokens\":324,\"prompt_tokens\":23,\"total_tokens\":347,\"completion_tokens_details\":{\"reasoning_tokens\":312},\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": ["prefix:meta-chat", "provider:meta", "protocol:openai-chat", "text", "reasoning", "usage", "effort:low"],
|
||||
"name": "meta-chat/streams-text-with-low-reasoning",
|
||||
"recordedAt": "2026-09-07T16:53:23.751Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"reasoning_effort\":\"low\",\"max_completion_tokens\":1024}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-01a07cc9-eb39-7ef3-b886-5d4215128b1d\",\"choices\":[{\"delta\":{\"content\":\"37887\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800002,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cc9-eb39-7ef3-b886-5d4215128b1d\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\",\"index\":0}],\"created\":1788800002,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"completion_tokens\":157,\"prompt_tokens\":23,\"total_tokens\":180,\"completion_tokens_details\":{\"reasoning_tokens\":145},\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": ["prefix:meta-chat", "provider:meta", "protocol:openai-chat", "text", "reasoning", "usage", "effort:max"],
|
||||
"name": "meta-chat/streams-text-with-max-reasoning",
|
||||
"recordedAt": "2026-09-07T16:53:33.749Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"reasoning_effort\":\"max\",\"max_completion_tokens\":1024}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-01a07cca-10dd-7793-999d-e037320a91de\",\"choices\":[{\"delta\":{\"content\":\"37887\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800012,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cca-10dd-7793-999d-e037320a91de\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\",\"index\":0}],\"created\":1788800012,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"completion_tokens\":195,\"prompt_tokens\":23,\"total_tokens\":218,\"completion_tokens_details\":{\"reasoning_tokens\":183},\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": [
|
||||
"prefix:meta-chat",
|
||||
"provider:meta",
|
||||
"protocol:openai-chat",
|
||||
"text",
|
||||
"reasoning",
|
||||
"usage",
|
||||
"effort:medium"
|
||||
],
|
||||
"name": "meta-chat/streams-text-with-medium-reasoning",
|
||||
"recordedAt": "2026-09-07T16:53:27.292Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"reasoning_effort\":\"medium\",\"max_completion_tokens\":1024}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-01a07cc9-f131-7fb0-8895-9f0c3e79220c\",\"choices\":[{\"delta\":{\"content\":\"37887\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800004,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cc9-f131-7fb0-8895-9f0c3e79220c\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\",\"index\":0}],\"created\":1788800004,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"completion_tokens\":273,\"prompt_tokens\":23,\"total_tokens\":296,\"completion_tokens_details\":{\"reasoning_tokens\":261},\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": [
|
||||
"prefix:meta-chat",
|
||||
"provider:meta",
|
||||
"protocol:openai-chat",
|
||||
"text",
|
||||
"reasoning",
|
||||
"usage",
|
||||
"effort:minimal"
|
||||
],
|
||||
"name": "meta-chat/streams-text-with-minimal-reasoning",
|
||||
"recordedAt": "2026-09-07T16:53:22.460Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"reasoning_effort\":\"minimal\",\"max_completion_tokens\":1024}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-01a07cc9-e817-7bb1-8dc5-5197d9a4c73e\",\"choices\":[{\"delta\":{\"content\":\"37887\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800002,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cc9-e817-7bb1-8dc5-5197d9a4c73e\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\",\"index\":0}],\"created\":1788800002,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"completion_tokens\":75,\"prompt_tokens\":23,\"total_tokens\":98,\"completion_tokens_details\":{\"reasoning_tokens\":63},\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": ["prefix:meta-chat", "provider:meta", "protocol:openai-chat", "text", "reasoning", "usage", "effort:xhigh"],
|
||||
"name": "meta-chat/streams-text-with-xhigh-reasoning",
|
||||
"recordedAt": "2026-09-07T16:53:32.103Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"reasoning_effort\":\"xhigh\",\"max_completion_tokens\":1024}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-01a07cca-09de-7083-a0cc-2100de752456\",\"choices\":[{\"delta\":{\"content\":\"37887\",\"role\":\"assistant\"},\"finish_reason\":null,\"index\":0}],\"created\":1788800010,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\"}\n\ndata: {\"id\":\"chatcmpl-01a07cca-09de-7083-a0cc-2100de752456\",\"choices\":[{\"delta\":{},\"finish_reason\":\"stop\",\"index\":0}],\"created\":1788800010,\"model\":\"muse-spark-1.3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"completion_tokens\":253,\"prompt_tokens\":23,\"total_tokens\":276,\"completion_tokens_details\":{\"reasoning_tokens\":241},\"prompt_tokens_details\":{\"cached_tokens\":0}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+29
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
+55
File diff suppressed because one or more lines are too long
+47
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": ["prefix:meta-messages", "provider:meta", "protocol:meta-messages", "tool", "tool-loop", "reasoning"],
|
||||
"name": "meta-messages/replays-encrypted-thinking-through-a-tool-loop",
|
||||
"recordedAt": "2026-09-07T17:27:03.540Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Look up the current weather in Paris using lookup_weather. After receiving the result, report Paris's weather in one short sentence.\"}]}],\"tools\":[{\"name\":\"lookup_weather\",\"description\":\"Look up current weather\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"tool_choice\":{\"type\":\"auto\"},\"stream\":true,\"max_tokens\":1024,\"thinking\":{\"type\":\"adaptive\",\"display\":\"omitted\"},\"output_config\":{\"effort\":\"low\"}}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"message\":{\"content\":[],\"id\":\"msg_6a9ef3e5a96d9a155dd4463b\",\"model\":\"muse-spark-1.3\",\"role\":\"assistant\",\"stop_reason\":null,\"stop_sequence\":null,\"type\":\"message\",\"usage\":{\"input_tokens\":0,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent: content_block_start\ndata: {\"content_block\":{\"data\":\"Q-PaDgGyJ4hIKk41uslnSV0PGvrTkwJ5D-t5skfjtkIt-ABXsehMcLKJJ8RJHRKW2-XhkpPrex0aOkIdqWl99vpCgtOHIFFaSc4b3oGxA8XDx4T_2aKANfYrR1DYwYzGe6ZZ-DQnU0bnpVUzCcXkghkLdyTcJr2p8cvVo1rymFpB0wZsbQRBhxCMR6PrY4i0aOTe8_waq_Po1a4l3YzKnzZIIvYP090o5kltv7MAwqChXjQeTJlKq7ECFa6HVeoTa43oiLmoD2Bzih0VfvBvQfbSh2uDypRM7-f65sp35-VuZfwsM33ZTvefzDbd8zd0D50I6wcybsj8gulDhWWpY7cxoN1Xasy-ImvisACGeppIN66maIFq5dMT2s8_CQ8a2EQ0hw9kwJaIiygZCdRofs-T1yaGWvnQxL6MpNh6SXux9T1ZfuexNrXOhz5cR3_s1euhq3-hI3GDCUDLAtkjiigSE3w6PExrwHTHnvkuAOTP0Lw7DH4NtKv-RFFeZaQOk_0Bi2EV43tR0Hq_chtEDiSpoezDjexPWfdZvhRIaO6PwyJaQ8jVOaLUr6bh6jQ3IM19lv6R7lY4Neno8fLxMwTbf7v7q02lfhOaZe3jR1fqOFUq8e4VXV76_rJBgzThqPNqO8OI_betgX5d2KMcwWAkaZjmrP3rxA7g5xp_Q7bkFiBaaTd3HbYIk_cKbtLOS6TIIphb4SX6ADA2qJ0zoo98P2NOceZODT2WrLjKCHl5dT6b9l2feH9m21pW576ULfKhVSMzuy0cmmWI7rv2P4q-2Fw2klsDVJAc6q22bFjfDgzhybKuhuM_p1SYb8aswNrgggV-cqHWDpF1FdVpL5fHMO74l1uD8Sj_9wuuD0asMQustuvsnYq2EdI0lLvONFMApWCU0s3QA8_P0Iyf0YoCZOm5QGnA7l3O5nAPkFF4kxLSsgRe9zuP6A4oKBDLN8EHwZ3pB4WZGWpUT12cJxplmT3_n8xKaMgaz13qs27uvUm3wMI1seyfpkMwUPHmt1ftpk9f_1OAg3fvQgIkWPTp6K9NzVzEry6SP7zbPfls8yn529Qrbki7ZM_oz3xEvDg367ZCe97eVnjiqRrYsYM2MmDsQq9lUwkgXb84kpK6a4pEzX9NDvhTqhw7RI6RL9E-2Ki4ciUfHv5LVTZ0rNweCo6SYXC11f8FCeObIW_Esr2mqYpORFS4SDMU-4I1HQfD9z6cPjL22APpv9a7Pp1phI8x_aQZkPU7LkyBWyVNDeusI7wq_LC0UgJ0vCAguKcAvN7gxwpCo5MEEZivRuYBldEMwRo4he2WQQke9KEokqREdlPF3Lvaav0fqPfXqhJyHAq8bYBHWdzMjDJ_dJwhdbLQ-iNLmrK5JNg2vPDglWSznBXbrSX4iyMFk1Ni2Y1SQUIOOxS_InIwCg\",\"type\":\"redacted_thinking\"},\"index\":0,\"type\":\"content_block_start\"}\n\nevent: content_block_stop\ndata: {\"index\":0,\"type\":\"content_block_stop\"}\n\nevent: content_block_start\ndata: {\"content_block\":{\"text\":\"\",\"type\":\"text\"},\"index\":1,\"type\":\"content_block_start\"}\n\nevent: content_block_delta\ndata: {\"delta\":{\"text\":\"I'll look up the current weather in Paris.\",\"type\":\"text_delta\"},\"index\":1,\"type\":\"content_block_delta\"}\n\nevent: content_block_stop\ndata: {\"index\":1,\"type\":\"content_block_stop\"}\n\nevent: content_block_start\ndata: {\"content_block\":{\"id\":\"call_01a07ce8bb767c109c12f0a202e2ac19\",\"input\":{},\"name\":\"lookup_weather\",\"type\":\"tool_use\"},\"index\":2,\"type\":\"content_block_start\"}\n\nevent: content_block_delta\ndata: {\"delta\":{\"partial_json\":\"{\\\"city\\\":\\\"Paris\\\"}\",\"type\":\"input_json_delta\"},\"index\":2,\"type\":\"content_block_delta\"}\n\nevent: content_block_stop\ndata: {\"index\":2,\"type\":\"content_block_stop\"}\n\nevent: message_delta\ndata: {\"delta\":{\"stop_reason\":\"tool_use\",\"stop_sequence\":null},\"type\":\"message_delta\",\"usage\":{\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":113,\"input_tokens\":451,\"output_tokens\":155,\"output_tokens_details\":{\"thinking_tokens\":87}}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Look up the current weather in Paris using lookup_weather. After receiving the result, report Paris's weather in one short sentence.\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"redacted_thinking\",\"data\":\"Q-PaDgGyJ4hIKk41uslnSV0PGvrTkwJ5D-t5skfjtkIt-ABXsehMcLKJJ8RJHRKW2-XhkpPrex0aOkIdqWl99vpCgtOHIFFaSc4b3oGxA8XDx4T_2aKANfYrR1DYwYzGe6ZZ-DQnU0bnpVUzCcXkghkLdyTcJr2p8cvVo1rymFpB0wZsbQRBhxCMR6PrY4i0aOTe8_waq_Po1a4l3YzKnzZIIvYP090o5kltv7MAwqChXjQeTJlKq7ECFa6HVeoTa43oiLmoD2Bzih0VfvBvQfbSh2uDypRM7-f65sp35-VuZfwsM33ZTvefzDbd8zd0D50I6wcybsj8gulDhWWpY7cxoN1Xasy-ImvisACGeppIN66maIFq5dMT2s8_CQ8a2EQ0hw9kwJaIiygZCdRofs-T1yaGWvnQxL6MpNh6SXux9T1ZfuexNrXOhz5cR3_s1euhq3-hI3GDCUDLAtkjiigSE3w6PExrwHTHnvkuAOTP0Lw7DH4NtKv-RFFeZaQOk_0Bi2EV43tR0Hq_chtEDiSpoezDjexPWfdZvhRIaO6PwyJaQ8jVOaLUr6bh6jQ3IM19lv6R7lY4Neno8fLxMwTbf7v7q02lfhOaZe3jR1fqOFUq8e4VXV76_rJBgzThqPNqO8OI_betgX5d2KMcwWAkaZjmrP3rxA7g5xp_Q7bkFiBaaTd3HbYIk_cKbtLOS6TIIphb4SX6ADA2qJ0zoo98P2NOceZODT2WrLjKCHl5dT6b9l2feH9m21pW576ULfKhVSMzuy0cmmWI7rv2P4q-2Fw2klsDVJAc6q22bFjfDgzhybKuhuM_p1SYb8aswNrgggV-cqHWDpF1FdVpL5fHMO74l1uD8Sj_9wuuD0asMQustuvsnYq2EdI0lLvONFMApWCU0s3QA8_P0Iyf0YoCZOm5QGnA7l3O5nAPkFF4kxLSsgRe9zuP6A4oKBDLN8EHwZ3pB4WZGWpUT12cJxplmT3_n8xKaMgaz13qs27uvUm3wMI1seyfpkMwUPHmt1ftpk9f_1OAg3fvQgIkWPTp6K9NzVzEry6SP7zbPfls8yn529Qrbki7ZM_oz3xEvDg367ZCe97eVnjiqRrYsYM2MmDsQq9lUwkgXb84kpK6a4pEzX9NDvhTqhw7RI6RL9E-2Ki4ciUfHv5LVTZ0rNweCo6SYXC11f8FCeObIW_Esr2mqYpORFS4SDMU-4I1HQfD9z6cPjL22APpv9a7Pp1phI8x_aQZkPU7LkyBWyVNDeusI7wq_LC0UgJ0vCAguKcAvN7gxwpCo5MEEZivRuYBldEMwRo4he2WQQke9KEokqREdlPF3Lvaav0fqPfXqhJyHAq8bYBHWdzMjDJ_dJwhdbLQ-iNLmrK5JNg2vPDglWSznBXbrSX4iyMFk1Ni2Y1SQUIOOxS_InIwCg\"},{\"type\":\"text\",\"text\":\"I'll look up the current weather in Paris.\"},{\"type\":\"tool_use\",\"id\":\"call_01a07ce8bb767c109c12f0a202e2ac19\",\"name\":\"lookup_weather\",\"input\":{\"city\":\"Paris\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"call_01a07ce8bb767c109c12f0a202e2ac19\",\"content\":\"{\\\"condition\\\":\\\"sunny\\\"}\"}]}],\"tools\":[{\"name\":\"lookup_weather\",\"description\":\"Look up current weather\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"tool_choice\":{\"type\":\"none\"},\"stream\":true,\"max_tokens\":1024,\"thinking\":{\"type\":\"adaptive\",\"display\":\"omitted\"},\"output_config\":{\"effort\":\"low\"}}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"message\":{\"content\":[],\"id\":\"msg_6a9ef3e77f6ef36fdd8f4925\",\"model\":\"muse-spark-1.3\",\"role\":\"assistant\",\"stop_reason\":null,\"stop_sequence\":null,\"type\":\"message\",\"usage\":{\"input_tokens\":0,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent: content_block_start\ndata: {\"content_block\":{\"data\":\"Q-PaDgH-GUZkiqnb_seFaP70it_GxAEIUjt2BLllpyzfckiBOUVwr72xGQsSnj0y9aOhoaQ24A_HB0MHh4XWyYziVdRgq6lDPLHkJlmMzbusZxUZUx7D7B8kD8HrBbiTeIFbFlHaM9MiZW_PpYY9fpkdc7aeuX0mORdK8XTT3JPjvW1HPp4Qqp_iEOl9G2iM2Y6xno8SqeTcbc4EQs1LePaKrq86dBPmXBjkgQbYfvIw57o0SBEyelcudtnzJnaluOyOQdV2Ytk_r_xrYSCoBwgbf2KBCOFjdeQyruuwVZZ32JJdVOpWLw8eopUwAo2xYOZP0g8S8hTmOFvDKuzXipm1OoAXwD8Swm6ED3IIo0hHA5xSfMygDCee47nd-EpShNPamkCKodfX1QvePEJsIQK2iTgkh8IGUeEEne5dxgLuXvEAbeqGDvEy6T7IoSgZnc-KPtH6SoWM_kgc_eF_oN73Nxg2prMyCqTUNg5Qs2WLPjA9wSLmmnCoiDr1bYNIuQyn6adgv0-nZZXETJoRAHJBj65Asa8kbLyCYesb192178xCj2aBSdwyj-jc0i328sa9STS7mUSI7KvOt0Yi3kllLs1aSnHW-ogsUJUM7tTf83VO9fRRU_aW4H6qr4OAr8jbBKSD3bxE0AekDd24ZS-8YIjiP1tMOAPZ2JGQrNqbxnaeqhCZzD2nl-E8TMXaAJIk4L3oZtV80xJiUW7mLEf_jQBPAWhph4ujbkDaufGvNrl4FXyBJ-XpKMIA5z0jAYU2b3ul5-Qn5Km7Oc8fPu1M_0XGAOKG-pF9ppr4y-an4B4mKDYoAiSHp3cjv-fW57D87wBfQPaJRjOzWhzqENO-5MlB0CEsnDtrLveE2ui8wSECszParUNk5SEaeSYvrXLY0QkaE7CTK9ljwTKjJM34r1a8o16KFxGuzMrloNlxIYIaO_suM9CDuf8wNwe8KkAV2Kt28g9LwkL5b3mtI7ZSjTdHYOOhFFMzs-sjXboQoGAJGOhMnCQNc3E5-goSzvOzEIXehSTs8Mzyq8d3C2k5F9PSgdO6ZouHVURDgbEXTqWqoqjQ8huk5AbrUX16QwhJambd6P-3i--Idz9CbIVuWIqiMm80TvYlMttobYxTyFDIJrKJTrVA0PkAOFvOMfYt27d7z2ZMrTf6Vtm_DNniuhVbvVU3ZcWbb4LO-XkwH3bfHB-sckpwURP34KzOMvogaqWaMAZlabdd-lQKCc7tMhmo9BrYwHHvLxAELD2qQnyym43Yo1iJNAyrqoUAFk6K029fDon7h9ybmKZdBxRtS3arUesY_91Xep0tA0Y1UYUKo8zKjK3Op_DbVyC5OoR8rxpumKiqk2PtG7RPf-WjEXGkleGqZtxix7ILSkQXxW6McY1r_6LAh2Nv0nUzqS019tTb7mx2OLyt2g\",\"type\":\"redacted_thinking\"},\"index\":0,\"type\":\"content_block_start\"}\n\nevent: content_block_stop\ndata: {\"index\":0,\"type\":\"content_block_stop\"}\n\nevent: content_block_start\ndata: {\"content_block\":{\"text\":\"\",\"type\":\"text\"},\"index\":1,\"type\":\"content_block_start\"}\n\nevent: content_block_delta\ndata: {\"delta\":{\"text\":\"It's sunny in Paris.\",\"type\":\"text_delta\"},\"index\":1,\"type\":\"content_block_delta\"}\n\nevent: content_block_stop\ndata: {\"index\":1,\"type\":\"content_block_stop\"}\n\nevent: message_delta\ndata: {\"delta\":{\"stop_reason\":\"end_turn\",\"stop_sequence\":null},\"type\":\"message_delta\",\"usage\":{\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"input_tokens\":210,\"output_tokens\":50,\"output_tokens_details\":{\"thinking_tokens\":35}}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": ["prefix:meta-messages", "provider:meta", "protocol:meta-messages", "text", "reasoning", "adaptive"],
|
||||
"name": "meta-messages/streams-text-with-adaptive-thinking",
|
||||
"recordedAt": "2026-09-07T17:26:18.565Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":2048,\"thinking\":{\"type\":\"adaptive\",\"display\":\"omitted\"},\"output_config\":{\"effort\":\"low\"}}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"message\":{\"content\":[],\"id\":\"msg_6a9ef3b8e46a777cfdc94a93\",\"model\":\"muse-spark-1.3\",\"role\":\"assistant\",\"stop_reason\":null,\"stop_sequence\":null,\"type\":\"message\",\"usage\":{\"input_tokens\":0,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent: content_block_start\ndata: {\"content_block\":{\"data\":\"Q-PaDgFtwwNGqSqKxPk9Zj-j9xogYigpDsDHrLKPV-DxmXcbhtXDPrGPuj5qB4l1FslhuEQFCA8zIRyNGaCmzM0JG4GOZe3LpFYM2iegBbi24l4V7souryAwUs_7PrInxObuguMwh2S66ML6PwlfVRVTAwPsgDSCl6Y9tkoDHr2KBRY2fzJhmjkotuFRK2LYvNp9pKi89JxnoIKK8B_UJc_B2r4vU_Txq9_rWTmo2eXFoGOSMZNaHpVrvACRQKC1jc6-8Pj5JkJN11_Cs2fHqlaCwOoPDVJxHXUXP1AMHU1mG0jR4qf9wUaz8kMmyCBBijlfQJ4G7nsQs7LJO9gS2ropmynDoO5IEIAFf7ekxLw54Fx3JigC0_qz4Jx4a04Ey8JBzWRlZNdqggpq2_I_VoT3S0zhCYDp8ZAJQs2JqvvF-ZmLcMPH1PmpkgRySqXl5TDxERIpdL3aOUzTl-PTHVMIGEcSAz84fFwU4p1kS5llGEGC6jHlClscEEto1Y-qthL6BoeDALzk7GHEMVQD0bfC4E5yGCh0_xlWqsG3XPj0wpYKBc0hfh7vjO1NpzPxCtaDjnRwR6TzSo6x_HrEL3VELArHhpYAXl30fNO-EepduZ3Hd_kWqWj_GhdIM4dRh2zoytbhIesVD7OvBqU47urKFnpXw4kswJ-NoVVNk00ysMMHwobT9BdJL9UCoXlNzyErPe8LkA9f0VrKkuLCg5FDr_DCEYXHXr7fdRmC3JTKuzvxffvPYppUt3hs5gbdXWgT2iZzunt4bSfFne7BPkj9OGREyfLcukvGAh_oqPLXuu0lert9wbTAqRUTyM5Y1nSjw3h2B3jv91mH78mGvhy8LeVNLkrSMxEa4GtrrUvlzkPnZayc_LE2Sr7JnQjhwylVNWvkcIAjstOZShjPKe4pUJwj-cUXmXZB7Zwr-Q9WLtprFgQoBvadd5DHD4aynsYEabKZVcOqhV8l2zyaUCGobUzdPqBC5kk5-VPmNTqm6Qs91mb1y_5ydmHjTWmSW6qtN_op-Xfwqr_hllvOjhnAvvDJWUOKH-YIgZw_k_db2mzW1hO093jSDMYv6wpiy_5XWMNJBjcH8hvR_pFjXIqScUnKPranEZvCyGfHR-UBNJ89s_JEE49chcIt8LiukBeXQ_TOe29kzWnT1tYtfGQXP8FY2Wukw5yhvP3coGp1-LPZRuw3BLP2tWmiijmyj5lMikp8MIeqOztN8zgsArZ9jq21EtDSNfpO_0C4GEOtCZQYvZHRpDeY966XDnN7Blenn_8FZ95M-M-1My8hsmF__JrnY4ZFZr2274f_FbyJaSqGj6H-YRuzawO2TVLWHxAr6v2LCiB_QX01PwUI1yaJmP0mI-Qz5zXgSHzfVzhF7l1zEnM8qIYcSXzD1Gp3rjpn2sq-rR-JLqeHq080Hl0X9c8lzozw3qCpvcTfA-4ZTdXU9ax3nt7emcPVFo9N_JBjYashC7KvjkIWjMhQoTbIRlO18gjEa-Dvtsmo4_xE1ApYRoylbhxg3_fQJjKLfCBv32V6BM8qWKINL7d1nYP7PtAKnglCdnT_dK0_pCK6ejGfmdWZgVj0DhVZUCXf2kN530Y0hoCb1jBgwJ16a5gUqJMtnWScarIGSVrsYMA_uEt7DwQzGYAGESVIgi8JVATkxoq4EbyOLCHX7MIKmAPGV2WWTjWAWLnE2ITjlXtBkUAwjq2v957BMgIqxSNxEjG75Gd0i1XjZAujCSCXMrywZ72-VdQy4cD6kzH9mv04fZ7_dqn9eKPHBY7_T7V6myRDj_ImkffXcygmd7F-_-kHMExI6ABas1WtfDjkYgbRM0jMtIHYL-W9xT8vCSLSdvHcb5Y8XSXT5GTwI7eIlBHnCvFrgunbCo9bJJlT2Gc1RcgeZ4rg3yu1MNF4Mfk6DBwDhduGh5l7nypL00B0HokLfF4H7N1oSKL9jdVE3oMyJuA9NV1SJiyqcneSVHBzqjFZ5sszFXPlBKEz31izxFToAF4tDYMR507zYLcxyLA4AmHlkmn0qeozPb5qk-qZB6yLywtewv8O1KqxieAEJnEmyiqGnoKBdkjpeYmplErSxJyzoRX4fXb9mOdb-izJgvqSQ5uLm0_EXf3OklpMoAJ2CPJ6cxpg_5bhiwbgEtafCuDyXVL9Zzi872yUb_Z-ATlqU1M2Ai67f1piHIUDzMn4kulXQhPMb_R4eznMbX_aRigQh92-t1USoFtX2vmyCUQageFcrHHK524gPQ7rkOfDvZ8GHPXi3YZFnzGkSKjQD0jumFtzDiRqYkkMECep0zgY8MjuWLMjlMuigpkzSm8GPZ2aFeIMxJCYR8iMf7fH9NyHAJnicx4wdW_UqqgY5jfVtDvPSL0SRScyyK0jNdmofDHjWp4Tehih5OOw81E3BYLCiIv2p2zTMRSTZxFyG3HI91tIEaJu_RnIMFxzCilaP1LcbMrjyFzBtLJiXXJ--eFYyIMYKgfbWIOTsjLLJGC8NS2wuzaXB-C6GLsuSEHci5a8f5KGqaXK99LvHtY4k36WhEoVUjQEGY7HNJrtdjBUlqDgnT9iO06gGd2QCGvlP4us-Z3q2Bcyhf0LzOgn_Bpjc6YBk4TNF1AMxG15qmhnsrWcGElkpk3Vh9npC8--vkvhh7pOPfTZlNjQQh900OemY9gwxHyCBbt1096g4qkYOntGJmw-wVjyWxOt9K9CaM9WxY3wFyOmwqiFL1PK4CMeKMZk54iZ1ZiyXDOvsO7qUa9XQGDy3W8ic6R3DUzdkxEEBFYHAjDy3qE\",\"type\":\"redacted_thinking\"},\"index\":0,\"type\":\"content_block_start\"}\n\nevent: content_block_stop\ndata: {\"index\":0,\"type\":\"content_block_stop\"}\n\nevent: content_block_start\ndata: {\"content_block\":{\"text\":\"\",\"type\":\"text\"},\"index\":1,\"type\":\"content_block_start\"}\n\nevent: content_block_delta\ndata: {\"delta\":{\"text\":\"37887\",\"type\":\"text_delta\"},\"index\":1,\"type\":\"content_block_delta\"}\n\nevent: content_block_stop\ndata: {\"index\":1,\"type\":\"content_block_stop\"}\n\nevent: message_delta\ndata: {\"delta\":{\"stop_reason\":\"end_turn\",\"stop_sequence\":null},\"type\":\"message_delta\",\"usage\":{\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"input_tokens\":23,\"output_tokens\":266,\"output_tokens_details\":{\"thinking_tokens\":254}}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "muse-spark-1.3",
|
||||
"tags": ["prefix:meta-messages", "provider:meta", "protocol:meta-messages", "text", "reasoning", "enabled"],
|
||||
"name": "meta-messages/streams-text-with-enabled-thinking",
|
||||
"recordedAt": "2026-09-07T17:26:20.464Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.meta.ai/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"muse-spark-1.3\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":2048,\"thinking\":{\"type\":\"enabled\",\"budget_tokens\":1024,\"display\":\"omitted\"},\"output_config\":{\"effort\":\"low\"}}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"message\":{\"content\":[],\"id\":\"msg_6a9ef3bbb7e691b3ea26427b\",\"model\":\"muse-spark-1.3\",\"role\":\"assistant\",\"stop_reason\":null,\"stop_sequence\":null,\"type\":\"message\",\"usage\":{\"input_tokens\":0,\"output_tokens\":0}},\"type\":\"message_start\"}\n\nevent: content_block_start\ndata: {\"content_block\":{\"data\":\"Q-PaDgEpowvGua1C8z2RSICyyeSLruZ1JBUhrhLhgqf_XauiaESRHyHgIPVF0Cfxp7eLB_ESNObq7vJNDLdffE-RaN5nEauXhRxH6fJErC-4H_KELZFGF-qNnGu2DWl-gEojkwwkq1HtTtT3rOEk5isGjdribnDvR7a1zkpG3I0BxE_UyseISDSbkev5tyV7DkiH4xyv2ZmwuO3HHGgmAztEek9vm0ZTElZ8PIPvHG6P38aYGTGKrTjyOhmN3LBa_NFvtQQkUMKRB3n7L_N5KB1NbYkPzLEJ6L5dL9DJZBSsZms0O62QZ2zs2oWZ-ekQWL4oIuiRozWVpmwzjtkJl9WXtyvdL-4MACucXMSN9V7hWzC50g-DgdeFPSslsA9gy619wTNPPIxPymGWeD9LYKR3iwTRLNYzuycHakNqikhiwz9MweMod5GLTdbtypZJcV7ourz58jmK4YKsqleVPVvXM6bIoNuT2yGj23-tAYxQszGXQMHxSTnaLAHl6sUdiwTqX4wbFYfX-ogkIZsrca9mv5E2gkH1wJl19GPCxFaSDCHxh3QAW0RIExKUJly9Ydpoegmojfo0F4Hjt13zDm03fLEQ0eY8GjxIIHDt_zVRQGTW8d4tgZpTt4K9H1TTefG34EerN7jl7L-WNUe_gKorN4aSYBS6S6ma4Vb91NlUQ4cEGBKVQvumYe16p9Xj6Te-tCuiBmTOCq6iDsTH-eMlip_Bc18MD2BCGr2NdF4PB2vqHGSPIvSHDRXBjoPNtm18opAsUnOBu7-tysb8-EKFd5z7JbWgegQWNs11FdX0uFtC-U9ROwbHLJ3IHk4m2UHc2USwi7v4Xe6FtnkJ0VCZTajFUTXW33lwO3UsHuqEbxVnU_Rzuj6Ryjb08bpXpJBjIEGf2wBS3_I78cuXKOChHu-evtnjezc77joRUP8_I8pWsQbQ6bHABD95p8q6ZdQpDr9XQALbVg3ZvD5_QgF59rIxkW9a2L78oQpu0O3UT7-jxNFe38-OXuEr3VTv7RzISu1zjvBZD0k9-2q-T9BAJmsK6oPajJQWKwHBYF3w6vbsQ8tRDdh2uerhlAIWU0YL92gPCmT3mR6HxSGjAx08t-gib_YrzvWn0oTfLNk_BNfAMpG7Mj2GYNbyTkd_tjNZ2fOwVKbygsoFIUEvh2B-xyHOYuhXfxzI8-Gt55FMGDLLKcHfgmOZAUz1xVkIdm6bcuRFuQppgTzYIr66GN6tsr9KxTN2GZ2NHCwexe0hSAGfKVyLr8QBxTDRlzubBqe-osgQJrJtS7uM1MuWK_8grkZrNsn6g3ami0JboEmM_Ct3gVhkXo6lhCCcjn1gnGX-HOLczT3Xty1wYkeayUpi9x326nrSmypxzbzCRS3bOaPvSoBCszri0uTfUnVQK5kTVuRD30fGxauPhA\",\"type\":\"redacted_thinking\"},\"index\":0,\"type\":\"content_block_start\"}\n\nevent: content_block_stop\ndata: {\"index\":0,\"type\":\"content_block_stop\"}\n\nevent: content_block_start\ndata: {\"content_block\":{\"text\":\"\",\"type\":\"text\"},\"index\":1,\"type\":\"content_block_start\"}\n\nevent: content_block_delta\ndata: {\"delta\":{\"text\":\"37887\",\"type\":\"text_delta\"},\"index\":1,\"type\":\"content_block_delta\"}\n\nevent: content_block_stop\ndata: {\"index\":1,\"type\":\"content_block_stop\"}\n\nevent: message_delta\ndata: {\"delta\":{\"stop_reason\":\"end_turn\",\"stop_sequence\":null},\"type\":\"message_delta\",\"usage\":{\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"input_tokens\":23,\"output_tokens\":143,\"output_tokens_details\":{\"thinking_tokens\":131}}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+56
File diff suppressed because one or more lines are too long
Vendored
+37
File diff suppressed because one or more lines are too long
+37
File diff suppressed because one or more lines are too long
+37
File diff suppressed because one or more lines are too long
+37
File diff suppressed because one or more lines are too long
Vendored
+37
File diff suppressed because one or more lines are too long
Vendored
+37
File diff suppressed because one or more lines are too long
+37
File diff suppressed because one or more lines are too long
Vendored
+56
File diff suppressed because one or more lines are too long
Vendored
+56
File diff suppressed because one or more lines are too long
+56
File diff suppressed because one or more lines are too long
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "MiniMax-M3",
|
||||
"tags": [
|
||||
"prefix:minimax-chat",
|
||||
"provider:minimax",
|
||||
"protocol:minimax-chat",
|
||||
"text",
|
||||
"usage",
|
||||
"thinking-off"
|
||||
],
|
||||
"name": "minimax-chat/m3-streams-text-with-thinking-disabled",
|
||||
"recordedAt": "2026-09-07T16:53:20.976Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.minimax.io/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"MiniMax-M3\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"max_completion_tokens\":1536,\"thinking\":{\"type\":\"disabled\"},\"reasoning_split\":true}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream; charset=utf-8"
|
||||
},
|
||||
"body": "data: {\"id\":\"d8d409a572a67df400527c6592b480df\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\"}}],\"created\":1788800000,\"model\":\"MiniMax-M3\",\"object\":\"chat.completion.chunk\",\"usage\":null,\"service_tier\":\"standard\"}\n\ndata: {\"id\":\"d8d409a572a67df400527c6592b480df\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"378\",\"role\":\"assistant\"}}],\"created\":1788800000,\"model\":\"MiniMax-M3\",\"object\":\"chat.completion.chunk\",\"usage\":null,\"service_tier\":\"standard\"}\n\ndata: {\"id\":\"d8d409a572a67df400527c6592b480df\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"87\",\"role\":\"assistant\"}}],\"created\":1788800000,\"model\":\"MiniMax-M3\",\"object\":\"chat.completion.chunk\",\"usage\":null,\"service_tier\":\"standard\"}\n\ndata: {\"id\":\"d8d409a572a67df400527c6592b480df\",\"choices\":[{\"finish_reason\":\"stop\",\"index\":0,\"delta\":{\"role\":\"assistant\"}}],\"created\":1788800000,\"model\":\"MiniMax-M3\",\"object\":\"chat.completion.chunk\",\"usage\":null,\"service_tier\":\"standard\"}\n\ndata: {\"id\":\"d8d409a572a67df400527c6592b480df\",\"choices\":[],\"created\":1788800000,\"model\":\"MiniMax-M3\",\"object\":\"chat.completion.chunk\",\"usage\":{\"total_tokens\":182,\"total_characters\":0,\"prompt_tokens\":179,\"completion_tokens\":3,\"prompt_tokens_details\":{\"cached_tokens\":128}},\"service_tier\":\"standard\",\"base_resp\":{\"status_code\":0,\"status_msg\":\"\"}}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "MiniMax-M2.7",
|
||||
"tags": [
|
||||
"prefix:minimax-messages",
|
||||
"provider:minimax",
|
||||
"protocol:anthropic-messages",
|
||||
"text",
|
||||
"usage",
|
||||
"reasoning"
|
||||
],
|
||||
"name": "minimax-messages/m2-7-streams-default-thinking",
|
||||
"recordedAt": "2026-09-07T16:53:20.721Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.minimax.io/anthropic/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"MiniMax-M2.7\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":1536}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream; charset=utf-8"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"bd0c49bb4f5e6f26b77bab9b5a917484\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"model\":\"MiniMax-M2.7\",\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":57,\"output_tokens\":0}}}\n\nevent: ping\ndata: {\"type\":\"ping\"}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"thinking\",\"thinking\":\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"The user\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" asks: \\\"What is 173 multiplied by 219? Reply with only the final integer.\\\" So we compute 173 * 219. Compute:\\n\\n173 * 219 = \"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 * (200 + 19) = 173*200 + 173*19 = 34600 + (173*19). 173*19 = 173*20\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" - 173 = 3460 - 173 = 3287. So total = 34600 + 3287 = 37887.\\n\\nAlternatively compute directly: 219 * \"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 = 219 * 173 = (219 * 100) + (219 * 70) + (219 * 3) = 21900 + 15330 + 657\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" = 37887.\\n\\nThus answer is 37887. We must reply with only the final integer: \\\"37887\\\". No extra text.\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"signature_delta\",\"signature\":\"1625da2f905565076ee90b9c2919db39b1719731c0820eca2f2a1c9c28324e87\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":1,\"content_block\":{\"type\":\"text\",\"text\":\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":1,\"delta\":{\"type\":\"text_delta\",\"text\":\"37887\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":1}\n\nevent: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\"},\"usage\":{\"input_tokens\":57,\"output_tokens\":187,\"output_tokens_details\":{\"thinking_tokens\":184}}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "MiniMax-M3",
|
||||
"tags": [
|
||||
"prefix:minimax-messages",
|
||||
"provider:minimax",
|
||||
"protocol:anthropic-messages",
|
||||
"tool",
|
||||
"tool-loop",
|
||||
"reasoning",
|
||||
"continuation",
|
||||
"usage"
|
||||
],
|
||||
"name": "minimax-messages/m3-continues-a-tool-loop-with-adaptive-thinking",
|
||||
"recordedAt": "2026-09-07T16:53:25.185Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.minimax.io/anthropic/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"MiniMax-M3\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Look up the current weather in Paris using get_weather before answering. After receiving the result, report the weather in one short sentence.\"}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get the current weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"tool_choice\":{\"type\":\"auto\"},\"stream\":true,\"max_tokens\":1536,\"thinking\":{\"type\":\"adaptive\"}}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream; charset=utf-8"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"6a532037868639a6189e7c0b9e1c9aa2\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"model\":\"MiniMax-M3\",\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":0,\"output_tokens\":0,\"service_tier\":\"standard\"},\"service_tier\":\"standard\"}}\n\nevent: ping\ndata: {\"type\":\"ping\"}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"thinking\",\"thinking\":\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"The user wants me\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" to look up the\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" current weather in Paris\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" using the get_\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"weather tool, then\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" report it\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" in one short sentence\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\". Let\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" me call the tool\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\".\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"signature_delta\",\"signature\":\"f05cb5f4873950f23d194289c41d79b96ebd37c9411a45b306ed44f135a910d4\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":1,\"content_block\":{\"type\":\"tool_use\",\"id\":\"call_01a07cc9f2d47d83a6424ff3\",\"name\":\"get_weather\",\"input\":{}}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":1,\"delta\":{\"type\":\"input_json_delta\",\"partial_json\":\"{\\\"city\\\":\\\"Paris\\\"}\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":1}\n\nevent: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"tool_use\"},\"usage\":{\"input_tokens\":239,\"output_tokens\":63,\"cache_read_input_tokens\":203,\"service_tier\":\"standard\",\"output_tokens_details\":{\"thinking_tokens\":33}}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.minimax.io/anthropic/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"MiniMax-M3\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Look up the current weather in Paris using get_weather before answering. After receiving the result, report the weather in one short sentence.\"}]},{\"role\":\"assistant\",\"content\":[{\"type\":\"thinking\",\"thinking\":\"The user wants me to look up the current weather in Paris using the get_weather tool, then report it in one short sentence. Let me call the tool.\",\"signature\":\"f05cb5f4873950f23d194289c41d79b96ebd37c9411a45b306ed44f135a910d4\"},{\"type\":\"tool_use\",\"id\":\"call_01a07cc9f2d47d83a6424ff3\",\"name\":\"get_weather\",\"input\":{\"city\":\"Paris\"}}]},{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"call_01a07cc9f2d47d83a6424ff3\",\"content\":\"{\\\"condition\\\":\\\"sunny\\\",\\\"temperature\\\":\\\"18C\\\"}\"}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get the current weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"tool_choice\":{\"type\":\"none\"},\"stream\":true,\"max_tokens\":1536,\"thinking\":{\"type\":\"adaptive\"}}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream; charset=utf-8"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"e9e7ea89f63eca1cd17a037aef28eed1\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"model\":\"MiniMax-M3\",\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":0,\"output_tokens\":0,\"service_tier\":\"standard\"},\"service_tier\":\"standard\"}}\n\nevent: ping\ndata: {\"type\":\"ping\"}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"The weather\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" in Paris is sunny\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" with\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" a\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" temperature of 18\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"°C.\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\nevent: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\"},\"usage\":{\"input_tokens\":164,\"output_tokens\":16,\"cache_read_input_tokens\":128,\"service_tier\":\"standard\"}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "MiniMax-M3",
|
||||
"tags": [
|
||||
"prefix:minimax-messages",
|
||||
"provider:minimax",
|
||||
"protocol:anthropic-messages",
|
||||
"tool",
|
||||
"thinking-off",
|
||||
"usage"
|
||||
],
|
||||
"name": "minimax-messages/m3-generates-a-named-tool-call-with-default-thinking-off",
|
||||
"recordedAt": "2026-09-07T16:53:24.366Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.minimax.io/anthropic/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"MiniMax-M3\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"Use get_weather to look up the current weather in Paris.\"}]}],\"tools\":[{\"name\":\"get_weather\",\"description\":\"Get the current weather in a city\",\"input_schema\":{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"enum\":[\"Paris\"]}},\"required\":[\"city\"],\"additionalProperties\":false}}],\"tool_choice\":{\"type\":\"tool\",\"name\":\"get_weather\"},\"stream\":true,\"max_tokens\":512}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream; charset=utf-8"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"a60a8adb2eff7545f809b9df2689f1b8\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"model\":\"MiniMax-M3\",\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":0,\"output_tokens\":0,\"service_tier\":\"standard\"},\"service_tier\":\"standard\"}}\n\nevent: ping\ndata: {\"type\":\"ping\"}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"I'll\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" look\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" up the current weather\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\" in Paris for you\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\".\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":1,\"content_block\":{\"type\":\"tool_use\",\"id\":\"call_b0246853f3c4432ea455cc99\",\"name\":\"get_weather\",\"input\":{}}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":1,\"delta\":{\"type\":\"input_json_delta\",\"partial_json\":\"{\\\"city\\\":\\\"Paris\\\"}\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":1}\n\nevent: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"tool_use\"},\"usage\":{\"input_tokens\":401,\"output_tokens\":39,\"service_tier\":\"standard\"}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "MiniMax-M3",
|
||||
"tags": [
|
||||
"prefix:minimax-messages",
|
||||
"provider:minimax",
|
||||
"protocol:anthropic-messages",
|
||||
"text",
|
||||
"usage",
|
||||
"reasoning"
|
||||
],
|
||||
"name": "minimax-messages/m3-streams-adaptive-thinking",
|
||||
"recordedAt": "2026-09-07T16:53:16.470Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.minimax.io/anthropic/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"MiniMax-M3\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":1536,\"thinking\":{\"type\":\"adaptive\"}}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream; charset=utf-8"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"ece24e3da050a8b1d7e8b1ad924a9e17\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"model\":\"MiniMax-M3\",\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":0,\"output_tokens\":0,\"service_tier\":\"standard\"},\"service_tier\":\"standard\"}}\n\nevent: ping\ndata: {\"type\":\"ping\"}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"thinking\",\"thinking\":\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" × 219\\n\\n\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 × 200\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" = 346\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"00\\n173 ×\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 19 = \"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"173 × 20\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" - 173 =\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 3460\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" - 173 =\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\" 3287\\n\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"34600 + \"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"3287 = \"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"thinking_delta\",\"thinking\":\"37887\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"signature_delta\",\"signature\":\"af0089d30b3ee7aff92a96e68064f4ed9346ca97de4f579555d2b3e1e61b53ea\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":1,\"content_block\":{\"type\":\"text\",\"text\":\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":1,\"delta\":{\"type\":\"text_delta\",\"text\":\"37887\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":1}\n\nevent: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\"},\"usage\":{\"input_tokens\":64,\"output_tokens\":54,\"cache_read_input_tokens\":128,\"service_tier\":\"standard\",\"output_tokens_details\":{\"thinking_tokens\":49}}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "MiniMax-M3",
|
||||
"tags": [
|
||||
"prefix:minimax-messages",
|
||||
"provider:minimax",
|
||||
"protocol:anthropic-messages",
|
||||
"text",
|
||||
"usage",
|
||||
"thinking-off"
|
||||
],
|
||||
"name": "minimax-messages/m3-streams-text-with-thinking-disabled",
|
||||
"recordedAt": "2026-09-07T16:53:16.028Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.minimax.io/anthropic/v1/messages",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"MiniMax-M3\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"stream\":true,\"max_tokens\":1536,\"thinking\":{\"type\":\"disabled\"}}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream; charset=utf-8"
|
||||
},
|
||||
"body": "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"01664c047875a0f573c966467c8cccc1\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[],\"model\":\"MiniMax-M3\",\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":0,\"output_tokens\":0,\"service_tier\":\"standard\"},\"service_tier\":\"standard\"}}\n\nevent: ping\ndata: {\"type\":\"ping\"}\n\nevent: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"378\"}}\n\nevent: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"87\"}}\n\nevent: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\nevent: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\"},\"usage\":{\"input_tokens\":51,\"output_tokens\":3,\"cache_read_input_tokens\":128,\"service_tier\":\"standard\"}}\n\nevent: message_stop\ndata: {\"type\":\"message_stop\"}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+56
File diff suppressed because one or more lines are too long
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "MiniMax-M3",
|
||||
"tags": [
|
||||
"prefix:minimax-responses",
|
||||
"provider:minimax",
|
||||
"protocol:open-responses",
|
||||
"text",
|
||||
"usage",
|
||||
"thinking-off"
|
||||
],
|
||||
"name": "minimax-responses/m3-streams-text-with-effort-none",
|
||||
"recordedAt": "2026-09-07T16:53:21.223Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.minimax.io/v1/responses",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"MiniMax-M3\",\"input\":[{\"role\":\"user\",\"content\":[{\"type\":\"input_text\",\"text\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}]}],\"reasoning\":{\"effort\":\"none\"},\"max_output_tokens\":1536,\"stream\":true}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream; charset=utf-8"
|
||||
},
|
||||
"body": "event: response.created\ndata: {\"type\":\"response.created\",\"sequence_number\":0,\"response\":{\"id\":\"40d878e9c7ecc67905d069cdf9bec7c0\",\"object\":\"response\",\"created_at\":1788800001,\"model\":\"MiniMax-M3\",\"status\":\"in_progress\",\"output\":[],\"output_text\":null,\"usage\":null,\"error\":null,\"incomplete_details\":null,\"instructions\":null,\"metadata\":{},\"tools\":null,\"tool_choice\":\"auto\",\"temperature\":1,\"top_p\":0.95,\"text\":{\"format\":{\"type\":\"text\"}},\"reasoning\":{\"effort\":\"none\",\"summary\":null},\"max_output_tokens\":1536,\"parallel_tool_calls\":true,\"previous_response_id\":null,\"conversation\":null,\"store\":false,\"service_tier\":\"standard\",\"safety_identifier\":null,\"truncation\":\"disabled\"}}\n\nevent: response.in_progress\ndata: {\"type\":\"response.in_progress\",\"sequence_number\":1,\"response\":{\"id\":\"40d878e9c7ecc67905d069cdf9bec7c0\",\"object\":\"response\",\"created_at\":1788800001,\"model\":\"MiniMax-M3\",\"status\":\"in_progress\",\"output\":[],\"output_text\":null,\"usage\":null,\"error\":null,\"incomplete_details\":null,\"instructions\":null,\"metadata\":{},\"tools\":null,\"tool_choice\":\"auto\",\"temperature\":1,\"top_p\":0.95,\"text\":{\"format\":{\"type\":\"text\"}},\"reasoning\":{\"effort\":\"none\",\"summary\":null},\"max_output_tokens\":1536,\"parallel_tool_calls\":true,\"previous_response_id\":null,\"conversation\":null,\"store\":false,\"service_tier\":\"standard\",\"safety_identifier\":null,\"truncation\":\"disabled\"}}\n\nevent: response.output_item.added\ndata: {\"type\":\"response.output_item.added\",\"sequence_number\":2,\"item\":{\"id\":\"40d878e9c7ecc67905d069cdf9bec7c0_msg\",\"type\":\"message\",\"status\":\"in_progress\",\"role\":\"assistant\",\"content\":[]},\"output_index\":0}\n\nevent: response.content_part.added\ndata: {\"type\":\"response.content_part.added\",\"sequence_number\":3,\"part\":{\"type\":\"output_text\",\"text\":\"\",\"annotations\":[]},\"output_index\":0,\"content_index\":0,\"item_id\":\"40d878e9c7ecc67905d069cdf9bec7c0_msg\"}\n\nevent: response.output_text.delta\ndata: {\"type\":\"response.output_text.delta\",\"sequence_number\":4,\"output_index\":0,\"content_index\":0,\"item_id\":\"40d878e9c7ecc67905d069cdf9bec7c0_msg\",\"delta\":\"378\"}\n\nevent: response.output_text.delta\ndata: {\"type\":\"response.output_text.delta\",\"sequence_number\":5,\"output_index\":0,\"content_index\":0,\"item_id\":\"40d878e9c7ecc67905d069cdf9bec7c0_msg\",\"delta\":\"87\"}\n\nevent: response.output_text.done\ndata: {\"type\":\"response.output_text.done\",\"sequence_number\":6,\"output_index\":0,\"content_index\":0,\"item_id\":\"40d878e9c7ecc67905d069cdf9bec7c0_msg\",\"text\":\"37887\"}\n\nevent: response.content_part.done\ndata: {\"type\":\"response.content_part.done\",\"sequence_number\":7,\"part\":{\"type\":\"output_text\",\"text\":\"37887\",\"annotations\":[]},\"output_index\":0,\"content_index\":0,\"item_id\":\"40d878e9c7ecc67905d069cdf9bec7c0_msg\"}\n\nevent: response.output_item.done\ndata: {\"type\":\"response.output_item.done\",\"sequence_number\":8,\"item\":{\"status\":\"completed\",\"role\":\"assistant\",\"content\":[{\"type\":\"output_text\",\"text\":\"37887\",\"annotations\":[]}],\"id\":\"40d878e9c7ecc67905d069cdf9bec7c0_msg\",\"type\":\"message\"},\"output_index\":0}\n\nevent: response.completed\ndata: {\"type\":\"response.completed\",\"sequence_number\":9,\"response\":{\"id\":\"40d878e9c7ecc67905d069cdf9bec7c0\",\"object\":\"response\",\"created_at\":1788800001,\"model\":\"MiniMax-M3\",\"status\":\"completed\",\"output\":[{\"id\":\"40d878e9c7ecc67905d069cdf9bec7c0_msg\",\"type\":\"message\",\"status\":\"completed\",\"role\":\"assistant\",\"content\":[{\"type\":\"output_text\",\"text\":\"37887\",\"annotations\":null}]}],\"output_text\":\"37887\",\"usage\":{\"input_tokens\":179,\"output_tokens\":3,\"total_tokens\":182,\"input_tokens_details\":{\"cached_tokens\":128}},\"error\":null,\"incomplete_details\":null,\"instructions\":null,\"metadata\":{},\"tools\":null,\"tool_choice\":\"auto\",\"temperature\":1,\"top_p\":0.95,\"text\":{\"format\":{\"type\":\"text\"}},\"reasoning\":{\"effort\":\"none\",\"summary\":null},\"max_output_tokens\":1536,\"parallel_tool_calls\":true,\"previous_response_id\":null,\"conversation\":null,\"store\":false,\"service_tier\":\"standard\",\"safety_identifier\":null,\"truncation\":\"disabled\"}}\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
Vendored
+29
File diff suppressed because one or more lines are too long
Vendored
+29
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
+74
File diff suppressed because one or more lines are too long
packages/ai/test/fixtures/recordings/moonshot-chat/kimi-k2-6-streams-text-with-default-thinking.json
Vendored
+29
File diff suppressed because one or more lines are too long
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"model": "kimi-k2.6",
|
||||
"tags": ["prefix:moonshot-chat", "provider:moonshot", "protocol:moonshot-chat", "text", "usage", "thinking-off"],
|
||||
"name": "moonshot-chat/kimi-k2-6-streams-text-with-disabled-thinking",
|
||||
"recordedAt": "2026-09-07T20:35:09.335Z"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"transport": "http",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.moonshot.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
"body": "{\"model\":\"kimi-k2.6\",\"messages\":[{\"role\":\"user\",\"content\":\"What is 173 multiplied by 219? Reply with only the final integer.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"max_tokens\":4096,\"thinking\":{\"type\":\"disabled\"}}"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"content-type": "text/event-stream"
|
||||
},
|
||||
"body": "data: {\"id\":\"chatcmpl-6a9f1ffd7d28eaca53fe9b4c\",\"object\":\"chat.completion.chunk\",\"created\":1788813309,\"model\":\"kimi-k2.6\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\"},\"finish_reason\":null}],\"system_fingerprint\":\"fpv0_45f9e909\"}\n\ndata: {\"id\":\"chatcmpl-6a9f1ffd7d28eaca53fe9b4c\",\"object\":\"chat.completion.chunk\",\"created\":1788813309,\"model\":\"kimi-k2.6\",\"choices\":[{\"index\":0,\"delta\":{\"reasoning_content\":\"\"},\"finish_reason\":null}],\"system_fingerprint\":\"fpv0_45f9e909\"}\n\ndata: {\"id\":\"chatcmpl-6a9f1ffd7d28eaca53fe9b4c\",\"object\":\"chat.completion.chunk\",\"created\":1788813309,\"model\":\"kimi-k2.6\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"378\"},\"finish_reason\":null}],\"system_fingerprint\":\"fpv0_45f9e909\"}\n\ndata: {\"id\":\"chatcmpl-6a9f1ffd7d28eaca53fe9b4c\",\"object\":\"chat.completion.chunk\",\"created\":1788813309,\"model\":\"kimi-k2.6\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"87\"},\"finish_reason\":null}],\"system_fingerprint\":\"fpv0_45f9e909\"}\n\ndata: {\"id\":\"chatcmpl-6a9f1ffd7d28eaca53fe9b4c\",\"object\":\"chat.completion.chunk\",\"created\":1788813309,\"model\":\"kimi-k2.6\",\"choices\":[{\"index\":0,\"delta\":{},\"finish_reason\":\"stop\",\"usage\":{\"prompt_tokens\":23,\"completion_tokens\":5,\"total_tokens\":28,\"completion_tokens_details\":{\"reasoning_tokens\":1}}}],\"system_fingerprint\":\"fpv0_45f9e909\"}\n\ndata: {\"id\":\"chatcmpl-6a9f1ffd7d28eaca53fe9b4c\",\"object\":\"chat.completion.chunk\",\"created\":1788813309,\"model\":\"kimi-k2.6\",\"choices\":[],\"usage\":{\"prompt_tokens\":23,\"completion_tokens\":5,\"total_tokens\":28,\"completion_tokens_details\":{\"reasoning_tokens\":1}}}\n\ndata: [DONE]\n\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
packages/ai/test/fixtures/recordings/moonshot-chat/kimi-k2-6-streams-text-with-enabled-thinking.json
Vendored
+29
File diff suppressed because one or more lines are too long
+74
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
+74
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
+74
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
+29
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user