mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-09 01:49:40 -10:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80273462bd | ||
|
|
fafe360672 | ||
|
|
d9b6f41940 | ||
|
|
f1ccf0eac3 | ||
|
|
d2aa924bc4 | ||
|
|
46861cd428 | ||
|
|
1c1825f8f0 | ||
|
|
a943995040 | ||
|
|
f0d2a2cf24 | ||
|
|
27ac612c82 | ||
|
|
baedb563f3 | ||
|
|
45c7914602 |
No files matched your search
@@ -52,10 +52,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Go 1.25.8
|
||||
- name: Go 1.26.2
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.25.8"
|
||||
go-version: "1.26.2"
|
||||
|
||||
- name: Install Minisign
|
||||
run: sudo apt-get update --fix-missing && sudo apt-get -y install minisign
|
||||
|
||||
@@ -16,10 +16,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Setup go environment
|
||||
- name: Go 1.25.8
|
||||
- name: Go 1.26.2
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.25.8"
|
||||
go-version: "1.26.2"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
@@ -25,10 +25,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.25.8
|
||||
- name: Go 1.26.2
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.25.8"
|
||||
go-version: "1.26.2"
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -71,10 +71,10 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.25.8
|
||||
- name: Go 1.26.2
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.25.8"
|
||||
go-version: "1.26.2"
|
||||
|
||||
- name: Install make
|
||||
run: choco install make -y --no-progress
|
||||
@@ -115,10 +115,10 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 180
|
||||
steps:
|
||||
- name: Go 1.25.8
|
||||
- name: Go 1.26.2
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.25.8"
|
||||
go-version: "1.26.2"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v6
|
||||
@@ -153,10 +153,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Go 1.25.8
|
||||
- name: Go 1.26.2
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "1.25.8"
|
||||
go-version: "1.26.2"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
Generated
+873
-1005
File diff suppressed because it is too large.
Load diff
@@ -26,8 +26,8 @@
|
||||
"asciinema-player": "^3.15.1",
|
||||
"fuse.js": "^7.3.0",
|
||||
"lunr": "^2.3.9",
|
||||
"mermaid": "^11.14.0",
|
||||
"next": "^16.2.4",
|
||||
"mermaid": "^11.15.0",
|
||||
"next": "^16.2.6",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.2.5",
|
||||
"react-dom": "^19.2.5",
|
||||
|
||||
@@ -9,20 +9,31 @@ if [[ "$EUID" -ne 0 ]];then
|
||||
exit
|
||||
fi
|
||||
|
||||
# Only include minisign in the package list when it isn't already on PATH.
|
||||
# The minisign apt package isn't in the default Ubuntu 22.04 repos, but
|
||||
# users often install it manually to /usr/local/bin first; without this
|
||||
# guard the apt-get call below fails the whole script (issue #2239).
|
||||
MINISIGN_PKG=(minisign)
|
||||
if command -v minisign &> /dev/null; then
|
||||
MINISIGN_PKG=()
|
||||
fi
|
||||
|
||||
# Determine OS type
|
||||
# Debian-based OS (Debian, Ubuntu, etc)
|
||||
if command -v apt-get &> /dev/null; then
|
||||
echo "Installing dependencies using apt..."
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -yqq \
|
||||
minisign curl build-essential git
|
||||
INSTALLER=(apt-get install -yqq)
|
||||
"${MINISIGN_PKG[@]}" curl build-essential git
|
||||
INSTALLER=(apt-get install -yqq)
|
||||
elif command -v yum &> /dev/null; then # Redhat-based OS (Fedora, CentOS, RHEL)
|
||||
echo "Installing dependencies using yum..."
|
||||
yum -y install minisign curl make git
|
||||
INSTALLER=(yum -y)
|
||||
yum -y install "${MINISIGN_PKG[@]}" curl make git
|
||||
INSTALLER=(yum -y)
|
||||
elif command -v pacman &>/dev/null; then # Arch-based (Manjaro, Garuda, Blackarch)
|
||||
echo "Installing dependencies using pacman..."
|
||||
pacman --noconfirm -S minisign
|
||||
echo "Installing dependencies using pacman..."
|
||||
if [[ ${#MINISIGN_PKG[@]} -gt 0 ]]; then
|
||||
pacman --noconfirm -S "${MINISIGN_PKG[@]}"
|
||||
fi
|
||||
INSTALLER=(pacman --noconfirm -S)
|
||||
else
|
||||
echo "Unsupported OS, exiting"
|
||||
@@ -31,9 +42,9 @@ fi
|
||||
|
||||
# Verify if necessary tools are installed
|
||||
for cmd in curl awk minisign; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
echo "$cmd could not be found, installing..."
|
||||
${INSTALLER[@]} "$cmd"
|
||||
${INSTALLER[@]} "$cmd"
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ replace github.com/reeflective/console => github.com/moloch--/console v0.0.0-202
|
||||
|
||||
require (
|
||||
charm.land/bubbles/v2 v2.0.0
|
||||
charm.land/fantasy v0.8.1
|
||||
charm.land/glamour/v2 v2.0.0
|
||||
charm.land/huh/v2 v2.0.3
|
||||
charm.land/lipgloss/v2 v2.0.2
|
||||
@@ -44,6 +43,7 @@ require (
|
||||
github.com/moloch--/sgn v0.0.5
|
||||
github.com/ncruces/go-sqlite3 v0.30.4
|
||||
github.com/nikoksr/notify v1.5.0
|
||||
github.com/openai/openai-go/v2 v2.7.1
|
||||
github.com/reeflective/console v0.1.25
|
||||
github.com/reeflective/readline v1.1.4
|
||||
github.com/rsteube/carapace v0.50.2
|
||||
@@ -59,13 +59,13 @@ require (
|
||||
github.com/ulikunitz/xz v0.5.15
|
||||
github.com/xlab/treeprint v1.2.0
|
||||
github.com/yiya1989/sshkrb5 v0.0.1
|
||||
golang.org/x/crypto v0.49.0
|
||||
golang.org/x/crypto v0.50.0
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa
|
||||
golang.org/x/mod v0.33.0
|
||||
golang.org/x/net v0.52.0
|
||||
golang.org/x/sys v0.42.0
|
||||
golang.org/x/term v0.41.0
|
||||
golang.org/x/text v0.35.0
|
||||
golang.org/x/mod v0.35.0
|
||||
golang.org/x/net v0.53.0
|
||||
golang.org/x/sys v0.43.0
|
||||
golang.org/x/term v0.42.0
|
||||
golang.org/x/text v0.37.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
|
||||
google.golang.org/api v0.269.0
|
||||
@@ -101,7 +101,6 @@ require (
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20250718055228-285ecf400b48 // indirect
|
||||
github.com/appleboy/go-fcm v1.2.6 // indirect
|
||||
github.com/atc0005/go-teams-notify/v2 v2.14.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect
|
||||
@@ -125,11 +124,10 @@ require (
|
||||
github.com/caarlos0/go-reddit/v3 v3.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab // indirect
|
||||
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect
|
||||
github.com/charmbracelet/x/exp/ordered v0.1.0 // indirect
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20250904123553-b4e2667e5ad5 // indirect
|
||||
github.com/charmbracelet/x/json v0.2.0 // indirect
|
||||
github.com/charmbracelet/x/termios v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.2.2 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||
@@ -154,8 +152,6 @@ require (
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc // indirect
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||
github.com/goccy/go-yaml v1.19.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
@@ -166,12 +162,9 @@ require (
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/gregdel/pushover v1.4.0 // indirect
|
||||
github.com/invopop/jsonschema v0.13.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kaptinlin/go-i18n v0.2.3 // indirect
|
||||
github.com/kaptinlin/jsonpointer v0.4.9 // indirect
|
||||
github.com/kaptinlin/jsonschema v0.6.10 // indirect
|
||||
github.com/kaptinlin/messageformat-go v0.4.9 // indirect
|
||||
github.com/kevinburke/go-types v0.0.0-20240719050749-165e75e768f7 // indirect
|
||||
github.com/kevinburke/rest v0.0.0-20250718180114-1a15e4f2364f // indirect
|
||||
github.com/kevinburke/twilio-go v0.0.0-20250718182727-5fe7adc01f29 // indirect
|
||||
@@ -186,7 +179,6 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/oapi-codegen/runtime v1.1.2 // indirect
|
||||
github.com/openai/openai-go/v2 v2.7.1 // indirect
|
||||
github.com/pires/go-proxyproto v0.8.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
@@ -195,7 +187,7 @@ require (
|
||||
github.com/sendgrid/rest v2.6.9+incompatible // indirect
|
||||
github.com/sendgrid/sendgrid-go v3.16.1+incompatible // indirect
|
||||
github.com/silenceper/wechat/v2 v2.1.11 // indirect
|
||||
github.com/slack-go/slack v0.17.3 // indirect
|
||||
github.com/slack-go/slack v0.24.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
|
||||
github.com/stretchr/objx v0.5.3 // indirect
|
||||
@@ -223,7 +215,6 @@ require (
|
||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.40.0 // indirect
|
||||
google.golang.org/appengine/v2 v2.0.6 // indirect
|
||||
google.golang.org/genai v1.49.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
gopkg.in/go-playground/validator.v9 v9.31.0 // indirect
|
||||
@@ -239,7 +230,7 @@ require (
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/akutz/memconn v0.1.0 // indirect
|
||||
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e // indirect
|
||||
github.com/atotto/clipboard v0.1.4 // indirect
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.3 // indirect
|
||||
@@ -281,7 +272,7 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.6 // indirect
|
||||
github.com/jackc/pgx/v5 v5.9.2 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jcmturner/gofork v1.7.6 // indirect
|
||||
github.com/jezek/xgb v1.1.1 // indirect
|
||||
@@ -326,7 +317,7 @@ require (
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/time v0.14.0
|
||||
golang.org/x/tools v0.42.0 // indirect
|
||||
golang.org/x/tools v0.44.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect
|
||||
|
||||
@@ -8,8 +8,6 @@ charm.land/bubbles/v2 v2.0.0 h1:tE3eK/pHjmtrDiRdoC9uGNLgpopOd8fjhEe31B/ai5s=
|
||||
charm.land/bubbles/v2 v2.0.0/go.mod h1:rCHoleP2XhU8um45NTuOWBPNVHxnkXKTiZqcclL/qOI=
|
||||
charm.land/bubbletea/v2 v2.0.2 h1:4CRtRnuZOdFDTWSff9r8QFt/9+z6Emubz3aDMnf/dx0=
|
||||
charm.land/bubbletea/v2 v2.0.2/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ=
|
||||
charm.land/fantasy v0.8.1 h1:2zQovDrd26g+/X2+/6bMomTX54HmZWNNHWeorDO0WRo=
|
||||
charm.land/fantasy v0.8.1/go.mod h1:KJ8vjy9FH7G2aeR/fL+os2uFHkQ4js2+UJVbsUKCXYM=
|
||||
charm.land/glamour/v2 v2.0.0 h1:IDBoqLEy7Hdpb9VOXN+khLP/XSxtJy1VsHuW/yF87+U=
|
||||
charm.land/glamour/v2 v2.0.0/go.mod h1:kjq9WB0s8vuUYZNYey2jp4Lgd9f4cKdzAw88FZtpj/w=
|
||||
charm.land/huh/v2 v2.0.3 h1:2cJsMqEPwSywGHvdlKsJyQKPtSJLVnFKyFbsYZTlLkU=
|
||||
@@ -122,8 +120,6 @@ github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 h1:cIAK2NNf2yafdgpF
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4/go.mod h1:SalMPBCab3yuID8nIhLfzwoBV+lBRyaC7NhuN8qL8xE=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.3 h1:4kQ/fa22KjDt13QCy1+bYADvdgcxpfH18f0zP542kZA=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.3/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5 h1:zWFmPmgw4sveAYi1mRqG+E/g0461cJ5M4bJ8/nc6d3Q=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.5/go.mod h1:nVUlMLVV8ycXSb7mSkcNu9e3v/1TJq2RTlrPwhYWr5c=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.11 h1:ftxI5sgz8jZkckuUHXfC/wMUc8u3fG1vQS0plr2F2Zs=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.11/go.mod h1:twF11+6ps9aNRKEDimksp923o44w/Thk9+8YIlzWMmo=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11 h1:NdV8cwCcAXrCWyxArt58BrvZJ9pZ9Fhf9w6Uh5W3Uyc=
|
||||
@@ -186,10 +182,10 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab h1:J7XQLgl9sefgTnTGrmX3xqvp5o6MCiBzEjGv5igAlc4=
|
||||
github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab/go.mod h1:hqlYqR7uPKOKfnNeicUbZp0Ps0GeYFlKYtwh5HGDCx8=
|
||||
github.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY=
|
||||
github.com/charmbracelet/colorprofile v0.4.2/go.mod h1:0rTi81QpwDElInthtrQ6Ni7cG0sDtwAd4C4le060fT8=
|
||||
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 h1:eyFRbAmexyt43hVfeyBofiGSEmJ7krjLOYt/9CF5NKA=
|
||||
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8/go.mod h1:SQpCTRNBtzJkwku5ye4S3HEuthAlGy2n9VXZnWkEW98=
|
||||
github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
|
||||
@@ -208,8 +204,6 @@ github.com/charmbracelet/x/exp/slice v0.0.0-20250904123553-b4e2667e5ad5 h1:DTSZx
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20250904123553-b4e2667e5ad5/go.mod h1:vI5nDVMWi6veaYH+0Fmvpbe/+cv/iJfMntdh+N0+Tms=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
|
||||
github.com/charmbracelet/x/json v0.2.0 h1:DqB+ZGx2h+Z+1s98HOuOyli+i97wsFQIxP2ZQANTPrQ=
|
||||
github.com/charmbracelet/x/json v0.2.0/go.mod h1:opFIflx2YgXgi49xVUu8gEQ21teFAxyMwvOiZhIvWNM=
|
||||
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
|
||||
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||
github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
|
||||
@@ -276,8 +270,6 @@ github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYC
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/drswork/go-twitter v0.0.0-20221107160839-dea1b6ed53d7 h1:uh1GSejOhVPRQmoXZxY82TiewZB8QXiaP1skL7Nun3Y=
|
||||
github.com/drswork/go-twitter v0.0.0-20221107160839-dea1b6ed53d7/go.mod h1:ncTaGuXc5v7AuiVekeJ0Nwh8Bf4cudukoj0qM/15UZE=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
@@ -354,8 +346,6 @@ github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaEL
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
||||
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO3g1nroKr2osU3JWZsJzkfi7rEg+oAB0Lo=
|
||||
github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737/go.mod h1:MIS0jDzbU/vuM9MC4YnBITCv+RYuTRq8dJzmCrFsK9g=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
@@ -364,8 +354,6 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
|
||||
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
|
||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg=
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU=
|
||||
@@ -467,8 +455,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
|
||||
github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
@@ -494,14 +482,6 @@ github.com/jsimonetti/rtnetlink v1.4.2 h1:Df9w9TZ3npHTyDn0Ev9e1uzmN2odmXd0QX+J5G
|
||||
github.com/jsimonetti/rtnetlink v1.4.2/go.mod h1:92s6LJdE+1iOrw+F2/RO7LYI2Qd8pPpFNNUYW06gcoM=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kaptinlin/go-i18n v0.2.3 h1:jyN/YOXXLcnGRBLdU+a8+6782B97fWE5aQqAHtvvk8Q=
|
||||
github.com/kaptinlin/go-i18n v0.2.3/go.mod h1:O+Ax4HkMO0Jt4OaP4E4WCx0PAADeWkwk8Jgt9bjAU1w=
|
||||
github.com/kaptinlin/jsonpointer v0.4.9 h1:o//bYf4PCvnMJIIX8bIg77KB6DO3wBPAabRyPRKh680=
|
||||
github.com/kaptinlin/jsonpointer v0.4.9/go.mod h1:9y0LgXavlmVE5FSHShY5LRlURJJVhbyVJSRWkilrTqA=
|
||||
github.com/kaptinlin/jsonschema v0.6.10 h1:CYded7nrwVu7pU1GaIjtd9dSzgqZjh7+LTKFaWqS08I=
|
||||
github.com/kaptinlin/jsonschema v0.6.10/go.mod h1:ZXZ4K5KrRmCCF1i6dgvBsQifl+WTb8XShKj0NpQNrz8=
|
||||
github.com/kaptinlin/messageformat-go v0.4.9 h1:FR5j5n4aL4nG0afKn9vvANrKxLu7HjmbhJnw5ogIwAQ=
|
||||
github.com/kaptinlin/messageformat-go v0.4.9/go.mod h1:qZzrGrlvWDz2KyyvN3dOWcK9PVSRV1BnfnNU+zB/RWc=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kbinani/screenshot v0.0.0-20250624051815-089614a94018 h1:NQYgMY188uWrS+E/7xMVpydsI48PMHcc7SfR4OxkDF4=
|
||||
@@ -551,8 +531,6 @@ github.com/mailgun/mailgun-go/v5 v5.8.1 h1:QoRa2oBqLq+8GTYgM4id/cKW/WySQRka3PtnW
|
||||
github.com/mailgun/mailgun-go/v5 v5.8.1/go.mod h1:qNTXXuJi9/myqpDLI8Mbn54WCXdto1kEHm6I2/WWYQQ=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mark3labs/mcp-go v0.43.2 h1:21PUSlWWiSbUPQwXIJ5WKlETixpFpq+WBpbMGDSVy/I=
|
||||
github.com/mark3labs/mcp-go v0.43.2/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw=
|
||||
github.com/mark3labs/mcp-go v0.45.0 h1:s0S8qR/9fWaQ3pHxz7pm1uQ0DrswoSnRIxKIjbiQtkc=
|
||||
github.com/mark3labs/mcp-go v0.45.0/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -645,8 +623,6 @@ github.com/openai/openai-go/v2 v2.7.1/go.mod h1:jrJs23apqJKKbT+pqtFgNKpRju/KP9zp
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||
@@ -698,8 +674,8 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||
github.com/slack-go/slack v0.17.3 h1:zV5qO3Q+WJAQ/XwbGfNFrRMaJ5T/naqaonyPV/1TP4g=
|
||||
github.com/slack-go/slack v0.17.3/go.mod h1:X+UqOufi3LYQHDnMG1vxf0J8asC6+WllXrVrhl8/Prk=
|
||||
github.com/slack-go/slack v0.24.0 h1:oMz5WcCBVTkxpBxeA8QVxxK70R+XV/a0qNka6TRNGHQ=
|
||||
github.com/slack-go/slack v0.24.0/go.mod h1:H0yR/YBuRJ39RkE+JpV/d/oEsbanzTRowR82bCN0cEs=
|
||||
github.com/sliverarmory/beignet v0.0.3 h1:ssR6AK9lirVulHZhQMyMmVAi0FcFwWxlh9LwKCJQ4X0=
|
||||
github.com/sliverarmory/beignet v0.0.3/go.mod h1:xXfTKBJqFBY/pakRFwJ+5+oGiSlg2CiCVUg/76kW1H4=
|
||||
github.com/sliverarmory/malasada v0.0.3 h1:b2KG2NhQVfBIIrbP8rGJwmdh7o8LH6NKYKH1DF4No1U=
|
||||
@@ -868,10 +844,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
|
||||
@@ -890,8 +864,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
||||
golang.org/x/net v0.0.0-20171115151908-9dfe39835686/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -913,10 +887,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
@@ -933,8 +905,6 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -975,8 +945,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -986,10 +956,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
||||
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
|
||||
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -1003,10 +971,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -1023,8 +989,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
|
||||
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1045,8 +1011,6 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine/v2 v2.0.6 h1:LvPZLGuchSBslPBp+LAhihBeGSiRh1myRoYK4NtuBIw=
|
||||
google.golang.org/appengine/v2 v2.0.6/go.mod h1:WoEXGoXNfa0mLvaH5sV3ZSGXwVmy8yf7Z1JKf3J3wLI=
|
||||
google.golang.org/genai v1.49.0 h1:Se+QJaH2GYK1aaR1o5S38mlU2GD5FnVvP76nfkV7LH0=
|
||||
google.golang.org/genai v1.49.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
@@ -1054,8 +1018,6 @@ google.golang.org/genproto v0.0.0-20260226221140-a57be14db171 h1:RxhCsti413yL0Ij
|
||||
google.golang.org/genproto v0.0.0-20260226221140-a57be14db171/go.mod h1:uhvzakVEqAuXU3TC2JCsxIRe5f77l+JySE3EqPoMyqM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
@@ -1063,8 +1025,6 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
|
||||
@@ -776,6 +776,8 @@ func (s *SliverHTTPC2) stagerHandler(resp http.ResponseWriter, req *http.Request
|
||||
nonces, err := getNoncesFromURL(req.URL, 0)
|
||||
if err != nil {
|
||||
s.defaultHandler(resp, req)
|
||||
// Added return statement to prevent duplicate HTML when serving websites
|
||||
return
|
||||
}
|
||||
|
||||
for _, nonce := range nonces {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package c2
|
||||
|
||||
/*
|
||||
Sliver Implant Framework
|
||||
Copyright (C) 2026 Bishop Fox
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"image"
|
||||
"image/png"
|
||||
"testing"
|
||||
|
||||
sliverEncoders "github.com/bishopfox/sliver/util/encoders"
|
||||
)
|
||||
|
||||
func TestDecodeReqBodyWithMaxLenRejectsOversizedPNG(t *testing.T) {
|
||||
img := image.NewNRGBA(image.Rect(0, 0, 1700, 1700))
|
||||
var encoded bytes.Buffer
|
||||
if err := png.Encode(&encoded, img); err != nil {
|
||||
t.Fatalf("png encode failed: %v", err)
|
||||
}
|
||||
|
||||
_, err := decodeReqBodyWithMaxLen(sliverEncoders.PNGEncoder{}, encoded.Bytes(), DefaultMaxUnauthBodyLength)
|
||||
if !errors.Is(err, sliverEncoders.ErrPNGTooLarge) {
|
||||
t.Fatalf("expected ErrPNGTooLarge, got %v", err)
|
||||
}
|
||||
}
|
||||
+13
-1
@@ -69,12 +69,24 @@ func (broker *eventBroker) Start() {
|
||||
}
|
||||
case event := <-broker.publish:
|
||||
for sub := range subscribers {
|
||||
sub <- event
|
||||
safeBrokerSend(sub, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// safeBrokerSend sends an event to a subscriber, recovering from a closed-channel
|
||||
// panic if the subscriber dropped its end without unsubscribing first (#2252).
|
||||
func safeBrokerSend(sub chan Event, event Event) {
|
||||
defer func() { _ = recover() }()
|
||||
select {
|
||||
case sub <- event:
|
||||
default:
|
||||
// Subscriber's buffer is full or it's gone; drop the event rather
|
||||
// than block the broker.
|
||||
}
|
||||
}
|
||||
|
||||
// Stop - Close the broker channel
|
||||
func (broker *eventBroker) Stop() {
|
||||
close(broker.stop)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package assets
|
||||
|
||||
const (
|
||||
goVersion = "1.25.8"
|
||||
garbleVersion = "1.25.8"
|
||||
goVersion = "1.26.2"
|
||||
garbleVersion = "1.26.2"
|
||||
zigVersion = "0.15.2"
|
||||
zigSourceParam = "source=sliver"
|
||||
|
||||
|
||||
+54
-3
@@ -20,6 +20,8 @@ package encoders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
@@ -36,11 +38,22 @@ const (
|
||||
|
||||
// we can shove three bytes into each pixel: R, G, and B.
|
||||
bytesPerPixel = 3
|
||||
|
||||
// DefaultMaxPNGDecodeLen is the maximum amount of pixel data Decode will
|
||||
// process. Callers handling untrusted data should use DecodeWithMaxLen with
|
||||
// a limit appropriate for the request they are processing.
|
||||
DefaultMaxPNGDecodeLen = 2 * 1024 * 1024 * 1024 // 2GB
|
||||
)
|
||||
|
||||
// ErrPNGTooLarge is returned when a PNG's dimensions or decoded payload exceed
|
||||
// the decode limit.
|
||||
var ErrPNGTooLarge = errors.New("png decoded payload exceeds maximum size")
|
||||
|
||||
// PNGEncoder - PNG image object
|
||||
type PNGEncoder struct{}
|
||||
|
||||
var _ LimitedDecoder = PNGEncoder{}
|
||||
|
||||
// Encode outputs a valid PNG file
|
||||
func (p PNGEncoder) Encode(data []byte) ([]byte, error) {
|
||||
img := imageFromBytes(data)
|
||||
@@ -54,12 +67,50 @@ func (p PNGEncoder) Encode(data []byte) ([]byte, error) {
|
||||
|
||||
// Decode reads a encoded PNG to get the original binary data
|
||||
func (p PNGEncoder) Decode(data []byte) ([]byte, error) {
|
||||
buf := bytes.NewBuffer(data)
|
||||
img, err := png.Decode(buf)
|
||||
return p.DecodeWithMaxLen(data, DefaultMaxPNGDecodeLen)
|
||||
}
|
||||
|
||||
// DecodeWithMaxLen reads an encoded PNG while limiting both the returned
|
||||
// payload and the three-byte-per-pixel representation used during decoding.
|
||||
// Since padding and escape sequences are removed after extracting the pixels,
|
||||
// this may conservatively reject an image whose final payload would fit.
|
||||
func (p PNGEncoder) DecodeWithMaxLen(data []byte, maxLen int64) ([]byte, error) {
|
||||
if maxLen < 0 {
|
||||
return nil, fmt.Errorf("invalid max decode length: %d", maxLen)
|
||||
}
|
||||
|
||||
config, err := png.DecodeConfig(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytesFromImage(img), nil
|
||||
if err := validatePNGDimensions(config.Width, config.Height, maxLen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img, err := png.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decoded := bytesFromImage(img)
|
||||
if int64(len(decoded)) > maxLen {
|
||||
return nil, fmt.Errorf("%w: decoded payload is %d bytes, limit is %d", ErrPNGTooLarge, len(decoded), maxLen)
|
||||
}
|
||||
return decoded, nil
|
||||
}
|
||||
|
||||
func validatePNGDimensions(width int, height int, maxLen int64) error {
|
||||
if width <= 0 || height <= 0 {
|
||||
return fmt.Errorf("invalid PNG dimensions: %dx%d", width, height)
|
||||
}
|
||||
|
||||
// bytesFromImage materializes three bytes for every pixel before removing
|
||||
// padding and escape sequences. Bound that intermediate representation
|
||||
// before png.Decode allocates storage based on attacker-controlled dimensions.
|
||||
maxPixels := maxLen / int64(bytesPerPixel)
|
||||
if int64(width) > maxPixels/int64(height) {
|
||||
return fmt.Errorf("%w: %dx%d image exceeds %d bytes", ErrPNGTooLarge, width, height, maxLen)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// imageFromBytes returns a valid image with data encoded in each pixel
|
||||
|
||||
@@ -20,6 +20,9 @@ package encoders
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash/crc32"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -62,3 +65,77 @@ func TestPNGRandomDataRandomSize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPNGDecodeWithMaxLen(t *testing.T) {
|
||||
const maxLen = 4 * bytesPerPixel
|
||||
payload := []byte{0x00, 0x01, 0x02, 0x03, 0x04}
|
||||
pngEncoder := new(PNGEncoder)
|
||||
encoded, err := pngEncoder.Encode(payload)
|
||||
if err != nil {
|
||||
t.Fatalf("png encode failed: %v", err)
|
||||
}
|
||||
|
||||
decoded, err := pngEncoder.DecodeWithMaxLen(encoded, maxLen)
|
||||
if err != nil {
|
||||
t.Fatalf("png decode failed: %v", err)
|
||||
}
|
||||
if !bytes.Equal(payload, decoded) {
|
||||
t.Fatalf("decoded payload does not match original: %q != %q", decoded, payload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPNGDecodeWithMaxLenRejectsOversizedPixelData(t *testing.T) {
|
||||
payload := bytes.Repeat([]byte("A"), 8192)
|
||||
pngEncoder := new(PNGEncoder)
|
||||
encoded, err := pngEncoder.Encode(payload)
|
||||
if err != nil {
|
||||
t.Fatalf("png encode failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = pngEncoder.DecodeWithMaxLen(encoded, int64(len(payload)-1))
|
||||
if !errors.Is(err, ErrPNGTooLarge) {
|
||||
t.Fatalf("expected ErrPNGTooLarge, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPNGDecodeWithMaxLenRejectsOversizedDimensionsBeforeDecode(t *testing.T) {
|
||||
const maxLen = 8 * 1024 * 1024
|
||||
pngEncoder := new(PNGEncoder)
|
||||
encoded, err := pngEncoder.Encode([]byte("abc"))
|
||||
if err != nil {
|
||||
t.Fatalf("png encode failed: %v", err)
|
||||
}
|
||||
|
||||
// A PNG starts with an eight-byte signature followed by its IHDR chunk.
|
||||
// Rewrite only the CRC-valid header and omit IDAT so this test remains safe
|
||||
// even if the preflight check regresses and png.Decode is called directly.
|
||||
const ihdrEnd = 33
|
||||
if len(encoded) < ihdrEnd || string(encoded[12:16]) != "IHDR" {
|
||||
t.Fatal("encoded PNG does not contain the expected IHDR chunk")
|
||||
}
|
||||
encoded = encoded[:ihdrEnd]
|
||||
binary.BigEndian.PutUint32(encoded[16:20], 4096)
|
||||
binary.BigEndian.PutUint32(encoded[20:24], 4096)
|
||||
binary.BigEndian.PutUint32(encoded[29:33], crc32.ChecksumIEEE(encoded[12:29]))
|
||||
|
||||
_, err = pngEncoder.DecodeWithMaxLen(encoded, maxLen)
|
||||
if !errors.Is(err, ErrPNGTooLarge) {
|
||||
t.Fatalf("expected ErrPNGTooLarge, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePNGDimensionsRejectsReportedBomb(t *testing.T) {
|
||||
err := validatePNGDimensions(32767, 32767, 8*1024*1024)
|
||||
if !errors.Is(err, ErrPNGTooLarge) {
|
||||
t.Fatalf("expected ErrPNGTooLarge, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePNGDimensionsPixelDataBoundary(t *testing.T) {
|
||||
if err := validatePNGDimensions(1, 1, bytesPerPixel); err != nil {
|
||||
t.Fatalf("expected one pixel to fit: %v", err)
|
||||
}
|
||||
if err := validatePNGDimensions(1, 1, bytesPerPixel-1); !errors.Is(err, ErrPNGTooLarge) {
|
||||
t.Fatalf("expected ErrPNGTooLarge, got %v", err)
|
||||
}
|
||||
}
|
||||
+341
-67
@@ -1,3 +1,4 @@
|
||||
// Package progress provides a simple progress bar for Bubble Tea applications.
|
||||
package progress
|
||||
|
||||
import (
|
||||
@@ -5,36 +6,97 @@ import (
|
||||
"image/color"
|
||||
"math"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
tea "charm.land/bubbletea/v2"
|
||||
"charm.land/lipgloss/v2"
|
||||
"github.com/charmbracelet/harmonica"
|
||||
"github.com/charmbracelet/x/ansi"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultFullCharHalfBlock = '▌'
|
||||
DefaultFullCharFullBlock = '█'
|
||||
DefaultEmptyCharBlock = '░'
|
||||
// ColorFunc is a function that can be used to dynamically fill the progress
|
||||
// bar based on the current percentage. total is the total filled percentage,
|
||||
// and current is the current percentage that is actively being filled with a
|
||||
// color.
|
||||
type ColorFunc func(total, current float64) color.Color
|
||||
|
||||
defaultWidth = 40
|
||||
// Internal ID management. Used during animating to assure that frame messages
|
||||
// can only be received by progress components that sent them.
|
||||
var lastID int64
|
||||
|
||||
func nextID() int {
|
||||
return int(atomic.AddInt64(&lastID, 1))
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultFullCharHalfBlock is the default character used to fill the progress
|
||||
// bar. It is a half block, which allows more granular color blending control,
|
||||
// by having a different foreground and background color, doubling blending
|
||||
// resolution.
|
||||
DefaultFullCharHalfBlock = '▌'
|
||||
|
||||
// DefaultFullCharFullBlock can also be used as a fill character for the
|
||||
// progress bar. Use this to disable the higher resolution blending which is
|
||||
// enabled when using [DefaultFullCharHalfBlock].
|
||||
DefaultFullCharFullBlock = '█'
|
||||
|
||||
// DefaultEmptyCharBlock is the default character used to fill the empty
|
||||
// portion of the progress bar.
|
||||
DefaultEmptyCharBlock = '░'
|
||||
|
||||
fps = 60
|
||||
defaultWidth = 40
|
||||
defaultFrequency = 18.0
|
||||
defaultDamping = 1.0
|
||||
)
|
||||
|
||||
var (
|
||||
defaultFullColor = lipgloss.Color("#7571F9")
|
||||
defaultEmptyColor = lipgloss.Color("#606060")
|
||||
defaultBlendStart = lipgloss.Color("#5A56E0") // Purple haze.
|
||||
defaultBlendEnd = lipgloss.Color("#EE6FF8") // Neon pink.
|
||||
defaultFullColor = lipgloss.Color("#7571F9") // Blueberry.
|
||||
defaultEmptyColor = lipgloss.Color("#606060") // Slate gray.
|
||||
)
|
||||
|
||||
// Option is used to set options in [New]. For example:
|
||||
//
|
||||
// progress := New(
|
||||
// WithColors(
|
||||
// lipgloss.Color("#5A56E0"),
|
||||
// lipgloss.Color("#EE6FF8"),
|
||||
// ),
|
||||
// WithoutPercentage(),
|
||||
// )
|
||||
type Option func(*Model)
|
||||
|
||||
// WithDefaultBlend sets a default blend of colors, which is a blend of purple
|
||||
// haze to neon pink.
|
||||
func WithDefaultBlend() Option {
|
||||
return WithColors(
|
||||
defaultBlendStart,
|
||||
defaultBlendEnd,
|
||||
)
|
||||
}
|
||||
|
||||
// WithColors sets the colors to use to fill the progress bar. Depending on the
|
||||
// number of colors passed in, will determine whether to use a solid fill or a
|
||||
// blend of colors.
|
||||
//
|
||||
// - 0 colors: clears all previously set colors, setting them back to defaults.
|
||||
// - 1 color: uses a solid fill with the given color.
|
||||
// - 2+ colors: uses a blend of the provided colors.
|
||||
func WithColors(colors ...color.Color) Option {
|
||||
if len(colors) == 0 {
|
||||
return func(m *Model) {
|
||||
m.FullColor = defaultFullColor
|
||||
m.blend = nil
|
||||
m.colorFunc = nil
|
||||
}
|
||||
}
|
||||
if len(colors) == 1 {
|
||||
return func(m *Model) {
|
||||
m.FullColor = colors[0]
|
||||
m.colorFunc = nil
|
||||
m.blend = nil
|
||||
}
|
||||
}
|
||||
@@ -43,39 +105,133 @@ func WithColors(colors ...color.Color) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func WithFillCharacters(full, empty rune) Option {
|
||||
// WithColorFunc sets a function that can be used to dynamically fill the progress
|
||||
// bar based on the current percentage. total is the total filled percentage, and
|
||||
// current is the current percentage that is actively being filled with a color.
|
||||
// When specified, this overrides any other defined colors and scaling.
|
||||
//
|
||||
// Example: A progress bar that changes color based on the total completed
|
||||
// percentage:
|
||||
//
|
||||
// WithColorFunc(func(total, current float64) color.Color {
|
||||
// if total <= 0.3 {
|
||||
// return lipgloss.Color("#FF0000")
|
||||
// }
|
||||
// if total <= 0.7 {
|
||||
// return lipgloss.Color("#00FF00")
|
||||
// }
|
||||
// return lipgloss.Color("#0000FF")
|
||||
// }),
|
||||
func WithColorFunc(fn ColorFunc) Option {
|
||||
return func(m *Model) {
|
||||
m.colorFunc = fn
|
||||
m.blend = nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithFillCharacters sets the characters used to construct the full and empty
|
||||
// components of the progress bar.
|
||||
func WithFillCharacters(full rune, empty rune) Option {
|
||||
return func(m *Model) {
|
||||
m.Full = full
|
||||
m.Empty = empty
|
||||
}
|
||||
}
|
||||
|
||||
// WithoutPercentage hides the numeric percentage.
|
||||
func WithoutPercentage() Option {
|
||||
return func(m *Model) {
|
||||
m.ShowPercentage = false
|
||||
}
|
||||
}
|
||||
|
||||
// WithWidth sets the initial width of the progress bar. Note that you can also
|
||||
// set the width via the Width property, which can come in handy if you're
|
||||
// waiting for a tea.WindowSizeMsg.
|
||||
func WithWidth(w int) Option {
|
||||
return func(m *Model) {
|
||||
m.SetWidth(w)
|
||||
}
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
width int
|
||||
Full rune
|
||||
FullColor color.Color
|
||||
Empty rune
|
||||
EmptyColor color.Color
|
||||
ShowPercentage bool
|
||||
PercentFormat string
|
||||
PercentageStyle lipgloss.Style
|
||||
blend []color.Color
|
||||
// WithSpringOptions sets the initial frequency and damping options for the
|
||||
// progress bar's built-in spring-based animation. Frequency corresponds to
|
||||
// speed, and damping to bounciness. For details see:
|
||||
//
|
||||
// https://github.com/charmbracelet/harmonica
|
||||
func WithSpringOptions(frequency, damping float64) Option {
|
||||
return func(m *Model) {
|
||||
m.SetSpringOptions(frequency, damping)
|
||||
m.springCustomized = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithScaled sets whether to scale the blend/gradient to fit the width of only
|
||||
// the filled portion of the progress bar. The default is false, which means the
|
||||
// percentage must be 100% to see the full color blend/gradient.
|
||||
//
|
||||
// This is ignored when not using blending/multiple colors.
|
||||
func WithScaled(enabled bool) Option {
|
||||
return func(m *Model) {
|
||||
m.scaleBlend = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// FrameMsg indicates that an animation step should occur.
|
||||
type FrameMsg struct {
|
||||
id int
|
||||
tag int
|
||||
}
|
||||
|
||||
// Model stores values we'll use when rendering the progress bar.
|
||||
type Model struct {
|
||||
// An identifier to keep us from receiving messages intended for other
|
||||
// progress bars.
|
||||
id int
|
||||
|
||||
// An identifier to keep us from receiving frame messages too quickly.
|
||||
tag int
|
||||
|
||||
// Total width of the progress bar, including percentage, if set.
|
||||
width int
|
||||
|
||||
// "Filled" sections of the progress bar.
|
||||
Full rune
|
||||
FullColor color.Color
|
||||
|
||||
// "Empty" sections of the progress bar.
|
||||
Empty rune
|
||||
EmptyColor color.Color
|
||||
|
||||
// Settings for rendering the numeric percentage.
|
||||
ShowPercentage bool
|
||||
PercentFormat string // a fmt string for a float
|
||||
PercentageStyle lipgloss.Style
|
||||
|
||||
// Members for animated transitions.
|
||||
spring harmonica.Spring
|
||||
springCustomized bool
|
||||
percentShown float64 // percent currently displaying
|
||||
targetPercent float64 // percent to which we're animating
|
||||
velocity float64
|
||||
|
||||
// Blend of colors to use. When len < 1, we use FullColor.
|
||||
blend []color.Color
|
||||
|
||||
// When true, we scale the blended colors to fit the width of the filled
|
||||
// section of the progress bar. When false, the width of the blend will be
|
||||
// set to the full width of the progress bar.
|
||||
scaleBlend bool
|
||||
|
||||
// colorFunc is used to dynamically fill the progress bar based on the
|
||||
// current percentage.
|
||||
colorFunc ColorFunc
|
||||
}
|
||||
|
||||
// New returns a model with default values.
|
||||
func New(opts ...Option) Model {
|
||||
m := Model{
|
||||
id: nextID(),
|
||||
width: defaultWidth,
|
||||
Full: DefaultFullCharHalfBlock,
|
||||
FullColor: defaultFullColor,
|
||||
@@ -84,24 +240,96 @@ func New(opts ...Option) Model {
|
||||
ShowPercentage: true,
|
||||
PercentFormat: " %3.0f%%",
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(&m)
|
||||
}
|
||||
|
||||
if !m.springCustomized {
|
||||
m.SetSpringOptions(defaultFrequency, defaultDamping)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Model) SetWidth(w int) {
|
||||
m.width = w
|
||||
// Init exists to satisfy the tea.Model interface.
|
||||
func (m Model) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Model) Width() int {
|
||||
return m.width
|
||||
// Update is used to animate the progress bar during transitions. Use
|
||||
// SetPercent to create the command you'll need to trigger the animation.
|
||||
//
|
||||
// If you're rendering with ViewAs you won't need this.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case FrameMsg:
|
||||
if msg.id != m.id || msg.tag != m.tag {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// If we've more or less reached equilibrium, stop updating.
|
||||
if !m.IsAnimating() {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
m.percentShown, m.velocity = m.spring.Update(m.percentShown, m.velocity, m.targetPercent)
|
||||
return m, m.nextFrame()
|
||||
|
||||
default:
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetSpringOptions sets the frequency and damping for the current spring.
|
||||
// Frequency corresponds to speed, and damping to bounciness. For details see:
|
||||
//
|
||||
// https://github.com/charmbracelet/harmonica
|
||||
func (m *Model) SetSpringOptions(frequency, damping float64) {
|
||||
m.spring = harmonica.NewSpring(harmonica.FPS(fps), frequency, damping)
|
||||
}
|
||||
|
||||
// Percent returns the current visible percentage on the model. This is only
|
||||
// relevant when you're animating the progress bar.
|
||||
//
|
||||
// If you're rendering with ViewAs you won't need this.
|
||||
func (m Model) Percent() float64 {
|
||||
return m.targetPercent
|
||||
}
|
||||
|
||||
// SetPercent sets the percentage state of the model as well as a command
|
||||
// necessary for animating the progress bar to this new percentage.
|
||||
//
|
||||
// If you're rendering with ViewAs you won't need this.
|
||||
func (m *Model) SetPercent(p float64) tea.Cmd {
|
||||
m.targetPercent = math.Max(0, math.Min(1, p))
|
||||
m.tag++
|
||||
return m.nextFrame()
|
||||
}
|
||||
|
||||
// IncrPercent increments the percentage by a given amount, returning a command
|
||||
// necessary to animate the progress bar to the new percentage.
|
||||
//
|
||||
// If you're rendering with ViewAs you won't need this.
|
||||
func (m *Model) IncrPercent(v float64) tea.Cmd {
|
||||
return m.SetPercent(m.Percent() + v)
|
||||
}
|
||||
|
||||
// DecrPercent decrements the percentage by a given amount, returning a command
|
||||
// necessary to animate the progress bar to the new percentage.
|
||||
//
|
||||
// If you're rendering with ViewAs you won't need this.
|
||||
func (m *Model) DecrPercent(v float64) tea.Cmd {
|
||||
return m.SetPercent(m.Percent() - v)
|
||||
}
|
||||
|
||||
// View renders an animated progress bar in its current state. To render
|
||||
// a static progress bar based on your own calculations use ViewAs instead.
|
||||
func (m Model) View() string {
|
||||
return m.ViewAs(0)
|
||||
return m.ViewAs(m.percentShown)
|
||||
}
|
||||
|
||||
// ViewAs renders the progress bar with a given percentage.
|
||||
func (m Model) ViewAs(percent float64) string {
|
||||
b := strings.Builder{}
|
||||
percentView := m.percentageView(percent)
|
||||
@@ -110,55 +338,101 @@ func (m Model) ViewAs(percent float64) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// SetWidth sets the width of the progress bar.
|
||||
func (m *Model) SetWidth(w int) {
|
||||
m.width = w
|
||||
}
|
||||
|
||||
// Width returns the width of the progress bar.
|
||||
func (m Model) Width() int {
|
||||
return m.width
|
||||
}
|
||||
|
||||
func (m *Model) nextFrame() tea.Cmd {
|
||||
return tea.Tick(time.Second/time.Duration(fps), func(time.Time) tea.Msg {
|
||||
return FrameMsg{id: m.id, tag: m.tag}
|
||||
})
|
||||
}
|
||||
|
||||
func (m Model) barView(b *strings.Builder, percent float64, textWidth int) {
|
||||
var (
|
||||
tw = max(0, m.width-textWidth) // total width
|
||||
fw = int(math.Round((float64(tw) * percent))) // filled width
|
||||
)
|
||||
|
||||
fw = max(0, min(tw, fw))
|
||||
|
||||
isHalfBlock := m.Full == DefaultFullCharHalfBlock
|
||||
|
||||
if m.colorFunc != nil { //nolint:nestif
|
||||
var style lipgloss.Style
|
||||
var current float64
|
||||
halfBlockPerc := 0.5 / float64(tw)
|
||||
for i := range fw {
|
||||
current = float64(i) / float64(tw)
|
||||
style = style.Foreground(m.colorFunc(percent, current))
|
||||
if isHalfBlock {
|
||||
style = style.Background(m.colorFunc(percent, min(current+halfBlockPerc, 1)))
|
||||
}
|
||||
b.WriteString(style.Render(string(m.Full)))
|
||||
}
|
||||
} else if len(m.blend) > 0 {
|
||||
var blend []color.Color
|
||||
|
||||
multiplier := 1
|
||||
if isHalfBlock {
|
||||
multiplier = 2
|
||||
}
|
||||
|
||||
if m.scaleBlend {
|
||||
blend = lipgloss.Blend1D(fw*multiplier, m.blend...)
|
||||
} else {
|
||||
blend = lipgloss.Blend1D(tw*multiplier, m.blend...)
|
||||
}
|
||||
|
||||
// Blend fill.
|
||||
var blendIndex int
|
||||
for i := range fw {
|
||||
if !isHalfBlock {
|
||||
b.WriteString(lipgloss.NewStyle().
|
||||
Foreground(blend[i]).
|
||||
Render(string(m.Full)))
|
||||
continue
|
||||
}
|
||||
|
||||
b.WriteString(lipgloss.NewStyle().
|
||||
Foreground(blend[blendIndex]).
|
||||
Background(blend[blendIndex+1]).
|
||||
Render(string(m.Full)))
|
||||
blendIndex += 2
|
||||
}
|
||||
} else {
|
||||
// Solid fill.
|
||||
b.WriteString(lipgloss.NewStyle().
|
||||
Foreground(m.FullColor).
|
||||
Render(strings.Repeat(string(m.Full), fw)))
|
||||
}
|
||||
|
||||
// Empty fill.
|
||||
n := max(0, tw-fw)
|
||||
b.WriteString(lipgloss.NewStyle().
|
||||
Foreground(m.EmptyColor).
|
||||
Render(strings.Repeat(string(m.Empty), n)))
|
||||
}
|
||||
|
||||
func (m Model) percentageView(percent float64) string {
|
||||
if !m.ShowPercentage {
|
||||
return ""
|
||||
}
|
||||
percent = math.Max(0, math.Min(1, percent))
|
||||
percentage := fmt.Sprintf(m.PercentFormat, percent*100)
|
||||
return m.PercentageStyle.Inline(true).Render(percentage)
|
||||
percentage := fmt.Sprintf(m.PercentFormat, percent*100) //nolint:mnd
|
||||
percentage = m.PercentageStyle.Inline(true).Render(percentage)
|
||||
return percentage
|
||||
}
|
||||
|
||||
func (m Model) barView(b *strings.Builder, percent float64, textWidth int) {
|
||||
totalWidth := maxInt(0, m.width-textWidth)
|
||||
filledWidth := int(math.Round(float64(totalWidth) * math.Max(0, math.Min(1, percent))))
|
||||
filledWidth = clampInt(filledWidth, 0, totalWidth)
|
||||
|
||||
if len(m.blend) > 1 {
|
||||
blend := lipgloss.Blend1D(totalWidth, m.blend...)
|
||||
for i := 0; i < filledWidth && i < len(blend); i++ {
|
||||
b.WriteString(lipgloss.NewStyle().
|
||||
Foreground(blend[i]).
|
||||
Render(string(m.Full)))
|
||||
}
|
||||
} else {
|
||||
b.WriteString(lipgloss.NewStyle().
|
||||
Foreground(m.FullColor).
|
||||
Render(strings.Repeat(string(m.Full), filledWidth)))
|
||||
}
|
||||
|
||||
emptyWidth := maxInt(0, totalWidth-filledWidth)
|
||||
if emptyWidth == 0 {
|
||||
return
|
||||
}
|
||||
b.WriteString(lipgloss.NewStyle().
|
||||
Foreground(m.EmptyColor).
|
||||
Render(strings.Repeat(string(m.Empty), emptyWidth)))
|
||||
}
|
||||
|
||||
func maxInt(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func clampInt(value, low, high int) int {
|
||||
if value < low {
|
||||
return low
|
||||
}
|
||||
if value > high {
|
||||
return high
|
||||
}
|
||||
return value
|
||||
// IsAnimating returns false if the progress bar reached equilibrium and is no
|
||||
// longer animating.
|
||||
func (m *Model) IsAnimating() bool {
|
||||
dist := math.Abs(m.percentShown - m.targetPercent)
|
||||
return !(dist < 0.001 && m.velocity < 0.01)
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
# https://editorconfig.org/
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.golden]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
||||
@@ -1 +0,0 @@
|
||||
providertests/testdata/**/*.yaml -diff linguist-generated=true
|
||||
@@ -1,42 +0,0 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
|
||||
# IDE specific files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS specific files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
*.log
|
||||
|
||||
# Binary output directory
|
||||
/bin/
|
||||
/dist/
|
||||
|
||||
# Local environment variables
|
||||
.env
|
||||
.env.local
|
||||
|
||||
manpages/
|
||||
*.patch
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
version: "2"
|
||||
run:
|
||||
tests: false
|
||||
linters:
|
||||
enable:
|
||||
- bodyclose
|
||||
# - exhaustive
|
||||
# - goconst
|
||||
- godot
|
||||
# - gomoddirectives
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- misspell
|
||||
- nakedret
|
||||
# - nestif
|
||||
- nilerr
|
||||
- noctx
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- tparallel
|
||||
- unconvert
|
||||
- unparam
|
||||
- whitespace
|
||||
# - wrapcheck
|
||||
exclusions:
|
||||
rules:
|
||||
- text: '(slog|log)\.\w+'
|
||||
linters:
|
||||
- noctx
|
||||
generated: lax
|
||||
presets:
|
||||
- common-false-positives
|
||||
issues:
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
formatters:
|
||||
enable:
|
||||
- gofumpt
|
||||
- goimports
|
||||
exclusions:
|
||||
generated: lax
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json
|
||||
|
||||
version: 2
|
||||
includes:
|
||||
- from_url:
|
||||
url: charmbracelet/meta/main/goreleaser-lib.yaml
|
||||
Vendored
-29
@@ -1,29 +0,0 @@
|
||||
# CRUSH.md - Fantasy AI SDK
|
||||
|
||||
## Build/Test/Lint Commands
|
||||
- **Build**: `go build ./...`
|
||||
- **Test all**: `task test` or `go test ./... -count=1`
|
||||
- **Test single**: `go test -run TestName ./package -v`
|
||||
- **Test with args**: `task test -- -v -run TestName`
|
||||
- **Lint**: `task lint` or `golangci-lint run`
|
||||
- **Format**: `task fmt` or `gofmt -s -w .`
|
||||
- **Modernize**: `task modernize` or `modernize -fix ./...`
|
||||
|
||||
## Code Style Guidelines
|
||||
- **Package naming**: lowercase, single word (ai, openai, anthropic, google)
|
||||
- **Imports**: standard library first, then third-party, then local packages
|
||||
- **Error handling**: Use custom error types with structured fields, wrap with context
|
||||
- **Types**: Use type aliases for function signatures (`type Option = func(*options)`)
|
||||
- **Naming**: CamelCase for exported, camelCase for unexported
|
||||
- **Constants**: Use const blocks with descriptive names (ProviderName, DefaultURL)
|
||||
- **Structs**: Embed anonymous structs for composition (APICallError embeds *AIError)
|
||||
- **Functions**: Return error as last parameter, use context.Context as first param
|
||||
- **Testing**: Use testify/assert, table-driven tests, recorder pattern for HTTP mocking
|
||||
- **Comments**: Godoc format for exported functions, explain complex logic inline
|
||||
- **JSON**: Use struct tags for marshaling, handle empty values gracefully
|
||||
|
||||
## Project Structure
|
||||
- `/ai` - Core AI abstractions and agent logic
|
||||
- `/openai`, `/anthropic`, `/google` - Provider implementations
|
||||
- `/providertests` - Cross-provider integration tests with VCR recordings
|
||||
- `/examples` - Usage examples for different patterns
|
||||
Vendored
-177
@@ -1,177 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
Copyright 2025-2026 Charmbracelet, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Vendored
-98
@@ -1,98 +0,0 @@
|
||||
# Fantasy
|
||||
|
||||
<p>
|
||||
<img width="475" alt="The Charm Fantasy logo" src="https://github.com/user-attachments/assets/b22c5862-792a-44c1-bc98-55a2e46c8fb9" /><br>
|
||||
<a href="https://github.com/charmbracelet/fantasy/releases"><img src="https://img.shields.io/github/release/charmbracelet/fantasy.svg" alt="Latest Release"></a>
|
||||
<a href="https://pkg.go.dev/charm.land/fantasy?tab=doc"><img src="https://godoc.org/charm.land/fantasy?status.svg" alt="GoDoc"></a>
|
||||
<a href="https://github.com/charmbracelet/fantasy/actions"><img src="https://github.com/charmbracelet/fantasy/actions/workflows/build.yml/badge.svg?branch=main" alt="Build Status"></a>
|
||||
</p>
|
||||
|
||||
Build AI agents with Go. Multi-provider, multi-model, one API.
|
||||
|
||||
1. Choose a model and provider
|
||||
2. Add some tools
|
||||
3. Compile to native machine code and let it rip
|
||||
|
||||
> [!NOTE]
|
||||
> Fantasy is currently a preview. Expect API changes.
|
||||
|
||||
```go
|
||||
import "charm.land/fantasy"
|
||||
import "charm.land/fantasy/providers/openrouter"
|
||||
|
||||
// Choose your fave provider.
|
||||
provider, err := openrouter.New(openrouter.WithAPIKey(myHotKey))
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Whoops:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Pick your fave model.
|
||||
model, err := provider.LanguageModel(ctx, "moonshotai/kimi-k2")
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Dang:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Make your own tools.
|
||||
cuteDogTool := fantasy.NewAgentTool(
|
||||
"cute_dog_tool",
|
||||
"Provide up-to-date info on cute dogs.",
|
||||
fetchCuteDogInfoFunc,
|
||||
)
|
||||
|
||||
// Equip your agent.
|
||||
agent := fantasy.NewAgent(
|
||||
model,
|
||||
fantasy.WithSystemPrompt("You are a moderately helpful, dog-centric assistant."),
|
||||
fantasy.WithTools(cuteDogTool),
|
||||
)
|
||||
|
||||
// Put that agent to work!
|
||||
const prompt = "Find all the cute dogs in Silver Lake, Los Angeles."
|
||||
result, err := agent.Generate(ctx, fantasy.AgentCall{Prompt: prompt})
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Oof:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(result.Response.Content.Text())
|
||||
```
|
||||
|
||||
🍔 For the full implementation and more [see the examples directory](https://github.com/charmbracelet/fantasy/tree/main/examples).
|
||||
|
||||
## Multi-model? Multi-provider?
|
||||
|
||||
Yeah! Fantasy is designed to support a wide variety of providers and models under a single API. While many providers such as Microsoft Azure, Amazon Bedrock, and OpenRouter have dedicated packages in Fantasy, many others work just fine with `openaicompat`, the generic OpenAI-compatible layer. That said, if you find a provider that’s not compatible and needs special treatment, please let us know in an issue (or open a PR).
|
||||
|
||||
## Work in Progress
|
||||
|
||||
We built Fantasy to power [Crush](https://github.com/charmbracelet/crush), a hot coding agent for glamourously invincible development. Given that, Fantasy does not yet support things like:
|
||||
|
||||
- Image models
|
||||
- Audio models
|
||||
- PDF uploads
|
||||
- Provider tools (e.g. web_search)
|
||||
|
||||
For things you’d like to see supported, PRs are welcome.
|
||||
|
||||
## Whatcha think?
|
||||
|
||||
We’d love to hear your thoughts on this project. Need help? We gotchu. You can find us on:
|
||||
|
||||
- [Slack](https://charm.land/slack)
|
||||
- [Discord][discord]
|
||||
- [Twitter](https://twitter.com/charmcli)
|
||||
- [The Fediverse](https://mastodon.social/@charmcli)
|
||||
- [Bluesky](https://bsky.app/profile/charm.land)
|
||||
|
||||
[discord]: https://charm.land/discord
|
||||
|
||||
---
|
||||
|
||||
Part of [Charm](https://charm.land).
|
||||
|
||||
<a href="https://charm.land/"><img alt="The Charm logo" src="https://stuff.charm.sh/charm-banner-next.jpg" width="400"></a>
|
||||
|
||||
Charm热爱开源 • Charm loves open source
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
version: "3"
|
||||
|
||||
tasks:
|
||||
fmt:
|
||||
desc: Run gofumpt for all packages
|
||||
cmds:
|
||||
- gofumpt -w .
|
||||
|
||||
modernize:
|
||||
desc: Run modernize for all packages
|
||||
cmds:
|
||||
- modernize -fix ./...
|
||||
|
||||
lint:
|
||||
desc: Run base linters for all packages
|
||||
cmds:
|
||||
- golangci-lint run
|
||||
|
||||
lint:fix:
|
||||
desc: Run base linters for all packages and applies fixes if possible
|
||||
cmds:
|
||||
- golangci-lint run --fix
|
||||
|
||||
test:
|
||||
desc: Run tests for all packages
|
||||
cmds:
|
||||
- go test ./... -count=1 {{.CLI_ARGS}}
|
||||
release:
|
||||
desc: Create and push a new tag following semver
|
||||
vars:
|
||||
NEXT:
|
||||
sh: svu next --always || go run github.com/caarlos0/svu/v3@latest next --always
|
||||
prompt: "This will release {{.NEXT}}. Continue?"
|
||||
preconditions:
|
||||
- sh: '[ $(git symbolic-ref --short HEAD) = "main" ]'
|
||||
msg: Not on main branch
|
||||
- sh: "[ $(git status --porcelain=2 | wc -l) = 0 ]"
|
||||
msg: "Git is dirty"
|
||||
cmds:
|
||||
- git commit --allow-empty -m "{{.NEXT}}"
|
||||
- git tag --annotate --sign -m "{{.NEXT}}" {{.NEXT}} {{.CLI_ARGS}}
|
||||
- echo "Pushing {{.NEXT}}..."
|
||||
- git push origin main --follow-tags
|
||||
Vendored
-1426
File diff suppressed because it is too large.
Load diff
Vendored
-560
@@ -1,560 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// ProviderOptionsData is an interface for provider-specific options data.
|
||||
// All implementations MUST also implement encoding/json.Marshaler and
|
||||
// encoding/json.Unmarshaler interfaces to ensure proper JSON serialization
|
||||
// with the provider registry system.
|
||||
//
|
||||
// Recommended implementation pattern using generic helpers:
|
||||
//
|
||||
// // Define type constants at the top of your file
|
||||
// const TypeMyProviderOptions = "myprovider.options"
|
||||
//
|
||||
// type MyProviderOptions struct {
|
||||
// Field string `json:"field"`
|
||||
// }
|
||||
//
|
||||
// // Register the type in init() - place at top of file after constants
|
||||
// func init() {
|
||||
// fantasy.RegisterProviderType(TypeMyProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
// var opts MyProviderOptions
|
||||
// if err := json.Unmarshal(data, &opts); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return &opts, nil
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// // Implement ProviderOptionsData interface
|
||||
// func (*MyProviderOptions) Options() {}
|
||||
//
|
||||
// // Implement json.Marshaler using the generic helper
|
||||
// func (m MyProviderOptions) MarshalJSON() ([]byte, error) {
|
||||
// type plain MyProviderOptions
|
||||
// return fantasy.MarshalProviderType(TypeMyProviderOptions, plain(m))
|
||||
// }
|
||||
//
|
||||
// // Implement json.Unmarshaler using the generic helper
|
||||
// // Note: Receives inner data after type routing by the registry.
|
||||
// func (m *MyProviderOptions) UnmarshalJSON(data []byte) error {
|
||||
// type plain MyProviderOptions
|
||||
// var p plain
|
||||
// if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// *m = MyProviderOptions(p)
|
||||
// return nil
|
||||
// }
|
||||
type ProviderOptionsData interface {
|
||||
// Options is a marker method that identifies types implementing this interface.
|
||||
Options()
|
||||
json.Marshaler
|
||||
json.Unmarshaler
|
||||
}
|
||||
|
||||
// ProviderMetadata represents additional provider-specific metadata.
|
||||
// They are passed through from the provider to the AI SDK and enable
|
||||
// provider-specific results that can be fully encapsulated in the provider.
|
||||
//
|
||||
// The outer map is keyed by the provider name, and the inner
|
||||
// map is keyed by the provider-specific metadata key.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// {
|
||||
// "anthropic": {
|
||||
// "signature": "sig....."
|
||||
// }
|
||||
// }
|
||||
type ProviderMetadata map[string]ProviderOptionsData
|
||||
|
||||
// ProviderOptions represents additional provider-specific options.
|
||||
// Options are additional input to the provider. They are passed through
|
||||
// to the provider from the AI SDK and enable provider-specific functionality
|
||||
// that can be fully encapsulated in the provider.
|
||||
//
|
||||
// This enables us to quickly ship provider-specific functionality
|
||||
// without affecting the core AI SDK.
|
||||
//
|
||||
// The outer map is keyed by the provider name, and the inner
|
||||
// map is keyed by the provider-specific option key.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// {
|
||||
// "anthropic": {
|
||||
// "cacheControl": { "type": "ephemeral" }
|
||||
// }
|
||||
// }
|
||||
type ProviderOptions map[string]ProviderOptionsData
|
||||
|
||||
// FinishReason represents why a language model finished generating a response.
|
||||
//
|
||||
// Can be one of the following:
|
||||
// - `stop`: model generated stop sequence
|
||||
// - `length`: model generated maximum number of tokens
|
||||
// - `content-filter`: content filter violation stopped the model
|
||||
// - `tool-calls`: model triggered tool calls
|
||||
// - `error`: model stopped because of an error
|
||||
// - `other`: model stopped for other reasons
|
||||
// - `unknown`: the model has not transmitted a finish reason.
|
||||
type FinishReason string
|
||||
|
||||
const (
|
||||
// FinishReasonStop indicates the model generated a stop sequence.
|
||||
FinishReasonStop FinishReason = "stop" // model generated stop sequence
|
||||
// FinishReasonLength indicates the model generated maximum number of tokens.
|
||||
FinishReasonLength FinishReason = "length" // model generated maximum number of tokens
|
||||
// FinishReasonContentFilter indicates content filter violation stopped the model.
|
||||
FinishReasonContentFilter FinishReason = "content-filter" // content filter violation stopped the model
|
||||
// FinishReasonToolCalls indicates the model triggered tool calls.
|
||||
FinishReasonToolCalls FinishReason = "tool-calls" // model triggered tool calls
|
||||
// FinishReasonError indicates the model stopped because of an error.
|
||||
FinishReasonError FinishReason = "error" // model stopped because of an error
|
||||
// FinishReasonOther indicates the model stopped for other reasons.
|
||||
FinishReasonOther FinishReason = "other" // model stopped for other reasons
|
||||
// FinishReasonUnknown indicates the model has not transmitted a finish reason.
|
||||
FinishReasonUnknown FinishReason = "unknown" // the model has not transmitted a finish reason
|
||||
)
|
||||
|
||||
// Prompt represents a list of messages for the language model.
|
||||
type Prompt []Message
|
||||
|
||||
// MessageRole represents the role of a message.
|
||||
type MessageRole string
|
||||
|
||||
const (
|
||||
// MessageRoleSystem represents a system message.
|
||||
MessageRoleSystem MessageRole = "system"
|
||||
// MessageRoleUser represents a user message.
|
||||
MessageRoleUser MessageRole = "user"
|
||||
// MessageRoleAssistant represents an assistant message.
|
||||
MessageRoleAssistant MessageRole = "assistant"
|
||||
// MessageRoleTool represents a tool message.
|
||||
MessageRoleTool MessageRole = "tool"
|
||||
)
|
||||
|
||||
// Message represents a message in a prompt.
|
||||
type Message struct {
|
||||
Role MessageRole `json:"role"`
|
||||
Content []MessagePart `json:"content"`
|
||||
ProviderOptions ProviderOptions `json:"provider_options"`
|
||||
}
|
||||
|
||||
// AsContentType converts a Content interface to a specific content type.
|
||||
func AsContentType[T Content](content Content) (T, bool) {
|
||||
var zero T
|
||||
if content == nil {
|
||||
return zero, false
|
||||
}
|
||||
switch v := any(content).(type) {
|
||||
case T:
|
||||
return v, true
|
||||
case *T:
|
||||
return *v, true
|
||||
default:
|
||||
return zero, false
|
||||
}
|
||||
}
|
||||
|
||||
// AsMessagePart converts a MessagePart interface to a specific message part type.
|
||||
func AsMessagePart[T MessagePart](content MessagePart) (T, bool) {
|
||||
var zero T
|
||||
if content == nil {
|
||||
return zero, false
|
||||
}
|
||||
switch v := any(content).(type) {
|
||||
case T:
|
||||
return v, true
|
||||
case *T:
|
||||
return *v, true
|
||||
default:
|
||||
return zero, false
|
||||
}
|
||||
}
|
||||
|
||||
// MessagePart represents a part of a message content.
|
||||
type MessagePart interface {
|
||||
GetType() ContentType
|
||||
Options() ProviderOptions
|
||||
}
|
||||
|
||||
// TextPart represents text content in a message.
|
||||
type TextPart struct {
|
||||
Text string `json:"text"`
|
||||
ProviderOptions ProviderOptions `json:"provider_options"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the text part.
|
||||
func (t TextPart) GetType() ContentType {
|
||||
return ContentTypeText
|
||||
}
|
||||
|
||||
// Options returns the provider options for the text part.
|
||||
func (t TextPart) Options() ProviderOptions {
|
||||
return t.ProviderOptions
|
||||
}
|
||||
|
||||
// ReasoningPart represents reasoning content in a message.
|
||||
type ReasoningPart struct {
|
||||
Text string `json:"text"`
|
||||
ProviderOptions ProviderOptions `json:"provider_options"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the reasoning part.
|
||||
func (r ReasoningPart) GetType() ContentType {
|
||||
return ContentTypeReasoning
|
||||
}
|
||||
|
||||
// Options returns the provider options for the reasoning part.
|
||||
func (r ReasoningPart) Options() ProviderOptions {
|
||||
return r.ProviderOptions
|
||||
}
|
||||
|
||||
// FilePart represents file content in a message.
|
||||
type FilePart struct {
|
||||
Filename string `json:"filename"`
|
||||
Data []byte `json:"data"`
|
||||
MediaType string `json:"media_type"`
|
||||
ProviderOptions ProviderOptions `json:"provider_options"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the file part.
|
||||
func (f FilePart) GetType() ContentType {
|
||||
return ContentTypeFile
|
||||
}
|
||||
|
||||
// Options returns the provider options for the file part.
|
||||
func (f FilePart) Options() ProviderOptions {
|
||||
return f.ProviderOptions
|
||||
}
|
||||
|
||||
// ToolCallPart represents a tool call in a message.
|
||||
type ToolCallPart struct {
|
||||
ToolCallID string `json:"tool_call_id"`
|
||||
ToolName string `json:"tool_name"`
|
||||
Input string `json:"input"` // the json string
|
||||
ProviderExecuted bool `json:"provider_executed"`
|
||||
ProviderOptions ProviderOptions `json:"provider_options"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the tool call part.
|
||||
func (t ToolCallPart) GetType() ContentType {
|
||||
return ContentTypeToolCall
|
||||
}
|
||||
|
||||
// Options returns the provider options for the tool call part.
|
||||
func (t ToolCallPart) Options() ProviderOptions {
|
||||
return t.ProviderOptions
|
||||
}
|
||||
|
||||
// ToolResultPart represents a tool result in a message.
|
||||
type ToolResultPart struct {
|
||||
ToolCallID string `json:"tool_call_id"`
|
||||
Output ToolResultOutputContent `json:"output"`
|
||||
ProviderOptions ProviderOptions `json:"provider_options"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the tool result part.
|
||||
func (t ToolResultPart) GetType() ContentType {
|
||||
return ContentTypeToolResult
|
||||
}
|
||||
|
||||
// Options returns the provider options for the tool result part.
|
||||
func (t ToolResultPart) Options() ProviderOptions {
|
||||
return t.ProviderOptions
|
||||
}
|
||||
|
||||
// ToolResultContentType represents the type of tool result output.
|
||||
type ToolResultContentType string
|
||||
|
||||
const (
|
||||
// ToolResultContentTypeText represents text output.
|
||||
ToolResultContentTypeText ToolResultContentType = "text"
|
||||
// ToolResultContentTypeError represents error text output.
|
||||
ToolResultContentTypeError ToolResultContentType = "error"
|
||||
// ToolResultContentTypeMedia represents content output.
|
||||
ToolResultContentTypeMedia ToolResultContentType = "media"
|
||||
)
|
||||
|
||||
// ToolResultOutputContent represents the output content of a tool result.
|
||||
type ToolResultOutputContent interface {
|
||||
GetType() ToolResultContentType
|
||||
}
|
||||
|
||||
// ToolResultOutputContentText represents text output content of a tool result.
|
||||
type ToolResultOutputContentText struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the tool result output content text.
|
||||
func (t ToolResultOutputContentText) GetType() ToolResultContentType {
|
||||
return ToolResultContentTypeText
|
||||
}
|
||||
|
||||
// ToolResultOutputContentError represents error output content of a tool result.
|
||||
type ToolResultOutputContentError struct {
|
||||
Error error `json:"error"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the tool result output content error.
|
||||
func (t ToolResultOutputContentError) GetType() ToolResultContentType {
|
||||
return ToolResultContentTypeError
|
||||
}
|
||||
|
||||
// ToolResultOutputContentMedia represents media output content of a tool result.
|
||||
type ToolResultOutputContentMedia struct {
|
||||
Data string `json:"data"` // for media type (base64)
|
||||
MediaType string `json:"media_type"` // for media type
|
||||
Text string `json:"text,omitempty"` // optional text content accompanying the media
|
||||
}
|
||||
|
||||
// GetType returns the type of the tool result output content media.
|
||||
func (t ToolResultOutputContentMedia) GetType() ToolResultContentType {
|
||||
return ToolResultContentTypeMedia
|
||||
}
|
||||
|
||||
// AsToolResultOutputType converts a ToolResultOutputContent interface to a specific type.
|
||||
func AsToolResultOutputType[T ToolResultOutputContent](content ToolResultOutputContent) (T, bool) {
|
||||
var zero T
|
||||
if content == nil {
|
||||
return zero, false
|
||||
}
|
||||
switch v := any(content).(type) {
|
||||
case T:
|
||||
return v, true
|
||||
case *T:
|
||||
return *v, true
|
||||
default:
|
||||
return zero, false
|
||||
}
|
||||
}
|
||||
|
||||
// ContentType represents the type of content.
|
||||
type ContentType string
|
||||
|
||||
const (
|
||||
// ContentTypeText represents text content.
|
||||
ContentTypeText ContentType = "text"
|
||||
// ContentTypeReasoning represents reasoning content.
|
||||
ContentTypeReasoning ContentType = "reasoning"
|
||||
// ContentTypeFile represents file content.
|
||||
ContentTypeFile ContentType = "file"
|
||||
// ContentTypeSource represents source content.
|
||||
ContentTypeSource ContentType = "source"
|
||||
// ContentTypeToolCall represents a tool call.
|
||||
ContentTypeToolCall ContentType = "tool-call"
|
||||
// ContentTypeToolResult represents a tool result.
|
||||
ContentTypeToolResult ContentType = "tool-result"
|
||||
)
|
||||
|
||||
// Content represents generated content from the model.
|
||||
type Content interface {
|
||||
GetType() ContentType
|
||||
}
|
||||
|
||||
// TextContent represents text that the model has generated.
|
||||
type TextContent struct {
|
||||
// The text content.
|
||||
Text string `json:"text"`
|
||||
ProviderMetadata ProviderMetadata `json:"provider_metadata"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the text content.
|
||||
func (t TextContent) GetType() ContentType {
|
||||
return ContentTypeText
|
||||
}
|
||||
|
||||
// ReasoningContent represents reasoning that the model has generated.
|
||||
type ReasoningContent struct {
|
||||
Text string `json:"text"`
|
||||
ProviderMetadata ProviderMetadata `json:"provider_metadata"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the reasoning content.
|
||||
func (r ReasoningContent) GetType() ContentType {
|
||||
return ContentTypeReasoning
|
||||
}
|
||||
|
||||
// FileContent represents a file that has been generated by the model.
|
||||
// Generated files as base64 encoded strings or binary data.
|
||||
// The files should be returned without any unnecessary conversion.
|
||||
type FileContent struct {
|
||||
// The IANA media type of the file, e.g. `image/png` or `audio/mp3`.
|
||||
// @see https://www.iana.org/assignments/media-types/media-types.xhtml
|
||||
MediaType string `json:"media_type"`
|
||||
// Generated file data as binary data.
|
||||
Data []byte `json:"data"`
|
||||
ProviderMetadata ProviderMetadata `json:"provider_metadata"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the file content.
|
||||
func (f FileContent) GetType() ContentType {
|
||||
return ContentTypeFile
|
||||
}
|
||||
|
||||
// SourceType represents the type of source.
|
||||
type SourceType string
|
||||
|
||||
const (
|
||||
// SourceTypeURL represents a URL source.
|
||||
SourceTypeURL SourceType = "url"
|
||||
// SourceTypeDocument represents a document source.
|
||||
SourceTypeDocument SourceType = "document"
|
||||
)
|
||||
|
||||
// SourceContent represents a source that has been used as input to generate the response.
|
||||
type SourceContent struct {
|
||||
SourceType SourceType `json:"source_type"` // "url" or "document"
|
||||
ID string `json:"id"`
|
||||
URL string `json:"url"` // for URL sources
|
||||
Title string `json:"title"`
|
||||
MediaType string `json:"media_type"` // for document sources (IANA media type)
|
||||
Filename string `json:"filename"` // for document sources
|
||||
ProviderMetadata ProviderMetadata `json:"provider_metadata"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the source content.
|
||||
func (s SourceContent) GetType() ContentType {
|
||||
return ContentTypeSource
|
||||
}
|
||||
|
||||
// ToolCallContent represents tool calls that the model has generated.
|
||||
type ToolCallContent struct {
|
||||
ToolCallID string `json:"tool_call_id"`
|
||||
ToolName string `json:"tool_name"`
|
||||
// Stringified JSON object with the tool call arguments.
|
||||
// Must match the parameters schema of the tool.
|
||||
Input string `json:"input"`
|
||||
// Whether the tool call will be executed by the provider.
|
||||
// If this flag is not set or is false, the tool call will be executed by the client.
|
||||
ProviderExecuted bool `json:"provider_executed"`
|
||||
// Additional provider-specific metadata for the tool call.
|
||||
ProviderMetadata ProviderMetadata `json:"provider_metadata"`
|
||||
// Whether this tool call is invalid (failed validation/parsing)
|
||||
Invalid bool `json:"invalid,omitempty"`
|
||||
// Error that occurred during validation/parsing (only set if Invalid is true)
|
||||
ValidationError error `json:"validation_error,omitempty"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the tool call content.
|
||||
func (t ToolCallContent) GetType() ContentType {
|
||||
return ContentTypeToolCall
|
||||
}
|
||||
|
||||
// ToolResultContent represents result of a tool call that has been executed by the provider.
|
||||
type ToolResultContent struct {
|
||||
// The ID of the tool call that this result is associated with.
|
||||
ToolCallID string `json:"tool_call_id"`
|
||||
// Name of the tool that generated this result.
|
||||
ToolName string `json:"tool_name"`
|
||||
// Result of the tool call. This is a JSON-serializable object.
|
||||
Result ToolResultOutputContent `json:"result"`
|
||||
ClientMetadata string `json:"client_metadata"` // Metadata from the client that executed the tool
|
||||
// Whether the tool result was generated by the provider.
|
||||
// If this flag is set to true, the tool result was generated by the provider.
|
||||
// If this flag is not set or is false, the tool result was generated by the client.
|
||||
ProviderExecuted bool `json:"provider_executed"`
|
||||
// Additional provider-specific metadata for the tool result.
|
||||
ProviderMetadata ProviderMetadata `json:"provider_metadata"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the tool result content.
|
||||
func (t ToolResultContent) GetType() ContentType {
|
||||
return ContentTypeToolResult
|
||||
}
|
||||
|
||||
// ToolType represents the type of tool.
|
||||
type ToolType string
|
||||
|
||||
const (
|
||||
// ToolTypeFunction represents a function tool.
|
||||
ToolTypeFunction ToolType = "function"
|
||||
// ToolTypeProviderDefined represents a provider-defined tool.
|
||||
ToolTypeProviderDefined ToolType = "provider-defined"
|
||||
)
|
||||
|
||||
// Tool represents a tool that can be used by the model.
|
||||
//
|
||||
// Note: this is **not** the user-facing tool definition. The AI SDK methods will
|
||||
// map the user-facing tool definitions to this format.
|
||||
type Tool interface {
|
||||
GetType() ToolType
|
||||
GetName() string
|
||||
}
|
||||
|
||||
// FunctionTool represents a function tool.
|
||||
//
|
||||
// A tool has a name, a description, and a set of parameters.
|
||||
type FunctionTool struct {
|
||||
// Name of the tool. Unique within this model call.
|
||||
Name string `json:"name"`
|
||||
// Description of the tool. The language model uses this to understand the
|
||||
// tool's purpose and to provide better completion suggestions.
|
||||
Description string `json:"description"`
|
||||
// InputSchema - the parameters that the tool expects. The language model uses this to
|
||||
// understand the tool's input requirements and to provide matching suggestions.
|
||||
InputSchema map[string]any `json:"input_schema"` // JSON Schema
|
||||
// ProviderOptions are provider-specific options for the tool.
|
||||
ProviderOptions ProviderOptions `json:"provider_options"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the function tool.
|
||||
func (f FunctionTool) GetType() ToolType {
|
||||
return ToolTypeFunction
|
||||
}
|
||||
|
||||
// GetName returns the name of the function tool.
|
||||
func (f FunctionTool) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
// ProviderDefinedTool represents the configuration of a tool that is defined by the provider.
|
||||
type ProviderDefinedTool struct {
|
||||
// ID of the tool. Should follow the format `<provider-name>.<unique-tool-name>`.
|
||||
ID string `json:"id"`
|
||||
// Name of the tool that the user must use in the tool set.
|
||||
Name string `json:"name"`
|
||||
// Args for configuring the tool. Must match the expected arguments defined by the provider for this tool.
|
||||
Args map[string]any `json:"args"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the provider-defined tool.
|
||||
func (p ProviderDefinedTool) GetType() ToolType {
|
||||
return ToolTypeProviderDefined
|
||||
}
|
||||
|
||||
// GetName returns the name of the provider-defined tool.
|
||||
func (p ProviderDefinedTool) GetName() string {
|
||||
return p.Name
|
||||
}
|
||||
|
||||
// NewUserMessage creates a new user message with the given prompt and optional files.
|
||||
func NewUserMessage(prompt string, files ...FilePart) Message {
|
||||
content := make([]MessagePart, 0, len(files)+1)
|
||||
content = append(content, TextPart{Text: prompt})
|
||||
|
||||
for _, f := range files {
|
||||
content = append(content, f)
|
||||
}
|
||||
|
||||
return Message{
|
||||
Role: MessageRoleUser,
|
||||
Content: content,
|
||||
}
|
||||
}
|
||||
|
||||
// NewSystemMessage creates a new system message with the given prompts.
|
||||
func NewSystemMessage(prompt ...string) Message {
|
||||
content := make([]MessagePart, 0, len(prompt))
|
||||
for _, p := range prompt {
|
||||
content = append(content, TextPart{Text: p})
|
||||
}
|
||||
|
||||
return Message{
|
||||
Role: MessageRoleSystem,
|
||||
Content: content,
|
||||
}
|
||||
}
|
||||
-1038
File diff suppressed because it is too large.
Load diff
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"$schema": "https://charm.land/crush.json",
|
||||
"lsp": {
|
||||
"gopls": {}
|
||||
}
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
{"flagWords":[],"words":["mapstructure","mapstructure","charmbracelet","providertests","joho","godotenv","stretchr","Quantizations","Logit","Probs","openrouter","openaisdk","Logprobs","Includable"],"version":"0.2","language":"en"}
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
// Package fantasy provides a unified interface for interacting with various AI language models.
|
||||
package fantasy
|
||||
Vendored
-104
@@ -1,104 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/x/exp/slice"
|
||||
)
|
||||
|
||||
// Error is a custom error type for the fantasy package.
|
||||
type Error struct {
|
||||
Message string
|
||||
Title string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (err *Error) Error() string {
|
||||
if err.Title == "" {
|
||||
return err.Message
|
||||
}
|
||||
return fmt.Sprintf("%s: %s", err.Title, err.Message)
|
||||
}
|
||||
|
||||
func (err Error) Unwrap() error {
|
||||
return err.Cause
|
||||
}
|
||||
|
||||
// ProviderError represents an error returned by an external provider.
|
||||
type ProviderError struct {
|
||||
Message string
|
||||
Title string
|
||||
Cause error
|
||||
|
||||
URL string
|
||||
StatusCode int
|
||||
RequestBody []byte
|
||||
ResponseHeaders map[string]string
|
||||
ResponseBody []byte
|
||||
}
|
||||
|
||||
func (m *ProviderError) Error() string {
|
||||
if m.Title == "" {
|
||||
return m.Message
|
||||
}
|
||||
return fmt.Sprintf("%s: %s", m.Title, m.Message)
|
||||
}
|
||||
|
||||
// IsRetryable checks if the error is retryable based on the status code.
|
||||
func (m *ProviderError) IsRetryable() bool {
|
||||
return m.StatusCode == http.StatusRequestTimeout || m.StatusCode == http.StatusConflict || m.StatusCode == http.StatusTooManyRequests
|
||||
}
|
||||
|
||||
// RetryError represents an error that occurred during retry operations.
|
||||
type RetryError struct {
|
||||
Errors []error
|
||||
}
|
||||
|
||||
func (e *RetryError) Error() string {
|
||||
if err, ok := slice.Last(e.Errors); ok {
|
||||
return fmt.Sprintf("retry error: %v", err)
|
||||
}
|
||||
return "retry error: no underlying errors"
|
||||
}
|
||||
|
||||
func (e RetryError) Unwrap() error {
|
||||
if err, ok := slice.Last(e.Errors); ok {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ErrorTitleForStatusCode returns a human-readable title for a given HTTP status code.
|
||||
func ErrorTitleForStatusCode(statusCode int) string {
|
||||
return strings.ToLower(http.StatusText(statusCode))
|
||||
}
|
||||
|
||||
// NoObjectGeneratedError is returned when object generation fails
|
||||
// due to parsing errors, validation errors, or model failures.
|
||||
type NoObjectGeneratedError struct {
|
||||
RawText string
|
||||
ParseError error
|
||||
ValidationError error
|
||||
Usage Usage
|
||||
FinishReason FinishReason
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e *NoObjectGeneratedError) Error() string {
|
||||
if e.ValidationError != nil {
|
||||
return fmt.Sprintf("object validation failed: %v", e.ValidationError)
|
||||
}
|
||||
if e.ParseError != nil {
|
||||
return fmt.Sprintf("failed to parse object: %v", e.ParseError)
|
||||
}
|
||||
return "failed to generate object"
|
||||
}
|
||||
|
||||
// IsNoObjectGeneratedError checks if an error is of type NoObjectGeneratedError.
|
||||
func IsNoObjectGeneratedError(err error) bool {
|
||||
var target *NoObjectGeneratedError
|
||||
return errors.As(err, &target)
|
||||
}
|
||||
-1648
File diff suppressed because it is too large.
Load diff
Vendored
-258
@@ -1,258 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"iter"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Usage represents token usage statistics for a model call.
|
||||
type Usage struct {
|
||||
InputTokens int64 `json:"input_tokens"`
|
||||
OutputTokens int64 `json:"output_tokens"`
|
||||
TotalTokens int64 `json:"total_tokens"`
|
||||
ReasoningTokens int64 `json:"reasoning_tokens"`
|
||||
CacheCreationTokens int64 `json:"cache_creation_tokens"`
|
||||
CacheReadTokens int64 `json:"cache_read_tokens"`
|
||||
}
|
||||
|
||||
func (u Usage) String() string {
|
||||
return fmt.Sprintf("Usage{Input: %d, Output: %d, Total: %d, Reasoning: %d, CacheCreation: %d, CacheRead: %d}",
|
||||
u.InputTokens,
|
||||
u.OutputTokens,
|
||||
u.TotalTokens,
|
||||
u.ReasoningTokens,
|
||||
u.CacheCreationTokens,
|
||||
u.CacheReadTokens,
|
||||
)
|
||||
}
|
||||
|
||||
// ResponseContent represents the content of a model response.
|
||||
type ResponseContent []Content
|
||||
|
||||
// Text returns the text content of the response.
|
||||
func (r ResponseContent) Text() string {
|
||||
for _, c := range r {
|
||||
if c.GetType() == ContentTypeText {
|
||||
if textContent, ok := AsContentType[TextContent](c); ok {
|
||||
return textContent.Text
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Reasoning returns all reasoning content parts.
|
||||
func (r ResponseContent) Reasoning() []ReasoningContent {
|
||||
var reasoning []ReasoningContent
|
||||
for _, c := range r {
|
||||
if c.GetType() == ContentTypeReasoning {
|
||||
if reasoningContent, ok := AsContentType[ReasoningContent](c); ok {
|
||||
reasoning = append(reasoning, reasoningContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
return reasoning
|
||||
}
|
||||
|
||||
// ReasoningText returns all reasoning content as a concatenated string.
|
||||
func (r ResponseContent) ReasoningText() string {
|
||||
var builder strings.Builder
|
||||
for _, reasoning := range r.Reasoning() {
|
||||
builder.WriteString(reasoning.Text)
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// Files returns all file content parts.
|
||||
func (r ResponseContent) Files() []FileContent {
|
||||
var files []FileContent
|
||||
for _, c := range r {
|
||||
if c.GetType() == ContentTypeFile {
|
||||
if fileContent, ok := AsContentType[FileContent](c); ok {
|
||||
files = append(files, fileContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
// Sources returns all source content parts.
|
||||
func (r ResponseContent) Sources() []SourceContent {
|
||||
var sources []SourceContent
|
||||
for _, c := range r {
|
||||
if c.GetType() == ContentTypeSource {
|
||||
if sourceContent, ok := AsContentType[SourceContent](c); ok {
|
||||
sources = append(sources, sourceContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
// ToolCalls returns all tool call content parts.
|
||||
func (r ResponseContent) ToolCalls() []ToolCallContent {
|
||||
var toolCalls []ToolCallContent
|
||||
for _, c := range r {
|
||||
if c.GetType() == ContentTypeToolCall {
|
||||
if toolCallContent, ok := AsContentType[ToolCallContent](c); ok {
|
||||
toolCalls = append(toolCalls, toolCallContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
return toolCalls
|
||||
}
|
||||
|
||||
// ToolResults returns all tool result content parts.
|
||||
func (r ResponseContent) ToolResults() []ToolResultContent {
|
||||
var toolResults []ToolResultContent
|
||||
for _, c := range r {
|
||||
if c.GetType() == ContentTypeToolResult {
|
||||
if toolResultContent, ok := AsContentType[ToolResultContent](c); ok {
|
||||
toolResults = append(toolResults, toolResultContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
return toolResults
|
||||
}
|
||||
|
||||
// Response represents a response from a language model.
|
||||
type Response struct {
|
||||
Content ResponseContent `json:"content"`
|
||||
FinishReason FinishReason `json:"finish_reason"`
|
||||
Usage Usage `json:"usage"`
|
||||
Warnings []CallWarning `json:"warnings"`
|
||||
|
||||
// for provider specific response metadata, the key is the provider id
|
||||
ProviderMetadata ProviderMetadata `json:"provider_metadata"`
|
||||
}
|
||||
|
||||
// StreamPartType represents the type of a stream part.
|
||||
type StreamPartType string
|
||||
|
||||
const (
|
||||
// StreamPartTypeWarnings represents warnings stream part type.
|
||||
StreamPartTypeWarnings StreamPartType = "warnings"
|
||||
// StreamPartTypeTextStart represents text start stream part type.
|
||||
StreamPartTypeTextStart StreamPartType = "text_start"
|
||||
// StreamPartTypeTextDelta represents text delta stream part type.
|
||||
StreamPartTypeTextDelta StreamPartType = "text_delta"
|
||||
// StreamPartTypeTextEnd represents text end stream part type.
|
||||
StreamPartTypeTextEnd StreamPartType = "text_end"
|
||||
|
||||
// StreamPartTypeReasoningStart represents reasoning start stream part type.
|
||||
StreamPartTypeReasoningStart StreamPartType = "reasoning_start"
|
||||
// StreamPartTypeReasoningDelta represents reasoning delta stream part type.
|
||||
StreamPartTypeReasoningDelta StreamPartType = "reasoning_delta"
|
||||
// StreamPartTypeReasoningEnd represents reasoning end stream part type.
|
||||
StreamPartTypeReasoningEnd StreamPartType = "reasoning_end"
|
||||
// StreamPartTypeToolInputStart represents tool input start stream part type.
|
||||
StreamPartTypeToolInputStart StreamPartType = "tool_input_start"
|
||||
// StreamPartTypeToolInputDelta represents tool input delta stream part type.
|
||||
StreamPartTypeToolInputDelta StreamPartType = "tool_input_delta"
|
||||
// StreamPartTypeToolInputEnd represents tool input end stream part type.
|
||||
StreamPartTypeToolInputEnd StreamPartType = "tool_input_end"
|
||||
// StreamPartTypeToolCall represents tool call stream part type.
|
||||
StreamPartTypeToolCall StreamPartType = "tool_call"
|
||||
// StreamPartTypeToolResult represents tool result stream part type.
|
||||
StreamPartTypeToolResult StreamPartType = "tool_result"
|
||||
// StreamPartTypeSource represents source stream part type.
|
||||
StreamPartTypeSource StreamPartType = "source"
|
||||
// StreamPartTypeFinish represents finish stream part type.
|
||||
StreamPartTypeFinish StreamPartType = "finish"
|
||||
// StreamPartTypeError represents error stream part type.
|
||||
StreamPartTypeError StreamPartType = "error"
|
||||
)
|
||||
|
||||
// StreamPart represents a part of a streaming response.
|
||||
type StreamPart struct {
|
||||
Type StreamPartType `json:"type"`
|
||||
ID string `json:"id"`
|
||||
ToolCallName string `json:"tool_call_name"`
|
||||
ToolCallInput string `json:"tool_call_input"`
|
||||
Delta string `json:"delta"`
|
||||
ProviderExecuted bool `json:"provider_executed"`
|
||||
Usage Usage `json:"usage"`
|
||||
FinishReason FinishReason `json:"finish_reason"`
|
||||
Error error `json:"error"`
|
||||
Warnings []CallWarning `json:"warnings"`
|
||||
|
||||
// Source-related fields
|
||||
SourceType SourceType `json:"source_type"`
|
||||
URL string `json:"url"`
|
||||
Title string `json:"title"`
|
||||
|
||||
ProviderMetadata ProviderMetadata `json:"provider_metadata"`
|
||||
}
|
||||
|
||||
// StreamResponse represents a streaming response sequence.
|
||||
type StreamResponse = iter.Seq[StreamPart]
|
||||
|
||||
// ToolChoice represents the tool choice preference for a model call.
|
||||
type ToolChoice string
|
||||
|
||||
const (
|
||||
// ToolChoiceNone indicates no tools should be used.
|
||||
ToolChoiceNone ToolChoice = "none"
|
||||
// ToolChoiceAuto indicates tools should be used automatically.
|
||||
ToolChoiceAuto ToolChoice = "auto"
|
||||
// ToolChoiceRequired indicates tools are required.
|
||||
ToolChoiceRequired ToolChoice = "required"
|
||||
)
|
||||
|
||||
// SpecificToolChoice creates a tool choice for a specific tool name.
|
||||
func SpecificToolChoice(name string) ToolChoice {
|
||||
return ToolChoice(name)
|
||||
}
|
||||
|
||||
// Call represents a call to a language model.
|
||||
type Call struct {
|
||||
Prompt Prompt `json:"prompt"`
|
||||
MaxOutputTokens *int64 `json:"max_output_tokens"`
|
||||
Temperature *float64 `json:"temperature"`
|
||||
TopP *float64 `json:"top_p"`
|
||||
TopK *int64 `json:"top_k"`
|
||||
PresencePenalty *float64 `json:"presence_penalty"`
|
||||
FrequencyPenalty *float64 `json:"frequency_penalty"`
|
||||
Tools []Tool `json:"tools"`
|
||||
ToolChoice *ToolChoice `json:"tool_choice"`
|
||||
|
||||
// for provider specific options, the key is the provider id
|
||||
ProviderOptions ProviderOptions `json:"provider_options"`
|
||||
}
|
||||
|
||||
// CallWarningType represents the type of call warning.
|
||||
type CallWarningType string
|
||||
|
||||
const (
|
||||
// CallWarningTypeUnsupportedSetting indicates an unsupported setting.
|
||||
CallWarningTypeUnsupportedSetting CallWarningType = "unsupported-setting"
|
||||
// CallWarningTypeUnsupportedTool indicates an unsupported tool.
|
||||
CallWarningTypeUnsupportedTool CallWarningType = "unsupported-tool"
|
||||
// CallWarningTypeOther indicates other warnings.
|
||||
CallWarningTypeOther CallWarningType = "other"
|
||||
)
|
||||
|
||||
// CallWarning represents a warning from the model provider for this call.
|
||||
// The call will proceed, but e.g. some settings might not be supported,
|
||||
// which can lead to suboptimal results.
|
||||
type CallWarning struct {
|
||||
Type CallWarningType `json:"type"`
|
||||
Setting string `json:"setting"`
|
||||
Tool Tool `json:"tool"`
|
||||
Details string `json:"details"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// LanguageModel represents a language model that can generate responses and stream responses.
|
||||
type LanguageModel interface {
|
||||
Generate(context.Context, Call) (*Response, error)
|
||||
Stream(context.Context, Call) (StreamResponse, error)
|
||||
|
||||
GenerateObject(context.Context, ObjectCall) (*ObjectResponse, error)
|
||||
StreamObject(context.Context, ObjectCall) (ObjectStreamResponse, error)
|
||||
|
||||
Provider() string
|
||||
Model() string
|
||||
}
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler for Call.
|
||||
func (c *Call) UnmarshalJSON(data []byte) error {
|
||||
var aux struct {
|
||||
Prompt Prompt `json:"prompt"`
|
||||
MaxOutputTokens *int64 `json:"max_output_tokens"`
|
||||
Temperature *float64 `json:"temperature"`
|
||||
TopP *float64 `json:"top_p"`
|
||||
TopK *int64 `json:"top_k"`
|
||||
PresencePenalty *float64 `json:"presence_penalty"`
|
||||
FrequencyPenalty *float64 `json:"frequency_penalty"`
|
||||
Tools []json.RawMessage `json:"tools"`
|
||||
ToolChoice *ToolChoice `json:"tool_choice"`
|
||||
ProviderOptions map[string]json.RawMessage `json:"provider_options"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Prompt = aux.Prompt
|
||||
c.MaxOutputTokens = aux.MaxOutputTokens
|
||||
c.Temperature = aux.Temperature
|
||||
c.TopP = aux.TopP
|
||||
c.TopK = aux.TopK
|
||||
c.PresencePenalty = aux.PresencePenalty
|
||||
c.FrequencyPenalty = aux.FrequencyPenalty
|
||||
c.ToolChoice = aux.ToolChoice
|
||||
|
||||
// Unmarshal Tools slice
|
||||
c.Tools = make([]Tool, len(aux.Tools))
|
||||
for i, rawTool := range aux.Tools {
|
||||
tool, err := UnmarshalTool(rawTool)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal tool at index %d: %w", i, err)
|
||||
}
|
||||
c.Tools[i] = tool
|
||||
}
|
||||
|
||||
// Unmarshal ProviderOptions
|
||||
if len(aux.ProviderOptions) > 0 {
|
||||
options, err := UnmarshalProviderOptions(aux.ProviderOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.ProviderOptions = options
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler for Response.
|
||||
func (r *Response) UnmarshalJSON(data []byte) error {
|
||||
var aux struct {
|
||||
Content json.RawMessage `json:"content"`
|
||||
FinishReason FinishReason `json:"finish_reason"`
|
||||
Usage Usage `json:"usage"`
|
||||
Warnings []CallWarning `json:"warnings"`
|
||||
ProviderMetadata map[string]json.RawMessage `json:"provider_metadata"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.FinishReason = aux.FinishReason
|
||||
r.Usage = aux.Usage
|
||||
r.Warnings = aux.Warnings
|
||||
|
||||
// Unmarshal ResponseContent (need to know the type definition)
|
||||
// If ResponseContent is []Content:
|
||||
var rawContent []json.RawMessage
|
||||
if err := json.Unmarshal(aux.Content, &rawContent); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
content := make([]Content, len(rawContent))
|
||||
for i, rawItem := range rawContent {
|
||||
item, err := UnmarshalContent(rawItem)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal content at index %d: %w", i, err)
|
||||
}
|
||||
content[i] = item
|
||||
}
|
||||
r.Content = content
|
||||
|
||||
// Unmarshal ProviderMetadata
|
||||
if len(aux.ProviderMetadata) > 0 {
|
||||
metadata, err := UnmarshalProviderMetadata(aux.ProviderMetadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.ProviderMetadata = metadata
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler for StreamPart.
|
||||
func (s StreamPart) MarshalJSON() ([]byte, error) {
|
||||
type alias StreamPart
|
||||
aux := struct {
|
||||
alias
|
||||
Error string `json:"error,omitempty"`
|
||||
}{
|
||||
alias: (alias)(s),
|
||||
}
|
||||
|
||||
// Marshal error to string
|
||||
if s.Error != nil {
|
||||
aux.Error = s.Error.Error()
|
||||
}
|
||||
|
||||
// Clear the original Error field to avoid duplicate marshaling
|
||||
aux.alias.Error = nil
|
||||
|
||||
return json.Marshal(aux)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler for StreamPart.
|
||||
func (s *StreamPart) UnmarshalJSON(data []byte) error {
|
||||
type alias StreamPart
|
||||
aux := struct {
|
||||
*alias
|
||||
Error string `json:"error"`
|
||||
ProviderMetadata map[string]json.RawMessage `json:"provider_metadata"`
|
||||
}{
|
||||
alias: (*alias)(s),
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Unmarshal error string back to error type
|
||||
if aux.Error != "" {
|
||||
s.Error = fmt.Errorf("%s", aux.Error)
|
||||
}
|
||||
|
||||
// Unmarshal ProviderMetadata
|
||||
if len(aux.ProviderMetadata) > 0 {
|
||||
metadata, err := UnmarshalProviderMetadata(aux.ProviderMetadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.ProviderMetadata = metadata
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Vendored
-233
@@ -1,233 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"iter"
|
||||
"reflect"
|
||||
|
||||
"charm.land/fantasy/schema"
|
||||
)
|
||||
|
||||
// ObjectMode specifies how structured output should be generated.
|
||||
type ObjectMode string
|
||||
|
||||
const (
|
||||
// ObjectModeAuto lets the provider choose the best approach.
|
||||
ObjectModeAuto ObjectMode = "auto"
|
||||
|
||||
// ObjectModeJSON forces the use of native JSON mode (if supported).
|
||||
ObjectModeJSON ObjectMode = "json"
|
||||
|
||||
// ObjectModeTool forces the use of tool-based approach.
|
||||
ObjectModeTool ObjectMode = "tool"
|
||||
|
||||
// ObjectModeText uses text generation with schema in prompt (fallback for models without tool/JSON support).
|
||||
ObjectModeText ObjectMode = "text"
|
||||
)
|
||||
|
||||
// ObjectCall represents a request to generate a structured object.
|
||||
type ObjectCall struct {
|
||||
Prompt Prompt
|
||||
Schema Schema
|
||||
SchemaName string
|
||||
SchemaDescription string
|
||||
|
||||
MaxOutputTokens *int64
|
||||
Temperature *float64
|
||||
TopP *float64
|
||||
TopK *int64
|
||||
PresencePenalty *float64
|
||||
FrequencyPenalty *float64
|
||||
|
||||
ProviderOptions ProviderOptions
|
||||
|
||||
RepairText schema.ObjectRepairFunc
|
||||
}
|
||||
|
||||
// ObjectResponse represents the response from a structured object generation.
|
||||
type ObjectResponse struct {
|
||||
Object any
|
||||
RawText string
|
||||
Usage Usage
|
||||
FinishReason FinishReason
|
||||
Warnings []CallWarning
|
||||
ProviderMetadata ProviderMetadata
|
||||
}
|
||||
|
||||
// ObjectStreamPartType indicates the type of stream part.
|
||||
type ObjectStreamPartType string
|
||||
|
||||
const (
|
||||
// ObjectStreamPartTypeObject is emitted when a new partial object is available.
|
||||
ObjectStreamPartTypeObject ObjectStreamPartType = "object"
|
||||
|
||||
// ObjectStreamPartTypeTextDelta is emitted for text deltas (if model generates text).
|
||||
ObjectStreamPartTypeTextDelta ObjectStreamPartType = "text-delta"
|
||||
|
||||
// ObjectStreamPartTypeError is emitted when an error occurs.
|
||||
ObjectStreamPartTypeError ObjectStreamPartType = "error"
|
||||
|
||||
// ObjectStreamPartTypeFinish is emitted when streaming completes.
|
||||
ObjectStreamPartTypeFinish ObjectStreamPartType = "finish"
|
||||
)
|
||||
|
||||
// ObjectStreamPart represents a single chunk in the object stream.
|
||||
type ObjectStreamPart struct {
|
||||
Type ObjectStreamPartType
|
||||
Object any
|
||||
Delta string
|
||||
Error error
|
||||
Usage Usage
|
||||
FinishReason FinishReason
|
||||
Warnings []CallWarning
|
||||
ProviderMetadata ProviderMetadata
|
||||
}
|
||||
|
||||
// ObjectStreamResponse is an iterator over ObjectStreamPart.
|
||||
type ObjectStreamResponse = iter.Seq[ObjectStreamPart]
|
||||
|
||||
// ObjectResult is a typed result wrapper returned by GenerateObject[T].
|
||||
type ObjectResult[T any] struct {
|
||||
Object T
|
||||
RawText string
|
||||
Usage Usage
|
||||
FinishReason FinishReason
|
||||
Warnings []CallWarning
|
||||
ProviderMetadata ProviderMetadata
|
||||
}
|
||||
|
||||
// StreamObjectResult provides typed access to a streaming object generation result.
|
||||
type StreamObjectResult[T any] struct {
|
||||
stream ObjectStreamResponse
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewStreamObjectResult creates a typed stream result from an untyped stream.
|
||||
func NewStreamObjectResult[T any](ctx context.Context, stream ObjectStreamResponse) *StreamObjectResult[T] {
|
||||
return &StreamObjectResult[T]{
|
||||
stream: stream,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// PartialObjectStream returns an iterator that yields progressively more complete objects.
|
||||
// Only emits when the object actually changes (deduplication).
|
||||
func (s *StreamObjectResult[T]) PartialObjectStream() iter.Seq[T] {
|
||||
return func(yield func(T) bool) {
|
||||
var lastObject T
|
||||
var hasEmitted bool
|
||||
|
||||
for part := range s.stream {
|
||||
if part.Type == ObjectStreamPartTypeObject && part.Object != nil {
|
||||
var current T
|
||||
if err := unmarshalObject(part.Object, ¤t); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !hasEmitted || !reflect.DeepEqual(current, lastObject) {
|
||||
if !yield(current) {
|
||||
return
|
||||
}
|
||||
lastObject = current
|
||||
hasEmitted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TextStream returns an iterator that yields text deltas.
|
||||
// Useful if the model generates explanatory text alongside the object.
|
||||
func (s *StreamObjectResult[T]) TextStream() iter.Seq[string] {
|
||||
return func(yield func(string) bool) {
|
||||
for part := range s.stream {
|
||||
if part.Type == ObjectStreamPartTypeTextDelta && part.Delta != "" {
|
||||
if !yield(part.Delta) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FullStream returns an iterator that yields all stream parts including errors and metadata.
|
||||
func (s *StreamObjectResult[T]) FullStream() iter.Seq[ObjectStreamPart] {
|
||||
return s.stream
|
||||
}
|
||||
|
||||
// Object waits for the stream to complete and returns the final object.
|
||||
// Returns an error if streaming fails or no valid object was generated.
|
||||
func (s *StreamObjectResult[T]) Object() (*ObjectResult[T], error) {
|
||||
var finalObject T
|
||||
var usage Usage
|
||||
var finishReason FinishReason
|
||||
var warnings []CallWarning
|
||||
var providerMetadata ProviderMetadata
|
||||
var rawText string
|
||||
var lastError error
|
||||
hasObject := false
|
||||
|
||||
for part := range s.stream {
|
||||
switch part.Type {
|
||||
case ObjectStreamPartTypeObject:
|
||||
if part.Object != nil {
|
||||
if err := unmarshalObject(part.Object, &finalObject); err == nil {
|
||||
hasObject = true
|
||||
if jsonBytes, err := json.Marshal(part.Object); err == nil {
|
||||
rawText = string(jsonBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case ObjectStreamPartTypeError:
|
||||
lastError = part.Error
|
||||
|
||||
case ObjectStreamPartTypeFinish:
|
||||
usage = part.Usage
|
||||
finishReason = part.FinishReason
|
||||
if len(part.Warnings) > 0 {
|
||||
warnings = part.Warnings
|
||||
}
|
||||
if len(part.ProviderMetadata) > 0 {
|
||||
providerMetadata = part.ProviderMetadata
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if lastError != nil {
|
||||
return nil, lastError
|
||||
}
|
||||
|
||||
if !hasObject {
|
||||
return nil, &NoObjectGeneratedError{
|
||||
RawText: rawText,
|
||||
ParseError: fmt.Errorf("no valid object generated in stream"),
|
||||
Usage: usage,
|
||||
FinishReason: finishReason,
|
||||
}
|
||||
}
|
||||
|
||||
return &ObjectResult[T]{
|
||||
Object: finalObject,
|
||||
RawText: rawText,
|
||||
Usage: usage,
|
||||
FinishReason: finishReason,
|
||||
Warnings: warnings,
|
||||
ProviderMetadata: providerMetadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func unmarshalObject(obj any, target any) error {
|
||||
jsonBytes, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal object: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(jsonBytes, target); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal into target type: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
-616
@@ -1,616 +0,0 @@
|
||||
// Package object provides utilities for generating structured objects with automatic schema generation.
|
||||
// It simplifies working with typed structured outputs by handling schema reflection and unmarshaling.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"charm.land/fantasy/schema"
|
||||
)
|
||||
|
||||
// Generate generates a structured object that matches the given type T.
|
||||
// The schema is automatically generated from T using reflection.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// type Recipe struct {
|
||||
// Name string `json:"name"`
|
||||
// Ingredients []string `json:"ingredients"`
|
||||
// }
|
||||
//
|
||||
// result, err := object.Generate[Recipe](ctx, model, fantasy.ObjectCall{
|
||||
// Prompt: fantasy.Prompt{fantasy.NewUserMessage("Generate a lasagna recipe")},
|
||||
// })
|
||||
func Generate[T any](
|
||||
ctx context.Context,
|
||||
model fantasy.LanguageModel,
|
||||
opts fantasy.ObjectCall,
|
||||
) (*fantasy.ObjectResult[T], error) {
|
||||
var zero T
|
||||
s := schema.Generate(reflect.TypeOf(zero))
|
||||
opts.Schema = s
|
||||
|
||||
resp, err := model.GenerateObject(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result T
|
||||
if err := unmarshal(resp.Object, &result); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal to %T: %w", result, err)
|
||||
}
|
||||
|
||||
return &fantasy.ObjectResult[T]{
|
||||
Object: result,
|
||||
RawText: resp.RawText,
|
||||
Usage: resp.Usage,
|
||||
FinishReason: resp.FinishReason,
|
||||
Warnings: resp.Warnings,
|
||||
ProviderMetadata: resp.ProviderMetadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Stream streams a structured object that matches the given type T.
|
||||
// Returns a StreamObjectResult[T] with progressive updates and deduplication.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// stream, err := object.Stream[Recipe](ctx, model, fantasy.ObjectCall{
|
||||
// Prompt: fantasy.Prompt{fantasy.NewUserMessage("Generate a lasagna recipe")},
|
||||
// })
|
||||
//
|
||||
// for partial := range stream.PartialObjectStream() {
|
||||
// fmt.Printf("Progress: %s\n", partial.Name)
|
||||
// }
|
||||
//
|
||||
// result, err := stream.Object() // Wait for final result
|
||||
func Stream[T any](
|
||||
ctx context.Context,
|
||||
model fantasy.LanguageModel,
|
||||
opts fantasy.ObjectCall,
|
||||
) (*fantasy.StreamObjectResult[T], error) {
|
||||
var zero T
|
||||
s := schema.Generate(reflect.TypeOf(zero))
|
||||
opts.Schema = s
|
||||
|
||||
stream, err := model.StreamObject(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return fantasy.NewStreamObjectResult[T](ctx, stream), nil
|
||||
}
|
||||
|
||||
// GenerateWithTool is a helper for providers without native JSON mode.
|
||||
// It converts the schema to a tool definition, forces the model to call it,
|
||||
// and extracts the tool's input as the structured output.
|
||||
func GenerateWithTool(
|
||||
ctx context.Context,
|
||||
model fantasy.LanguageModel,
|
||||
call fantasy.ObjectCall,
|
||||
) (*fantasy.ObjectResponse, error) {
|
||||
toolName := call.SchemaName
|
||||
if toolName == "" {
|
||||
toolName = "generate_object"
|
||||
}
|
||||
|
||||
toolDescription := call.SchemaDescription
|
||||
if toolDescription == "" {
|
||||
toolDescription = "Generate a structured object matching the schema"
|
||||
}
|
||||
|
||||
tool := fantasy.FunctionTool{
|
||||
Name: toolName,
|
||||
Description: toolDescription,
|
||||
InputSchema: schema.ToMap(call.Schema),
|
||||
}
|
||||
|
||||
toolChoice := fantasy.SpecificToolChoice(tool.Name)
|
||||
resp, err := model.Generate(ctx, fantasy.Call{
|
||||
Prompt: call.Prompt,
|
||||
Tools: []fantasy.Tool{tool},
|
||||
ToolChoice: &toolChoice,
|
||||
MaxOutputTokens: call.MaxOutputTokens,
|
||||
Temperature: call.Temperature,
|
||||
TopP: call.TopP,
|
||||
TopK: call.TopK,
|
||||
PresencePenalty: call.PresencePenalty,
|
||||
FrequencyPenalty: call.FrequencyPenalty,
|
||||
ProviderOptions: call.ProviderOptions,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tool-based generation failed: %w", err)
|
||||
}
|
||||
|
||||
toolCalls := resp.Content.ToolCalls()
|
||||
if len(toolCalls) == 0 {
|
||||
return nil, &fantasy.NoObjectGeneratedError{
|
||||
RawText: resp.Content.Text(),
|
||||
ParseError: fmt.Errorf("no tool call generated"),
|
||||
Usage: resp.Usage,
|
||||
FinishReason: resp.FinishReason,
|
||||
}
|
||||
}
|
||||
|
||||
toolCall := toolCalls[0]
|
||||
|
||||
var obj any
|
||||
if call.RepairText != nil {
|
||||
obj, err = schema.ParseAndValidateWithRepair(ctx, toolCall.Input, call.Schema, call.RepairText)
|
||||
} else {
|
||||
obj, err = schema.ParseAndValidate(toolCall.Input, call.Schema)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if nogErr, ok := err.(*fantasy.NoObjectGeneratedError); ok {
|
||||
nogErr.Usage = resp.Usage
|
||||
nogErr.FinishReason = resp.FinishReason
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &fantasy.ObjectResponse{
|
||||
Object: obj,
|
||||
RawText: toolCall.Input,
|
||||
Usage: resp.Usage,
|
||||
FinishReason: resp.FinishReason,
|
||||
Warnings: resp.Warnings,
|
||||
ProviderMetadata: resp.ProviderMetadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateWithText is a helper for providers without tool or JSON mode support.
|
||||
// It adds the schema to the system prompt and parses the text response as JSON.
|
||||
// This is a fallback for older models or simple providers.
|
||||
func GenerateWithText(
|
||||
ctx context.Context,
|
||||
model fantasy.LanguageModel,
|
||||
call fantasy.ObjectCall,
|
||||
) (*fantasy.ObjectResponse, error) {
|
||||
jsonSchemaBytes, err := json.Marshal(call.Schema)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal schema: %w", err)
|
||||
}
|
||||
|
||||
schemaInstruction := fmt.Sprintf(
|
||||
"You must respond with valid JSON that matches this schema: %s\n"+
|
||||
"Respond ONLY with the JSON object, no additional text or explanation.",
|
||||
string(jsonSchemaBytes),
|
||||
)
|
||||
|
||||
enhancedPrompt := make(fantasy.Prompt, 0, len(call.Prompt)+1)
|
||||
|
||||
hasSystem := false
|
||||
for _, msg := range call.Prompt {
|
||||
if msg.Role == fantasy.MessageRoleSystem {
|
||||
hasSystem = true
|
||||
existingText := ""
|
||||
if len(msg.Content) > 0 {
|
||||
if textPart, ok := msg.Content[0].(fantasy.TextPart); ok {
|
||||
existingText = textPart.Text
|
||||
}
|
||||
}
|
||||
enhancedPrompt = append(enhancedPrompt, fantasy.NewSystemMessage(existingText+"\n\n"+schemaInstruction))
|
||||
} else {
|
||||
enhancedPrompt = append(enhancedPrompt, msg)
|
||||
}
|
||||
}
|
||||
|
||||
if !hasSystem {
|
||||
enhancedPrompt = append(fantasy.Prompt{fantasy.NewSystemMessage(schemaInstruction)}, call.Prompt...)
|
||||
}
|
||||
|
||||
resp, err := model.Generate(ctx, fantasy.Call{
|
||||
Prompt: enhancedPrompt,
|
||||
MaxOutputTokens: call.MaxOutputTokens,
|
||||
Temperature: call.Temperature,
|
||||
TopP: call.TopP,
|
||||
TopK: call.TopK,
|
||||
PresencePenalty: call.PresencePenalty,
|
||||
FrequencyPenalty: call.FrequencyPenalty,
|
||||
ProviderOptions: call.ProviderOptions,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("text-based generation failed: %w", err)
|
||||
}
|
||||
|
||||
textContent := resp.Content.Text()
|
||||
if textContent == "" {
|
||||
return nil, &fantasy.NoObjectGeneratedError{
|
||||
RawText: "",
|
||||
ParseError: fmt.Errorf("no text content in response"),
|
||||
Usage: resp.Usage,
|
||||
FinishReason: resp.FinishReason,
|
||||
}
|
||||
}
|
||||
|
||||
var obj any
|
||||
if call.RepairText != nil {
|
||||
obj, err = schema.ParseAndValidateWithRepair(ctx, textContent, call.Schema, call.RepairText)
|
||||
} else {
|
||||
obj, err = schema.ParseAndValidate(textContent, call.Schema)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if nogErr, ok := err.(*schema.ParseError); ok {
|
||||
return nil, &fantasy.NoObjectGeneratedError{
|
||||
RawText: nogErr.RawText,
|
||||
ParseError: nogErr.ParseError,
|
||||
ValidationError: nogErr.ValidationError,
|
||||
Usage: resp.Usage,
|
||||
FinishReason: resp.FinishReason,
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &fantasy.ObjectResponse{
|
||||
Object: obj,
|
||||
RawText: textContent,
|
||||
Usage: resp.Usage,
|
||||
FinishReason: resp.FinishReason,
|
||||
Warnings: resp.Warnings,
|
||||
ProviderMetadata: resp.ProviderMetadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StreamWithTool is a helper for providers without native JSON streaming.
|
||||
// It uses streaming tool calls to extract and parse the structured output progressively.
|
||||
func StreamWithTool(
|
||||
ctx context.Context,
|
||||
model fantasy.LanguageModel,
|
||||
call fantasy.ObjectCall,
|
||||
) (fantasy.ObjectStreamResponse, error) {
|
||||
// Create a tool from the schema
|
||||
toolName := call.SchemaName
|
||||
if toolName == "" {
|
||||
toolName = "generate_object"
|
||||
}
|
||||
|
||||
toolDescription := call.SchemaDescription
|
||||
if toolDescription == "" {
|
||||
toolDescription = "Generate a structured object matching the schema"
|
||||
}
|
||||
|
||||
tool := fantasy.FunctionTool{
|
||||
Name: toolName,
|
||||
Description: toolDescription,
|
||||
InputSchema: schema.ToMap(call.Schema),
|
||||
}
|
||||
|
||||
// Make a streaming Generate call with forced tool choice
|
||||
toolChoice := fantasy.SpecificToolChoice(tool.Name)
|
||||
stream, err := model.Stream(ctx, fantasy.Call{
|
||||
Prompt: call.Prompt,
|
||||
Tools: []fantasy.Tool{tool},
|
||||
ToolChoice: &toolChoice,
|
||||
MaxOutputTokens: call.MaxOutputTokens,
|
||||
Temperature: call.Temperature,
|
||||
TopP: call.TopP,
|
||||
TopK: call.TopK,
|
||||
PresencePenalty: call.PresencePenalty,
|
||||
FrequencyPenalty: call.FrequencyPenalty,
|
||||
ProviderOptions: call.ProviderOptions,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tool-based streaming failed: %w", err)
|
||||
}
|
||||
|
||||
// Convert the text stream to object stream parts
|
||||
return func(yield func(fantasy.ObjectStreamPart) bool) {
|
||||
var accumulated string
|
||||
var lastParsedObject any
|
||||
var usage fantasy.Usage
|
||||
var finishReason fantasy.FinishReason
|
||||
var warnings []fantasy.CallWarning
|
||||
var providerMetadata fantasy.ProviderMetadata
|
||||
var streamErr error
|
||||
|
||||
for part := range stream {
|
||||
switch part.Type {
|
||||
case fantasy.StreamPartTypeTextDelta:
|
||||
accumulated += part.Delta
|
||||
|
||||
obj, state, parseErr := schema.ParsePartialJSON(accumulated)
|
||||
|
||||
if state == schema.ParseStateSuccessful || state == schema.ParseStateRepaired {
|
||||
if err := schema.ValidateAgainstSchema(obj, call.Schema); err == nil {
|
||||
if !reflect.DeepEqual(obj, lastParsedObject) {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Object: obj,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
lastParsedObject = obj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if state == schema.ParseStateFailed && call.RepairText != nil {
|
||||
repairedText, repairErr := call.RepairText(ctx, accumulated, parseErr)
|
||||
if repairErr == nil {
|
||||
obj2, state2, _ := schema.ParsePartialJSON(repairedText)
|
||||
if (state2 == schema.ParseStateSuccessful || state2 == schema.ParseStateRepaired) &&
|
||||
schema.ValidateAgainstSchema(obj2, call.Schema) == nil {
|
||||
if !reflect.DeepEqual(obj2, lastParsedObject) {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Object: obj2,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
lastParsedObject = obj2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case fantasy.StreamPartTypeToolInputDelta:
|
||||
accumulated += part.Delta
|
||||
|
||||
obj, state, parseErr := schema.ParsePartialJSON(accumulated)
|
||||
if state == schema.ParseStateSuccessful || state == schema.ParseStateRepaired {
|
||||
if err := schema.ValidateAgainstSchema(obj, call.Schema); err == nil {
|
||||
if !reflect.DeepEqual(obj, lastParsedObject) {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Object: obj,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
lastParsedObject = obj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if state == schema.ParseStateFailed && call.RepairText != nil {
|
||||
repairedText, repairErr := call.RepairText(ctx, accumulated, parseErr)
|
||||
if repairErr == nil {
|
||||
obj2, state2, _ := schema.ParsePartialJSON(repairedText)
|
||||
if (state2 == schema.ParseStateSuccessful || state2 == schema.ParseStateRepaired) &&
|
||||
schema.ValidateAgainstSchema(obj2, call.Schema) == nil {
|
||||
if !reflect.DeepEqual(obj2, lastParsedObject) {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Object: obj2,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
lastParsedObject = obj2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case fantasy.StreamPartTypeToolCall:
|
||||
toolInput := part.ToolCallInput
|
||||
|
||||
var obj any
|
||||
var err error
|
||||
if call.RepairText != nil {
|
||||
obj, err = schema.ParseAndValidateWithRepair(ctx, toolInput, call.Schema, call.RepairText)
|
||||
} else {
|
||||
obj, err = schema.ParseAndValidate(toolInput, call.Schema)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
if !reflect.DeepEqual(obj, lastParsedObject) {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Object: obj,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
lastParsedObject = obj
|
||||
}
|
||||
}
|
||||
|
||||
case fantasy.StreamPartTypeError:
|
||||
streamErr = part.Error
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeError,
|
||||
Error: part.Error,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
|
||||
case fantasy.StreamPartTypeFinish:
|
||||
usage = part.Usage
|
||||
finishReason = part.FinishReason
|
||||
|
||||
case fantasy.StreamPartTypeWarnings:
|
||||
warnings = part.Warnings
|
||||
}
|
||||
|
||||
if len(part.ProviderMetadata) > 0 {
|
||||
providerMetadata = part.ProviderMetadata
|
||||
}
|
||||
}
|
||||
|
||||
if streamErr == nil && lastParsedObject != nil {
|
||||
yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeFinish,
|
||||
Usage: usage,
|
||||
FinishReason: finishReason,
|
||||
Warnings: warnings,
|
||||
ProviderMetadata: providerMetadata,
|
||||
})
|
||||
} else if streamErr == nil && lastParsedObject == nil {
|
||||
yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeError,
|
||||
Error: &fantasy.NoObjectGeneratedError{
|
||||
RawText: accumulated,
|
||||
ParseError: fmt.Errorf("no valid object generated in stream"),
|
||||
Usage: usage,
|
||||
FinishReason: finishReason,
|
||||
},
|
||||
})
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StreamWithText is a helper for providers without tool or JSON streaming support.
|
||||
// It adds the schema to the system prompt and parses the streamed text as JSON progressively.
|
||||
func StreamWithText(
|
||||
ctx context.Context,
|
||||
model fantasy.LanguageModel,
|
||||
call fantasy.ObjectCall,
|
||||
) (fantasy.ObjectStreamResponse, error) {
|
||||
jsonSchemaMap := schema.ToMap(call.Schema)
|
||||
jsonSchemaBytes, err := json.Marshal(jsonSchemaMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal schema: %w", err)
|
||||
}
|
||||
|
||||
schemaInstruction := fmt.Sprintf(
|
||||
"You must respond with valid JSON that matches this schema: %s\n"+
|
||||
"Respond ONLY with the JSON object, no additional text or explanation.",
|
||||
string(jsonSchemaBytes),
|
||||
)
|
||||
|
||||
enhancedPrompt := make(fantasy.Prompt, 0, len(call.Prompt)+1)
|
||||
|
||||
hasSystem := false
|
||||
for _, msg := range call.Prompt {
|
||||
if msg.Role == fantasy.MessageRoleSystem {
|
||||
hasSystem = true
|
||||
existingText := ""
|
||||
if len(msg.Content) > 0 {
|
||||
if textPart, ok := msg.Content[0].(fantasy.TextPart); ok {
|
||||
existingText = textPart.Text
|
||||
}
|
||||
}
|
||||
enhancedPrompt = append(enhancedPrompt, fantasy.NewSystemMessage(existingText+"\n\n"+schemaInstruction))
|
||||
} else {
|
||||
enhancedPrompt = append(enhancedPrompt, msg)
|
||||
}
|
||||
}
|
||||
|
||||
if !hasSystem {
|
||||
enhancedPrompt = append(fantasy.Prompt{fantasy.NewSystemMessage(schemaInstruction)}, call.Prompt...)
|
||||
}
|
||||
|
||||
stream, err := model.Stream(ctx, fantasy.Call{
|
||||
Prompt: enhancedPrompt,
|
||||
MaxOutputTokens: call.MaxOutputTokens,
|
||||
Temperature: call.Temperature,
|
||||
TopP: call.TopP,
|
||||
TopK: call.TopK,
|
||||
PresencePenalty: call.PresencePenalty,
|
||||
FrequencyPenalty: call.FrequencyPenalty,
|
||||
ProviderOptions: call.ProviderOptions,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("text-based streaming failed: %w", err)
|
||||
}
|
||||
|
||||
return func(yield func(fantasy.ObjectStreamPart) bool) {
|
||||
var accumulated string
|
||||
var lastParsedObject any
|
||||
var usage fantasy.Usage
|
||||
var finishReason fantasy.FinishReason
|
||||
var warnings []fantasy.CallWarning
|
||||
var providerMetadata fantasy.ProviderMetadata
|
||||
var streamErr error
|
||||
|
||||
for part := range stream {
|
||||
switch part.Type {
|
||||
case fantasy.StreamPartTypeTextDelta:
|
||||
accumulated += part.Delta
|
||||
|
||||
obj, state, parseErr := schema.ParsePartialJSON(accumulated)
|
||||
|
||||
if state == schema.ParseStateSuccessful || state == schema.ParseStateRepaired {
|
||||
if err := schema.ValidateAgainstSchema(obj, call.Schema); err == nil {
|
||||
if !reflect.DeepEqual(obj, lastParsedObject) {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Object: obj,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
lastParsedObject = obj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if state == schema.ParseStateFailed && call.RepairText != nil {
|
||||
repairedText, repairErr := call.RepairText(ctx, accumulated, parseErr)
|
||||
if repairErr == nil {
|
||||
obj2, state2, _ := schema.ParsePartialJSON(repairedText)
|
||||
if (state2 == schema.ParseStateSuccessful || state2 == schema.ParseStateRepaired) &&
|
||||
schema.ValidateAgainstSchema(obj2, call.Schema) == nil {
|
||||
if !reflect.DeepEqual(obj2, lastParsedObject) {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Object: obj2,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
lastParsedObject = obj2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case fantasy.StreamPartTypeError:
|
||||
streamErr = part.Error
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeError,
|
||||
Error: part.Error,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
|
||||
case fantasy.StreamPartTypeFinish:
|
||||
usage = part.Usage
|
||||
finishReason = part.FinishReason
|
||||
|
||||
case fantasy.StreamPartTypeWarnings:
|
||||
warnings = part.Warnings
|
||||
}
|
||||
|
||||
if len(part.ProviderMetadata) > 0 {
|
||||
providerMetadata = part.ProviderMetadata
|
||||
}
|
||||
}
|
||||
|
||||
if streamErr == nil && lastParsedObject != nil {
|
||||
yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeFinish,
|
||||
Usage: usage,
|
||||
FinishReason: finishReason,
|
||||
Warnings: warnings,
|
||||
ProviderMetadata: providerMetadata,
|
||||
})
|
||||
} else if streamErr == nil && lastParsedObject == nil {
|
||||
yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeError,
|
||||
Error: &fantasy.NoObjectGeneratedError{
|
||||
RawText: accumulated,
|
||||
ParseError: fmt.Errorf("no valid object generated in stream"),
|
||||
Usage: usage,
|
||||
FinishReason: finishReason,
|
||||
},
|
||||
})
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func unmarshal(obj any, target any) error {
|
||||
jsonBytes, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal object: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(jsonBytes, target); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal into target type: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Provider represents a provider of language models.
|
||||
type Provider interface {
|
||||
Name() string
|
||||
LanguageModel(ctx context.Context, modelID string) (LanguageModel, error)
|
||||
}
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// providerDataJSON is the serialized wrapper used by the registry.
|
||||
type providerDataJSON struct {
|
||||
Type string `json:"type"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
// UnmarshalFunc converts raw JSON into a ProviderOptionsData implementation.
|
||||
type UnmarshalFunc func([]byte) (ProviderOptionsData, error)
|
||||
|
||||
// providerRegistry uses sync.Map for lock-free reads after initialization.
|
||||
// All registrations happen in init() functions before concurrent access.
|
||||
var providerRegistry sync.Map
|
||||
|
||||
// RegisterProviderType registers a provider type ID with its unmarshal function.
|
||||
// Type IDs must be globally unique (e.g. "openai.options").
|
||||
// This should only be called during package initialization (init functions).
|
||||
func RegisterProviderType(typeID string, unmarshalFn UnmarshalFunc) {
|
||||
providerRegistry.Store(typeID, unmarshalFn)
|
||||
}
|
||||
|
||||
// unmarshalProviderData routes a typed payload to the correct constructor.
|
||||
func unmarshalProviderData(data []byte) (ProviderOptionsData, error) {
|
||||
var pj providerDataJSON
|
||||
if err := json.Unmarshal(data, &pj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
val, exists := providerRegistry.Load(pj.Type)
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("unknown provider data type: %s", pj.Type)
|
||||
}
|
||||
|
||||
unmarshalFn := val.(UnmarshalFunc) //nolint:forcetypeassert // type enforced by RegisterProviderType
|
||||
return unmarshalFn(pj.Data)
|
||||
}
|
||||
|
||||
// unmarshalProviderDataMap is a helper for unmarshaling maps of provider data.
|
||||
func unmarshalProviderDataMap(data map[string]json.RawMessage) (map[string]ProviderOptionsData, error) {
|
||||
result := make(map[string]ProviderOptionsData)
|
||||
for provider, rawData := range data {
|
||||
providerData, err := unmarshalProviderData(rawData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal provider data for %s: %w", provider, err)
|
||||
}
|
||||
result[provider] = providerData
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UnmarshalProviderOptions unmarshals a map of provider options by type.
|
||||
func UnmarshalProviderOptions(data map[string]json.RawMessage) (ProviderOptions, error) {
|
||||
return unmarshalProviderDataMap(data)
|
||||
}
|
||||
|
||||
// UnmarshalProviderMetadata unmarshals a map of provider metadata by type.
|
||||
func UnmarshalProviderMetadata(data map[string]json.RawMessage) (ProviderMetadata, error) {
|
||||
return unmarshalProviderDataMap(data)
|
||||
}
|
||||
|
||||
// MarshalProviderType marshals provider data with a type wrapper using generics.
|
||||
// To avoid infinite recursion, use the "type plain T" pattern before calling this.
|
||||
//
|
||||
// Usage in provider types:
|
||||
//
|
||||
// func (o ProviderOptions) MarshalJSON() ([]byte, error) {
|
||||
// type plain ProviderOptions
|
||||
// return fantasy.MarshalProviderType(TypeProviderOptions, plain(o))
|
||||
// }
|
||||
func MarshalProviderType[T any](typeID string, data T) ([]byte, error) {
|
||||
rawData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(providerDataJSON{
|
||||
Type: typeID,
|
||||
Data: json.RawMessage(rawData),
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalProviderType unmarshals provider data without type wrapper using generics.
|
||||
// To avoid infinite recursion, unmarshal to a plain type first.
|
||||
// Note: This receives the inner 'data' field after type routing by the registry.
|
||||
//
|
||||
// Usage in provider types:
|
||||
//
|
||||
// func (o *ProviderOptions) UnmarshalJSON(data []byte) error {
|
||||
// type plain ProviderOptions
|
||||
// var p plain
|
||||
// if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// *o = ProviderOptions(p)
|
||||
// return nil
|
||||
// }
|
||||
func UnmarshalProviderType[T any](data []byte, target *T) error {
|
||||
return json.Unmarshal(data, target)
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,29 +0,0 @@
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/smithy-go/auth/bearer"
|
||||
)
|
||||
|
||||
func bedrockBasicAuthConfig(apiKey string) aws.Config {
|
||||
return aws.Config{
|
||||
Region: cmp.Or(os.Getenv("AWS_REGION"), "us-east-1"),
|
||||
BearerAuthTokenProvider: bearer.StaticTokenProvider{Token: bearer.Token{Value: apiKey}},
|
||||
}
|
||||
}
|
||||
|
||||
func bedrockPrefixModelWithRegion(modelID string) string {
|
||||
region := os.Getenv("AWS_REGION")
|
||||
if len(region) < 2 {
|
||||
region = "us-east-1"
|
||||
}
|
||||
prefix := region[:2] + "."
|
||||
if strings.HasPrefix(modelID, prefix) {
|
||||
return modelID
|
||||
}
|
||||
return prefix + modelID
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"github.com/charmbracelet/anthropic-sdk-go"
|
||||
)
|
||||
|
||||
func toProviderErr(err error) error {
|
||||
var apiErr *anthropic.Error
|
||||
if errors.As(err, &apiErr) {
|
||||
return &fantasy.ProviderError{
|
||||
Title: cmp.Or(fantasy.ErrorTitleForStatusCode(apiErr.StatusCode), "provider request failed"),
|
||||
Message: apiErr.Error(),
|
||||
Cause: apiErr,
|
||||
URL: apiErr.Request.URL.String(),
|
||||
StatusCode: apiErr.StatusCode,
|
||||
RequestBody: apiErr.DumpRequest(true),
|
||||
ResponseHeaders: toHeaderMap(apiErr.Response.Header),
|
||||
ResponseBody: apiErr.DumpResponse(true),
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func toHeaderMap(in http.Header) (out map[string]string) {
|
||||
out = make(map[string]string, len(in))
|
||||
for k, v := range in {
|
||||
if l := len(v); l > 0 {
|
||||
out[k] = v[l-1]
|
||||
in[strings.ToLower(k)] = v
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type googleDummyTokenSource struct{}
|
||||
|
||||
func (googleDummyTokenSource) Token() (*oauth2.Token, error) {
|
||||
return &oauth2.Token{AccessToken: "dummy-token"}, nil
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
// Package anthropic provides an implementation of the fantasy AI SDK for Anthropic's language models.
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"charm.land/fantasy"
|
||||
)
|
||||
|
||||
// Global type identifiers for Anthropic-specific provider data.
|
||||
const (
|
||||
TypeProviderOptions = Name + ".options"
|
||||
TypeReasoningOptionMetadata = Name + ".reasoning_metadata"
|
||||
TypeProviderCacheControl = Name + ".cache_control_options"
|
||||
)
|
||||
|
||||
// Register Anthropic provider-specific types with the global registry.
|
||||
func init() {
|
||||
fantasy.RegisterProviderType(TypeProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ProviderOptions
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
fantasy.RegisterProviderType(TypeReasoningOptionMetadata, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ReasoningOptionMetadata
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
fantasy.RegisterProviderType(TypeProviderCacheControl, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ProviderCacheControlOptions
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ProviderOptions represents additional options for the Anthropic provider.
|
||||
type ProviderOptions struct {
|
||||
SendReasoning *bool `json:"send_reasoning"`
|
||||
Thinking *ThinkingProviderOption `json:"thinking"`
|
||||
DisableParallelToolUse *bool `json:"disable_parallel_tool_use"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptions interface.
|
||||
func (o *ProviderOptions) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ProviderOptions.
|
||||
func (o ProviderOptions) MarshalJSON() ([]byte, error) {
|
||||
type plain ProviderOptions
|
||||
return fantasy.MarshalProviderType(TypeProviderOptions, plain(o))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderOptions.
|
||||
func (o *ProviderOptions) UnmarshalJSON(data []byte) error {
|
||||
type plain ProviderOptions
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = ProviderOptions(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ThinkingProviderOption represents thinking options for the Anthropic provider.
|
||||
type ThinkingProviderOption struct {
|
||||
BudgetTokens int64 `json:"budget_tokens"`
|
||||
}
|
||||
|
||||
// ReasoningOptionMetadata represents reasoning metadata for the Anthropic provider.
|
||||
type ReasoningOptionMetadata struct {
|
||||
Signature string `json:"signature"`
|
||||
RedactedData string `json:"redacted_data"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptions interface.
|
||||
func (*ReasoningOptionMetadata) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ReasoningOptionMetadata.
|
||||
func (m ReasoningOptionMetadata) MarshalJSON() ([]byte, error) {
|
||||
type plain ReasoningOptionMetadata
|
||||
return fantasy.MarshalProviderType(TypeReasoningOptionMetadata, plain(m))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ReasoningOptionMetadata.
|
||||
func (m *ReasoningOptionMetadata) UnmarshalJSON(data []byte) error {
|
||||
type plain ReasoningOptionMetadata
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = ReasoningOptionMetadata(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProviderCacheControlOptions represents cache control options for the Anthropic provider.
|
||||
type ProviderCacheControlOptions struct {
|
||||
CacheControl CacheControl `json:"cache_control"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptions interface.
|
||||
func (*ProviderCacheControlOptions) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ProviderCacheControlOptions.
|
||||
func (o ProviderCacheControlOptions) MarshalJSON() ([]byte, error) {
|
||||
type plain ProviderCacheControlOptions
|
||||
return fantasy.MarshalProviderType(TypeProviderCacheControl, plain(o))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderCacheControlOptions.
|
||||
func (o *ProviderCacheControlOptions) UnmarshalJSON(data []byte) error {
|
||||
type plain ProviderCacheControlOptions
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = ProviderCacheControlOptions(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CacheControl represents cache control settings for the Anthropic provider.
|
||||
type CacheControl struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// NewProviderOptions creates new provider options for the Anthropic provider.
|
||||
func NewProviderOptions(opts *ProviderOptions) fantasy.ProviderOptions {
|
||||
return fantasy.ProviderOptions{
|
||||
Name: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// NewProviderCacheControlOptions creates new cache control options for the Anthropic provider.
|
||||
func NewProviderCacheControlOptions(opts *ProviderCacheControlOptions) fantasy.ProviderOptions {
|
||||
return fantasy.ProviderOptions{
|
||||
Name: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseOptions parses provider options from a map for the Anthropic provider.
|
||||
func ParseOptions(data map[string]any) (*ProviderOptions, error) {
|
||||
var options ProviderOptions
|
||||
if err := fantasy.ParseOptions(data, &options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &options, nil
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
# Google Provider
|
||||
|
||||
This document describes how to get an API keys for Google Gemini and Vertex.
|
||||
|
||||
## Gemini
|
||||
|
||||
Simply navigate to [this page](https://aistudio.google.com/apikey) in the
|
||||
Google AI Studio and create a new API key.
|
||||
|
||||
## Vertex
|
||||
|
||||
### Install `gcloud`
|
||||
|
||||
Install the `gcloud` command line tool. Install via Homebrew, Nix, or download
|
||||
it from [here](https://cloud.google.com/sdk/docs/install).
|
||||
|
||||
```bash
|
||||
# Homebrew
|
||||
brew install --cask google-cloud-sdk
|
||||
|
||||
# Nix
|
||||
nix-env -iA nixpkgs.google-cloud-sdk
|
||||
```
|
||||
|
||||
### Authenticate
|
||||
|
||||
Then authenticate with your Google account:
|
||||
|
||||
```bash
|
||||
gcloud auth login
|
||||
```
|
||||
|
||||
### Create And Setup Project
|
||||
|
||||
Navigate here to create a new project if you haven't already:
|
||||
https://console.cloud.google.com/projectcreate
|
||||
|
||||
Alternatively, you can create a new project via the command line:
|
||||
|
||||
```bash
|
||||
gcloud projects create {YOUR_PROJECT_ID} --name="{YOUR_PROJECT_NAME}"
|
||||
```
|
||||
|
||||
Set the project on your machine:
|
||||
|
||||
```bash
|
||||
gcloud config set project {YOUR_PROJECT_ID}
|
||||
```
|
||||
|
||||
Enable the Vertex AI API:
|
||||
|
||||
```bash
|
||||
gcloud services enable aiplatform.googleapis.com
|
||||
```
|
||||
|
||||
### Setup Env
|
||||
|
||||
Finally, you need to run this command to ensure that libraries will be able to
|
||||
find your credentials.
|
||||
|
||||
```bash
|
||||
gcloud auth application-default login
|
||||
```
|
||||
@@ -1,15 +0,0 @@
|
||||
// Package google provides an implementation of the fantasy AI SDK for Google's language models.
|
||||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cloud.google.com/go/auth"
|
||||
)
|
||||
|
||||
type dummyTokenProvider struct{}
|
||||
|
||||
// Token implements the auth.TokenProvider interface.
|
||||
func (dummyTokenProvider) Token(_ context.Context) (*auth.Token, error) {
|
||||
return &auth.Token{Value: "dummy-token"}, nil
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"errors"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"google.golang.org/genai"
|
||||
)
|
||||
|
||||
func toProviderErr(err error) error {
|
||||
var apiErr genai.APIError
|
||||
if !errors.As(err, &apiErr) {
|
||||
return err
|
||||
}
|
||||
return &fantasy.ProviderError{
|
||||
Message: apiErr.Message,
|
||||
Title: cmp.Or(fantasy.ErrorTitleForStatusCode(apiErr.Code), "provider request failed"),
|
||||
Cause: err,
|
||||
StatusCode: apiErr.Code,
|
||||
ResponseBody: []byte(apiErr.Message),
|
||||
}
|
||||
}
|
||||
-1431
File diff suppressed because it is too large.
Load diff
@@ -1,132 +0,0 @@
|
||||
// Package google provides an implementation of the fantasy AI SDK for Google's language models.
|
||||
package google
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"charm.land/fantasy"
|
||||
)
|
||||
|
||||
// Global type identifiers for Google-specific provider data.
|
||||
const (
|
||||
TypeProviderOptions = Name + ".options"
|
||||
TypeReasoningMetadata = Name + ".reasoning_metadata"
|
||||
)
|
||||
|
||||
// Register Google provider-specific types with the global registry.
|
||||
func init() {
|
||||
fantasy.RegisterProviderType(TypeProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ProviderOptions
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
fantasy.RegisterProviderType(TypeReasoningMetadata, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ReasoningMetadata
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ThinkingConfig represents thinking configuration for the Google provider.
|
||||
type ThinkingConfig struct {
|
||||
ThinkingBudget *int64 `json:"thinking_budget"`
|
||||
IncludeThoughts *bool `json:"include_thoughts"`
|
||||
}
|
||||
|
||||
// ReasoningMetadata represents reasoning metadata for the Google provider.
|
||||
type ReasoningMetadata struct {
|
||||
Signature string `json:"signature"`
|
||||
ToolID string `json:"tool_id"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptionsData interface for ReasoningMetadata.
|
||||
func (m *ReasoningMetadata) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ReasoningMetadata.
|
||||
func (m ReasoningMetadata) MarshalJSON() ([]byte, error) {
|
||||
type plain ReasoningMetadata
|
||||
return fantasy.MarshalProviderType(TypeReasoningMetadata, plain(m))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ReasoningMetadata.
|
||||
func (m *ReasoningMetadata) UnmarshalJSON(data []byte) error {
|
||||
type plain ReasoningMetadata
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = ReasoningMetadata(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SafetySetting represents safety settings for the Google provider.
|
||||
type SafetySetting struct {
|
||||
// 'HARM_CATEGORY_UNSPECIFIED',
|
||||
// 'HARM_CATEGORY_HATE_SPEECH',
|
||||
// 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
||||
// 'HARM_CATEGORY_HARASSMENT',
|
||||
// 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
||||
// 'HARM_CATEGORY_CIVIC_INTEGRITY',
|
||||
Category string `json:"category"`
|
||||
|
||||
// 'HARM_BLOCK_THRESHOLD_UNSPECIFIED',
|
||||
// 'BLOCK_LOW_AND_ABOVE',
|
||||
// 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// 'BLOCK_ONLY_HIGH',
|
||||
// 'BLOCK_NONE',
|
||||
// 'OFF',
|
||||
Threshold string `json:"threshold"`
|
||||
}
|
||||
|
||||
// ProviderOptions represents additional options for the Google provider.
|
||||
type ProviderOptions struct {
|
||||
ThinkingConfig *ThinkingConfig `json:"thinking_config"`
|
||||
|
||||
// Optional.
|
||||
// The name of the cached content used as context to serve the prediction.
|
||||
// Format: cachedContents/{cachedContent}
|
||||
CachedContent string `json:"cached_content"`
|
||||
|
||||
// Optional. A list of unique safety settings for blocking unsafe content.
|
||||
SafetySettings []SafetySetting `json:"safety_settings"`
|
||||
// 'HARM_BLOCK_THRESHOLD_UNSPECIFIED',
|
||||
// 'BLOCK_LOW_AND_ABOVE',
|
||||
// 'BLOCK_MEDIUM_AND_ABOVE',
|
||||
// 'BLOCK_ONLY_HIGH',
|
||||
// 'BLOCK_NONE',
|
||||
// 'OFF',
|
||||
Threshold string `json:"threshold"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptionsData interface for ProviderOptions.
|
||||
func (o *ProviderOptions) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ProviderOptions.
|
||||
func (o ProviderOptions) MarshalJSON() ([]byte, error) {
|
||||
type plain ProviderOptions
|
||||
return fantasy.MarshalProviderType(TypeProviderOptions, plain(o))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderOptions.
|
||||
func (o *ProviderOptions) UnmarshalJSON(data []byte) error {
|
||||
type plain ProviderOptions
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = ProviderOptions(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseOptions parses provider options from a map for the Google provider.
|
||||
func ParseOptions(data map[string]any) (*ProviderOptions, error) {
|
||||
var options ProviderOptions
|
||||
if err := fantasy.ParseOptions(data, &options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &options, nil
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package google
|
||||
|
||||
func depointerSlice[T any](s []*T) []T {
|
||||
result := make([]T, 0, len(s))
|
||||
for _, v := range s {
|
||||
if v != nil {
|
||||
result = append(result, *v)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"github.com/openai/openai-go/v2"
|
||||
)
|
||||
|
||||
func toProviderErr(err error) error {
|
||||
var apiErr *openai.Error
|
||||
if errors.As(err, &apiErr) {
|
||||
return &fantasy.ProviderError{
|
||||
Title: cmp.Or(fantasy.ErrorTitleForStatusCode(apiErr.StatusCode), "provider request failed"),
|
||||
Message: toProviderErrMessage(apiErr),
|
||||
Cause: apiErr,
|
||||
URL: apiErr.Request.URL.String(),
|
||||
StatusCode: apiErr.StatusCode,
|
||||
RequestBody: apiErr.DumpRequest(true),
|
||||
ResponseHeaders: toHeaderMap(apiErr.Response.Header),
|
||||
ResponseBody: apiErr.DumpResponse(true),
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func toProviderErrMessage(apiErr *openai.Error) string {
|
||||
if apiErr.Message != "" {
|
||||
return apiErr.Message
|
||||
}
|
||||
|
||||
// For some OpenAI-compatible providers, the SDK is not always able to parse
|
||||
// the error message correctly.
|
||||
// Fallback to returning the raw response body in such cases.
|
||||
data, _ := io.ReadAll(apiErr.Response.Body)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func toHeaderMap(in http.Header) (out map[string]string) {
|
||||
out = make(map[string]string, len(in))
|
||||
for k, v := range in {
|
||||
if l := len(v); l > 0 {
|
||||
out[k] = v[l-1]
|
||||
in[strings.ToLower(k)] = v
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -1,948 +0,0 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"charm.land/fantasy/object"
|
||||
"charm.land/fantasy/schema"
|
||||
xjson "github.com/charmbracelet/x/json"
|
||||
"github.com/google/uuid"
|
||||
"github.com/openai/openai-go/v2"
|
||||
"github.com/openai/openai-go/v2/packages/param"
|
||||
"github.com/openai/openai-go/v2/shared"
|
||||
)
|
||||
|
||||
type languageModel struct {
|
||||
provider string
|
||||
modelID string
|
||||
client openai.Client
|
||||
objectMode fantasy.ObjectMode
|
||||
prepareCallFunc LanguageModelPrepareCallFunc
|
||||
mapFinishReasonFunc LanguageModelMapFinishReasonFunc
|
||||
extraContentFunc LanguageModelExtraContentFunc
|
||||
usageFunc LanguageModelUsageFunc
|
||||
streamUsageFunc LanguageModelStreamUsageFunc
|
||||
streamExtraFunc LanguageModelStreamExtraFunc
|
||||
streamProviderMetadataFunc LanguageModelStreamProviderMetadataFunc
|
||||
toPromptFunc LanguageModelToPromptFunc
|
||||
}
|
||||
|
||||
// LanguageModelOption is a function that configures a languageModel.
|
||||
type LanguageModelOption = func(*languageModel)
|
||||
|
||||
// WithLanguageModelPrepareCallFunc sets the prepare call function for the language model.
|
||||
func WithLanguageModelPrepareCallFunc(fn LanguageModelPrepareCallFunc) LanguageModelOption {
|
||||
return func(l *languageModel) {
|
||||
l.prepareCallFunc = fn
|
||||
}
|
||||
}
|
||||
|
||||
// WithLanguageModelMapFinishReasonFunc sets the map finish reason function for the language model.
|
||||
func WithLanguageModelMapFinishReasonFunc(fn LanguageModelMapFinishReasonFunc) LanguageModelOption {
|
||||
return func(l *languageModel) {
|
||||
l.mapFinishReasonFunc = fn
|
||||
}
|
||||
}
|
||||
|
||||
// WithLanguageModelExtraContentFunc sets the extra content function for the language model.
|
||||
func WithLanguageModelExtraContentFunc(fn LanguageModelExtraContentFunc) LanguageModelOption {
|
||||
return func(l *languageModel) {
|
||||
l.extraContentFunc = fn
|
||||
}
|
||||
}
|
||||
|
||||
// WithLanguageModelStreamExtraFunc sets the stream extra function for the language model.
|
||||
func WithLanguageModelStreamExtraFunc(fn LanguageModelStreamExtraFunc) LanguageModelOption {
|
||||
return func(l *languageModel) {
|
||||
l.streamExtraFunc = fn
|
||||
}
|
||||
}
|
||||
|
||||
// WithLanguageModelUsageFunc sets the usage function for the language model.
|
||||
func WithLanguageModelUsageFunc(fn LanguageModelUsageFunc) LanguageModelOption {
|
||||
return func(l *languageModel) {
|
||||
l.usageFunc = fn
|
||||
}
|
||||
}
|
||||
|
||||
// WithLanguageModelStreamUsageFunc sets the stream usage function for the language model.
|
||||
func WithLanguageModelStreamUsageFunc(fn LanguageModelStreamUsageFunc) LanguageModelOption {
|
||||
return func(l *languageModel) {
|
||||
l.streamUsageFunc = fn
|
||||
}
|
||||
}
|
||||
|
||||
// WithLanguageModelToPromptFunc sets the to prompt function for the language model.
|
||||
func WithLanguageModelToPromptFunc(fn LanguageModelToPromptFunc) LanguageModelOption {
|
||||
return func(l *languageModel) {
|
||||
l.toPromptFunc = fn
|
||||
}
|
||||
}
|
||||
|
||||
// WithLanguageModelObjectMode sets the object generation mode.
|
||||
func WithLanguageModelObjectMode(om fantasy.ObjectMode) LanguageModelOption {
|
||||
return func(l *languageModel) {
|
||||
// not supported
|
||||
if om == fantasy.ObjectModeJSON {
|
||||
om = fantasy.ObjectModeAuto
|
||||
}
|
||||
l.objectMode = om
|
||||
}
|
||||
}
|
||||
|
||||
func newLanguageModel(modelID string, provider string, client openai.Client, opts ...LanguageModelOption) languageModel {
|
||||
model := languageModel{
|
||||
modelID: modelID,
|
||||
provider: provider,
|
||||
client: client,
|
||||
objectMode: fantasy.ObjectModeAuto,
|
||||
prepareCallFunc: DefaultPrepareCallFunc,
|
||||
mapFinishReasonFunc: DefaultMapFinishReasonFunc,
|
||||
usageFunc: DefaultUsageFunc,
|
||||
streamUsageFunc: DefaultStreamUsageFunc,
|
||||
streamProviderMetadataFunc: DefaultStreamProviderMetadataFunc,
|
||||
toPromptFunc: DefaultToPrompt,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&model)
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
type streamToolCall struct {
|
||||
id string
|
||||
name string
|
||||
arguments string
|
||||
hasFinished bool
|
||||
}
|
||||
|
||||
// Model implements fantasy.LanguageModel.
|
||||
func (o languageModel) Model() string {
|
||||
return o.modelID
|
||||
}
|
||||
|
||||
// Provider implements fantasy.LanguageModel.
|
||||
func (o languageModel) Provider() string {
|
||||
return o.provider
|
||||
}
|
||||
|
||||
func (o languageModel) prepareParams(call fantasy.Call) (*openai.ChatCompletionNewParams, []fantasy.CallWarning, error) {
|
||||
params := &openai.ChatCompletionNewParams{}
|
||||
messages, warnings := o.toPromptFunc(call.Prompt, o.provider, o.modelID)
|
||||
if call.TopK != nil {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "top_k",
|
||||
})
|
||||
}
|
||||
|
||||
if call.MaxOutputTokens != nil {
|
||||
params.MaxTokens = param.NewOpt(*call.MaxOutputTokens)
|
||||
}
|
||||
if call.Temperature != nil {
|
||||
params.Temperature = param.NewOpt(*call.Temperature)
|
||||
}
|
||||
if call.TopP != nil {
|
||||
params.TopP = param.NewOpt(*call.TopP)
|
||||
}
|
||||
if call.FrequencyPenalty != nil {
|
||||
params.FrequencyPenalty = param.NewOpt(*call.FrequencyPenalty)
|
||||
}
|
||||
if call.PresencePenalty != nil {
|
||||
params.PresencePenalty = param.NewOpt(*call.PresencePenalty)
|
||||
}
|
||||
|
||||
if isReasoningModel(o.modelID) {
|
||||
// remove unsupported settings for reasoning models
|
||||
// see https://platform.openai.com/docs/guides/reasoning#limitations
|
||||
if call.Temperature != nil {
|
||||
params.Temperature = param.Opt[float64]{}
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "temperature",
|
||||
Details: "temperature is not supported for reasoning models",
|
||||
})
|
||||
}
|
||||
if call.TopP != nil {
|
||||
params.TopP = param.Opt[float64]{}
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "TopP",
|
||||
Details: "TopP is not supported for reasoning models",
|
||||
})
|
||||
}
|
||||
if call.FrequencyPenalty != nil {
|
||||
params.FrequencyPenalty = param.Opt[float64]{}
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "FrequencyPenalty",
|
||||
Details: "FrequencyPenalty is not supported for reasoning models",
|
||||
})
|
||||
}
|
||||
if call.PresencePenalty != nil {
|
||||
params.PresencePenalty = param.Opt[float64]{}
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "PresencePenalty",
|
||||
Details: "PresencePenalty is not supported for reasoning models",
|
||||
})
|
||||
}
|
||||
|
||||
// reasoning models use max_completion_tokens instead of max_tokens
|
||||
if call.MaxOutputTokens != nil {
|
||||
if !params.MaxCompletionTokens.Valid() {
|
||||
params.MaxCompletionTokens = param.NewOpt(*call.MaxOutputTokens)
|
||||
}
|
||||
params.MaxTokens = param.Opt[int64]{}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle search preview models
|
||||
if isSearchPreviewModel(o.modelID) {
|
||||
if call.Temperature != nil {
|
||||
params.Temperature = param.Opt[float64]{}
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "temperature",
|
||||
Details: "temperature is not supported for the search preview models and has been removed.",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
optionsWarnings, err := o.prepareCallFunc(o, params, call)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(optionsWarnings) > 0 {
|
||||
warnings = append(warnings, optionsWarnings...)
|
||||
}
|
||||
|
||||
params.Messages = messages
|
||||
params.Model = o.modelID
|
||||
|
||||
if len(call.Tools) > 0 {
|
||||
tools, toolChoice, toolWarnings := toOpenAiTools(call.Tools, call.ToolChoice)
|
||||
params.Tools = tools
|
||||
if toolChoice != nil {
|
||||
params.ToolChoice = *toolChoice
|
||||
}
|
||||
warnings = append(warnings, toolWarnings...)
|
||||
}
|
||||
return params, warnings, nil
|
||||
}
|
||||
|
||||
// Generate implements fantasy.LanguageModel.
|
||||
func (o languageModel) Generate(ctx context.Context, call fantasy.Call) (*fantasy.Response, error) {
|
||||
params, warnings, err := o.prepareParams(call)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := o.client.Chat.Completions.New(ctx, *params)
|
||||
if err != nil {
|
||||
return nil, toProviderErr(err)
|
||||
}
|
||||
|
||||
if len(response.Choices) == 0 {
|
||||
return nil, &fantasy.Error{Title: "no response", Message: "no response generated"}
|
||||
}
|
||||
choice := response.Choices[0]
|
||||
content := make([]fantasy.Content, 0, 1+len(choice.Message.ToolCalls)+len(choice.Message.Annotations))
|
||||
text := choice.Message.Content
|
||||
if text != "" {
|
||||
content = append(content, fantasy.TextContent{
|
||||
Text: text,
|
||||
})
|
||||
}
|
||||
if o.extraContentFunc != nil {
|
||||
extraContent := o.extraContentFunc(choice)
|
||||
content = append(content, extraContent...)
|
||||
}
|
||||
for _, tc := range choice.Message.ToolCalls {
|
||||
toolCallID := tc.ID
|
||||
content = append(content, fantasy.ToolCallContent{
|
||||
ProviderExecuted: false,
|
||||
ToolCallID: toolCallID,
|
||||
ToolName: tc.Function.Name,
|
||||
Input: tc.Function.Arguments,
|
||||
})
|
||||
}
|
||||
for _, annotation := range choice.Message.Annotations {
|
||||
if annotation.Type == "url_citation" {
|
||||
content = append(content, fantasy.SourceContent{
|
||||
SourceType: fantasy.SourceTypeURL,
|
||||
ID: uuid.NewString(),
|
||||
URL: annotation.URLCitation.URL,
|
||||
Title: annotation.URLCitation.Title,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
usage, providerMetadata := o.usageFunc(*response)
|
||||
|
||||
mappedFinishReason := o.mapFinishReasonFunc(choice.FinishReason)
|
||||
if len(choice.Message.ToolCalls) > 0 {
|
||||
mappedFinishReason = fantasy.FinishReasonToolCalls
|
||||
}
|
||||
return &fantasy.Response{
|
||||
Content: content,
|
||||
Usage: usage,
|
||||
FinishReason: mappedFinishReason,
|
||||
ProviderMetadata: fantasy.ProviderMetadata{
|
||||
Name: providerMetadata,
|
||||
},
|
||||
Warnings: warnings,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Stream implements fantasy.LanguageModel.
|
||||
func (o languageModel) Stream(ctx context.Context, call fantasy.Call) (fantasy.StreamResponse, error) {
|
||||
params, warnings, err := o.prepareParams(call)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params.StreamOptions = openai.ChatCompletionStreamOptionsParam{
|
||||
IncludeUsage: openai.Bool(true),
|
||||
}
|
||||
|
||||
stream := o.client.Chat.Completions.NewStreaming(ctx, *params)
|
||||
isActiveText := false
|
||||
toolCalls := make(map[int64]streamToolCall)
|
||||
|
||||
providerMetadata := fantasy.ProviderMetadata{
|
||||
Name: &ProviderMetadata{},
|
||||
}
|
||||
acc := openai.ChatCompletionAccumulator{}
|
||||
extraContext := make(map[string]any)
|
||||
var usage fantasy.Usage
|
||||
var finishReason string
|
||||
return func(yield func(fantasy.StreamPart) bool) {
|
||||
if len(warnings) > 0 {
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeWarnings,
|
||||
Warnings: warnings,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
for stream.Next() {
|
||||
chunk := stream.Current()
|
||||
acc.AddChunk(chunk)
|
||||
usage, providerMetadata = o.streamUsageFunc(chunk, extraContext, providerMetadata)
|
||||
if len(chunk.Choices) == 0 {
|
||||
continue
|
||||
}
|
||||
for _, choice := range chunk.Choices {
|
||||
if choice.FinishReason != "" {
|
||||
finishReason = choice.FinishReason
|
||||
}
|
||||
switch {
|
||||
case choice.Delta.Content != "":
|
||||
if !isActiveText {
|
||||
isActiveText = true
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeTextStart,
|
||||
ID: "0",
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeTextDelta,
|
||||
ID: "0",
|
||||
Delta: choice.Delta.Content,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
case len(choice.Delta.ToolCalls) > 0:
|
||||
if isActiveText {
|
||||
isActiveText = false
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeTextEnd,
|
||||
ID: "0",
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, toolCallDelta := range choice.Delta.ToolCalls {
|
||||
if existingToolCall, ok := toolCalls[toolCallDelta.Index]; ok {
|
||||
if existingToolCall.hasFinished {
|
||||
continue
|
||||
}
|
||||
if toolCallDelta.Function.Arguments != "" {
|
||||
existingToolCall.arguments += toolCallDelta.Function.Arguments
|
||||
}
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeToolInputDelta,
|
||||
ID: existingToolCall.id,
|
||||
Delta: toolCallDelta.Function.Arguments,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
toolCalls[toolCallDelta.Index] = existingToolCall
|
||||
if xjson.IsValid(existingToolCall.arguments) {
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeToolInputEnd,
|
||||
ID: existingToolCall.id,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeToolCall,
|
||||
ID: existingToolCall.id,
|
||||
ToolCallName: existingToolCall.name,
|
||||
ToolCallInput: existingToolCall.arguments,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
existingToolCall.hasFinished = true
|
||||
toolCalls[toolCallDelta.Index] = existingToolCall
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
if toolCallDelta.Type != "function" {
|
||||
err = &fantasy.Error{Title: "invalid provider response", Message: "expected 'function' type."}
|
||||
}
|
||||
if toolCallDelta.ID == "" {
|
||||
err = &fantasy.Error{Title: "invalid provider response", Message: "expected 'id' to be a string."}
|
||||
}
|
||||
if toolCallDelta.Function.Name == "" {
|
||||
err = &fantasy.Error{Title: "invalid provider response", Message: "expected 'function.name' to be a string."}
|
||||
}
|
||||
if err != nil {
|
||||
yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeError,
|
||||
Error: toProviderErr(stream.Err()),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeToolInputStart,
|
||||
ID: toolCallDelta.ID,
|
||||
ToolCallName: toolCallDelta.Function.Name,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
toolCalls[toolCallDelta.Index] = streamToolCall{
|
||||
id: toolCallDelta.ID,
|
||||
name: toolCallDelta.Function.Name,
|
||||
arguments: toolCallDelta.Function.Arguments,
|
||||
}
|
||||
|
||||
exTc := toolCalls[toolCallDelta.Index]
|
||||
if exTc.arguments != "" {
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeToolInputDelta,
|
||||
ID: exTc.id,
|
||||
Delta: exTc.arguments,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
if xjson.IsValid(toolCalls[toolCallDelta.Index].arguments) {
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeToolInputEnd,
|
||||
ID: toolCallDelta.ID,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeToolCall,
|
||||
ID: exTc.id,
|
||||
ToolCallName: exTc.name,
|
||||
ToolCallInput: exTc.arguments,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
exTc.hasFinished = true
|
||||
toolCalls[toolCallDelta.Index] = exTc
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if o.streamExtraFunc != nil {
|
||||
updatedContext, shouldContinue := o.streamExtraFunc(chunk, yield, extraContext)
|
||||
if !shouldContinue {
|
||||
return
|
||||
}
|
||||
extraContext = updatedContext
|
||||
}
|
||||
}
|
||||
|
||||
for _, choice := range chunk.Choices {
|
||||
if annotations := parseAnnotationsFromDelta(choice.Delta); len(annotations) > 0 {
|
||||
for _, annotation := range annotations {
|
||||
if annotation.Type == "url_citation" {
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeSource,
|
||||
ID: uuid.NewString(),
|
||||
SourceType: fantasy.SourceTypeURL,
|
||||
URL: annotation.URLCitation.URL,
|
||||
Title: annotation.URLCitation.Title,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err := stream.Err()
|
||||
if err == nil || errors.Is(err, io.EOF) {
|
||||
if isActiveText {
|
||||
isActiveText = false
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeTextEnd,
|
||||
ID: "0",
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(acc.Choices) > 0 {
|
||||
choice := acc.Choices[0]
|
||||
providerMetadata = o.streamProviderMetadataFunc(choice, providerMetadata)
|
||||
|
||||
for _, annotation := range choice.Message.Annotations {
|
||||
if annotation.Type == "url_citation" {
|
||||
if !yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeSource,
|
||||
ID: acc.ID,
|
||||
SourceType: fantasy.SourceTypeURL,
|
||||
URL: annotation.URLCitation.URL,
|
||||
Title: annotation.URLCitation.Title,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mappedFinishReason := o.mapFinishReasonFunc(finishReason)
|
||||
if len(acc.Choices) > 0 {
|
||||
choice := acc.Choices[0]
|
||||
if len(choice.Message.ToolCalls) > 0 {
|
||||
mappedFinishReason = fantasy.FinishReasonToolCalls
|
||||
}
|
||||
}
|
||||
yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeFinish,
|
||||
Usage: usage,
|
||||
FinishReason: mappedFinishReason,
|
||||
ProviderMetadata: providerMetadata,
|
||||
})
|
||||
return
|
||||
} else { //nolint: revive
|
||||
yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeError,
|
||||
Error: toProviderErr(err),
|
||||
})
|
||||
return
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func isReasoningModel(modelID string) bool {
|
||||
return strings.HasPrefix(modelID, "o1") || strings.Contains(modelID, "-o1") ||
|
||||
strings.HasPrefix(modelID, "o3") || strings.Contains(modelID, "-o3") ||
|
||||
strings.HasPrefix(modelID, "o4") || strings.Contains(modelID, "-o4") ||
|
||||
strings.HasPrefix(modelID, "oss") || strings.Contains(modelID, "-oss") ||
|
||||
strings.Contains(modelID, "gpt-5") || strings.Contains(modelID, "gpt-5-chat")
|
||||
}
|
||||
|
||||
func isSearchPreviewModel(modelID string) bool {
|
||||
return strings.Contains(modelID, "search-preview")
|
||||
}
|
||||
|
||||
func supportsFlexProcessing(modelID string) bool {
|
||||
return strings.HasPrefix(modelID, "o3") || strings.Contains(modelID, "-o3") ||
|
||||
strings.Contains(modelID, "o4-mini") || strings.Contains(modelID, "gpt-5")
|
||||
}
|
||||
|
||||
func supportsPriorityProcessing(modelID string) bool {
|
||||
return strings.Contains(modelID, "gpt-4") || strings.Contains(modelID, "gpt-5") ||
|
||||
strings.Contains(modelID, "gpt-5-mini") || strings.HasPrefix(modelID, "o3") ||
|
||||
strings.Contains(modelID, "-o3") || strings.Contains(modelID, "o4-mini")
|
||||
}
|
||||
|
||||
func toOpenAiTools(tools []fantasy.Tool, toolChoice *fantasy.ToolChoice) (openAiTools []openai.ChatCompletionToolUnionParam, openAiToolChoice *openai.ChatCompletionToolChoiceOptionUnionParam, warnings []fantasy.CallWarning) {
|
||||
for _, tool := range tools {
|
||||
if tool.GetType() == fantasy.ToolTypeFunction {
|
||||
ft, ok := tool.(fantasy.FunctionTool)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
openAiTools = append(openAiTools, openai.ChatCompletionToolUnionParam{
|
||||
OfFunction: &openai.ChatCompletionFunctionToolParam{
|
||||
Function: shared.FunctionDefinitionParam{
|
||||
Name: ft.Name,
|
||||
Description: param.NewOpt(ft.Description),
|
||||
Parameters: openai.FunctionParameters(ft.InputSchema),
|
||||
Strict: param.NewOpt(false),
|
||||
},
|
||||
Type: "function",
|
||||
},
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedTool,
|
||||
Tool: tool,
|
||||
Message: "tool is not supported",
|
||||
})
|
||||
}
|
||||
if toolChoice == nil {
|
||||
return openAiTools, openAiToolChoice, warnings
|
||||
}
|
||||
|
||||
switch *toolChoice {
|
||||
case fantasy.ToolChoiceAuto:
|
||||
openAiToolChoice = &openai.ChatCompletionToolChoiceOptionUnionParam{
|
||||
OfAuto: param.NewOpt("auto"),
|
||||
}
|
||||
case fantasy.ToolChoiceNone:
|
||||
openAiToolChoice = &openai.ChatCompletionToolChoiceOptionUnionParam{
|
||||
OfAuto: param.NewOpt("none"),
|
||||
}
|
||||
case fantasy.ToolChoiceRequired:
|
||||
openAiToolChoice = &openai.ChatCompletionToolChoiceOptionUnionParam{
|
||||
OfAuto: param.NewOpt("required"),
|
||||
}
|
||||
default:
|
||||
openAiToolChoice = &openai.ChatCompletionToolChoiceOptionUnionParam{
|
||||
OfFunctionToolChoice: &openai.ChatCompletionNamedToolChoiceParam{
|
||||
Type: "function",
|
||||
Function: openai.ChatCompletionNamedToolChoiceFunctionParam{
|
||||
Name: string(*toolChoice),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return openAiTools, openAiToolChoice, warnings
|
||||
}
|
||||
|
||||
// parseAnnotationsFromDelta parses annotations from the raw JSON of a delta.
|
||||
func parseAnnotationsFromDelta(delta openai.ChatCompletionChunkChoiceDelta) []openai.ChatCompletionMessageAnnotation {
|
||||
var annotations []openai.ChatCompletionMessageAnnotation
|
||||
|
||||
// Parse the raw JSON to extract annotations
|
||||
var deltaData map[string]any
|
||||
if err := json.Unmarshal([]byte(delta.RawJSON()), &deltaData); err != nil {
|
||||
return annotations
|
||||
}
|
||||
|
||||
// Check if annotations exist in the delta
|
||||
if annotationsData, ok := deltaData["annotations"].([]any); ok {
|
||||
for _, annotationData := range annotationsData {
|
||||
if annotationMap, ok := annotationData.(map[string]any); ok {
|
||||
if annotationType, ok := annotationMap["type"].(string); ok && annotationType == "url_citation" {
|
||||
if urlCitationData, ok := annotationMap["url_citation"].(map[string]any); ok {
|
||||
url, urlOk := urlCitationData["url"].(string)
|
||||
title, titleOk := urlCitationData["title"].(string)
|
||||
if urlOk && titleOk {
|
||||
annotation := openai.ChatCompletionMessageAnnotation{
|
||||
Type: "url_citation",
|
||||
URLCitation: openai.ChatCompletionMessageAnnotationURLCitation{
|
||||
URL: url,
|
||||
Title: title,
|
||||
},
|
||||
}
|
||||
annotations = append(annotations, annotation)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return annotations
|
||||
}
|
||||
|
||||
// GenerateObject implements fantasy.LanguageModel.
|
||||
func (o languageModel) GenerateObject(ctx context.Context, call fantasy.ObjectCall) (*fantasy.ObjectResponse, error) {
|
||||
switch o.objectMode {
|
||||
case fantasy.ObjectModeText:
|
||||
return object.GenerateWithText(ctx, o, call)
|
||||
case fantasy.ObjectModeTool:
|
||||
return object.GenerateWithTool(ctx, o, call)
|
||||
default:
|
||||
return o.generateObjectWithJSONMode(ctx, call)
|
||||
}
|
||||
}
|
||||
|
||||
// StreamObject implements fantasy.LanguageModel.
|
||||
func (o languageModel) StreamObject(ctx context.Context, call fantasy.ObjectCall) (fantasy.ObjectStreamResponse, error) {
|
||||
switch o.objectMode {
|
||||
case fantasy.ObjectModeTool:
|
||||
return object.StreamWithTool(ctx, o, call)
|
||||
case fantasy.ObjectModeText:
|
||||
return object.StreamWithText(ctx, o, call)
|
||||
default:
|
||||
return o.streamObjectWithJSONMode(ctx, call)
|
||||
}
|
||||
}
|
||||
|
||||
func (o languageModel) generateObjectWithJSONMode(ctx context.Context, call fantasy.ObjectCall) (*fantasy.ObjectResponse, error) {
|
||||
jsonSchemaMap := schema.ToMap(call.Schema)
|
||||
|
||||
addAdditionalPropertiesFalse(jsonSchemaMap)
|
||||
|
||||
schemaName := call.SchemaName
|
||||
if schemaName == "" {
|
||||
schemaName = "response"
|
||||
}
|
||||
|
||||
fantasyCall := fantasy.Call{
|
||||
Prompt: call.Prompt,
|
||||
MaxOutputTokens: call.MaxOutputTokens,
|
||||
Temperature: call.Temperature,
|
||||
TopP: call.TopP,
|
||||
PresencePenalty: call.PresencePenalty,
|
||||
FrequencyPenalty: call.FrequencyPenalty,
|
||||
ProviderOptions: call.ProviderOptions,
|
||||
}
|
||||
|
||||
params, warnings, err := o.prepareParams(fantasyCall)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params.ResponseFormat = openai.ChatCompletionNewParamsResponseFormatUnion{
|
||||
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{
|
||||
JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
|
||||
Name: schemaName,
|
||||
Description: param.NewOpt(call.SchemaDescription),
|
||||
Schema: jsonSchemaMap,
|
||||
Strict: param.NewOpt(true),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
response, err := o.client.Chat.Completions.New(ctx, *params)
|
||||
if err != nil {
|
||||
return nil, toProviderErr(err)
|
||||
}
|
||||
|
||||
if len(response.Choices) == 0 {
|
||||
usage, _ := o.usageFunc(*response)
|
||||
return nil, &fantasy.NoObjectGeneratedError{
|
||||
RawText: "",
|
||||
ParseError: fmt.Errorf("no choices in response"),
|
||||
Usage: usage,
|
||||
FinishReason: fantasy.FinishReasonUnknown,
|
||||
}
|
||||
}
|
||||
|
||||
choice := response.Choices[0]
|
||||
jsonText := choice.Message.Content
|
||||
|
||||
var obj any
|
||||
if call.RepairText != nil {
|
||||
obj, err = schema.ParseAndValidateWithRepair(ctx, jsonText, call.Schema, call.RepairText)
|
||||
} else {
|
||||
obj, err = schema.ParseAndValidate(jsonText, call.Schema)
|
||||
}
|
||||
|
||||
usage, _ := o.usageFunc(*response)
|
||||
finishReason := o.mapFinishReasonFunc(choice.FinishReason)
|
||||
|
||||
if err != nil {
|
||||
if nogErr, ok := err.(*fantasy.NoObjectGeneratedError); ok {
|
||||
nogErr.Usage = usage
|
||||
nogErr.FinishReason = finishReason
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &fantasy.ObjectResponse{
|
||||
Object: obj,
|
||||
RawText: jsonText,
|
||||
Usage: usage,
|
||||
FinishReason: finishReason,
|
||||
Warnings: warnings,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o languageModel) streamObjectWithJSONMode(ctx context.Context, call fantasy.ObjectCall) (fantasy.ObjectStreamResponse, error) {
|
||||
jsonSchemaMap := schema.ToMap(call.Schema)
|
||||
|
||||
addAdditionalPropertiesFalse(jsonSchemaMap)
|
||||
|
||||
schemaName := call.SchemaName
|
||||
if schemaName == "" {
|
||||
schemaName = "response"
|
||||
}
|
||||
|
||||
fantasyCall := fantasy.Call{
|
||||
Prompt: call.Prompt,
|
||||
MaxOutputTokens: call.MaxOutputTokens,
|
||||
Temperature: call.Temperature,
|
||||
TopP: call.TopP,
|
||||
PresencePenalty: call.PresencePenalty,
|
||||
FrequencyPenalty: call.FrequencyPenalty,
|
||||
ProviderOptions: call.ProviderOptions,
|
||||
}
|
||||
|
||||
params, warnings, err := o.prepareParams(fantasyCall)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params.ResponseFormat = openai.ChatCompletionNewParamsResponseFormatUnion{
|
||||
OfJSONSchema: &shared.ResponseFormatJSONSchemaParam{
|
||||
JSONSchema: shared.ResponseFormatJSONSchemaJSONSchemaParam{
|
||||
Name: schemaName,
|
||||
Description: param.NewOpt(call.SchemaDescription),
|
||||
Schema: jsonSchemaMap,
|
||||
Strict: param.NewOpt(true),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
params.StreamOptions = openai.ChatCompletionStreamOptionsParam{
|
||||
IncludeUsage: openai.Bool(true),
|
||||
}
|
||||
|
||||
stream := o.client.Chat.Completions.NewStreaming(ctx, *params)
|
||||
|
||||
return func(yield func(fantasy.ObjectStreamPart) bool) {
|
||||
if len(warnings) > 0 {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Warnings: warnings,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var accumulated string
|
||||
var lastParsedObject any
|
||||
var usage fantasy.Usage
|
||||
var finishReason fantasy.FinishReason
|
||||
var providerMetadata fantasy.ProviderMetadata
|
||||
var streamErr error
|
||||
|
||||
for stream.Next() {
|
||||
chunk := stream.Current()
|
||||
|
||||
// Update usage
|
||||
usage, providerMetadata = o.streamUsageFunc(chunk, make(map[string]any), providerMetadata)
|
||||
|
||||
if len(chunk.Choices) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
choice := chunk.Choices[0]
|
||||
if choice.FinishReason != "" {
|
||||
finishReason = o.mapFinishReasonFunc(choice.FinishReason)
|
||||
}
|
||||
|
||||
if choice.Delta.Content != "" {
|
||||
accumulated += choice.Delta.Content
|
||||
|
||||
obj, state, parseErr := schema.ParsePartialJSON(accumulated)
|
||||
|
||||
if state == schema.ParseStateSuccessful || state == schema.ParseStateRepaired {
|
||||
if err := schema.ValidateAgainstSchema(obj, call.Schema); err == nil {
|
||||
if !reflect.DeepEqual(obj, lastParsedObject) {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Object: obj,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
lastParsedObject = obj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if state == schema.ParseStateFailed && call.RepairText != nil {
|
||||
repairedText, repairErr := call.RepairText(ctx, accumulated, parseErr)
|
||||
if repairErr == nil {
|
||||
obj2, state2, _ := schema.ParsePartialJSON(repairedText)
|
||||
if (state2 == schema.ParseStateSuccessful || state2 == schema.ParseStateRepaired) &&
|
||||
schema.ValidateAgainstSchema(obj2, call.Schema) == nil {
|
||||
if !reflect.DeepEqual(obj2, lastParsedObject) {
|
||||
if !yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeObject,
|
||||
Object: obj2,
|
||||
}) {
|
||||
return
|
||||
}
|
||||
lastParsedObject = obj2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := stream.Err()
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
streamErr = toProviderErr(err)
|
||||
yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeError,
|
||||
Error: streamErr,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if lastParsedObject != nil {
|
||||
yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeFinish,
|
||||
Usage: usage,
|
||||
FinishReason: finishReason,
|
||||
ProviderMetadata: providerMetadata,
|
||||
})
|
||||
} else {
|
||||
yield(fantasy.ObjectStreamPart{
|
||||
Type: fantasy.ObjectStreamPartTypeError,
|
||||
Error: &fantasy.NoObjectGeneratedError{
|
||||
RawText: accumulated,
|
||||
ParseError: fmt.Errorf("no valid object generated in stream"),
|
||||
Usage: usage,
|
||||
FinishReason: finishReason,
|
||||
},
|
||||
})
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// addAdditionalPropertiesFalse recursively adds "additionalProperties": false to all object schemas.
|
||||
// This is required by OpenAI's strict mode for structured outputs.
|
||||
func addAdditionalPropertiesFalse(schema map[string]any) {
|
||||
if schema["type"] == "object" {
|
||||
if _, hasAdditional := schema["additionalProperties"]; !hasAdditional {
|
||||
schema["additionalProperties"] = false
|
||||
}
|
||||
|
||||
// Recursively process nested properties
|
||||
if properties, ok := schema["properties"].(map[string]any); ok {
|
||||
for _, propValue := range properties {
|
||||
if propSchema, ok := propValue.(map[string]any); ok {
|
||||
addAdditionalPropertiesFalse(propSchema)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle array items
|
||||
if items, ok := schema["items"].(map[string]any); ok {
|
||||
addAdditionalPropertiesFalse(items)
|
||||
}
|
||||
}
|
||||
@@ -1,578 +0,0 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"github.com/openai/openai-go/v2"
|
||||
"github.com/openai/openai-go/v2/packages/param"
|
||||
"github.com/openai/openai-go/v2/shared"
|
||||
)
|
||||
|
||||
// LanguageModelPrepareCallFunc is a function that prepares the call for the language model.
|
||||
type LanguageModelPrepareCallFunc = func(model fantasy.LanguageModel, params *openai.ChatCompletionNewParams, call fantasy.Call) ([]fantasy.CallWarning, error)
|
||||
|
||||
// LanguageModelMapFinishReasonFunc is a function that maps the finish reason for the language model.
|
||||
type LanguageModelMapFinishReasonFunc = func(finishReason string) fantasy.FinishReason
|
||||
|
||||
// LanguageModelUsageFunc is a function that calculates usage for the language model.
|
||||
type LanguageModelUsageFunc = func(choice openai.ChatCompletion) (fantasy.Usage, fantasy.ProviderOptionsData)
|
||||
|
||||
// LanguageModelExtraContentFunc is a function that adds extra content for the language model.
|
||||
type LanguageModelExtraContentFunc = func(choice openai.ChatCompletionChoice) []fantasy.Content
|
||||
|
||||
// LanguageModelStreamExtraFunc is a function that handles stream extra functionality for the language model.
|
||||
type LanguageModelStreamExtraFunc = func(chunk openai.ChatCompletionChunk, yield func(fantasy.StreamPart) bool, ctx map[string]any) (map[string]any, bool)
|
||||
|
||||
// LanguageModelStreamUsageFunc is a function that calculates stream usage for the language model.
|
||||
type LanguageModelStreamUsageFunc = func(chunk openai.ChatCompletionChunk, ctx map[string]any, metadata fantasy.ProviderMetadata) (fantasy.Usage, fantasy.ProviderMetadata)
|
||||
|
||||
// LanguageModelStreamProviderMetadataFunc is a function that handles stream provider metadata for the language model.
|
||||
type LanguageModelStreamProviderMetadataFunc = func(choice openai.ChatCompletionChoice, metadata fantasy.ProviderMetadata) fantasy.ProviderMetadata
|
||||
|
||||
// LanguageModelToPromptFunc is a function that handles converting fantasy prompts to openai sdk messages.
|
||||
type LanguageModelToPromptFunc = func(prompt fantasy.Prompt, provider, model string) ([]openai.ChatCompletionMessageParamUnion, []fantasy.CallWarning)
|
||||
|
||||
// DefaultPrepareCallFunc is the default implementation for preparing a call to the language model.
|
||||
func DefaultPrepareCallFunc(model fantasy.LanguageModel, params *openai.ChatCompletionNewParams, call fantasy.Call) ([]fantasy.CallWarning, error) {
|
||||
if call.ProviderOptions == nil {
|
||||
return nil, nil
|
||||
}
|
||||
var warnings []fantasy.CallWarning
|
||||
providerOptions := &ProviderOptions{}
|
||||
if v, ok := call.ProviderOptions[Name]; ok {
|
||||
providerOptions, ok = v.(*ProviderOptions)
|
||||
if !ok {
|
||||
return nil, &fantasy.Error{Title: "invalid argument", Message: "openai provider options should be *openai.ProviderOptions"}
|
||||
}
|
||||
}
|
||||
|
||||
if providerOptions.LogitBias != nil {
|
||||
params.LogitBias = providerOptions.LogitBias
|
||||
}
|
||||
if providerOptions.LogProbs != nil && providerOptions.TopLogProbs != nil {
|
||||
providerOptions.LogProbs = nil
|
||||
}
|
||||
if providerOptions.LogProbs != nil {
|
||||
params.Logprobs = param.NewOpt(*providerOptions.LogProbs)
|
||||
}
|
||||
if providerOptions.TopLogProbs != nil {
|
||||
params.TopLogprobs = param.NewOpt(*providerOptions.TopLogProbs)
|
||||
}
|
||||
if providerOptions.User != nil {
|
||||
params.User = param.NewOpt(*providerOptions.User)
|
||||
}
|
||||
if providerOptions.ParallelToolCalls != nil {
|
||||
params.ParallelToolCalls = param.NewOpt(*providerOptions.ParallelToolCalls)
|
||||
}
|
||||
if providerOptions.MaxCompletionTokens != nil {
|
||||
params.MaxCompletionTokens = param.NewOpt(*providerOptions.MaxCompletionTokens)
|
||||
}
|
||||
|
||||
if providerOptions.TextVerbosity != nil {
|
||||
params.Verbosity = openai.ChatCompletionNewParamsVerbosity(*providerOptions.TextVerbosity)
|
||||
}
|
||||
if providerOptions.Prediction != nil {
|
||||
// Convert map[string]any to ChatCompletionPredictionContentParam
|
||||
if content, ok := providerOptions.Prediction["content"]; ok {
|
||||
if contentStr, ok := content.(string); ok {
|
||||
params.Prediction = openai.ChatCompletionPredictionContentParam{
|
||||
Content: openai.ChatCompletionPredictionContentContentUnionParam{
|
||||
OfString: param.NewOpt(contentStr),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if providerOptions.Store != nil {
|
||||
params.Store = param.NewOpt(*providerOptions.Store)
|
||||
}
|
||||
if providerOptions.Metadata != nil {
|
||||
// Convert map[string]any to map[string]string
|
||||
metadata := make(map[string]string)
|
||||
for k, v := range providerOptions.Metadata {
|
||||
if str, ok := v.(string); ok {
|
||||
metadata[k] = str
|
||||
}
|
||||
}
|
||||
params.Metadata = metadata
|
||||
}
|
||||
if providerOptions.PromptCacheKey != nil {
|
||||
params.PromptCacheKey = param.NewOpt(*providerOptions.PromptCacheKey)
|
||||
}
|
||||
if providerOptions.SafetyIdentifier != nil {
|
||||
params.SafetyIdentifier = param.NewOpt(*providerOptions.SafetyIdentifier)
|
||||
}
|
||||
if providerOptions.ServiceTier != nil {
|
||||
params.ServiceTier = openai.ChatCompletionNewParamsServiceTier(*providerOptions.ServiceTier)
|
||||
}
|
||||
|
||||
if providerOptions.ReasoningEffort != nil {
|
||||
switch *providerOptions.ReasoningEffort {
|
||||
case ReasoningEffortMinimal:
|
||||
params.ReasoningEffort = shared.ReasoningEffortMinimal
|
||||
case ReasoningEffortLow:
|
||||
params.ReasoningEffort = shared.ReasoningEffortLow
|
||||
case ReasoningEffortMedium:
|
||||
params.ReasoningEffort = shared.ReasoningEffortMedium
|
||||
case ReasoningEffortHigh:
|
||||
params.ReasoningEffort = shared.ReasoningEffortHigh
|
||||
default:
|
||||
return nil, fmt.Errorf("reasoning model `%s` not supported", *providerOptions.ReasoningEffort)
|
||||
}
|
||||
}
|
||||
|
||||
if isReasoningModel(model.Model()) {
|
||||
if providerOptions.LogitBias != nil {
|
||||
params.LogitBias = nil
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "LogitBias",
|
||||
Message: "LogitBias is not supported for reasoning models",
|
||||
})
|
||||
}
|
||||
if providerOptions.LogProbs != nil {
|
||||
params.Logprobs = param.Opt[bool]{}
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "Logprobs",
|
||||
Message: "Logprobs is not supported for reasoning models",
|
||||
})
|
||||
}
|
||||
if providerOptions.TopLogProbs != nil {
|
||||
params.TopLogprobs = param.Opt[int64]{}
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "TopLogprobs",
|
||||
Message: "TopLogprobs is not supported for reasoning models",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Handle service tier validation
|
||||
if providerOptions.ServiceTier != nil {
|
||||
serviceTier := *providerOptions.ServiceTier
|
||||
if serviceTier == "flex" && !supportsFlexProcessing(model.Model()) {
|
||||
params.ServiceTier = ""
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "ServiceTier",
|
||||
Details: "flex processing is only available for o3, o4-mini, and gpt-5 models",
|
||||
})
|
||||
} else if serviceTier == "priority" && !supportsPriorityProcessing(model.Model()) {
|
||||
params.ServiceTier = ""
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeUnsupportedSetting,
|
||||
Setting: "ServiceTier",
|
||||
Details: "priority processing is only available for supported models (gpt-4, gpt-5, gpt-5-mini, o3, o4-mini) and requires Enterprise access. gpt-5-nano is not supported",
|
||||
})
|
||||
}
|
||||
}
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
// DefaultMapFinishReasonFunc is the default implementation for mapping finish reasons.
|
||||
func DefaultMapFinishReasonFunc(finishReason string) fantasy.FinishReason {
|
||||
switch finishReason {
|
||||
case "stop":
|
||||
return fantasy.FinishReasonStop
|
||||
case "length":
|
||||
return fantasy.FinishReasonLength
|
||||
case "content_filter":
|
||||
return fantasy.FinishReasonContentFilter
|
||||
case "function_call", "tool_calls":
|
||||
return fantasy.FinishReasonToolCalls
|
||||
default:
|
||||
return fantasy.FinishReasonUnknown
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultUsageFunc is the default implementation for calculating usage.
|
||||
func DefaultUsageFunc(response openai.ChatCompletion) (fantasy.Usage, fantasy.ProviderOptionsData) {
|
||||
completionTokenDetails := response.Usage.CompletionTokensDetails
|
||||
promptTokenDetails := response.Usage.PromptTokensDetails
|
||||
|
||||
// Build provider metadata
|
||||
providerMetadata := &ProviderMetadata{}
|
||||
|
||||
// Add logprobs if available
|
||||
if len(response.Choices) > 0 && len(response.Choices[0].Logprobs.Content) > 0 {
|
||||
providerMetadata.Logprobs = response.Choices[0].Logprobs.Content
|
||||
}
|
||||
|
||||
// Add prediction tokens if available
|
||||
if completionTokenDetails.AcceptedPredictionTokens > 0 || completionTokenDetails.RejectedPredictionTokens > 0 {
|
||||
if completionTokenDetails.AcceptedPredictionTokens > 0 {
|
||||
providerMetadata.AcceptedPredictionTokens = completionTokenDetails.AcceptedPredictionTokens
|
||||
}
|
||||
if completionTokenDetails.RejectedPredictionTokens > 0 {
|
||||
providerMetadata.RejectedPredictionTokens = completionTokenDetails.RejectedPredictionTokens
|
||||
}
|
||||
}
|
||||
return fantasy.Usage{
|
||||
InputTokens: response.Usage.PromptTokens,
|
||||
OutputTokens: response.Usage.CompletionTokens,
|
||||
TotalTokens: response.Usage.TotalTokens,
|
||||
ReasoningTokens: completionTokenDetails.ReasoningTokens,
|
||||
CacheReadTokens: promptTokenDetails.CachedTokens,
|
||||
}, providerMetadata
|
||||
}
|
||||
|
||||
// DefaultStreamUsageFunc is the default implementation for calculating stream usage.
|
||||
func DefaultStreamUsageFunc(chunk openai.ChatCompletionChunk, _ map[string]any, metadata fantasy.ProviderMetadata) (fantasy.Usage, fantasy.ProviderMetadata) {
|
||||
if chunk.Usage.TotalTokens == 0 {
|
||||
return fantasy.Usage{}, nil
|
||||
}
|
||||
streamProviderMetadata := &ProviderMetadata{}
|
||||
if metadata != nil {
|
||||
if providerMetadata, ok := metadata[Name]; ok {
|
||||
converted, ok := providerMetadata.(*ProviderMetadata)
|
||||
if ok {
|
||||
streamProviderMetadata = converted
|
||||
}
|
||||
}
|
||||
}
|
||||
// we do this here because the acc does not add prompt details
|
||||
completionTokenDetails := chunk.Usage.CompletionTokensDetails
|
||||
promptTokenDetails := chunk.Usage.PromptTokensDetails
|
||||
usage := fantasy.Usage{
|
||||
InputTokens: chunk.Usage.PromptTokens,
|
||||
OutputTokens: chunk.Usage.CompletionTokens,
|
||||
TotalTokens: chunk.Usage.TotalTokens,
|
||||
ReasoningTokens: completionTokenDetails.ReasoningTokens,
|
||||
CacheReadTokens: promptTokenDetails.CachedTokens,
|
||||
}
|
||||
|
||||
// Add prediction tokens if available
|
||||
if completionTokenDetails.AcceptedPredictionTokens > 0 || completionTokenDetails.RejectedPredictionTokens > 0 {
|
||||
if completionTokenDetails.AcceptedPredictionTokens > 0 {
|
||||
streamProviderMetadata.AcceptedPredictionTokens = completionTokenDetails.AcceptedPredictionTokens
|
||||
}
|
||||
if completionTokenDetails.RejectedPredictionTokens > 0 {
|
||||
streamProviderMetadata.RejectedPredictionTokens = completionTokenDetails.RejectedPredictionTokens
|
||||
}
|
||||
}
|
||||
|
||||
return usage, fantasy.ProviderMetadata{
|
||||
Name: streamProviderMetadata,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultStreamProviderMetadataFunc is the default implementation for handling stream provider metadata.
|
||||
func DefaultStreamProviderMetadataFunc(choice openai.ChatCompletionChoice, metadata fantasy.ProviderMetadata) fantasy.ProviderMetadata {
|
||||
if metadata == nil {
|
||||
metadata = fantasy.ProviderMetadata{}
|
||||
}
|
||||
streamProviderMetadata, ok := metadata[Name]
|
||||
if !ok {
|
||||
streamProviderMetadata = &ProviderMetadata{}
|
||||
}
|
||||
if converted, ok := streamProviderMetadata.(*ProviderMetadata); ok {
|
||||
converted.Logprobs = choice.Logprobs.Content
|
||||
metadata[Name] = converted
|
||||
}
|
||||
return metadata
|
||||
}
|
||||
|
||||
// DefaultToPrompt converts a fantasy prompt to OpenAI format with default handling.
|
||||
func DefaultToPrompt(prompt fantasy.Prompt, _, _ string) ([]openai.ChatCompletionMessageParamUnion, []fantasy.CallWarning) {
|
||||
var messages []openai.ChatCompletionMessageParamUnion
|
||||
var warnings []fantasy.CallWarning
|
||||
for _, msg := range prompt {
|
||||
switch msg.Role {
|
||||
case fantasy.MessageRoleSystem:
|
||||
var systemPromptParts []string
|
||||
for _, c := range msg.Content {
|
||||
if c.GetType() != fantasy.ContentTypeText {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "system prompt can only have text content",
|
||||
})
|
||||
continue
|
||||
}
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "system prompt text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
text := textPart.Text
|
||||
if strings.TrimSpace(text) != "" {
|
||||
systemPromptParts = append(systemPromptParts, textPart.Text)
|
||||
}
|
||||
}
|
||||
if len(systemPromptParts) == 0 {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "system prompt has no text parts",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openai.SystemMessage(strings.Join(systemPromptParts, "\n")))
|
||||
case fantasy.MessageRoleUser:
|
||||
// simple user message just text content
|
||||
if len(msg.Content) == 1 && msg.Content[0].GetType() == fantasy.ContentTypeText {
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](msg.Content[0])
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "user message text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openai.UserMessage(textPart.Text))
|
||||
continue
|
||||
}
|
||||
// text content and attachments
|
||||
// for now we only support image content later we need to check
|
||||
// TODO: add the supported media types to the language model so we
|
||||
// can use that to validate the data here.
|
||||
var content []openai.ChatCompletionContentPartUnionParam
|
||||
for _, c := range msg.Content {
|
||||
switch c.GetType() {
|
||||
case fantasy.ContentTypeText:
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "user message text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
content = append(content, openai.ChatCompletionContentPartUnionParam{
|
||||
OfText: &openai.ChatCompletionContentPartTextParam{
|
||||
Text: textPart.Text,
|
||||
},
|
||||
})
|
||||
case fantasy.ContentTypeFile:
|
||||
filePart, ok := fantasy.AsContentType[fantasy.FilePart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "user message file part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(filePart.MediaType, "image/"):
|
||||
// Handle image files
|
||||
base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
|
||||
data := "data:" + filePart.MediaType + ";base64," + base64Encoded
|
||||
imageURL := openai.ChatCompletionContentPartImageImageURLParam{URL: data}
|
||||
|
||||
// Check for provider-specific options like image detail
|
||||
if providerOptions, ok := filePart.ProviderOptions[Name]; ok {
|
||||
if detail, ok := providerOptions.(*ProviderFileOptions); ok {
|
||||
imageURL.Detail = detail.ImageDetail
|
||||
}
|
||||
}
|
||||
|
||||
imageBlock := openai.ChatCompletionContentPartImageParam{ImageURL: imageURL}
|
||||
content = append(content, openai.ChatCompletionContentPartUnionParam{OfImageURL: &imageBlock})
|
||||
|
||||
case filePart.MediaType == "audio/wav":
|
||||
// Handle WAV audio files
|
||||
base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
|
||||
audioBlock := openai.ChatCompletionContentPartInputAudioParam{
|
||||
InputAudio: openai.ChatCompletionContentPartInputAudioInputAudioParam{
|
||||
Data: base64Encoded,
|
||||
Format: "wav",
|
||||
},
|
||||
}
|
||||
content = append(content, openai.ChatCompletionContentPartUnionParam{OfInputAudio: &audioBlock})
|
||||
|
||||
case filePart.MediaType == "audio/mpeg" || filePart.MediaType == "audio/mp3":
|
||||
// Handle MP3 audio files
|
||||
base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
|
||||
audioBlock := openai.ChatCompletionContentPartInputAudioParam{
|
||||
InputAudio: openai.ChatCompletionContentPartInputAudioInputAudioParam{
|
||||
Data: base64Encoded,
|
||||
Format: "mp3",
|
||||
},
|
||||
}
|
||||
content = append(content, openai.ChatCompletionContentPartUnionParam{OfInputAudio: &audioBlock})
|
||||
|
||||
case filePart.MediaType == "application/pdf":
|
||||
// Handle PDF files
|
||||
dataStr := string(filePart.Data)
|
||||
|
||||
// Check if data looks like a file ID (starts with "file-")
|
||||
if strings.HasPrefix(dataStr, "file-") {
|
||||
fileBlock := openai.ChatCompletionContentPartFileParam{
|
||||
File: openai.ChatCompletionContentPartFileFileParam{
|
||||
FileID: param.NewOpt(dataStr),
|
||||
},
|
||||
}
|
||||
content = append(content, openai.ChatCompletionContentPartUnionParam{OfFile: &fileBlock})
|
||||
} else {
|
||||
// Handle as base64 data
|
||||
base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
|
||||
data := "data:application/pdf;base64," + base64Encoded
|
||||
|
||||
filename := filePart.Filename
|
||||
if filename == "" {
|
||||
// Generate default filename based on content index
|
||||
filename = fmt.Sprintf("part-%d.pdf", len(content))
|
||||
}
|
||||
|
||||
fileBlock := openai.ChatCompletionContentPartFileParam{
|
||||
File: openai.ChatCompletionContentPartFileFileParam{
|
||||
Filename: param.NewOpt(filename),
|
||||
FileData: param.NewOpt(data),
|
||||
},
|
||||
}
|
||||
content = append(content, openai.ChatCompletionContentPartUnionParam{OfFile: &fileBlock})
|
||||
}
|
||||
|
||||
default:
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: fmt.Sprintf("file part media type %s not supported", filePart.MediaType),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hasVisibleUserContent(content) {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "dropping empty user message (contains neither user-facing content nor tool results)",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openai.UserMessage(content))
|
||||
case fantasy.MessageRoleAssistant:
|
||||
// simple assistant message just text content
|
||||
if len(msg.Content) == 1 && msg.Content[0].GetType() == fantasy.ContentTypeText {
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](msg.Content[0])
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "assistant message text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openai.AssistantMessage(textPart.Text))
|
||||
continue
|
||||
}
|
||||
assistantMsg := openai.ChatCompletionAssistantMessageParam{
|
||||
Role: "assistant",
|
||||
}
|
||||
for _, c := range msg.Content {
|
||||
switch c.GetType() {
|
||||
case fantasy.ContentTypeText:
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "assistant message text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
assistantMsg.Content = openai.ChatCompletionAssistantMessageParamContentUnion{
|
||||
OfString: param.NewOpt(textPart.Text),
|
||||
}
|
||||
case fantasy.ContentTypeToolCall:
|
||||
toolCallPart, ok := fantasy.AsContentType[fantasy.ToolCallPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "assistant message tool part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
assistantMsg.ToolCalls = append(assistantMsg.ToolCalls,
|
||||
openai.ChatCompletionMessageToolCallUnionParam{
|
||||
OfFunction: &openai.ChatCompletionMessageFunctionToolCallParam{
|
||||
ID: toolCallPart.ToolCallID,
|
||||
Type: "function",
|
||||
Function: openai.ChatCompletionMessageFunctionToolCallFunctionParam{
|
||||
Name: toolCallPart.ToolName,
|
||||
Arguments: toolCallPart.Input,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
if !hasVisibleAssistantContent(&assistantMsg) {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "dropping empty assistant message (contains neither user-facing content nor tool calls)",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openai.ChatCompletionMessageParamUnion{
|
||||
OfAssistant: &assistantMsg,
|
||||
})
|
||||
case fantasy.MessageRoleTool:
|
||||
for _, c := range msg.Content {
|
||||
if c.GetType() != fantasy.ContentTypeToolResult {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "tool message can only have tool result content",
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
toolResultPart, ok := fantasy.AsContentType[fantasy.ToolResultPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "tool message result part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
switch toolResultPart.Output.GetType() {
|
||||
case fantasy.ToolResultContentTypeText:
|
||||
output, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentText](toolResultPart.Output)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "tool result output does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openai.ToolMessage(output.Text, toolResultPart.ToolCallID))
|
||||
case fantasy.ToolResultContentTypeError:
|
||||
// TODO: check if better handling is needed
|
||||
output, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentError](toolResultPart.Output)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "tool result output does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openai.ToolMessage(output.Error.Error(), toolResultPart.ToolCallID))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return messages, warnings
|
||||
}
|
||||
|
||||
func hasVisibleUserContent(content []openai.ChatCompletionContentPartUnionParam) bool {
|
||||
for _, part := range content {
|
||||
if part.OfText != nil || part.OfImageURL != nil || part.OfInputAudio != nil || part.OfFile != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasVisibleAssistantContent(msg *openai.ChatCompletionAssistantMessageParam) bool {
|
||||
// Check if there's text content
|
||||
if !param.IsOmitted(msg.Content.OfString) || len(msg.Content.OfArrayOfContentParts) > 0 {
|
||||
return true
|
||||
}
|
||||
// Check if there are tool calls
|
||||
if len(msg.ToolCalls) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
// Package openai provides an implementation of the fantasy AI SDK for OpenAI's language models.
|
||||
package openai
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"maps"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"github.com/openai/openai-go/v2"
|
||||
"github.com/openai/openai-go/v2/option"
|
||||
)
|
||||
|
||||
const (
|
||||
// Name is the name of the OpenAI provider.
|
||||
Name = "openai"
|
||||
// DefaultURL is the default URL for the OpenAI API.
|
||||
DefaultURL = "https://api.openai.com/v1"
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
options options
|
||||
}
|
||||
|
||||
type options struct {
|
||||
baseURL string
|
||||
apiKey string
|
||||
organization string
|
||||
project string
|
||||
name string
|
||||
useResponsesAPI bool
|
||||
headers map[string]string
|
||||
client option.HTTPClient
|
||||
sdkOptions []option.RequestOption
|
||||
objectMode fantasy.ObjectMode
|
||||
languageModelOptions []LanguageModelOption
|
||||
}
|
||||
|
||||
// Option defines a function that configures OpenAI provider options.
|
||||
type Option = func(*options)
|
||||
|
||||
// New creates a new OpenAI provider with the given options.
|
||||
func New(opts ...Option) (fantasy.Provider, error) {
|
||||
providerOptions := options{
|
||||
headers: map[string]string{},
|
||||
languageModelOptions: make([]LanguageModelOption, 0),
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&providerOptions)
|
||||
}
|
||||
|
||||
providerOptions.baseURL = cmp.Or(providerOptions.baseURL, DefaultURL)
|
||||
providerOptions.name = cmp.Or(providerOptions.name, Name)
|
||||
|
||||
if providerOptions.organization != "" {
|
||||
providerOptions.headers["OpenAi-Organization"] = providerOptions.organization
|
||||
}
|
||||
if providerOptions.project != "" {
|
||||
providerOptions.headers["OpenAi-Project"] = providerOptions.project
|
||||
}
|
||||
|
||||
return &provider{options: providerOptions}, nil
|
||||
}
|
||||
|
||||
// WithBaseURL sets the base URL for the OpenAI provider.
|
||||
func WithBaseURL(baseURL string) Option {
|
||||
return func(o *options) {
|
||||
o.baseURL = baseURL
|
||||
}
|
||||
}
|
||||
|
||||
// WithAPIKey sets the API key for the OpenAI provider.
|
||||
func WithAPIKey(apiKey string) Option {
|
||||
return func(o *options) {
|
||||
o.apiKey = apiKey
|
||||
}
|
||||
}
|
||||
|
||||
// WithOrganization sets the organization for the OpenAI provider.
|
||||
func WithOrganization(organization string) Option {
|
||||
return func(o *options) {
|
||||
o.organization = organization
|
||||
}
|
||||
}
|
||||
|
||||
// WithProject sets the project for the OpenAI provider.
|
||||
func WithProject(project string) Option {
|
||||
return func(o *options) {
|
||||
o.project = project
|
||||
}
|
||||
}
|
||||
|
||||
// WithName sets the name for the OpenAI provider.
|
||||
func WithName(name string) Option {
|
||||
return func(o *options) {
|
||||
o.name = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaders sets the headers for the OpenAI provider.
|
||||
func WithHeaders(headers map[string]string) Option {
|
||||
return func(o *options) {
|
||||
maps.Copy(o.headers, headers)
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPClient sets the HTTP client for the OpenAI provider.
|
||||
func WithHTTPClient(client option.HTTPClient) Option {
|
||||
return func(o *options) {
|
||||
o.client = client
|
||||
}
|
||||
}
|
||||
|
||||
// WithSDKOptions sets the SDK options for the OpenAI provider.
|
||||
func WithSDKOptions(opts ...option.RequestOption) Option {
|
||||
return func(o *options) {
|
||||
o.sdkOptions = append(o.sdkOptions, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
// WithLanguageModelOptions sets the language model options for the OpenAI provider.
|
||||
func WithLanguageModelOptions(opts ...LanguageModelOption) Option {
|
||||
return func(o *options) {
|
||||
o.languageModelOptions = append(o.languageModelOptions, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
// WithUseResponsesAPI configures the provider to use the responses API for models that support it.
|
||||
func WithUseResponsesAPI() Option {
|
||||
return func(o *options) {
|
||||
o.useResponsesAPI = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithObjectMode sets the object generation mode.
|
||||
func WithObjectMode(om fantasy.ObjectMode) Option {
|
||||
return func(o *options) {
|
||||
// not supported
|
||||
if om == fantasy.ObjectModeJSON {
|
||||
om = fantasy.ObjectModeAuto
|
||||
}
|
||||
o.objectMode = om
|
||||
}
|
||||
}
|
||||
|
||||
// LanguageModel implements fantasy.Provider.
|
||||
func (o *provider) LanguageModel(_ context.Context, modelID string) (fantasy.LanguageModel, error) {
|
||||
openaiClientOptions := make([]option.RequestOption, 0, 5+len(o.options.headers)+len(o.options.sdkOptions))
|
||||
openaiClientOptions = append(openaiClientOptions, option.WithMaxRetries(0))
|
||||
|
||||
if o.options.apiKey != "" {
|
||||
openaiClientOptions = append(openaiClientOptions, option.WithAPIKey(o.options.apiKey))
|
||||
}
|
||||
if o.options.baseURL != "" {
|
||||
openaiClientOptions = append(openaiClientOptions, option.WithBaseURL(o.options.baseURL))
|
||||
}
|
||||
|
||||
for key, value := range o.options.headers {
|
||||
openaiClientOptions = append(openaiClientOptions, option.WithHeader(key, value))
|
||||
}
|
||||
|
||||
if o.options.client != nil {
|
||||
openaiClientOptions = append(openaiClientOptions, option.WithHTTPClient(o.options.client))
|
||||
}
|
||||
|
||||
openaiClientOptions = append(openaiClientOptions, o.options.sdkOptions...)
|
||||
|
||||
client := openai.NewClient(openaiClientOptions...)
|
||||
|
||||
if o.options.useResponsesAPI && IsResponsesModel(modelID) {
|
||||
// Not supported for responses API
|
||||
objectMode := o.options.objectMode
|
||||
if objectMode == fantasy.ObjectModeJSON {
|
||||
objectMode = fantasy.ObjectModeAuto
|
||||
}
|
||||
return newResponsesLanguageModel(modelID, o.options.name, client, objectMode), nil
|
||||
}
|
||||
|
||||
o.options.languageModelOptions = append(o.options.languageModelOptions, WithLanguageModelObjectMode(o.options.objectMode))
|
||||
|
||||
return newLanguageModel(
|
||||
modelID,
|
||||
o.options.name,
|
||||
client,
|
||||
o.options.languageModelOptions...,
|
||||
), nil
|
||||
}
|
||||
|
||||
func (o *provider) Name() string {
|
||||
return Name
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
// Package openai provides an implementation of the fantasy AI SDK for OpenAI's language models.
|
||||
package openai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"github.com/openai/openai-go/v2"
|
||||
)
|
||||
|
||||
// ReasoningEffort represents the reasoning effort level for OpenAI models.
|
||||
type ReasoningEffort string
|
||||
|
||||
const (
|
||||
// ReasoningEffortMinimal represents minimal reasoning effort.
|
||||
ReasoningEffortMinimal ReasoningEffort = "minimal"
|
||||
// ReasoningEffortLow represents low reasoning effort.
|
||||
ReasoningEffortLow ReasoningEffort = "low"
|
||||
// ReasoningEffortMedium represents medium reasoning effort.
|
||||
ReasoningEffortMedium ReasoningEffort = "medium"
|
||||
// ReasoningEffortHigh represents high reasoning effort.
|
||||
ReasoningEffortHigh ReasoningEffort = "high"
|
||||
)
|
||||
|
||||
// Global type identifiers for OpenAI-specific provider data.
|
||||
const (
|
||||
TypeProviderOptions = Name + ".options"
|
||||
TypeProviderFileOptions = Name + ".file_options"
|
||||
TypeProviderMetadata = Name + ".metadata"
|
||||
)
|
||||
|
||||
// Register OpenAI provider-specific types with the global registry.
|
||||
func init() {
|
||||
fantasy.RegisterProviderType(TypeProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ProviderOptions
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
fantasy.RegisterProviderType(TypeProviderFileOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ProviderFileOptions
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
fantasy.RegisterProviderType(TypeProviderMetadata, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ProviderMetadata
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ProviderMetadata represents additional metadata from OpenAI provider.
|
||||
type ProviderMetadata struct {
|
||||
Logprobs []openai.ChatCompletionTokenLogprob `json:"logprobs"`
|
||||
AcceptedPredictionTokens int64 `json:"accepted_prediction_tokens"`
|
||||
RejectedPredictionTokens int64 `json:"rejected_prediction_tokens"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptions interface.
|
||||
func (*ProviderMetadata) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ProviderMetadata.
|
||||
func (m ProviderMetadata) MarshalJSON() ([]byte, error) {
|
||||
type plain ProviderMetadata
|
||||
return fantasy.MarshalProviderType(TypeProviderMetadata, plain(m))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderMetadata.
|
||||
func (m *ProviderMetadata) UnmarshalJSON(data []byte) error {
|
||||
type plain ProviderMetadata
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = ProviderMetadata(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProviderOptions represents additional options for OpenAI provider.
|
||||
type ProviderOptions struct {
|
||||
LogitBias map[string]int64 `json:"logit_bias"`
|
||||
LogProbs *bool `json:"log_probs"`
|
||||
TopLogProbs *int64 `json:"top_log_probs"`
|
||||
ParallelToolCalls *bool `json:"parallel_tool_calls"`
|
||||
User *string `json:"user"`
|
||||
ReasoningEffort *ReasoningEffort `json:"reasoning_effort"`
|
||||
MaxCompletionTokens *int64 `json:"max_completion_tokens"`
|
||||
TextVerbosity *string `json:"text_verbosity"`
|
||||
Prediction map[string]any `json:"prediction"`
|
||||
Store *bool `json:"store"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
PromptCacheKey *string `json:"prompt_cache_key"`
|
||||
SafetyIdentifier *string `json:"safety_identifier"`
|
||||
ServiceTier *string `json:"service_tier"`
|
||||
StructuredOutputs *bool `json:"structured_outputs"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptions interface.
|
||||
func (*ProviderOptions) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ProviderOptions.
|
||||
func (o ProviderOptions) MarshalJSON() ([]byte, error) {
|
||||
type plain ProviderOptions
|
||||
return fantasy.MarshalProviderType(TypeProviderOptions, plain(o))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderOptions.
|
||||
func (o *ProviderOptions) UnmarshalJSON(data []byte) error {
|
||||
type plain ProviderOptions
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = ProviderOptions(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProviderFileOptions represents file options for OpenAI provider.
|
||||
type ProviderFileOptions struct {
|
||||
ImageDetail string `json:"image_detail"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptions interface.
|
||||
func (*ProviderFileOptions) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ProviderFileOptions.
|
||||
func (o ProviderFileOptions) MarshalJSON() ([]byte, error) {
|
||||
type plain ProviderFileOptions
|
||||
return fantasy.MarshalProviderType(TypeProviderFileOptions, plain(o))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderFileOptions.
|
||||
func (o *ProviderFileOptions) UnmarshalJSON(data []byte) error {
|
||||
type plain ProviderFileOptions
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = ProviderFileOptions(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReasoningEffortOption creates a pointer to a ReasoningEffort value.
|
||||
func ReasoningEffortOption(e ReasoningEffort) *ReasoningEffort {
|
||||
return &e
|
||||
}
|
||||
|
||||
// NewProviderOptions creates new provider options for OpenAI.
|
||||
func NewProviderOptions(opts *ProviderOptions) fantasy.ProviderOptions {
|
||||
return fantasy.ProviderOptions{
|
||||
Name: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// NewProviderFileOptions creates new file options for OpenAI.
|
||||
func NewProviderFileOptions(opts *ProviderFileOptions) fantasy.ProviderOptions {
|
||||
return fantasy.ProviderOptions{
|
||||
Name: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseOptions parses provider options from a map.
|
||||
func ParseOptions(data map[string]any) (*ProviderOptions, error) {
|
||||
var options ProviderOptions
|
||||
if err := fantasy.ParseOptions(data, &options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &options, nil
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,222 +0,0 @@
|
||||
// Package openai provides an implementation of the fantasy AI SDK for OpenAI's language models.
|
||||
package openai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
|
||||
"charm.land/fantasy"
|
||||
)
|
||||
|
||||
// Global type identifiers for OpenAI Responses API-specific data.
|
||||
const (
|
||||
TypeResponsesProviderOptions = Name + ".responses.options"
|
||||
TypeResponsesReasoningMetadata = Name + ".responses.reasoning_metadata"
|
||||
)
|
||||
|
||||
// Register OpenAI Responses API-specific types with the global registry.
|
||||
func init() {
|
||||
fantasy.RegisterProviderType(TypeResponsesProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ResponsesProviderOptions
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
fantasy.RegisterProviderType(TypeResponsesReasoningMetadata, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ResponsesReasoningMetadata
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ResponsesReasoningMetadata represents reasoning metadata for OpenAI Responses API.
|
||||
type ResponsesReasoningMetadata struct {
|
||||
ItemID string `json:"item_id"`
|
||||
EncryptedContent *string `json:"encrypted_content"`
|
||||
Summary []string `json:"summary"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptions interface.
|
||||
func (*ResponsesReasoningMetadata) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ResponsesReasoningMetadata.
|
||||
func (m ResponsesReasoningMetadata) MarshalJSON() ([]byte, error) {
|
||||
type plain ResponsesReasoningMetadata
|
||||
return fantasy.MarshalProviderType(TypeResponsesReasoningMetadata, plain(m))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ResponsesReasoningMetadata.
|
||||
func (m *ResponsesReasoningMetadata) UnmarshalJSON(data []byte) error {
|
||||
type plain ResponsesReasoningMetadata
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = ResponsesReasoningMetadata(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IncludeType represents the type of content to include for OpenAI Responses API.
|
||||
type IncludeType string
|
||||
|
||||
const (
|
||||
// IncludeReasoningEncryptedContent includes encrypted reasoning content.
|
||||
IncludeReasoningEncryptedContent IncludeType = "reasoning.encrypted_content"
|
||||
// IncludeFileSearchCallResults includes file search call results.
|
||||
IncludeFileSearchCallResults IncludeType = "file_search_call.results"
|
||||
// IncludeMessageOutputTextLogprobs includes message output text log probabilities.
|
||||
IncludeMessageOutputTextLogprobs IncludeType = "message.output_text.logprobs"
|
||||
)
|
||||
|
||||
// ServiceTier represents the service tier for OpenAI Responses API.
|
||||
type ServiceTier string
|
||||
|
||||
const (
|
||||
// ServiceTierAuto represents the auto service tier.
|
||||
ServiceTierAuto ServiceTier = "auto"
|
||||
// ServiceTierFlex represents the flex service tier.
|
||||
ServiceTierFlex ServiceTier = "flex"
|
||||
// ServiceTierPriority represents the priority service tier.
|
||||
ServiceTierPriority ServiceTier = "priority"
|
||||
)
|
||||
|
||||
// TextVerbosity represents the text verbosity level for OpenAI Responses API.
|
||||
type TextVerbosity string
|
||||
|
||||
const (
|
||||
// TextVerbosityLow represents low text verbosity.
|
||||
TextVerbosityLow TextVerbosity = "low"
|
||||
// TextVerbosityMedium represents medium text verbosity.
|
||||
TextVerbosityMedium TextVerbosity = "medium"
|
||||
// TextVerbosityHigh represents high text verbosity.
|
||||
TextVerbosityHigh TextVerbosity = "high"
|
||||
)
|
||||
|
||||
// ResponsesProviderOptions represents additional options for OpenAI Responses API.
|
||||
type ResponsesProviderOptions struct {
|
||||
Include []IncludeType `json:"include"`
|
||||
Instructions *string `json:"instructions"`
|
||||
Logprobs any `json:"logprobs"`
|
||||
MaxToolCalls *int64 `json:"max_tool_calls"`
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
ParallelToolCalls *bool `json:"parallel_tool_calls"`
|
||||
PromptCacheKey *string `json:"prompt_cache_key"`
|
||||
ReasoningEffort *ReasoningEffort `json:"reasoning_effort"`
|
||||
ReasoningSummary *string `json:"reasoning_summary"`
|
||||
SafetyIdentifier *string `json:"safety_identifier"`
|
||||
ServiceTier *ServiceTier `json:"service_tier"`
|
||||
StrictJSONSchema *bool `json:"strict_json_schema"`
|
||||
TextVerbosity *TextVerbosity `json:"text_verbosity"`
|
||||
User *string `json:"user"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptions interface.
|
||||
func (*ResponsesProviderOptions) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ResponsesProviderOptions.
|
||||
func (o ResponsesProviderOptions) MarshalJSON() ([]byte, error) {
|
||||
type plain ResponsesProviderOptions
|
||||
return fantasy.MarshalProviderType(TypeResponsesProviderOptions, plain(o))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ResponsesProviderOptions.
|
||||
func (o *ResponsesProviderOptions) UnmarshalJSON(data []byte) error {
|
||||
type plain ResponsesProviderOptions
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = ResponsesProviderOptions(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// responsesReasoningModelIds lists the model IDs that support reasoning for OpenAI Responses API.
|
||||
var responsesReasoningModelIDs = []string{
|
||||
"o1",
|
||||
"o1-2024-12-17",
|
||||
"o3-mini",
|
||||
"o3-mini-2025-01-31",
|
||||
"o3",
|
||||
"o3-2025-04-16",
|
||||
"o4-mini",
|
||||
"o4-mini-2025-04-16",
|
||||
"codex-mini-latest",
|
||||
"gpt-5",
|
||||
"gpt-5-2025-08-07",
|
||||
"gpt-5-mini",
|
||||
"gpt-5-mini-2025-08-07",
|
||||
"gpt-5-nano",
|
||||
"gpt-5-nano-2025-08-07",
|
||||
"gpt-5-codex",
|
||||
"gpt-5-chat",
|
||||
"gpt-5-pro",
|
||||
"gpt-5.1",
|
||||
"gpt-5.1-codex",
|
||||
"gpt-5.1-codex-max",
|
||||
"gpt-5.1-codex-mini",
|
||||
"gpt-5.1-chat",
|
||||
"gpt-5.2",
|
||||
"gpt-5.2-codex",
|
||||
"gpt-5.3",
|
||||
"gpt-5.3-codex",
|
||||
"gpt-oss-120b",
|
||||
}
|
||||
|
||||
// responsesModelIds lists all model IDs for OpenAI Responses API.
|
||||
var responsesModelIDs = append([]string{
|
||||
"gpt-4.1",
|
||||
"gpt-4.1-2025-04-14",
|
||||
"gpt-4.1-mini",
|
||||
"gpt-4.1-mini-2025-04-14",
|
||||
"gpt-4.1-nano",
|
||||
"gpt-4.1-nano-2025-04-14",
|
||||
"gpt-4o",
|
||||
"gpt-4o-2024-05-13",
|
||||
"gpt-4o-2024-08-06",
|
||||
"gpt-4o-2024-11-20",
|
||||
"gpt-4o-mini",
|
||||
"gpt-4o-mini-2024-07-18",
|
||||
"gpt-4-turbo",
|
||||
"gpt-4-turbo-2024-04-09",
|
||||
"gpt-4-turbo-preview",
|
||||
"gpt-4-0125-preview",
|
||||
"gpt-4-1106-preview",
|
||||
"gpt-4",
|
||||
"gpt-4-0613",
|
||||
"gpt-4.5-preview",
|
||||
"gpt-4.5-preview-2025-02-27",
|
||||
"gpt-3.5-turbo-0125",
|
||||
"gpt-3.5-turbo",
|
||||
"gpt-3.5-turbo-1106",
|
||||
"chatgpt-4o-latest",
|
||||
"gpt-5-chat-latest",
|
||||
}, responsesReasoningModelIDs...)
|
||||
|
||||
// NewResponsesProviderOptions creates new provider options for OpenAI Responses API.
|
||||
func NewResponsesProviderOptions(opts *ResponsesProviderOptions) fantasy.ProviderOptions {
|
||||
return fantasy.ProviderOptions{
|
||||
Name: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseResponsesOptions parses provider options from a map for OpenAI Responses API.
|
||||
func ParseResponsesOptions(data map[string]any) (*ResponsesProviderOptions, error) {
|
||||
var options ResponsesProviderOptions
|
||||
if err := fantasy.ParseOptions(data, &options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &options, nil
|
||||
}
|
||||
|
||||
// IsResponsesModel checks if a model ID is a Responses API model for OpenAI.
|
||||
func IsResponsesModel(modelID string) bool {
|
||||
return slices.Contains(responsesModelIDs, modelID)
|
||||
}
|
||||
|
||||
// IsResponsesReasoningModel checks if a model ID is a Responses API reasoning model for OpenAI.
|
||||
func IsResponsesReasoningModel(modelID string) bool {
|
||||
return slices.Contains(responsesReasoningModelIDs, modelID)
|
||||
}
|
||||
@@ -1,444 +0,0 @@
|
||||
package openaicompat
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"charm.land/fantasy/providers/openai"
|
||||
openaisdk "github.com/openai/openai-go/v2"
|
||||
"github.com/openai/openai-go/v2/packages/param"
|
||||
"github.com/openai/openai-go/v2/shared"
|
||||
)
|
||||
|
||||
const reasoningStartedCtx = "reasoning_started"
|
||||
|
||||
// PrepareCallFunc prepares the call for the language model.
|
||||
func PrepareCallFunc(_ fantasy.LanguageModel, params *openaisdk.ChatCompletionNewParams, call fantasy.Call) ([]fantasy.CallWarning, error) {
|
||||
providerOptions := &ProviderOptions{}
|
||||
if v, ok := call.ProviderOptions[Name]; ok {
|
||||
providerOptions, ok = v.(*ProviderOptions)
|
||||
if !ok {
|
||||
return nil, &fantasy.Error{Title: "invalid argument", Message: "openai-compat provider options should be *openaicompat.ProviderOptions"}
|
||||
}
|
||||
}
|
||||
|
||||
if providerOptions.ReasoningEffort != nil {
|
||||
switch *providerOptions.ReasoningEffort {
|
||||
case openai.ReasoningEffortMinimal:
|
||||
params.ReasoningEffort = shared.ReasoningEffortMinimal
|
||||
case openai.ReasoningEffortLow:
|
||||
params.ReasoningEffort = shared.ReasoningEffortLow
|
||||
case openai.ReasoningEffortMedium:
|
||||
params.ReasoningEffort = shared.ReasoningEffortMedium
|
||||
case openai.ReasoningEffortHigh:
|
||||
params.ReasoningEffort = shared.ReasoningEffortHigh
|
||||
default:
|
||||
return nil, fmt.Errorf("reasoning model `%s` not supported", *providerOptions.ReasoningEffort)
|
||||
}
|
||||
}
|
||||
|
||||
if providerOptions.User != nil {
|
||||
params.User = param.NewOpt(*providerOptions.User)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ExtraContentFunc adds extra content to the response.
|
||||
func ExtraContentFunc(choice openaisdk.ChatCompletionChoice) []fantasy.Content {
|
||||
var content []fantasy.Content
|
||||
reasoningData := ReasoningData{}
|
||||
err := json.Unmarshal([]byte(choice.Message.RawJSON()), &reasoningData)
|
||||
if err != nil {
|
||||
return content
|
||||
}
|
||||
if reasoningData.ReasoningContent != "" {
|
||||
content = append(content, fantasy.ReasoningContent{
|
||||
Text: reasoningData.ReasoningContent,
|
||||
})
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
func extractReasoningContext(ctx map[string]any) bool {
|
||||
reasoningStarted, ok := ctx[reasoningStartedCtx]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
b, ok := reasoningStarted.(bool)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// StreamExtraFunc handles extra functionality for streaming responses.
|
||||
func StreamExtraFunc(chunk openaisdk.ChatCompletionChunk, yield func(fantasy.StreamPart) bool, ctx map[string]any) (map[string]any, bool) {
|
||||
if len(chunk.Choices) == 0 {
|
||||
return ctx, true
|
||||
}
|
||||
|
||||
reasoningStarted := extractReasoningContext(ctx)
|
||||
|
||||
for inx, choice := range chunk.Choices {
|
||||
reasoningData := ReasoningData{}
|
||||
err := json.Unmarshal([]byte(choice.Delta.RawJSON()), &reasoningData)
|
||||
if err != nil {
|
||||
yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeError,
|
||||
Error: &fantasy.Error{Title: "stream error", Message: "error unmarshalling delta", Cause: err},
|
||||
})
|
||||
return ctx, false
|
||||
}
|
||||
|
||||
emitEvent := func(reasoningContent string) bool {
|
||||
if !reasoningStarted {
|
||||
shouldContinue := yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeReasoningStart,
|
||||
ID: fmt.Sprintf("%d", inx),
|
||||
})
|
||||
if !shouldContinue {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeReasoningDelta,
|
||||
ID: fmt.Sprintf("%d", inx),
|
||||
Delta: reasoningContent,
|
||||
})
|
||||
}
|
||||
if reasoningData.ReasoningContent != "" {
|
||||
if !reasoningStarted {
|
||||
ctx[reasoningStartedCtx] = true
|
||||
}
|
||||
return ctx, emitEvent(reasoningData.ReasoningContent)
|
||||
}
|
||||
if reasoningStarted && (choice.Delta.Content != "" || len(choice.Delta.ToolCalls) > 0) {
|
||||
ctx[reasoningStartedCtx] = false
|
||||
return ctx, yield(fantasy.StreamPart{
|
||||
Type: fantasy.StreamPartTypeReasoningEnd,
|
||||
ID: fmt.Sprintf("%d", inx),
|
||||
})
|
||||
}
|
||||
}
|
||||
return ctx, true
|
||||
}
|
||||
|
||||
// ToPromptFunc converts a fantasy prompt to OpenAI format with reasoning support.
|
||||
// It handles fantasy.ContentTypeReasoning in assistant messages by adding the
|
||||
// reasoning_content field to the message JSON.
|
||||
func ToPromptFunc(prompt fantasy.Prompt, _, _ string) ([]openaisdk.ChatCompletionMessageParamUnion, []fantasy.CallWarning) {
|
||||
var messages []openaisdk.ChatCompletionMessageParamUnion
|
||||
var warnings []fantasy.CallWarning
|
||||
for _, msg := range prompt {
|
||||
switch msg.Role {
|
||||
case fantasy.MessageRoleSystem:
|
||||
var systemPromptParts []string
|
||||
for _, c := range msg.Content {
|
||||
if c.GetType() != fantasy.ContentTypeText {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "system prompt can only have text content",
|
||||
})
|
||||
continue
|
||||
}
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "system prompt text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
text := textPart.Text
|
||||
if strings.TrimSpace(text) != "" {
|
||||
systemPromptParts = append(systemPromptParts, textPart.Text)
|
||||
}
|
||||
}
|
||||
if len(systemPromptParts) == 0 {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "system prompt has no text parts",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openaisdk.SystemMessage(strings.Join(systemPromptParts, "\n")))
|
||||
case fantasy.MessageRoleUser:
|
||||
// simple user message just text content
|
||||
if len(msg.Content) == 1 && msg.Content[0].GetType() == fantasy.ContentTypeText {
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](msg.Content[0])
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "user message text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openaisdk.UserMessage(textPart.Text))
|
||||
continue
|
||||
}
|
||||
// text content and attachments
|
||||
var content []openaisdk.ChatCompletionContentPartUnionParam
|
||||
for _, c := range msg.Content {
|
||||
switch c.GetType() {
|
||||
case fantasy.ContentTypeText:
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "user message text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
content = append(content, openaisdk.ChatCompletionContentPartUnionParam{
|
||||
OfText: &openaisdk.ChatCompletionContentPartTextParam{
|
||||
Text: textPart.Text,
|
||||
},
|
||||
})
|
||||
case fantasy.ContentTypeFile:
|
||||
filePart, ok := fantasy.AsContentType[fantasy.FilePart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "user message file part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(filePart.MediaType, "image/"):
|
||||
// Handle image files
|
||||
base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
|
||||
data := "data:" + filePart.MediaType + ";base64," + base64Encoded
|
||||
imageURL := openaisdk.ChatCompletionContentPartImageImageURLParam{URL: data}
|
||||
|
||||
// Check for provider-specific options like image detail
|
||||
if providerOptions, ok := filePart.ProviderOptions[openai.Name]; ok {
|
||||
if detail, ok := providerOptions.(*openai.ProviderFileOptions); ok {
|
||||
imageURL.Detail = detail.ImageDetail
|
||||
}
|
||||
}
|
||||
|
||||
imageBlock := openaisdk.ChatCompletionContentPartImageParam{ImageURL: imageURL}
|
||||
content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfImageURL: &imageBlock})
|
||||
|
||||
case filePart.MediaType == "audio/wav":
|
||||
// Handle WAV audio files
|
||||
base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
|
||||
audioBlock := openaisdk.ChatCompletionContentPartInputAudioParam{
|
||||
InputAudio: openaisdk.ChatCompletionContentPartInputAudioInputAudioParam{
|
||||
Data: base64Encoded,
|
||||
Format: "wav",
|
||||
},
|
||||
}
|
||||
content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfInputAudio: &audioBlock})
|
||||
|
||||
case filePart.MediaType == "audio/mpeg" || filePart.MediaType == "audio/mp3":
|
||||
// Handle MP3 audio files
|
||||
base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
|
||||
audioBlock := openaisdk.ChatCompletionContentPartInputAudioParam{
|
||||
InputAudio: openaisdk.ChatCompletionContentPartInputAudioInputAudioParam{
|
||||
Data: base64Encoded,
|
||||
Format: "mp3",
|
||||
},
|
||||
}
|
||||
content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfInputAudio: &audioBlock})
|
||||
|
||||
case filePart.MediaType == "application/pdf":
|
||||
// Handle PDF files
|
||||
dataStr := string(filePart.Data)
|
||||
|
||||
// Check if data looks like a file ID (starts with "file-")
|
||||
if strings.HasPrefix(dataStr, "file-") {
|
||||
fileBlock := openaisdk.ChatCompletionContentPartFileParam{
|
||||
File: openaisdk.ChatCompletionContentPartFileFileParam{
|
||||
FileID: param.NewOpt(dataStr),
|
||||
},
|
||||
}
|
||||
content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfFile: &fileBlock})
|
||||
} else {
|
||||
// Handle as base64 data
|
||||
base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
|
||||
data := "data:application/pdf;base64," + base64Encoded
|
||||
|
||||
filename := filePart.Filename
|
||||
if filename == "" {
|
||||
// Generate default filename based on content index
|
||||
filename = fmt.Sprintf("part-%d.pdf", len(content))
|
||||
}
|
||||
|
||||
fileBlock := openaisdk.ChatCompletionContentPartFileParam{
|
||||
File: openaisdk.ChatCompletionContentPartFileFileParam{
|
||||
Filename: param.NewOpt(filename),
|
||||
FileData: param.NewOpt(data),
|
||||
},
|
||||
}
|
||||
content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfFile: &fileBlock})
|
||||
}
|
||||
|
||||
default:
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: fmt.Sprintf("file part media type %s not supported", filePart.MediaType),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hasVisibleCompatUserContent(content) {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "dropping empty user message (contains neither user-facing content nor tool results)",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openaisdk.UserMessage(content))
|
||||
case fantasy.MessageRoleAssistant:
|
||||
// simple assistant message just text content
|
||||
if len(msg.Content) == 1 && msg.Content[0].GetType() == fantasy.ContentTypeText {
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](msg.Content[0])
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "assistant message text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openaisdk.AssistantMessage(textPart.Text))
|
||||
continue
|
||||
}
|
||||
assistantMsg := openaisdk.ChatCompletionAssistantMessageParam{
|
||||
Role: "assistant",
|
||||
}
|
||||
var reasoningText string
|
||||
for _, c := range msg.Content {
|
||||
switch c.GetType() {
|
||||
case fantasy.ContentTypeText:
|
||||
textPart, ok := fantasy.AsContentType[fantasy.TextPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "assistant message text part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
assistantMsg.Content = openaisdk.ChatCompletionAssistantMessageParamContentUnion{
|
||||
OfString: param.NewOpt(textPart.Text),
|
||||
}
|
||||
case fantasy.ContentTypeReasoning:
|
||||
reasoningPart, ok := fantasy.AsContentType[fantasy.ReasoningPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "assistant message reasoning part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
reasoningText = reasoningPart.Text
|
||||
case fantasy.ContentTypeToolCall:
|
||||
toolCallPart, ok := fantasy.AsContentType[fantasy.ToolCallPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "assistant message tool part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
assistantMsg.ToolCalls = append(assistantMsg.ToolCalls,
|
||||
openaisdk.ChatCompletionMessageToolCallUnionParam{
|
||||
OfFunction: &openaisdk.ChatCompletionMessageFunctionToolCallParam{
|
||||
ID: toolCallPart.ToolCallID,
|
||||
Type: "function",
|
||||
Function: openaisdk.ChatCompletionMessageFunctionToolCallFunctionParam{
|
||||
Name: toolCallPart.ToolName,
|
||||
Arguments: toolCallPart.Input,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
// Add reasoning_content field if present
|
||||
if reasoningText != "" {
|
||||
assistantMsg.SetExtraFields(map[string]any{
|
||||
"reasoning_content": reasoningText,
|
||||
})
|
||||
}
|
||||
if !hasVisibleCompatAssistantContent(&assistantMsg) {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "dropping empty assistant message (contains neither user-facing content nor tool calls)",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openaisdk.ChatCompletionMessageParamUnion{
|
||||
OfAssistant: &assistantMsg,
|
||||
})
|
||||
case fantasy.MessageRoleTool:
|
||||
for _, c := range msg.Content {
|
||||
if c.GetType() != fantasy.ContentTypeToolResult {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "tool message can only have tool result content",
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
toolResultPart, ok := fantasy.AsContentType[fantasy.ToolResultPart](c)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "tool message result part does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
switch toolResultPart.Output.GetType() {
|
||||
case fantasy.ToolResultContentTypeText:
|
||||
output, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentText](toolResultPart.Output)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "tool result output does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openaisdk.ToolMessage(output.Text, toolResultPart.ToolCallID))
|
||||
case fantasy.ToolResultContentTypeError:
|
||||
output, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentError](toolResultPart.Output)
|
||||
if !ok {
|
||||
warnings = append(warnings, fantasy.CallWarning{
|
||||
Type: fantasy.CallWarningTypeOther,
|
||||
Message: "tool result output does not have the right type",
|
||||
})
|
||||
continue
|
||||
}
|
||||
messages = append(messages, openaisdk.ToolMessage(output.Error.Error(), toolResultPart.ToolCallID))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return messages, warnings
|
||||
}
|
||||
|
||||
func hasVisibleCompatUserContent(content []openaisdk.ChatCompletionContentPartUnionParam) bool {
|
||||
for _, part := range content {
|
||||
if part.OfText != nil || part.OfImageURL != nil || part.OfInputAudio != nil || part.OfFile != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasVisibleCompatAssistantContent(msg *openaisdk.ChatCompletionAssistantMessageParam) bool {
|
||||
// Check if there's text content
|
||||
if !param.IsOmitted(msg.Content.OfString) || len(msg.Content.OfArrayOfContentParts) > 0 {
|
||||
return true
|
||||
}
|
||||
// Check if there are tool calls
|
||||
if len(msg.ToolCalls) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
// Package openaicompat provides an implementation of the fantasy AI SDK for OpenAI-compatible APIs.
|
||||
package openaicompat
|
||||
|
||||
import (
|
||||
"charm.land/fantasy"
|
||||
"charm.land/fantasy/providers/openai"
|
||||
"github.com/openai/openai-go/v2/option"
|
||||
)
|
||||
|
||||
type options struct {
|
||||
openaiOptions []openai.Option
|
||||
languageModelOptions []openai.LanguageModelOption
|
||||
sdkOptions []option.RequestOption
|
||||
objectMode fantasy.ObjectMode
|
||||
}
|
||||
|
||||
const (
|
||||
// Name is the name of the OpenAI-compatible provider.
|
||||
Name = "openai-compat"
|
||||
)
|
||||
|
||||
// Option defines a function that configures OpenAI-compatible provider options.
|
||||
type Option = func(*options)
|
||||
|
||||
// New creates a new OpenAI-compatible provider with the given options.
|
||||
func New(opts ...Option) (fantasy.Provider, error) {
|
||||
providerOptions := options{
|
||||
openaiOptions: []openai.Option{
|
||||
openai.WithName(Name),
|
||||
},
|
||||
languageModelOptions: []openai.LanguageModelOption{
|
||||
openai.WithLanguageModelPrepareCallFunc(PrepareCallFunc),
|
||||
openai.WithLanguageModelStreamExtraFunc(StreamExtraFunc),
|
||||
openai.WithLanguageModelExtraContentFunc(ExtraContentFunc),
|
||||
openai.WithLanguageModelToPromptFunc(ToPromptFunc),
|
||||
},
|
||||
objectMode: fantasy.ObjectModeTool, // Default to tool mode for openai-compat
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&providerOptions)
|
||||
}
|
||||
|
||||
// Handle object mode: convert unsupported modes to tool
|
||||
// OpenAI-compat endpoints don't support native JSON mode, so we use tool or text
|
||||
objectMode := providerOptions.objectMode
|
||||
if objectMode == fantasy.ObjectModeAuto || objectMode == fantasy.ObjectModeJSON {
|
||||
objectMode = fantasy.ObjectModeTool
|
||||
}
|
||||
|
||||
providerOptions.openaiOptions = append(
|
||||
providerOptions.openaiOptions,
|
||||
openai.WithSDKOptions(providerOptions.sdkOptions...),
|
||||
openai.WithLanguageModelOptions(providerOptions.languageModelOptions...),
|
||||
openai.WithObjectMode(objectMode),
|
||||
)
|
||||
return openai.New(providerOptions.openaiOptions...)
|
||||
}
|
||||
|
||||
// WithBaseURL sets the base URL for the OpenAI-compatible provider.
|
||||
func WithBaseURL(url string) Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithBaseURL(url))
|
||||
}
|
||||
}
|
||||
|
||||
// WithAPIKey sets the API key for the OpenAI-compatible provider.
|
||||
func WithAPIKey(apiKey string) Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithAPIKey(apiKey))
|
||||
}
|
||||
}
|
||||
|
||||
// WithName sets the name for the OpenAI-compatible provider.
|
||||
func WithName(name string) Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithName(name))
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaders sets the headers for the OpenAI-compatible provider.
|
||||
func WithHeaders(headers map[string]string) Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithHeaders(headers))
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPClient sets the HTTP client for the OpenAI-compatible provider.
|
||||
func WithHTTPClient(client option.HTTPClient) Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithHTTPClient(client))
|
||||
}
|
||||
}
|
||||
|
||||
// WithSDKOptions sets the SDK options for the OpenAI-compatible provider.
|
||||
func WithSDKOptions(opts ...option.RequestOption) Option {
|
||||
return func(o *options) {
|
||||
o.sdkOptions = append(o.sdkOptions, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
// WithObjectMode sets the object generation mode for the OpenAI-compatible provider.
|
||||
// Supported modes: ObjectModeTool, ObjectModeText.
|
||||
// ObjectModeAuto and ObjectModeJSON are automatically converted to ObjectModeTool
|
||||
// since OpenAI-compatible endpoints typically don't support native JSON mode.
|
||||
func WithObjectMode(om fantasy.ObjectMode) Option {
|
||||
return func(o *options) {
|
||||
o.objectMode = om
|
||||
}
|
||||
}
|
||||
|
||||
// WithUseResponsesAPI configures the provider to use the responses API for models that support it.
|
||||
func WithUseResponsesAPI() Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithUseResponsesAPI())
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// Package openaicompat provides an implementation of the fantasy AI SDK for OpenAI-compatible APIs.
|
||||
package openaicompat
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"charm.land/fantasy/providers/openai"
|
||||
)
|
||||
|
||||
// Global type identifiers for OpenAI-compatible provider data.
|
||||
const (
|
||||
TypeProviderOptions = Name + ".options"
|
||||
)
|
||||
|
||||
// Register OpenAI-compatible provider-specific types with the global registry.
|
||||
func init() {
|
||||
fantasy.RegisterProviderType(TypeProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ProviderOptions
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ProviderOptions represents additional options for the OpenAI-compatible provider.
|
||||
type ProviderOptions struct {
|
||||
User *string `json:"user"`
|
||||
ReasoningEffort *openai.ReasoningEffort `json:"reasoning_effort"`
|
||||
}
|
||||
|
||||
// ReasoningData represents reasoning data for OpenAI-compatible provider.
|
||||
type ReasoningData struct {
|
||||
ReasoningContent string `json:"reasoning_content"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptions interface.
|
||||
func (*ProviderOptions) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ProviderOptions.
|
||||
func (o ProviderOptions) MarshalJSON() ([]byte, error) {
|
||||
type plain ProviderOptions
|
||||
return fantasy.MarshalProviderType(TypeProviderOptions, plain(o))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderOptions.
|
||||
func (o *ProviderOptions) UnmarshalJSON(data []byte) error {
|
||||
type plain ProviderOptions
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = ProviderOptions(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewProviderOptions creates new provider options for the OpenAI-compatible provider.
|
||||
func NewProviderOptions(opts *ProviderOptions) fantasy.ProviderOptions {
|
||||
return fantasy.ProviderOptions{
|
||||
Name: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseOptions parses provider options from a map for OpenAI-compatible provider.
|
||||
func ParseOptions(data map[string]any) (*ProviderOptions, error) {
|
||||
var options ProviderOptions
|
||||
if err := fantasy.ParseOptions(data, &options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &options, nil
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,113 +0,0 @@
|
||||
// Package openrouter provides an implementation of the fantasy AI SDK for OpenRouter's language models.
|
||||
package openrouter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"charm.land/fantasy/providers/openai"
|
||||
"github.com/openai/openai-go/v2/option"
|
||||
)
|
||||
|
||||
type options struct {
|
||||
openaiOptions []openai.Option
|
||||
languageModelOptions []openai.LanguageModelOption
|
||||
objectMode fantasy.ObjectMode
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultURL is the default URL for the OpenRouter API.
|
||||
DefaultURL = "https://openrouter.ai/api/v1"
|
||||
// Name is the name of the OpenRouter provider.
|
||||
Name = "openrouter"
|
||||
)
|
||||
|
||||
// Option defines a function that configures OpenRouter provider options.
|
||||
type Option = func(*options)
|
||||
|
||||
// New creates a new OpenRouter provider with the given options.
|
||||
func New(opts ...Option) (fantasy.Provider, error) {
|
||||
providerOptions := options{
|
||||
openaiOptions: []openai.Option{
|
||||
openai.WithName(Name),
|
||||
openai.WithBaseURL(DefaultURL),
|
||||
},
|
||||
languageModelOptions: []openai.LanguageModelOption{
|
||||
openai.WithLanguageModelPrepareCallFunc(languagePrepareModelCall),
|
||||
openai.WithLanguageModelUsageFunc(languageModelUsage),
|
||||
openai.WithLanguageModelStreamUsageFunc(languageModelStreamUsage),
|
||||
openai.WithLanguageModelStreamExtraFunc(languageModelStreamExtra),
|
||||
openai.WithLanguageModelExtraContentFunc(languageModelExtraContent),
|
||||
openai.WithLanguageModelToPromptFunc(languageModelToPrompt),
|
||||
},
|
||||
objectMode: fantasy.ObjectModeTool, // Default to tool mode for openrouter
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&providerOptions)
|
||||
}
|
||||
|
||||
// Handle object mode: convert unsupported modes to tool
|
||||
// OpenRouter doesn't support native JSON mode, so we use tool or text
|
||||
objectMode := providerOptions.objectMode
|
||||
if objectMode == fantasy.ObjectModeAuto || objectMode == fantasy.ObjectModeJSON {
|
||||
objectMode = fantasy.ObjectModeTool
|
||||
}
|
||||
|
||||
providerOptions.openaiOptions = append(
|
||||
providerOptions.openaiOptions,
|
||||
openai.WithLanguageModelOptions(providerOptions.languageModelOptions...),
|
||||
openai.WithObjectMode(objectMode),
|
||||
)
|
||||
return openai.New(providerOptions.openaiOptions...)
|
||||
}
|
||||
|
||||
// WithAPIKey sets the API key for the OpenRouter provider.
|
||||
func WithAPIKey(apiKey string) Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithAPIKey(apiKey))
|
||||
}
|
||||
}
|
||||
|
||||
// WithName sets the name for the OpenRouter provider.
|
||||
func WithName(name string) Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithName(name))
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeaders sets the headers for the OpenRouter provider.
|
||||
func WithHeaders(headers map[string]string) Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithHeaders(headers))
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPClient sets the HTTP client for the OpenRouter provider.
|
||||
func WithHTTPClient(client option.HTTPClient) Option {
|
||||
return func(o *options) {
|
||||
o.openaiOptions = append(o.openaiOptions, openai.WithHTTPClient(client))
|
||||
}
|
||||
}
|
||||
|
||||
// WithObjectMode sets the object generation mode for the OpenRouter provider.
|
||||
// Supported modes: ObjectModeTool, ObjectModeText.
|
||||
// ObjectModeAuto and ObjectModeJSON are automatically converted to ObjectModeTool
|
||||
// since OpenRouter doesn't support native JSON mode.
|
||||
func WithObjectMode(om fantasy.ObjectMode) Option {
|
||||
return func(o *options) {
|
||||
o.objectMode = om
|
||||
}
|
||||
}
|
||||
|
||||
func structToMapJSON(s any) (map[string]any, error) {
|
||||
var result map[string]any
|
||||
jsonBytes, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(jsonBytes, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
// Package openrouter provides an implementation of the fantasy AI SDK for OpenRouter's language models.
|
||||
package openrouter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"charm.land/fantasy"
|
||||
)
|
||||
|
||||
// ReasoningEffort represents the reasoning effort level for OpenRouter models.
|
||||
type ReasoningEffort string
|
||||
|
||||
const (
|
||||
// ReasoningEffortLow represents low reasoning effort.
|
||||
ReasoningEffortLow ReasoningEffort = "low"
|
||||
// ReasoningEffortMedium represents medium reasoning effort.
|
||||
ReasoningEffortMedium ReasoningEffort = "medium"
|
||||
// ReasoningEffortHigh represents high reasoning effort.
|
||||
ReasoningEffortHigh ReasoningEffort = "high"
|
||||
)
|
||||
|
||||
// Global type identifiers for OpenRouter-specific provider data.
|
||||
const (
|
||||
TypeProviderOptions = Name + ".options"
|
||||
TypeProviderMetadata = Name + ".metadata"
|
||||
)
|
||||
|
||||
// Register OpenRouter provider-specific types with the global registry.
|
||||
func init() {
|
||||
fantasy.RegisterProviderType(TypeProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ProviderOptions
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
fantasy.RegisterProviderType(TypeProviderMetadata, func(data []byte) (fantasy.ProviderOptionsData, error) {
|
||||
var v ProviderMetadata
|
||||
if err := json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
})
|
||||
}
|
||||
|
||||
// PromptTokensDetails represents details about prompt tokens for OpenRouter.
|
||||
type PromptTokensDetails struct {
|
||||
CachedTokens int64 `json:"cached_tokens"`
|
||||
}
|
||||
|
||||
// CompletionTokensDetails represents details about completion tokens for OpenRouter.
|
||||
type CompletionTokensDetails struct {
|
||||
ReasoningTokens int64 `json:"reasoning_tokens"`
|
||||
}
|
||||
|
||||
// CostDetails represents cost details for OpenRouter.
|
||||
type CostDetails struct {
|
||||
UpstreamInferenceCost float64 `json:"upstream_inference_cost"`
|
||||
UpstreamInferencePromptCost float64 `json:"upstream_inference_prompt_cost"`
|
||||
UpstreamInferenceCompletionsCost float64 `json:"upstream_inference_completions_cost"`
|
||||
}
|
||||
|
||||
// UsageAccounting represents usage accounting details for OpenRouter.
|
||||
type UsageAccounting struct {
|
||||
PromptTokens int64 `json:"prompt_tokens"`
|
||||
PromptTokensDetails PromptTokensDetails `json:"prompt_tokens_details"`
|
||||
CompletionTokens int64 `json:"completion_tokens"`
|
||||
CompletionTokensDetails CompletionTokensDetails `json:"completion_tokens_details"`
|
||||
TotalTokens int64 `json:"total_tokens"`
|
||||
Cost float64 `json:"cost"`
|
||||
CostDetails CostDetails `json:"cost_details"`
|
||||
}
|
||||
|
||||
// ProviderMetadata represents metadata from OpenRouter provider.
|
||||
type ProviderMetadata struct {
|
||||
Provider string `json:"provider"`
|
||||
Usage UsageAccounting `json:"usage"`
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptionsData interface for ProviderMetadata.
|
||||
func (*ProviderMetadata) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ProviderMetadata.
|
||||
func (m ProviderMetadata) MarshalJSON() ([]byte, error) {
|
||||
type plain ProviderMetadata
|
||||
return fantasy.MarshalProviderType(TypeProviderMetadata, plain(m))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderMetadata.
|
||||
func (m *ProviderMetadata) UnmarshalJSON(data []byte) error {
|
||||
type plain ProviderMetadata
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = ProviderMetadata(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReasoningOptions represents reasoning options for OpenRouter.
|
||||
type ReasoningOptions struct {
|
||||
// Whether reasoning is enabled
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
// Whether to exclude reasoning from the response
|
||||
Exclude *bool `json:"exclude,omitempty"`
|
||||
// Maximum number of tokens to use for reasoning
|
||||
MaxTokens *int64 `json:"max_tokens,omitempty"`
|
||||
// Reasoning effort level: "low" | "medium" | "high"
|
||||
Effort *ReasoningEffort `json:"effort,omitempty"`
|
||||
}
|
||||
|
||||
// Provider represents provider routing preferences for OpenRouter.
|
||||
type Provider struct {
|
||||
// List of provider slugs to try in order (e.g. ["anthropic", "openai"])
|
||||
Order []string `json:"order,omitempty"`
|
||||
// Whether to allow backup providers when primary is unavailable (default: true)
|
||||
AllowFallbacks *bool `json:"allow_fallbacks,omitempty"`
|
||||
// Only use providers that support all parameters in your request (default: false)
|
||||
RequireParameters *bool `json:"require_parameters,omitempty"`
|
||||
// Control whether to use providers that may store data: "allow" | "deny"
|
||||
DataCollection *string `json:"data_collection,omitempty"`
|
||||
// List of provider slugs to allow for this request
|
||||
Only []string `json:"only,omitempty"`
|
||||
// List of provider slugs to skip for this request
|
||||
Ignore []string `json:"ignore,omitempty"`
|
||||
// List of quantization levels to filter by (e.g. ["int4", "int8"])
|
||||
Quantizations []string `json:"quantizations,omitempty"`
|
||||
// Sort providers by "price" | "throughput" | "latency"
|
||||
Sort *string `json:"sort,omitempty"`
|
||||
}
|
||||
|
||||
// ProviderOptions represents additional options for OpenRouter provider.
|
||||
type ProviderOptions struct {
|
||||
Reasoning *ReasoningOptions `json:"reasoning,omitempty"`
|
||||
ExtraBody map[string]any `json:"extra_body,omitempty"`
|
||||
IncludeUsage *bool `json:"include_usage,omitempty"`
|
||||
// Modify the likelihood of specified tokens appearing in the completion.
|
||||
// Accepts a map that maps tokens (specified by their token ID) to an associated bias value from -100 to 100.
|
||||
// The bias is added to the logits generated by the model prior to sampling.
|
||||
LogitBias map[string]int64 `json:"logit_bias,omitempty"`
|
||||
// Return the log probabilities of the tokens. Including logprobs will increase the response size.
|
||||
// Setting to true will return the log probabilities of the tokens that were generated.
|
||||
LogProbs *bool `json:"log_probs,omitempty"`
|
||||
// Whether to enable parallel function calling during tool use. Default to true.
|
||||
ParallelToolCalls *bool `json:"parallel_tool_calls,omitempty"`
|
||||
// A unique identifier representing your end-user, which can help OpenRouter to monitor and detect abuse.
|
||||
User *string `json:"user,omitempty"`
|
||||
// Provider routing preferences to control request routing behavior
|
||||
Provider *Provider `json:"provider,omitempty"`
|
||||
// TODO: add the web search plugin config
|
||||
}
|
||||
|
||||
// Options implements the ProviderOptionsData interface for ProviderOptions.
|
||||
func (*ProviderOptions) Options() {}
|
||||
|
||||
// MarshalJSON implements custom JSON marshaling with type info for ProviderOptions.
|
||||
func (o ProviderOptions) MarshalJSON() ([]byte, error) {
|
||||
type plain ProviderOptions
|
||||
return fantasy.MarshalProviderType(TypeProviderOptions, plain(o))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderOptions.
|
||||
func (o *ProviderOptions) UnmarshalJSON(data []byte) error {
|
||||
type plain ProviderOptions
|
||||
var p plain
|
||||
if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = ProviderOptions(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReasoningDetail represents a reasoning detail for OpenRouter.
|
||||
type ReasoningDetail struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Signature string `json:"signature,omitempty"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
// ReasoningData represents reasoning data for OpenRouter.
|
||||
type ReasoningData struct {
|
||||
Reasoning string `json:"reasoning"`
|
||||
ReasoningDetails []ReasoningDetail `json:"reasoning_details"`
|
||||
}
|
||||
|
||||
// ReasoningEffortOption creates a pointer to a ReasoningEffort value for OpenRouter.
|
||||
func ReasoningEffortOption(e ReasoningEffort) *ReasoningEffort {
|
||||
return &e
|
||||
}
|
||||
|
||||
// NewProviderOptions creates new provider options for OpenRouter.
|
||||
func NewProviderOptions(opts *ProviderOptions) fantasy.ProviderOptions {
|
||||
return fantasy.ProviderOptions{
|
||||
Name: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseOptions parses provider options from a map for OpenRouter.
|
||||
func ParseOptions(data map[string]any) (*ProviderOptions, error) {
|
||||
var options ProviderOptions
|
||||
if err := fantasy.ParseOptions(data, &options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &options, nil
|
||||
}
|
||||
Vendored
-137
@@ -1,137 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RetryFn is a function that returns a value and an error.
|
||||
type RetryFn[T any] func() (T, error)
|
||||
|
||||
// RetryFunction is a function that retries another function.
|
||||
type RetryFunction[T any] func(ctx context.Context, fn RetryFn[T]) (T, error)
|
||||
|
||||
// getRetryDelayInMs calculates the retry delay based on error headers and exponential backoff.
|
||||
func getRetryDelayInMs(err error, exponentialBackoffDelay time.Duration) time.Duration {
|
||||
var providerErr *ProviderError
|
||||
if !errors.As(err, &providerErr) || providerErr.ResponseHeaders == nil {
|
||||
return exponentialBackoffDelay
|
||||
}
|
||||
|
||||
headers := providerErr.ResponseHeaders
|
||||
var ms time.Duration
|
||||
|
||||
// retry-ms is more precise than retry-after and used by e.g. OpenAI
|
||||
if retryAfterMs, exists := headers["retry-after-ms"]; exists {
|
||||
if timeoutMs, err := strconv.ParseFloat(retryAfterMs, 64); err == nil {
|
||||
ms = time.Duration(timeoutMs) * time.Millisecond
|
||||
}
|
||||
}
|
||||
|
||||
// About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
|
||||
if retryAfter, exists := headers["retry-after"]; exists && ms == 0 {
|
||||
if timeoutSeconds, err := strconv.ParseFloat(retryAfter, 64); err == nil {
|
||||
ms = time.Duration(timeoutSeconds) * time.Second
|
||||
} else {
|
||||
// Try parsing as HTTP date
|
||||
if t, err := time.Parse(time.RFC1123, retryAfter); err == nil {
|
||||
ms = time.Until(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the delay is reasonable:
|
||||
// 0 <= ms < 60 seconds or ms < exponentialBackoffDelay
|
||||
if ms > 0 && (ms < 60*time.Second || ms < exponentialBackoffDelay) {
|
||||
return ms
|
||||
}
|
||||
|
||||
return exponentialBackoffDelay
|
||||
}
|
||||
|
||||
// isAbortError checks if the error is a context cancellation error.
|
||||
func isAbortError(err error) bool {
|
||||
return errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)
|
||||
}
|
||||
|
||||
// RetryWithExponentialBackoffRespectingRetryHeaders creates a retry function that retries
|
||||
// a failed operation with exponential backoff, while respecting rate limit headers
|
||||
// (retry-after-ms and retry-after) if they are provided and reasonable (0-60 seconds).
|
||||
func RetryWithExponentialBackoffRespectingRetryHeaders[T any](options RetryOptions) RetryFunction[T] {
|
||||
return func(ctx context.Context, fn RetryFn[T]) (T, error) {
|
||||
return retryWithExponentialBackoff(ctx, fn, options, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// RetryOptions configures the retry behavior.
|
||||
type RetryOptions struct {
|
||||
MaxRetries int
|
||||
InitialDelayIn time.Duration
|
||||
BackoffFactor float64
|
||||
OnRetry OnRetryCallback
|
||||
}
|
||||
|
||||
// OnRetryCallback defines a function that is called when a retry occurs.
|
||||
type OnRetryCallback = func(err *ProviderError, delay time.Duration)
|
||||
|
||||
// DefaultRetryOptions returns the default retry options.
|
||||
// DefaultRetryOptions returns the default retry options.
|
||||
func DefaultRetryOptions() RetryOptions {
|
||||
return RetryOptions{
|
||||
MaxRetries: 2,
|
||||
InitialDelayIn: 2000 * time.Millisecond,
|
||||
BackoffFactor: 2.0,
|
||||
}
|
||||
}
|
||||
|
||||
// retryWithExponentialBackoff implements the retry logic with exponential backoff.
|
||||
func retryWithExponentialBackoff[T any](ctx context.Context, fn RetryFn[T], options RetryOptions, allErrors []error) (T, error) {
|
||||
var zero T
|
||||
result, err := fn()
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if isAbortError(err) {
|
||||
return zero, err // don't retry when the request was aborted
|
||||
}
|
||||
|
||||
if options.MaxRetries == 0 {
|
||||
return zero, err // don't wrap the error when retries are disabled
|
||||
}
|
||||
|
||||
newErrors := append(allErrors, err)
|
||||
tryNumber := len(newErrors)
|
||||
|
||||
if tryNumber > options.MaxRetries {
|
||||
return zero, &RetryError{newErrors}
|
||||
}
|
||||
|
||||
var providerErr *ProviderError
|
||||
if errors.As(err, &providerErr) && providerErr.IsRetryable() && tryNumber <= options.MaxRetries {
|
||||
delay := getRetryDelayInMs(err, options.InitialDelayIn)
|
||||
if options.OnRetry != nil {
|
||||
options.OnRetry(providerErr, delay)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(delay):
|
||||
// Continue with retry
|
||||
case <-ctx.Done():
|
||||
return zero, ctx.Err()
|
||||
}
|
||||
|
||||
newOptions := options
|
||||
newOptions.InitialDelayIn = time.Duration(float64(options.InitialDelayIn) * options.BackoffFactor)
|
||||
|
||||
return retryWithExponentialBackoff(ctx, fn, newOptions, newErrors)
|
||||
}
|
||||
|
||||
if tryNumber == 1 {
|
||||
return zero, err // don't wrap the error when a non-retryable error occurs on the first try
|
||||
}
|
||||
|
||||
return zero, &RetryError{newErrors}
|
||||
}
|
||||
-442
@@ -1,442 +0,0 @@
|
||||
// Package schema provides JSON schema generation and validation utilities.
|
||||
// It supports automatic schema generation from Go types and validation of parsed objects.
|
||||
package schema
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"charm.land/fantasy/jsonrepair"
|
||||
"github.com/kaptinlin/jsonschema"
|
||||
)
|
||||
|
||||
// ObjectRepairFunc is a function that attempts to repair invalid JSON output.
|
||||
// It receives the raw text and the error encountered during parsing or validation,
|
||||
// and returns repaired text or an error if repair is not possible.
|
||||
type ObjectRepairFunc func(ctx context.Context, text string, err error) (string, error)
|
||||
|
||||
// ParseError is returned when object generation fails
|
||||
// due to parsing errors, validation errors, or model failures.
|
||||
type ParseError struct {
|
||||
RawText string
|
||||
ParseError error
|
||||
ValidationError error
|
||||
}
|
||||
|
||||
// Schema represents a JSON schema for tool input validation.
|
||||
type Schema struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Properties map[string]*Schema `json:"properties,omitempty"`
|
||||
Required []string `json:"required,omitempty"`
|
||||
Items *Schema `json:"items,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Enum []any `json:"enum,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Minimum *float64 `json:"minimum,omitempty"`
|
||||
Maximum *float64 `json:"maximum,omitempty"`
|
||||
MinLength *int `json:"minLength,omitempty"`
|
||||
MaxLength *int `json:"maxLength,omitempty"`
|
||||
}
|
||||
|
||||
// ParseState represents the state of JSON parsing.
|
||||
type ParseState string
|
||||
|
||||
const (
|
||||
// ParseStateUndefined means input was undefined/empty.
|
||||
ParseStateUndefined ParseState = "undefined"
|
||||
|
||||
// ParseStateSuccessful means JSON parsed without repair.
|
||||
ParseStateSuccessful ParseState = "successful"
|
||||
|
||||
// ParseStateRepaired means JSON parsed after repair.
|
||||
ParseStateRepaired ParseState = "repaired"
|
||||
|
||||
// ParseStateFailed means JSON could not be parsed even after repair.
|
||||
ParseStateFailed ParseState = "failed"
|
||||
)
|
||||
|
||||
// ToParameters converts a Schema to the parameters map format expected by ToolInfo.
|
||||
func ToParameters(s Schema) map[string]any {
|
||||
if s.Properties == nil {
|
||||
return make(map[string]any)
|
||||
}
|
||||
|
||||
result := make(map[string]any)
|
||||
for name, propSchema := range s.Properties {
|
||||
result[name] = ToMap(*propSchema)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Generate generates a JSON schema from a reflect.Type.
|
||||
// It recursively processes struct fields, arrays, maps, and primitive types.
|
||||
func Generate(t reflect.Type) Schema {
|
||||
return generateSchemaRecursive(t, make(map[reflect.Type]bool))
|
||||
}
|
||||
|
||||
func generateSchemaRecursive(t reflect.Type, visited map[reflect.Type]bool) Schema {
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
if visited[t] {
|
||||
return Schema{Type: "object"}
|
||||
}
|
||||
visited[t] = true
|
||||
defer delete(visited, t)
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.String:
|
||||
return Schema{Type: "string"}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return Schema{Type: "integer"}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return Schema{Type: "number"}
|
||||
case reflect.Bool:
|
||||
return Schema{Type: "boolean"}
|
||||
case reflect.Slice, reflect.Array:
|
||||
itemSchema := generateSchemaRecursive(t.Elem(), visited)
|
||||
return Schema{
|
||||
Type: "array",
|
||||
Items: &itemSchema,
|
||||
}
|
||||
case reflect.Map:
|
||||
if t.Key().Kind() == reflect.String {
|
||||
valueSchema := generateSchemaRecursive(t.Elem(), visited)
|
||||
schema := Schema{
|
||||
Type: "object",
|
||||
Properties: map[string]*Schema{
|
||||
"*": &valueSchema,
|
||||
},
|
||||
}
|
||||
return schema
|
||||
}
|
||||
return Schema{Type: "object"}
|
||||
case reflect.Struct:
|
||||
schema := Schema{
|
||||
Type: "object",
|
||||
Properties: make(map[string]*Schema),
|
||||
}
|
||||
for i := range t.NumField() {
|
||||
field := t.Field(i)
|
||||
|
||||
if !field.IsExported() {
|
||||
continue
|
||||
}
|
||||
|
||||
jsonTag := field.Tag.Get("json")
|
||||
if jsonTag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldName := field.Name
|
||||
required := true
|
||||
|
||||
if jsonTag != "" {
|
||||
parts := strings.Split(jsonTag, ",")
|
||||
if parts[0] != "" {
|
||||
fieldName = parts[0]
|
||||
}
|
||||
|
||||
if slices.Contains(parts[1:], "omitempty") {
|
||||
required = false
|
||||
}
|
||||
} else {
|
||||
fieldName = toSnakeCase(fieldName)
|
||||
}
|
||||
|
||||
fieldSchema := generateSchemaRecursive(field.Type, visited)
|
||||
|
||||
if desc := field.Tag.Get("description"); desc != "" {
|
||||
fieldSchema.Description = desc
|
||||
}
|
||||
|
||||
if enumTag := field.Tag.Get("enum"); enumTag != "" {
|
||||
enumValues := strings.Split(enumTag, ",")
|
||||
fieldSchema.Enum = make([]any, len(enumValues))
|
||||
for i, v := range enumValues {
|
||||
fieldSchema.Enum[i] = strings.TrimSpace(v)
|
||||
}
|
||||
}
|
||||
|
||||
schema.Properties[fieldName] = &fieldSchema
|
||||
|
||||
if required {
|
||||
schema.Required = append(schema.Required, fieldName)
|
||||
}
|
||||
}
|
||||
|
||||
return schema
|
||||
case reflect.Interface:
|
||||
return Schema{Type: "object"}
|
||||
default:
|
||||
return Schema{Type: "object"}
|
||||
}
|
||||
}
|
||||
|
||||
// ToMap converts a Schema to a map representation suitable for JSON Schema.
|
||||
func ToMap(schema Schema) map[string]any {
|
||||
result := make(map[string]any)
|
||||
|
||||
if schema.Type != "" {
|
||||
result["type"] = schema.Type
|
||||
}
|
||||
|
||||
if schema.Description != "" {
|
||||
result["description"] = schema.Description
|
||||
}
|
||||
|
||||
if len(schema.Enum) > 0 {
|
||||
result["enum"] = schema.Enum
|
||||
}
|
||||
|
||||
if schema.Format != "" {
|
||||
result["format"] = schema.Format
|
||||
}
|
||||
|
||||
if schema.Minimum != nil {
|
||||
result["minimum"] = *schema.Minimum
|
||||
}
|
||||
|
||||
if schema.Maximum != nil {
|
||||
result["maximum"] = *schema.Maximum
|
||||
}
|
||||
|
||||
if schema.MinLength != nil {
|
||||
result["minLength"] = *schema.MinLength
|
||||
}
|
||||
|
||||
if schema.MaxLength != nil {
|
||||
result["maxLength"] = *schema.MaxLength
|
||||
}
|
||||
|
||||
if schema.Properties != nil {
|
||||
props := make(map[string]any)
|
||||
for name, propSchema := range schema.Properties {
|
||||
props[name] = ToMap(*propSchema)
|
||||
}
|
||||
result["properties"] = props
|
||||
}
|
||||
|
||||
if len(schema.Required) > 0 {
|
||||
result["required"] = schema.Required
|
||||
}
|
||||
|
||||
if schema.Items != nil {
|
||||
itemsMap := ToMap(*schema.Items)
|
||||
// Ensure type is always set for items, even if it was blank for llama.cpp compatibility
|
||||
if _, hasType := itemsMap["type"]; !hasType && schema.Items.Type == "" {
|
||||
if len(schema.Items.Properties) > 0 {
|
||||
itemsMap["type"] = "object"
|
||||
}
|
||||
}
|
||||
result["items"] = itemsMap
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ParsePartialJSON attempts to parse potentially incomplete JSON.
|
||||
// It first tries standard JSON parsing, then attempts repair if that fails.
|
||||
//
|
||||
// Returns:
|
||||
// - result: The parsed JSON value (map, slice, or primitive)
|
||||
// - state: Indicates whether parsing succeeded, needed repair, or failed
|
||||
// - err: The error if parsing failed completely
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// obj, state, err := ParsePartialJSON(`{"name": "John", "age": 25`)
|
||||
// // Result: map[string]any{"name": "John", "age": 25}, ParseStateRepaired, nil
|
||||
func ParsePartialJSON(text string) (any, ParseState, error) {
|
||||
if text == "" {
|
||||
return nil, ParseStateUndefined, nil
|
||||
}
|
||||
|
||||
var result any
|
||||
if err := json.Unmarshal([]byte(text), &result); err == nil {
|
||||
return result, ParseStateSuccessful, nil
|
||||
}
|
||||
|
||||
repaired, err := jsonrepair.RepairJSON(text)
|
||||
if err != nil {
|
||||
return nil, ParseStateFailed, fmt.Errorf("json repair failed: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal([]byte(repaired), &result); err != nil {
|
||||
return nil, ParseStateFailed, fmt.Errorf("failed to parse repaired json: %w", err)
|
||||
}
|
||||
|
||||
return result, ParseStateRepaired, nil
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e *ParseError) Error() string {
|
||||
if e.ValidationError != nil {
|
||||
return fmt.Sprintf("object validation failed: %v", e.ValidationError)
|
||||
}
|
||||
if e.ParseError != nil {
|
||||
return fmt.Sprintf("failed to parse object: %v", e.ParseError)
|
||||
}
|
||||
return "failed to generate object"
|
||||
}
|
||||
|
||||
// ParseAndValidate combines JSON parsing and validation.
|
||||
// Returns the parsed object if both parsing and validation succeed.
|
||||
func ParseAndValidate(text string, schema Schema) (any, error) {
|
||||
obj, state, err := ParsePartialJSON(text)
|
||||
if state == ParseStateFailed {
|
||||
return nil, &ParseError{
|
||||
RawText: text,
|
||||
ParseError: err,
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateAgainstSchema(obj, schema); err != nil {
|
||||
return nil, &ParseError{
|
||||
RawText: text,
|
||||
ValidationError: err,
|
||||
}
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// ValidateAgainstSchema validates a parsed object against a Schema.
|
||||
func ValidateAgainstSchema(obj any, schema Schema) error {
|
||||
return validateAgainstSchema(obj, schema)
|
||||
}
|
||||
|
||||
func validateAgainstSchema(obj any, schema Schema) error {
|
||||
jsonSchemaBytes, err := json.Marshal(schema)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal schema: %w", err)
|
||||
}
|
||||
|
||||
compiler := jsonschema.NewCompiler()
|
||||
validator, err := compiler.Compile(jsonSchemaBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid schema: %w", err)
|
||||
}
|
||||
|
||||
result := validator.Validate(obj)
|
||||
if !result.IsValid() {
|
||||
var errMsgs []string
|
||||
for field, validationErr := range result.Errors {
|
||||
errMsgs = append(errMsgs, fmt.Sprintf("%s: %s", field, validationErr.Message))
|
||||
}
|
||||
return fmt.Errorf("validation failed: %s", strings.Join(errMsgs, "; "))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseAndValidateWithRepair attempts parsing, validation, and custom repair.
|
||||
func ParseAndValidateWithRepair(
|
||||
ctx context.Context,
|
||||
text string,
|
||||
schema Schema,
|
||||
repair ObjectRepairFunc,
|
||||
) (any, error) {
|
||||
obj, state, parseErr := ParsePartialJSON(text)
|
||||
|
||||
if state == ParseStateSuccessful || state == ParseStateRepaired {
|
||||
validationErr := validateAgainstSchema(obj, schema)
|
||||
if validationErr == nil {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
if repair != nil {
|
||||
repairedText, repairErr := repair(ctx, text, validationErr)
|
||||
if repairErr == nil {
|
||||
obj2, state2, _ := ParsePartialJSON(repairedText)
|
||||
if state2 == ParseStateSuccessful || state2 == ParseStateRepaired {
|
||||
if err := validateAgainstSchema(obj2, schema); err == nil {
|
||||
return obj2, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, &ParseError{
|
||||
RawText: text,
|
||||
ValidationError: validationErr,
|
||||
}
|
||||
}
|
||||
|
||||
if repair != nil {
|
||||
repairedText, repairErr := repair(ctx, text, parseErr)
|
||||
if repairErr == nil {
|
||||
obj2, state2, parseErr2 := ParsePartialJSON(repairedText)
|
||||
if state2 == ParseStateSuccessful || state2 == ParseStateRepaired {
|
||||
if err := validateAgainstSchema(obj2, schema); err == nil {
|
||||
return obj2, nil
|
||||
}
|
||||
}
|
||||
return nil, &ParseError{
|
||||
RawText: repairedText,
|
||||
ParseError: parseErr2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, &ParseError{
|
||||
RawText: text,
|
||||
ParseError: parseErr,
|
||||
}
|
||||
}
|
||||
|
||||
func toSnakeCase(s string) string {
|
||||
var result strings.Builder
|
||||
for i, r := range s {
|
||||
if i > 0 && r >= 'A' && r <= 'Z' {
|
||||
result.WriteByte('_')
|
||||
}
|
||||
result.WriteRune(r)
|
||||
}
|
||||
return strings.ToLower(result.String())
|
||||
}
|
||||
|
||||
// Normalize recursively normalizes a raw JSON Schema map so it is
|
||||
// compatible with providers that reject type-arrays (e.g. OpenAI). Type
|
||||
// arrays are converted to anyOf and bare "array" types get "items":{}.
|
||||
func Normalize(node map[string]any) {
|
||||
for _, child := range node {
|
||||
switch v := child.(type) {
|
||||
case map[string]any:
|
||||
Normalize(v)
|
||||
case []any:
|
||||
for _, item := range v {
|
||||
if m, ok := item.(map[string]any); ok {
|
||||
Normalize(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typeArr, ok := node["type"].([]any)
|
||||
if !ok {
|
||||
if node["type"] == "array" {
|
||||
if _, has := node["items"]; !has {
|
||||
node["items"] = map[string]any{}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
anyOf := make([]any, 0, len(typeArr))
|
||||
for _, t := range typeArr {
|
||||
variant := map[string]any{"type": t}
|
||||
if t == "array" {
|
||||
variant["items"] = map[string]any{}
|
||||
}
|
||||
anyOf = append(anyOf, variant)
|
||||
}
|
||||
delete(node, "type")
|
||||
node["anyOf"] = anyOf
|
||||
}
|
||||
Vendored
-175
@@ -1,175 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"charm.land/fantasy/schema"
|
||||
)
|
||||
|
||||
// Schema represents a JSON schema for tool input validation.
|
||||
type Schema = schema.Schema
|
||||
|
||||
// ToolInfo represents tool metadata, matching the existing pattern.
|
||||
type ToolInfo struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Parameters map[string]any `json:"parameters"`
|
||||
Required []string `json:"required"`
|
||||
Parallel bool `json:"parallel"` // Whether this tool can run in parallel with other tools
|
||||
}
|
||||
|
||||
// ToolCall represents a tool invocation, matching the existing pattern.
|
||||
type ToolCall struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Input string `json:"input"`
|
||||
}
|
||||
|
||||
// ToolResponse represents the response from a tool execution, matching the existing pattern.
|
||||
type ToolResponse struct {
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content"`
|
||||
// Data contains binary data for image/media responses (e.g., image bytes, audio data).
|
||||
Data []byte `json:"data,omitempty"`
|
||||
// MediaType specifies the MIME type of the media (e.g., "image/png", "audio/wav").
|
||||
MediaType string `json:"media_type,omitempty"`
|
||||
Metadata string `json:"metadata,omitempty"`
|
||||
IsError bool `json:"is_error"`
|
||||
}
|
||||
|
||||
// NewTextResponse creates a text response.
|
||||
func NewTextResponse(content string) ToolResponse {
|
||||
return ToolResponse{
|
||||
Type: "text",
|
||||
Content: content,
|
||||
}
|
||||
}
|
||||
|
||||
// NewTextErrorResponse creates an error response.
|
||||
func NewTextErrorResponse(content string) ToolResponse {
|
||||
return ToolResponse{
|
||||
Type: "text",
|
||||
Content: content,
|
||||
IsError: true,
|
||||
}
|
||||
}
|
||||
|
||||
// NewImageResponse creates an image response with binary data.
|
||||
func NewImageResponse(data []byte, mediaType string) ToolResponse {
|
||||
return ToolResponse{
|
||||
Type: "image",
|
||||
Data: data,
|
||||
MediaType: mediaType,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMediaResponse creates a media response with binary data (e.g., audio, video).
|
||||
func NewMediaResponse(data []byte, mediaType string) ToolResponse {
|
||||
return ToolResponse{
|
||||
Type: "media",
|
||||
Data: data,
|
||||
MediaType: mediaType,
|
||||
}
|
||||
}
|
||||
|
||||
// WithResponseMetadata adds metadata to a response.
|
||||
func WithResponseMetadata(response ToolResponse, metadata any) ToolResponse {
|
||||
if metadata != nil {
|
||||
metadataBytes, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
return response
|
||||
}
|
||||
response.Metadata = string(metadataBytes)
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
// AgentTool represents a tool that can be called by a language model.
|
||||
// This matches the existing BaseTool interface pattern.
|
||||
type AgentTool interface {
|
||||
Info() ToolInfo
|
||||
Run(ctx context.Context, params ToolCall) (ToolResponse, error)
|
||||
ProviderOptions() ProviderOptions
|
||||
SetProviderOptions(opts ProviderOptions)
|
||||
}
|
||||
|
||||
// NewAgentTool creates a typed tool from a function with automatic schema generation.
|
||||
// This is the recommended way to create tools.
|
||||
func NewAgentTool[TInput any](
|
||||
name string,
|
||||
description string,
|
||||
fn func(ctx context.Context, input TInput, call ToolCall) (ToolResponse, error),
|
||||
) AgentTool {
|
||||
var input TInput
|
||||
schema := schema.Generate(reflect.TypeOf(input))
|
||||
|
||||
return &funcToolWrapper[TInput]{
|
||||
name: name,
|
||||
description: description,
|
||||
fn: fn,
|
||||
schema: schema,
|
||||
parallel: false, // Default to sequential execution
|
||||
}
|
||||
}
|
||||
|
||||
// NewParallelAgentTool creates a typed tool from a function with automatic schema generation.
|
||||
// This also marks a tool as safe to run in parallel with other tools.
|
||||
func NewParallelAgentTool[TInput any](
|
||||
name string,
|
||||
description string,
|
||||
fn func(ctx context.Context, input TInput, call ToolCall) (ToolResponse, error),
|
||||
) AgentTool {
|
||||
tool := NewAgentTool(name, description, fn)
|
||||
// Try to use the SetParallel method if available
|
||||
if setter, ok := tool.(interface{ SetParallel(bool) }); ok {
|
||||
setter.SetParallel(true)
|
||||
}
|
||||
return tool
|
||||
}
|
||||
|
||||
// funcToolWrapper wraps a function to implement the AgentTool interface.
|
||||
type funcToolWrapper[TInput any] struct {
|
||||
name string
|
||||
description string
|
||||
fn func(ctx context.Context, input TInput, call ToolCall) (ToolResponse, error)
|
||||
schema Schema
|
||||
providerOptions ProviderOptions
|
||||
parallel bool
|
||||
}
|
||||
|
||||
func (w *funcToolWrapper[TInput]) SetProviderOptions(opts ProviderOptions) {
|
||||
w.providerOptions = opts
|
||||
}
|
||||
|
||||
func (w *funcToolWrapper[TInput]) ProviderOptions() ProviderOptions {
|
||||
return w.providerOptions
|
||||
}
|
||||
|
||||
func (w *funcToolWrapper[TInput]) SetParallel(parallel bool) {
|
||||
w.parallel = parallel
|
||||
}
|
||||
|
||||
func (w *funcToolWrapper[TInput]) Info() ToolInfo {
|
||||
if w.schema.Required == nil {
|
||||
w.schema.Required = []string{}
|
||||
}
|
||||
return ToolInfo{
|
||||
Name: w.name,
|
||||
Description: w.description,
|
||||
Parameters: schema.ToParameters(w.schema),
|
||||
Required: w.schema.Required,
|
||||
Parallel: w.parallel,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *funcToolWrapper[TInput]) Run(ctx context.Context, params ToolCall) (ToolResponse, error) {
|
||||
var input TInput
|
||||
if err := json.Unmarshal([]byte(params.Input), &input); err != nil {
|
||||
return NewTextErrorResponse(fmt.Sprintf("invalid parameters: %s", err)), nil
|
||||
}
|
||||
|
||||
return w.fn(ctx, input, params)
|
||||
}
|
||||
Vendored
-20
@@ -1,20 +0,0 @@
|
||||
package fantasy
|
||||
|
||||
import "github.com/go-viper/mapstructure/v2"
|
||||
|
||||
// Opt creates a pointer to the given value.
|
||||
func Opt[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
// ParseOptions parses the given options map into the provided struct.
|
||||
func ParseOptions[T any](options map[string]any, m *T) error {
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
TagName: "json",
|
||||
Result: m,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return decoder.Decode(options)
|
||||
}
|
||||
-500
@@ -1,500 +0,0 @@
|
||||
// Copyright 2016 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package civil implements types for civil time, a time-zone-independent
|
||||
// representation of time that follows the rules of the proleptic
|
||||
// Gregorian calendar with exactly 24-hour days, 60-minute hours, and 60-second
|
||||
// minutes.
|
||||
//
|
||||
// Because they lack location information, these types do not represent unique
|
||||
// moments or intervals of time. Use time.Time for that purpose.
|
||||
package civil
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Date represents a date (year, month, day).
|
||||
//
|
||||
// This type does not include location information, and therefore does not
|
||||
// describe a unique 24-hour timespan.
|
||||
type Date struct {
|
||||
Year int // Year (e.g., 2014).
|
||||
Month time.Month // Month of the year (January = 1, ...).
|
||||
Day int // Day of the month, starting at 1.
|
||||
}
|
||||
|
||||
// DateOf returns the Date in which a time occurs in that time's location.
|
||||
func DateOf(t time.Time) Date {
|
||||
var d Date
|
||||
d.Year, d.Month, d.Day = t.Date()
|
||||
return d
|
||||
}
|
||||
|
||||
// ParseDate parses a string in RFC3339 full-date format and returns the date value it represents.
|
||||
func ParseDate(s string) (Date, error) {
|
||||
t, err := time.Parse("2006-01-02", s)
|
||||
if err != nil {
|
||||
return Date{}, err
|
||||
}
|
||||
return DateOf(t), nil
|
||||
}
|
||||
|
||||
// String returns the date in RFC3339 full-date format.
|
||||
func (d Date) String() string {
|
||||
return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day)
|
||||
}
|
||||
|
||||
// IsValid reports whether the date is valid.
|
||||
func (d Date) IsValid() bool {
|
||||
return DateOf(d.In(time.UTC)) == d
|
||||
}
|
||||
|
||||
// In returns the time corresponding to time 00:00:00 of the date in the location.
|
||||
//
|
||||
// In is always consistent with time.Date, even when time.Date returns a time
|
||||
// on a different day. For example, if loc is America/Indiana/Vincennes, then both
|
||||
//
|
||||
// time.Date(1955, time.May, 1, 0, 0, 0, 0, loc)
|
||||
//
|
||||
// and
|
||||
//
|
||||
// civil.Date{Year: 1955, Month: time.May, Day: 1}.In(loc)
|
||||
//
|
||||
// return 23:00:00 on April 30, 1955.
|
||||
//
|
||||
// In panics if loc is nil.
|
||||
func (d Date) In(loc *time.Location) time.Time {
|
||||
return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, loc)
|
||||
}
|
||||
|
||||
// AddDays returns the date that is n days in the future.
|
||||
// n can also be negative to go into the past.
|
||||
func (d Date) AddDays(n int) Date {
|
||||
return DateOf(d.In(time.UTC).AddDate(0, 0, n))
|
||||
}
|
||||
|
||||
// AddMonths returns the date that is n months in the future.
|
||||
// n can also be negative to go into the past.
|
||||
func (d Date) AddMonths(n int) Date {
|
||||
return DateOf(d.In(time.UTC).AddDate(0, n, 0))
|
||||
}
|
||||
|
||||
// AddYears returns the date that is n years in the future.
|
||||
// n can also be negative to go into the past.
|
||||
func (d Date) AddYears(n int) Date {
|
||||
return DateOf(d.In(time.UTC).AddDate(n, 0, 0))
|
||||
}
|
||||
|
||||
// DaysSince returns the signed number of days between the date and s, not including the end day.
|
||||
// This is the inverse operation to AddDays.
|
||||
func (d Date) DaysSince(s Date) (days int) {
|
||||
// We convert to Unix time so we do not have to worry about leap seconds:
|
||||
// Unix time increases by exactly 86400 seconds per day.
|
||||
deltaUnix := d.In(time.UTC).Unix() - s.In(time.UTC).Unix()
|
||||
return int(deltaUnix / 86400)
|
||||
}
|
||||
|
||||
// Before reports whether d occurs before d2.
|
||||
func (d Date) Before(d2 Date) bool {
|
||||
if d.Year != d2.Year {
|
||||
return d.Year < d2.Year
|
||||
}
|
||||
if d.Month != d2.Month {
|
||||
return d.Month < d2.Month
|
||||
}
|
||||
return d.Day < d2.Day
|
||||
}
|
||||
|
||||
// After reports whether d occurs after d2.
|
||||
func (d Date) After(d2 Date) bool {
|
||||
return d2.Before(d)
|
||||
}
|
||||
|
||||
// Compare compares d and d2. If d is before d2, it returns -1;
|
||||
// if d is after d2, it returns +1; otherwise it returns 0.
|
||||
func (d Date) Compare(d2 Date) int {
|
||||
if d.Before(d2) {
|
||||
return -1
|
||||
} else if d.After(d2) {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IsZero reports whether date fields are set to their default value.
|
||||
func (d Date) IsZero() bool {
|
||||
return (d.Year == 0) && (int(d.Month) == 0) && (d.Day == 0)
|
||||
}
|
||||
|
||||
// Weekday returns the day of the week for the date.
|
||||
func (d Date) Weekday() time.Weekday {
|
||||
return d.In(time.UTC).Weekday()
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// The output is the result of d.String().
|
||||
func (d Date) MarshalText() ([]byte, error) {
|
||||
return []byte(d.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The date is expected to be a string in a format accepted by ParseDate.
|
||||
func (d *Date) UnmarshalText(data []byte) error {
|
||||
var err error
|
||||
*d, err = ParseDate(string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (d Date) Value() (driver.Value, error) {
|
||||
return d.String(), nil
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (d *Date) Scan(v any) error {
|
||||
switch vt := v.(type) {
|
||||
case time.Time:
|
||||
*d = DateOf(vt)
|
||||
case *time.Time:
|
||||
if vt != nil {
|
||||
*d = DateOf(*vt)
|
||||
}
|
||||
case string:
|
||||
var err error
|
||||
*d, err = ParseDate(vt)
|
||||
return err
|
||||
case *string:
|
||||
var err error
|
||||
if vt != nil {
|
||||
*d, err = ParseDate(*vt)
|
||||
}
|
||||
return err
|
||||
case []byte:
|
||||
var err error
|
||||
*d, err = ParseDate(string(vt))
|
||||
return err
|
||||
case *[]byte:
|
||||
var err error
|
||||
if vt != nil {
|
||||
*d, err = ParseDate(string(*vt))
|
||||
}
|
||||
return err
|
||||
case Date:
|
||||
*d = vt
|
||||
case *Date:
|
||||
*d = *vt
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for Date: %T", v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A Time represents a time with nanosecond precision.
|
||||
//
|
||||
// This type does not include location information, and therefore does not
|
||||
// describe a unique moment in time.
|
||||
//
|
||||
// This type exists to represent the TIME type in storage-based APIs like BigQuery.
|
||||
// Most operations on Times are unlikely to be meaningful. Prefer the DateTime type.
|
||||
type Time struct {
|
||||
Hour int // The hour of the day in 24-hour format; range [0-23]
|
||||
Minute int // The minute of the hour; range [0-59]
|
||||
Second int // The second of the minute; range [0-59]
|
||||
Nanosecond int // The nanosecond of the second; range [0-999999999]
|
||||
}
|
||||
|
||||
// TimeOf returns the Time representing the time of day in which a time occurs
|
||||
// in that time's location. It ignores the date.
|
||||
func TimeOf(t time.Time) Time {
|
||||
var tm Time
|
||||
tm.Hour, tm.Minute, tm.Second = t.Clock()
|
||||
tm.Nanosecond = t.Nanosecond()
|
||||
return tm
|
||||
}
|
||||
|
||||
// ParseTime parses a string and returns the time value it represents.
|
||||
// ParseTime accepts an extended form of the RFC3339 partial-time format. After
|
||||
// the HH:MM:SS part of the string, an optional fractional part may appear,
|
||||
// consisting of a decimal point followed by one to nine decimal digits.
|
||||
// (RFC3339 admits only one digit after the decimal point).
|
||||
func ParseTime(s string) (Time, error) {
|
||||
t, err := time.Parse("15:04:05.999999999", s)
|
||||
if err != nil {
|
||||
return Time{}, err
|
||||
}
|
||||
return TimeOf(t), nil
|
||||
}
|
||||
|
||||
// String returns the date in the format described in ParseTime. If Nanoseconds
|
||||
// is zero, no fractional part will be generated. Otherwise, the result will
|
||||
// end with a fractional part consisting of a decimal point and nine digits.
|
||||
func (t Time) String() string {
|
||||
s := fmt.Sprintf("%02d:%02d:%02d", t.Hour, t.Minute, t.Second)
|
||||
if t.Nanosecond == 0 {
|
||||
return s
|
||||
}
|
||||
return s + fmt.Sprintf(".%09d", t.Nanosecond)
|
||||
}
|
||||
|
||||
// IsValid reports whether the time is valid.
|
||||
func (t Time) IsValid() bool {
|
||||
// Construct a non-zero time.
|
||||
tm := time.Date(2, 2, 2, t.Hour, t.Minute, t.Second, t.Nanosecond, time.UTC)
|
||||
return TimeOf(tm) == t
|
||||
}
|
||||
|
||||
// IsZero reports whether time fields are set to their default value.
|
||||
func (t Time) IsZero() bool {
|
||||
return (t.Hour == 0) && (t.Minute == 0) && (t.Second == 0) && (t.Nanosecond == 0)
|
||||
}
|
||||
|
||||
// Before reports whether t occurs before t2.
|
||||
func (t Time) Before(t2 Time) bool {
|
||||
if t.Hour != t2.Hour {
|
||||
return t.Hour < t2.Hour
|
||||
}
|
||||
if t.Minute != t2.Minute {
|
||||
return t.Minute < t2.Minute
|
||||
}
|
||||
if t.Second != t2.Second {
|
||||
return t.Second < t2.Second
|
||||
}
|
||||
|
||||
return t.Nanosecond < t2.Nanosecond
|
||||
}
|
||||
|
||||
// After reports whether t occurs after t2.
|
||||
func (t Time) After(t2 Time) bool {
|
||||
return t2.Before(t)
|
||||
}
|
||||
|
||||
// Compare compares t and t2. If t is before t2, it returns -1;
|
||||
// if t is after t2, it returns +1; otherwise it returns 0.
|
||||
func (t Time) Compare(t2 Time) int {
|
||||
if t.Before(t2) {
|
||||
return -1
|
||||
} else if t.After(t2) {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// The output is the result of t.String().
|
||||
func (t Time) MarshalText() ([]byte, error) {
|
||||
return []byte(t.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The time is expected to be a string in a format accepted by ParseTime.
|
||||
func (t *Time) UnmarshalText(data []byte) error {
|
||||
var err error
|
||||
*t, err = ParseTime(string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (t Time) Value() (driver.Value, error) {
|
||||
return t.String(), nil
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (t *Time) Scan(v any) error {
|
||||
switch vt := v.(type) {
|
||||
case time.Time:
|
||||
*t = TimeOf(vt)
|
||||
case *time.Time:
|
||||
if vt != nil {
|
||||
*t = TimeOf(*vt)
|
||||
}
|
||||
case string:
|
||||
var err error
|
||||
*t, err = ParseTime(vt)
|
||||
return err
|
||||
case *string:
|
||||
var err error
|
||||
if vt != nil {
|
||||
*t, err = ParseTime(*vt)
|
||||
}
|
||||
return err
|
||||
case []byte:
|
||||
var err error
|
||||
*t, err = ParseTime(string(vt))
|
||||
return err
|
||||
case *[]byte:
|
||||
var err error
|
||||
if vt != nil {
|
||||
*t, err = ParseTime(string(*vt))
|
||||
}
|
||||
return err
|
||||
case Time:
|
||||
*t = vt
|
||||
case *Time:
|
||||
*t = *vt
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for Time: %T", v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A DateTime represents a date and time.
|
||||
//
|
||||
// This type does not include location information, and therefore does not
|
||||
// describe a unique moment in time.
|
||||
type DateTime struct {
|
||||
Date Date
|
||||
Time Time
|
||||
}
|
||||
|
||||
// Note: We deliberately do not embed Date into DateTime, to avoid promoting AddDays and Sub.
|
||||
|
||||
// DateTimeOf returns the DateTime in which a time occurs in that time's location.
|
||||
func DateTimeOf(t time.Time) DateTime {
|
||||
return DateTime{
|
||||
Date: DateOf(t),
|
||||
Time: TimeOf(t),
|
||||
}
|
||||
}
|
||||
|
||||
// ParseDateTime parses a string and returns the DateTime it represents.
|
||||
// ParseDateTime accepts a variant of the RFC3339 date-time format that omits
|
||||
// the time offset but includes an optional fractional time, as described in
|
||||
// ParseTime. Informally, the accepted format is
|
||||
//
|
||||
// YYYY-MM-DDTHH:MM:SS[.FFFFFFFFF]
|
||||
//
|
||||
// where the 'T' may be a lower-case 't'.
|
||||
func ParseDateTime(s string) (DateTime, error) {
|
||||
t, err := time.Parse("2006-01-02T15:04:05.999999999", s)
|
||||
if err != nil {
|
||||
t, err = time.Parse("2006-01-02t15:04:05.999999999", s)
|
||||
if err != nil {
|
||||
return DateTime{}, err
|
||||
}
|
||||
}
|
||||
return DateTimeOf(t), nil
|
||||
}
|
||||
|
||||
// String returns the date in the format described in ParseDate.
|
||||
func (dt DateTime) String() string {
|
||||
return dt.Date.String() + "T" + dt.Time.String()
|
||||
}
|
||||
|
||||
// IsValid reports whether the datetime is valid.
|
||||
func (dt DateTime) IsValid() bool {
|
||||
return dt.Date.IsValid() && dt.Time.IsValid()
|
||||
}
|
||||
|
||||
// In returns the time corresponding to the DateTime in the given location.
|
||||
//
|
||||
// If the time is missing or ambigous at the location, In returns the same
|
||||
// result as time.Date. For example, if loc is America/Indiana/Vincennes, then
|
||||
// both
|
||||
//
|
||||
// time.Date(1955, time.May, 1, 0, 30, 0, 0, loc)
|
||||
//
|
||||
// and
|
||||
//
|
||||
// civil.DateTime{
|
||||
// civil.Date{Year: 1955, Month: time.May, Day: 1}},
|
||||
// civil.Time{Minute: 30}}.In(loc)
|
||||
//
|
||||
// return 23:30:00 on April 30, 1955.
|
||||
//
|
||||
// In panics if loc is nil.
|
||||
func (dt DateTime) In(loc *time.Location) time.Time {
|
||||
return time.Date(dt.Date.Year, dt.Date.Month, dt.Date.Day, dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc)
|
||||
}
|
||||
|
||||
// Before reports whether dt occurs before dt2.
|
||||
func (dt DateTime) Before(dt2 DateTime) bool {
|
||||
return dt.In(time.UTC).Before(dt2.In(time.UTC))
|
||||
}
|
||||
|
||||
// After reports whether dt occurs after dt2.
|
||||
func (dt DateTime) After(dt2 DateTime) bool {
|
||||
return dt2.Before(dt)
|
||||
}
|
||||
|
||||
// Compare compares dt and dt2. If dt is before dt2, it returns -1;
|
||||
// if dt is after dt2, it returns +1; otherwise it returns 0.
|
||||
func (dt DateTime) Compare(dt2 DateTime) int {
|
||||
return dt.In(time.UTC).Compare(dt2.In(time.UTC))
|
||||
}
|
||||
|
||||
// IsZero reports whether datetime fields are set to their default value.
|
||||
func (dt DateTime) IsZero() bool {
|
||||
return dt.Date.IsZero() && dt.Time.IsZero()
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// The output is the result of dt.String().
|
||||
func (dt DateTime) MarshalText() ([]byte, error) {
|
||||
return []byte(dt.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The datetime is expected to be a string in a format accepted by ParseDateTime
|
||||
func (dt *DateTime) UnmarshalText(data []byte) error {
|
||||
var err error
|
||||
*dt, err = ParseDateTime(string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
// Value implements the database/sql/driver Valuer interface.
|
||||
func (dt DateTime) Value() (driver.Value, error) {
|
||||
return dt.String(), nil
|
||||
}
|
||||
|
||||
// Scan implements the database/sql Scanner interface.
|
||||
func (dt *DateTime) Scan(v any) error {
|
||||
switch vt := v.(type) {
|
||||
case time.Time:
|
||||
*dt = DateTimeOf(vt)
|
||||
case *time.Time:
|
||||
if vt != nil {
|
||||
*dt = DateTimeOf(*vt)
|
||||
}
|
||||
case string:
|
||||
var err error
|
||||
*dt, err = ParseDateTime(vt)
|
||||
return err
|
||||
case *string:
|
||||
var err error
|
||||
if vt != nil {
|
||||
*dt, err = ParseDateTime(*vt)
|
||||
}
|
||||
return err
|
||||
case []byte:
|
||||
var err error
|
||||
*dt, err = ParseDateTime(string(vt))
|
||||
return err
|
||||
case *[]byte:
|
||||
var err error
|
||||
if vt != nil {
|
||||
*dt, err = ParseDateTime(string(*vt))
|
||||
}
|
||||
return err
|
||||
case DateTime:
|
||||
*dt = vt
|
||||
case *DateTime:
|
||||
*dt = *vt
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for DateTime: %T", v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-170
@@ -1,170 +0,0 @@
|
||||
# v1.7.5 (2026-02-23)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.7.4 (2025-12-02)
|
||||
|
||||
* **Dependency Update**: Upgrade to smithy-go v1.24.0. Notably this version of the library reduces the allocation footprint of the middleware system. We observe a ~10% reduction in allocations per SDK call with this change.
|
||||
|
||||
# v1.7.3 (2025-11-04)
|
||||
|
||||
* **Dependency Update**: Upgrade to smithy-go v1.23.2 which should convey some passive reduction of overall allocations, especially when not using the metrics system.
|
||||
|
||||
# v1.7.2 (2025-10-16)
|
||||
|
||||
* **Dependency Update**: Bump minimum Go version to 1.23.
|
||||
|
||||
# v1.7.1 (2025-08-27)
|
||||
|
||||
* **Dependency Update**: Update to smithy-go v1.23.0.
|
||||
|
||||
# v1.7.0 (2025-07-28)
|
||||
|
||||
* **Feature**: Add support for HTTP interceptors.
|
||||
|
||||
# v1.6.11 (2025-06-17)
|
||||
|
||||
* **Dependency Update**: Update to smithy-go v1.22.4.
|
||||
|
||||
# v1.6.10 (2025-02-18)
|
||||
|
||||
* **Bug Fix**: Bump go version to 1.22
|
||||
|
||||
# v1.6.9 (2025-02-14)
|
||||
|
||||
* **Bug Fix**: Remove max limit on event stream messages
|
||||
|
||||
# v1.6.8 (2025-01-24)
|
||||
|
||||
* **Dependency Update**: Upgrade to smithy-go v1.22.2.
|
||||
|
||||
# v1.6.7 (2024-11-18)
|
||||
|
||||
* **Dependency Update**: Update to smithy-go v1.22.1.
|
||||
|
||||
# v1.6.6 (2024-10-04)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.5 (2024-09-20)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.4 (2024-08-15)
|
||||
|
||||
* **Dependency Update**: Bump minimum Go version to 1.21.
|
||||
|
||||
# v1.6.3 (2024-06-28)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.2 (2024-03-29)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.1 (2024-02-21)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.6.0 (2024-02-13)
|
||||
|
||||
* **Feature**: Bump minimum Go version to 1.20 per our language support policy.
|
||||
|
||||
# v1.5.4 (2023-12-07)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.5.3 (2023-11-30)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.5.2 (2023-11-29)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.5.1 (2023-11-15)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.5.0 (2023-10-31)
|
||||
|
||||
* **Feature**: **BREAKING CHANGE**: Bump minimum go version to 1.19 per the revised [go version support policy](https://aws.amazon.com/blogs/developer/aws-sdk-for-go-aligns-with-go-release-policy-on-supported-runtimes/).
|
||||
|
||||
# v1.4.14 (2023-10-06)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.13 (2023-08-18)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.12 (2023-08-07)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.11 (2023-07-31)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.10 (2022-12-02)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.9 (2022-10-24)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.8 (2022-09-14)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.7 (2022-09-02)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.6 (2022-08-31)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.5 (2022-08-29)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.4 (2022-08-09)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.3 (2022-06-29)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.2 (2022-06-07)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.1 (2022-03-24)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
||||
# v1.4.0 (2022-03-08)
|
||||
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
# v1.3.0 (2022-02-24)
|
||||
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
# v1.2.0 (2022-01-14)
|
||||
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
# v1.1.0 (2022-01-07)
|
||||
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
# v1.0.0 (2021-11-06)
|
||||
|
||||
* **Announcement**: Support has been added for AWS EventStream APIs for Kinesis, S3, and Transcribe Streaming. Support for the Lex Runtime V2 EventStream API will be added in a future release.
|
||||
* **Release**: Protocol support has been added for AWS event stream.
|
||||
* **Feature**: Updated `github.com/aws/smithy-go` to latest version
|
||||
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type decodedMessage struct {
|
||||
rawMessage
|
||||
Headers decodedHeaders `json:"headers"`
|
||||
}
|
||||
type jsonMessage struct {
|
||||
Length json.Number `json:"total_length"`
|
||||
HeadersLen json.Number `json:"headers_length"`
|
||||
PreludeCRC json.Number `json:"prelude_crc"`
|
||||
Headers decodedHeaders `json:"headers"`
|
||||
Payload []byte `json:"payload"`
|
||||
CRC json.Number `json:"message_crc"`
|
||||
}
|
||||
|
||||
func (d *decodedMessage) UnmarshalJSON(b []byte) (err error) {
|
||||
var jsonMsg jsonMessage
|
||||
if err = json.Unmarshal(b, &jsonMsg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Length, err = numAsUint32(jsonMsg.Length)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.HeadersLen, err = numAsUint32(jsonMsg.HeadersLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.PreludeCRC, err = numAsUint32(jsonMsg.PreludeCRC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Headers = jsonMsg.Headers
|
||||
d.Payload = jsonMsg.Payload
|
||||
d.CRC, err = numAsUint32(jsonMsg.CRC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *decodedMessage) MarshalJSON() ([]byte, error) {
|
||||
jsonMsg := jsonMessage{
|
||||
Length: json.Number(strconv.Itoa(int(d.Length))),
|
||||
HeadersLen: json.Number(strconv.Itoa(int(d.HeadersLen))),
|
||||
PreludeCRC: json.Number(strconv.Itoa(int(d.PreludeCRC))),
|
||||
Headers: d.Headers,
|
||||
Payload: d.Payload,
|
||||
CRC: json.Number(strconv.Itoa(int(d.CRC))),
|
||||
}
|
||||
|
||||
return json.Marshal(jsonMsg)
|
||||
}
|
||||
|
||||
func numAsUint32(n json.Number) (uint32, error) {
|
||||
v, err := n.Int64()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get int64 json number, %v", err)
|
||||
}
|
||||
|
||||
return uint32(v), nil
|
||||
}
|
||||
|
||||
func (d decodedMessage) Message() Message {
|
||||
return Message{
|
||||
Headers: Headers(d.Headers),
|
||||
Payload: d.Payload,
|
||||
}
|
||||
}
|
||||
|
||||
type decodedHeaders Headers
|
||||
|
||||
func (hs *decodedHeaders) UnmarshalJSON(b []byte) error {
|
||||
var jsonHeaders []struct {
|
||||
Name string `json:"name"`
|
||||
Type valueType `json:"type"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(b))
|
||||
decoder.UseNumber()
|
||||
if err := decoder.Decode(&jsonHeaders); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var headers Headers
|
||||
for _, h := range jsonHeaders {
|
||||
value, err := valueFromType(h.Type, h.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headers.Set(h.Name, value)
|
||||
}
|
||||
*hs = decodedHeaders(headers)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func valueFromType(typ valueType, val interface{}) (Value, error) {
|
||||
switch typ {
|
||||
case trueValueType:
|
||||
return BoolValue(true), nil
|
||||
case falseValueType:
|
||||
return BoolValue(false), nil
|
||||
case int8ValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return Int8Value(int8(v)), err
|
||||
case int16ValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return Int16Value(int16(v)), err
|
||||
case int32ValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return Int32Value(int32(v)), err
|
||||
case int64ValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return Int64Value(v), err
|
||||
case bytesValueType:
|
||||
v, err := base64.StdEncoding.DecodeString(val.(string))
|
||||
return BytesValue(v), err
|
||||
case stringValueType:
|
||||
v, err := base64.StdEncoding.DecodeString(val.(string))
|
||||
return StringValue(string(v)), err
|
||||
case timestampValueType:
|
||||
v, err := val.(json.Number).Int64()
|
||||
return TimestampValue(timeFromEpochMilli(v)), err
|
||||
case uuidValueType:
|
||||
v, err := base64.StdEncoding.DecodeString(val.(string))
|
||||
var tv UUIDValue
|
||||
copy(tv[:], v)
|
||||
return tv, err
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown type, %s, %T", typ.String(), val))
|
||||
}
|
||||
}
|
||||
-218
@@ -1,218 +0,0 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
)
|
||||
|
||||
// DecoderOptions is the Decoder configuration options.
|
||||
type DecoderOptions struct {
|
||||
Logger logging.Logger
|
||||
LogMessages bool
|
||||
}
|
||||
|
||||
// Decoder provides decoding of an Event Stream messages.
|
||||
type Decoder struct {
|
||||
options DecoderOptions
|
||||
}
|
||||
|
||||
// NewDecoder initializes and returns a Decoder for decoding event
|
||||
// stream messages from the reader provided.
|
||||
func NewDecoder(optFns ...func(*DecoderOptions)) *Decoder {
|
||||
options := DecoderOptions{}
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&options)
|
||||
}
|
||||
|
||||
return &Decoder{
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// Decode attempts to decode a single message from the event stream reader.
|
||||
// Will return the event stream message, or error if decodeMessage fails to read
|
||||
// the message from the stream.
|
||||
//
|
||||
// payloadBuf is a byte slice that will be used in the returned Message.Payload. Callers
|
||||
// must ensure that the Message.Payload from a previous decode has been consumed before passing in the same underlying
|
||||
// payloadBuf byte slice.
|
||||
func (d *Decoder) Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
||||
if d.options.Logger != nil && d.options.LogMessages {
|
||||
debugMsgBuf := bytes.NewBuffer(nil)
|
||||
reader = io.TeeReader(reader, debugMsgBuf)
|
||||
defer func() {
|
||||
logMessageDecode(d.options.Logger, debugMsgBuf, m, err)
|
||||
}()
|
||||
}
|
||||
|
||||
m, err = decodeMessage(reader, payloadBuf)
|
||||
|
||||
return m, err
|
||||
}
|
||||
|
||||
// decodeMessage attempts to decode a single message from the event stream reader.
|
||||
// Will return the event stream message, or error if decodeMessage fails to read
|
||||
// the message from the reader.
|
||||
func decodeMessage(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
||||
crc := crc32.New(crc32IEEETable)
|
||||
hashReader := io.TeeReader(reader, crc)
|
||||
|
||||
prelude, err := decodePrelude(hashReader, crc)
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
|
||||
if prelude.HeadersLen > 0 {
|
||||
lr := io.LimitReader(hashReader, int64(prelude.HeadersLen))
|
||||
m.Headers, err = decodeHeaders(lr)
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if payloadLen := prelude.PayloadLen(); payloadLen > 0 {
|
||||
buf, err := decodePayload(payloadBuf, io.LimitReader(hashReader, int64(payloadLen)))
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
m.Payload = buf
|
||||
}
|
||||
|
||||
msgCRC := crc.Sum32()
|
||||
if err := validateCRC(reader, msgCRC); err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func logMessageDecode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
|
||||
w := bytes.NewBuffer(nil)
|
||||
defer func() { logger.Logf(logging.Debug, w.String()) }()
|
||||
|
||||
fmt.Fprintf(w, "Raw message:\n%s\n",
|
||||
hex.Dump(msgBuf.Bytes()))
|
||||
|
||||
if decodeErr != nil {
|
||||
fmt.Fprintf(w, "decodeMessage error: %v\n", decodeErr)
|
||||
return
|
||||
}
|
||||
|
||||
rawMsg, err := msg.rawMessage()
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "failed to create raw message, %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
decodedMsg := decodedMessage{
|
||||
rawMessage: rawMsg,
|
||||
Headers: decodedHeaders(msg.Headers),
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "Decoded message:\n")
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(decodedMsg); err != nil {
|
||||
fmt.Fprintf(w, "failed to generate decoded message, %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func decodePrelude(r io.Reader, crc hash.Hash32) (messagePrelude, error) {
|
||||
var p messagePrelude
|
||||
|
||||
var err error
|
||||
p.Length, err = decodeUint32(r)
|
||||
if err != nil {
|
||||
return messagePrelude{}, err
|
||||
}
|
||||
|
||||
p.HeadersLen, err = decodeUint32(r)
|
||||
if err != nil {
|
||||
return messagePrelude{}, err
|
||||
}
|
||||
|
||||
if err := p.ValidateLens(); err != nil {
|
||||
return messagePrelude{}, err
|
||||
}
|
||||
|
||||
preludeCRC := crc.Sum32()
|
||||
if err := validateCRC(r, preludeCRC); err != nil {
|
||||
return messagePrelude{}, err
|
||||
}
|
||||
|
||||
p.PreludeCRC = preludeCRC
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func decodePayload(buf []byte, r io.Reader) ([]byte, error) {
|
||||
w := bytes.NewBuffer(buf[0:0])
|
||||
|
||||
_, err := io.Copy(w, r)
|
||||
return w.Bytes(), err
|
||||
}
|
||||
|
||||
func decodeUint8(r io.Reader) (uint8, error) {
|
||||
type byteReader interface {
|
||||
ReadByte() (byte, error)
|
||||
}
|
||||
|
||||
if br, ok := r.(byteReader); ok {
|
||||
v, err := br.ReadByte()
|
||||
return v, err
|
||||
}
|
||||
|
||||
var b [1]byte
|
||||
_, err := io.ReadFull(r, b[:])
|
||||
return b[0], err
|
||||
}
|
||||
|
||||
func decodeUint16(r io.Reader) (uint16, error) {
|
||||
var b [2]byte
|
||||
bs := b[:]
|
||||
_, err := io.ReadFull(r, bs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return binary.BigEndian.Uint16(bs), nil
|
||||
}
|
||||
|
||||
func decodeUint32(r io.Reader) (uint32, error) {
|
||||
var b [4]byte
|
||||
bs := b[:]
|
||||
_, err := io.ReadFull(r, bs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return binary.BigEndian.Uint32(bs), nil
|
||||
}
|
||||
|
||||
func decodeUint64(r io.Reader) (uint64, error) {
|
||||
var b [8]byte
|
||||
bs := b[:]
|
||||
_, err := io.ReadFull(r, bs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return binary.BigEndian.Uint64(bs), nil
|
||||
}
|
||||
|
||||
func validateCRC(r io.Reader, expect uint32) error {
|
||||
msgCRC, err := decodeUint32(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if msgCRC != expect {
|
||||
return ChecksumError{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
)
|
||||
|
||||
// EncoderOptions is the configuration options for Encoder.
|
||||
type EncoderOptions struct {
|
||||
Logger logging.Logger
|
||||
LogMessages bool
|
||||
}
|
||||
|
||||
// Encoder provides EventStream message encoding.
|
||||
type Encoder struct {
|
||||
options EncoderOptions
|
||||
|
||||
headersBuf *bytes.Buffer
|
||||
messageBuf *bytes.Buffer
|
||||
}
|
||||
|
||||
// NewEncoder initializes and returns an Encoder to encode Event Stream
|
||||
// messages.
|
||||
func NewEncoder(optFns ...func(*EncoderOptions)) *Encoder {
|
||||
o := EncoderOptions{}
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(&o)
|
||||
}
|
||||
|
||||
return &Encoder{
|
||||
options: o,
|
||||
headersBuf: bytes.NewBuffer(nil),
|
||||
messageBuf: bytes.NewBuffer(nil),
|
||||
}
|
||||
}
|
||||
|
||||
// Encode encodes a single EventStream message to the io.Writer the Encoder
|
||||
// was created with. An error is returned if writing the message fails.
|
||||
func (e *Encoder) Encode(w io.Writer, msg Message) (err error) {
|
||||
e.headersBuf.Reset()
|
||||
e.messageBuf.Reset()
|
||||
|
||||
var writer io.Writer = e.messageBuf
|
||||
if e.options.Logger != nil && e.options.LogMessages {
|
||||
encodeMsgBuf := bytes.NewBuffer(nil)
|
||||
writer = io.MultiWriter(writer, encodeMsgBuf)
|
||||
defer func() {
|
||||
logMessageEncode(e.options.Logger, encodeMsgBuf, msg, err)
|
||||
}()
|
||||
}
|
||||
|
||||
if err = EncodeHeaders(e.headersBuf, msg.Headers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
crc := crc32.New(crc32IEEETable)
|
||||
hashWriter := io.MultiWriter(writer, crc)
|
||||
|
||||
headersLen := uint32(e.headersBuf.Len())
|
||||
payloadLen := uint32(len(msg.Payload))
|
||||
|
||||
if err = encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if headersLen > 0 {
|
||||
if _, err = io.Copy(hashWriter, e.headersBuf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if payloadLen > 0 {
|
||||
if _, err = hashWriter.Write(msg.Payload); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
msgCRC := crc.Sum32()
|
||||
if err := binary.Write(writer, binary.BigEndian, msgCRC); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(w, e.messageBuf)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func logMessageEncode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, encodeErr error) {
|
||||
w := bytes.NewBuffer(nil)
|
||||
defer func() { logger.Logf(logging.Debug, w.String()) }()
|
||||
|
||||
fmt.Fprintf(w, "Message to encode:\n")
|
||||
encoder := json.NewEncoder(w)
|
||||
if err := encoder.Encode(msg); err != nil {
|
||||
fmt.Fprintf(w, "Failed to get encoded message, %v\n", err)
|
||||
}
|
||||
|
||||
if encodeErr != nil {
|
||||
fmt.Fprintf(w, "Encode error: %v\n", encodeErr)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "Raw message:\n%s\n", hex.Dump(msgBuf.Bytes()))
|
||||
}
|
||||
|
||||
func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error {
|
||||
p := messagePrelude{
|
||||
Length: minMsgLen + headersLen + payloadLen,
|
||||
HeadersLen: headersLen,
|
||||
}
|
||||
if err := p.ValidateLens(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := binaryWriteFields(w, binary.BigEndian,
|
||||
p.Length,
|
||||
p.HeadersLen,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.PreludeCRC = crc.Sum32()
|
||||
err = binary.Write(w, binary.BigEndian, p.PreludeCRC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeHeaders writes the header values to the writer encoded in the event
|
||||
// stream format. Returns an error if a header fails to encode.
|
||||
func EncodeHeaders(w io.Writer, headers Headers) error {
|
||||
for _, h := range headers {
|
||||
hn := headerName{
|
||||
Len: uint8(len(h.Name)),
|
||||
}
|
||||
copy(hn.Name[:hn.Len], h.Name)
|
||||
if err := hn.encode(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := h.Value.encode(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func binaryWriteFields(w io.Writer, order binary.ByteOrder, vs ...interface{}) error {
|
||||
for _, v := range vs {
|
||||
if err := binary.Write(w, order, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package eventstream
|
||||
|
||||
import "fmt"
|
||||
|
||||
// LengthError provides the error for items being larger than a maximum length.
|
||||
type LengthError struct {
|
||||
Part string
|
||||
Want int
|
||||
Have int
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func (e LengthError) Error() string {
|
||||
return fmt.Sprintf("%s length invalid, %d/%d, %v",
|
||||
e.Part, e.Want, e.Have, e.Value)
|
||||
}
|
||||
|
||||
// ChecksumError provides the error for message checksum invalidation errors.
|
||||
type ChecksumError struct{}
|
||||
|
||||
func (e ChecksumError) Error() string {
|
||||
return "message checksum mismatch"
|
||||
}
|
||||
Generated
Vendored
-24
@@ -1,24 +0,0 @@
|
||||
package eventstreamapi
|
||||
|
||||
// EventStream headers with specific meaning to async API functionality.
|
||||
const (
|
||||
ChunkSignatureHeader = `:chunk-signature` // chunk signature for message
|
||||
DateHeader = `:date` // Date header for signature
|
||||
ContentTypeHeader = ":content-type" // message payload content-type
|
||||
|
||||
// Message header and values
|
||||
MessageTypeHeader = `:message-type` // Identifies type of message.
|
||||
EventMessageType = `event`
|
||||
ErrorMessageType = `error`
|
||||
ExceptionMessageType = `exception`
|
||||
|
||||
// Message Events
|
||||
EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats".
|
||||
|
||||
// Message Error
|
||||
ErrorCodeHeader = `:error-code`
|
||||
ErrorMessageHeader = `:error-message`
|
||||
|
||||
// Message Exception
|
||||
ExceptionTypeHeader = `:exception-type`
|
||||
)
|
||||
Generated
Vendored
-71
@@ -1,71 +0,0 @@
|
||||
package eventstreamapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
"io"
|
||||
)
|
||||
|
||||
type eventStreamWriterKey struct{}
|
||||
|
||||
// GetInputStreamWriter returns EventTypeHeader io.PipeWriter used for the operation's input event stream.
|
||||
func GetInputStreamWriter(ctx context.Context) io.WriteCloser {
|
||||
writeCloser, _ := middleware.GetStackValue(ctx, eventStreamWriterKey{}).(io.WriteCloser)
|
||||
return writeCloser
|
||||
}
|
||||
|
||||
func setInputStreamWriter(ctx context.Context, writeCloser io.WriteCloser) context.Context {
|
||||
return middleware.WithStackValue(ctx, eventStreamWriterKey{}, writeCloser)
|
||||
}
|
||||
|
||||
// InitializeStreamWriter is a Finalize middleware initializes an in-memory pipe for sending event stream messages
|
||||
// via the HTTP request body.
|
||||
type InitializeStreamWriter struct{}
|
||||
|
||||
// AddInitializeStreamWriter adds the InitializeStreamWriter middleware to the provided stack.
|
||||
func AddInitializeStreamWriter(stack *middleware.Stack) error {
|
||||
return stack.Finalize.Add(&InitializeStreamWriter{}, middleware.After)
|
||||
}
|
||||
|
||||
// ID returns the identifier for the middleware.
|
||||
func (i *InitializeStreamWriter) ID() string {
|
||||
return "InitializeStreamWriter"
|
||||
}
|
||||
|
||||
// HandleFinalize is the middleware implementation.
|
||||
func (i *InitializeStreamWriter) HandleFinalize(
|
||||
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
request, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown transport type: %T", in.Request)
|
||||
}
|
||||
|
||||
inputReader, inputWriter := io.Pipe()
|
||||
defer func() {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
_ = inputReader.Close()
|
||||
_ = inputWriter.Close()
|
||||
}()
|
||||
|
||||
request, err = request.SetStream(inputReader)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
in.Request = request
|
||||
|
||||
ctx = setInputStreamWriter(ctx, inputWriter)
|
||||
|
||||
out, metadata, err = next.HandleFinalize(ctx, in)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
||||
Generated
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package eventstreamapi
|
||||
|
||||
import smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
|
||||
// ApplyHTTPTransportFixes applies fixes to the HTTP request for proper event stream functionality.
|
||||
//
|
||||
// This operation is a no-op for Go 1.18 and above.
|
||||
func ApplyHTTPTransportFixes(r *smithyhttp.Request) error {
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
-12
@@ -1,12 +0,0 @@
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package eventstreamapi
|
||||
|
||||
import smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
|
||||
// ApplyHTTPTransportFixes applies fixes to the HTTP request for proper event stream functionality.
|
||||
func ApplyHTTPTransportFixes(r *smithyhttp.Request) error {
|
||||
r.Header.Set("Expect", "100-continue")
|
||||
return nil
|
||||
}
|
||||
Generated
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
// Code generated by internal/repotools/cmd/updatemodulemeta DO NOT EDIT.
|
||||
|
||||
package eventstream
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.7.5"
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Headers are a collection of EventStream header values.
|
||||
type Headers []Header
|
||||
|
||||
// Header is a single EventStream Key Value header pair.
|
||||
type Header struct {
|
||||
Name string
|
||||
Value Value
|
||||
}
|
||||
|
||||
// Set associates the name with a value. If the header name already exists in
|
||||
// the Headers the value will be replaced with the new one.
|
||||
func (hs *Headers) Set(name string, value Value) {
|
||||
var i int
|
||||
for ; i < len(*hs); i++ {
|
||||
if (*hs)[i].Name == name {
|
||||
(*hs)[i].Value = value
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
*hs = append(*hs, Header{
|
||||
Name: name, Value: value,
|
||||
})
|
||||
}
|
||||
|
||||
// Get returns the Value associated with the header. Nil is returned if the
|
||||
// value does not exist.
|
||||
func (hs Headers) Get(name string) Value {
|
||||
for i := 0; i < len(hs); i++ {
|
||||
if h := hs[i]; h.Name == name {
|
||||
return h.Value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Del deletes the value in the Headers if it exists.
|
||||
func (hs *Headers) Del(name string) {
|
||||
for i := 0; i < len(*hs); i++ {
|
||||
if (*hs)[i].Name == name {
|
||||
copy((*hs)[i:], (*hs)[i+1:])
|
||||
(*hs) = (*hs)[:len(*hs)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of the headers
|
||||
func (hs Headers) Clone() Headers {
|
||||
o := make(Headers, 0, len(hs))
|
||||
for _, h := range hs {
|
||||
o.Set(h.Name, h.Value)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func decodeHeaders(r io.Reader) (Headers, error) {
|
||||
hs := Headers{}
|
||||
|
||||
for {
|
||||
name, err := decodeHeaderName(r)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
// EOF while getting header name means no more headers
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := decodeHeaderValue(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hs.Set(name, value)
|
||||
}
|
||||
|
||||
return hs, nil
|
||||
}
|
||||
|
||||
func decodeHeaderName(r io.Reader) (string, error) {
|
||||
var n headerName
|
||||
|
||||
var err error
|
||||
n.Len, err = decodeUint8(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
name := n.Name[:n.Len]
|
||||
if _, err := io.ReadFull(r, name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(name), nil
|
||||
}
|
||||
|
||||
func decodeHeaderValue(r io.Reader) (Value, error) {
|
||||
var raw rawValue
|
||||
|
||||
typ, err := decodeUint8(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw.Type = valueType(typ)
|
||||
|
||||
var v Value
|
||||
|
||||
switch raw.Type {
|
||||
case trueValueType:
|
||||
v = BoolValue(true)
|
||||
case falseValueType:
|
||||
v = BoolValue(false)
|
||||
case int8ValueType:
|
||||
var tv Int8Value
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case int16ValueType:
|
||||
var tv Int16Value
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case int32ValueType:
|
||||
var tv Int32Value
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case int64ValueType:
|
||||
var tv Int64Value
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case bytesValueType:
|
||||
var tv BytesValue
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case stringValueType:
|
||||
var tv StringValue
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case timestampValueType:
|
||||
var tv TimestampValue
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
case uuidValueType:
|
||||
var tv UUIDValue
|
||||
err = tv.decode(r)
|
||||
v = tv
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown value type %d", raw.Type))
|
||||
}
|
||||
|
||||
// Error could be EOF, let caller deal with it
|
||||
return v, err
|
||||
}
|
||||
|
||||
const maxHeaderNameLen = 255
|
||||
|
||||
type headerName struct {
|
||||
Len uint8
|
||||
Name [maxHeaderNameLen]byte
|
||||
}
|
||||
|
||||
func (v headerName) encode(w io.Writer) error {
|
||||
if err := binary.Write(w, binary.BigEndian, v.Len); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := w.Write(v.Name[:v.Len])
|
||||
return err
|
||||
}
|
||||
-521
@@ -1,521 +0,0 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const maxHeaderValueLen = 1<<15 - 1 // 2^15-1 or 32KB - 1
|
||||
|
||||
// valueType is the EventStream header value type.
|
||||
type valueType uint8
|
||||
|
||||
// Header value types
|
||||
const (
|
||||
trueValueType valueType = iota
|
||||
falseValueType
|
||||
int8ValueType // Byte
|
||||
int16ValueType // Short
|
||||
int32ValueType // Integer
|
||||
int64ValueType // Long
|
||||
bytesValueType
|
||||
stringValueType
|
||||
timestampValueType
|
||||
uuidValueType
|
||||
)
|
||||
|
||||
func (t valueType) String() string {
|
||||
switch t {
|
||||
case trueValueType:
|
||||
return "bool"
|
||||
case falseValueType:
|
||||
return "bool"
|
||||
case int8ValueType:
|
||||
return "int8"
|
||||
case int16ValueType:
|
||||
return "int16"
|
||||
case int32ValueType:
|
||||
return "int32"
|
||||
case int64ValueType:
|
||||
return "int64"
|
||||
case bytesValueType:
|
||||
return "byte_array"
|
||||
case stringValueType:
|
||||
return "string"
|
||||
case timestampValueType:
|
||||
return "timestamp"
|
||||
case uuidValueType:
|
||||
return "uuid"
|
||||
default:
|
||||
return fmt.Sprintf("unknown value type %d", uint8(t))
|
||||
}
|
||||
}
|
||||
|
||||
type rawValue struct {
|
||||
Type valueType
|
||||
Len uint16 // Only set for variable length slices
|
||||
Value []byte // byte representation of value, BigEndian encoding.
|
||||
}
|
||||
|
||||
func (r rawValue) encodeScalar(w io.Writer, v interface{}) error {
|
||||
return binaryWriteFields(w, binary.BigEndian,
|
||||
r.Type,
|
||||
v,
|
||||
)
|
||||
}
|
||||
|
||||
func (r rawValue) encodeFixedSlice(w io.Writer, v []byte) error {
|
||||
binary.Write(w, binary.BigEndian, r.Type)
|
||||
|
||||
_, err := w.Write(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r rawValue) encodeBytes(w io.Writer, v []byte) error {
|
||||
if len(v) > maxHeaderValueLen {
|
||||
return LengthError{
|
||||
Part: "header value",
|
||||
Want: maxHeaderValueLen, Have: len(v),
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
r.Len = uint16(len(v))
|
||||
|
||||
err := binaryWriteFields(w, binary.BigEndian,
|
||||
r.Type,
|
||||
r.Len,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write(v)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r rawValue) encodeString(w io.Writer, v string) error {
|
||||
if len(v) > maxHeaderValueLen {
|
||||
return LengthError{
|
||||
Part: "header value",
|
||||
Want: maxHeaderValueLen, Have: len(v),
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
r.Len = uint16(len(v))
|
||||
|
||||
type stringWriter interface {
|
||||
WriteString(string) (int, error)
|
||||
}
|
||||
|
||||
err := binaryWriteFields(w, binary.BigEndian,
|
||||
r.Type,
|
||||
r.Len,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sw, ok := w.(stringWriter); ok {
|
||||
_, err = sw.WriteString(v)
|
||||
} else {
|
||||
_, err = w.Write([]byte(v))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func decodeFixedBytesValue(r io.Reader, buf []byte) error {
|
||||
_, err := io.ReadFull(r, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
func decodeBytesValue(r io.Reader) ([]byte, error) {
|
||||
var raw rawValue
|
||||
var err error
|
||||
raw.Len, err = decodeUint16(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := make([]byte, raw.Len)
|
||||
_, err = io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func decodeStringValue(r io.Reader) (string, error) {
|
||||
v, err := decodeBytesValue(r)
|
||||
return string(v), err
|
||||
}
|
||||
|
||||
// Value represents the abstract header value.
|
||||
type Value interface {
|
||||
Get() interface{}
|
||||
String() string
|
||||
valueType() valueType
|
||||
encode(io.Writer) error
|
||||
}
|
||||
|
||||
// An BoolValue provides eventstream encoding, and representation
|
||||
// of a Go bool value.
|
||||
type BoolValue bool
|
||||
|
||||
// Get returns the underlying type
|
||||
func (v BoolValue) Get() interface{} {
|
||||
return bool(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (v BoolValue) valueType() valueType {
|
||||
if v {
|
||||
return trueValueType
|
||||
}
|
||||
return falseValueType
|
||||
}
|
||||
|
||||
func (v BoolValue) String() string {
|
||||
return strconv.FormatBool(bool(v))
|
||||
}
|
||||
|
||||
// encode encodes the BoolValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v BoolValue) encode(w io.Writer) error {
|
||||
return binary.Write(w, binary.BigEndian, v.valueType())
|
||||
}
|
||||
|
||||
// An Int8Value provides eventstream encoding, and representation of a Go
|
||||
// int8 value.
|
||||
type Int8Value int8
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v Int8Value) Get() interface{} {
|
||||
return int8(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (Int8Value) valueType() valueType {
|
||||
return int8ValueType
|
||||
}
|
||||
|
||||
func (v Int8Value) String() string {
|
||||
return fmt.Sprintf("0x%02x", int8(v))
|
||||
}
|
||||
|
||||
// encode encodes the Int8Value into an eventstream binary value
|
||||
// representation.
|
||||
func (v Int8Value) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
return raw.encodeScalar(w, v)
|
||||
}
|
||||
|
||||
func (v *Int8Value) decode(r io.Reader) error {
|
||||
n, err := decodeUint8(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = Int8Value(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An Int16Value provides eventstream encoding, and representation of a Go
|
||||
// int16 value.
|
||||
type Int16Value int16
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v Int16Value) Get() interface{} {
|
||||
return int16(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (Int16Value) valueType() valueType {
|
||||
return int16ValueType
|
||||
}
|
||||
|
||||
func (v Int16Value) String() string {
|
||||
return fmt.Sprintf("0x%04x", int16(v))
|
||||
}
|
||||
|
||||
// encode encodes the Int16Value into an eventstream binary value
|
||||
// representation.
|
||||
func (v Int16Value) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
return raw.encodeScalar(w, v)
|
||||
}
|
||||
|
||||
func (v *Int16Value) decode(r io.Reader) error {
|
||||
n, err := decodeUint16(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = Int16Value(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An Int32Value provides eventstream encoding, and representation of a Go
|
||||
// int32 value.
|
||||
type Int32Value int32
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v Int32Value) Get() interface{} {
|
||||
return int32(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (Int32Value) valueType() valueType {
|
||||
return int32ValueType
|
||||
}
|
||||
|
||||
func (v Int32Value) String() string {
|
||||
return fmt.Sprintf("0x%08x", int32(v))
|
||||
}
|
||||
|
||||
// encode encodes the Int32Value into an eventstream binary value
|
||||
// representation.
|
||||
func (v Int32Value) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
return raw.encodeScalar(w, v)
|
||||
}
|
||||
|
||||
func (v *Int32Value) decode(r io.Reader) error {
|
||||
n, err := decodeUint32(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = Int32Value(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An Int64Value provides eventstream encoding, and representation of a Go
|
||||
// int64 value.
|
||||
type Int64Value int64
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v Int64Value) Get() interface{} {
|
||||
return int64(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (Int64Value) valueType() valueType {
|
||||
return int64ValueType
|
||||
}
|
||||
|
||||
func (v Int64Value) String() string {
|
||||
return fmt.Sprintf("0x%016x", int64(v))
|
||||
}
|
||||
|
||||
// encode encodes the Int64Value into an eventstream binary value
|
||||
// representation.
|
||||
func (v Int64Value) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
return raw.encodeScalar(w, v)
|
||||
}
|
||||
|
||||
func (v *Int64Value) decode(r io.Reader) error {
|
||||
n, err := decodeUint64(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = Int64Value(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An BytesValue provides eventstream encoding, and representation of a Go
|
||||
// byte slice.
|
||||
type BytesValue []byte
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v BytesValue) Get() interface{} {
|
||||
return []byte(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (BytesValue) valueType() valueType {
|
||||
return bytesValueType
|
||||
}
|
||||
|
||||
func (v BytesValue) String() string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(v))
|
||||
}
|
||||
|
||||
// encode encodes the BytesValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v BytesValue) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
return raw.encodeBytes(w, []byte(v))
|
||||
}
|
||||
|
||||
func (v *BytesValue) decode(r io.Reader) error {
|
||||
buf, err := decodeBytesValue(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = BytesValue(buf)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An StringValue provides eventstream encoding, and representation of a Go
|
||||
// string.
|
||||
type StringValue string
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v StringValue) Get() interface{} {
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (StringValue) valueType() valueType {
|
||||
return stringValueType
|
||||
}
|
||||
|
||||
func (v StringValue) String() string {
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// encode encodes the StringValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v StringValue) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
return raw.encodeString(w, string(v))
|
||||
}
|
||||
|
||||
func (v *StringValue) decode(r io.Reader) error {
|
||||
s, err := decodeStringValue(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = StringValue(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// An TimestampValue provides eventstream encoding, and representation of a Go
|
||||
// timestamp.
|
||||
type TimestampValue time.Time
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v TimestampValue) Get() interface{} {
|
||||
return time.Time(v)
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (TimestampValue) valueType() valueType {
|
||||
return timestampValueType
|
||||
}
|
||||
|
||||
func (v TimestampValue) epochMilli() int64 {
|
||||
nano := time.Time(v).UnixNano()
|
||||
msec := nano / int64(time.Millisecond)
|
||||
return msec
|
||||
}
|
||||
|
||||
func (v TimestampValue) String() string {
|
||||
msec := v.epochMilli()
|
||||
return strconv.FormatInt(msec, 10)
|
||||
}
|
||||
|
||||
// encode encodes the TimestampValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v TimestampValue) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
msec := v.epochMilli()
|
||||
return raw.encodeScalar(w, msec)
|
||||
}
|
||||
|
||||
func (v *TimestampValue) decode(r io.Reader) error {
|
||||
n, err := decodeUint64(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*v = TimestampValue(timeFromEpochMilli(int64(n)))
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface
|
||||
func (v TimestampValue) MarshalJSON() ([]byte, error) {
|
||||
return []byte(v.String()), nil
|
||||
}
|
||||
|
||||
func timeFromEpochMilli(t int64) time.Time {
|
||||
secs := t / 1e3
|
||||
msec := t % 1e3
|
||||
return time.Unix(secs, msec*int64(time.Millisecond)).UTC()
|
||||
}
|
||||
|
||||
// An UUIDValue provides eventstream encoding, and representation of a UUID
|
||||
// value.
|
||||
type UUIDValue [16]byte
|
||||
|
||||
// Get returns the underlying value.
|
||||
func (v UUIDValue) Get() interface{} {
|
||||
return v[:]
|
||||
}
|
||||
|
||||
// valueType returns the EventStream header value type value.
|
||||
func (UUIDValue) valueType() valueType {
|
||||
return uuidValueType
|
||||
}
|
||||
|
||||
func (v UUIDValue) String() string {
|
||||
var scratch [36]byte
|
||||
|
||||
const dash = '-'
|
||||
|
||||
hex.Encode(scratch[:8], v[0:4])
|
||||
scratch[8] = dash
|
||||
hex.Encode(scratch[9:13], v[4:6])
|
||||
scratch[13] = dash
|
||||
hex.Encode(scratch[14:18], v[6:8])
|
||||
scratch[18] = dash
|
||||
hex.Encode(scratch[19:23], v[8:10])
|
||||
scratch[23] = dash
|
||||
hex.Encode(scratch[24:], v[10:])
|
||||
|
||||
return string(scratch[:])
|
||||
}
|
||||
|
||||
// encode encodes the UUIDValue into an eventstream binary value
|
||||
// representation.
|
||||
func (v UUIDValue) encode(w io.Writer) error {
|
||||
raw := rawValue{
|
||||
Type: v.valueType(),
|
||||
}
|
||||
|
||||
return raw.encodeFixedSlice(w, v[:])
|
||||
}
|
||||
|
||||
func (v *UUIDValue) decode(r io.Reader) error {
|
||||
tv := (*v)[:]
|
||||
return decodeFixedBytesValue(r, tv)
|
||||
}
|
||||
-99
@@ -1,99 +0,0 @@
|
||||
package eventstream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"hash/crc32"
|
||||
)
|
||||
|
||||
const preludeLen = 8
|
||||
const preludeCRCLen = 4
|
||||
const msgCRCLen = 4
|
||||
const minMsgLen = preludeLen + preludeCRCLen + msgCRCLen
|
||||
|
||||
var crc32IEEETable = crc32.MakeTable(crc32.IEEE)
|
||||
|
||||
// A Message provides the eventstream message representation.
|
||||
type Message struct {
|
||||
Headers Headers
|
||||
Payload []byte
|
||||
}
|
||||
|
||||
func (m *Message) rawMessage() (rawMessage, error) {
|
||||
var raw rawMessage
|
||||
|
||||
if len(m.Headers) > 0 {
|
||||
var headers bytes.Buffer
|
||||
if err := EncodeHeaders(&headers, m.Headers); err != nil {
|
||||
return rawMessage{}, err
|
||||
}
|
||||
raw.Headers = headers.Bytes()
|
||||
raw.HeadersLen = uint32(len(raw.Headers))
|
||||
}
|
||||
|
||||
raw.Length = raw.HeadersLen + uint32(len(m.Payload)) + minMsgLen
|
||||
|
||||
hash := crc32.New(crc32IEEETable)
|
||||
binaryWriteFields(hash, binary.BigEndian, raw.Length, raw.HeadersLen)
|
||||
raw.PreludeCRC = hash.Sum32()
|
||||
|
||||
binaryWriteFields(hash, binary.BigEndian, raw.PreludeCRC)
|
||||
|
||||
if raw.HeadersLen > 0 {
|
||||
hash.Write(raw.Headers)
|
||||
}
|
||||
|
||||
// Read payload bytes and update hash for it as well.
|
||||
if len(m.Payload) > 0 {
|
||||
raw.Payload = m.Payload
|
||||
hash.Write(raw.Payload)
|
||||
}
|
||||
|
||||
raw.CRC = hash.Sum32()
|
||||
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of the message.
|
||||
func (m Message) Clone() Message {
|
||||
var payload []byte
|
||||
if m.Payload != nil {
|
||||
payload = make([]byte, len(m.Payload))
|
||||
copy(payload, m.Payload)
|
||||
}
|
||||
|
||||
return Message{
|
||||
Headers: m.Headers.Clone(),
|
||||
Payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
type messagePrelude struct {
|
||||
Length uint32
|
||||
HeadersLen uint32
|
||||
PreludeCRC uint32
|
||||
}
|
||||
|
||||
func (p messagePrelude) PayloadLen() uint32 {
|
||||
return p.Length - p.HeadersLen - minMsgLen
|
||||
}
|
||||
|
||||
func (p messagePrelude) ValidateLens() error {
|
||||
if p.Length == 0 {
|
||||
return LengthError{
|
||||
Part: "message prelude",
|
||||
Want: minMsgLen,
|
||||
Have: int(p.Length),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type rawMessage struct {
|
||||
messagePrelude
|
||||
|
||||
Headers []byte
|
||||
Payload []byte
|
||||
|
||||
CRC uint32
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
.prism.log
|
||||
codegen.log
|
||||
Brewfile.lock.json
|
||||
.idea/
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
{
|
||||
".": "1.26.0"
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
configured_endpoints: 34
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic%2Fanthropic-29a6b7ba51942cd606e5bf4b533e5aac1bef42f6d4b1f7f45f756304cf676782.yml
|
||||
openapi_spec_hash: 58021ab18daccd5c45a930ffd7d6ab4d
|
||||
config_hash: 4e204fead5f0af80eb9effa1d1e34dca
|
||||
-1
@@ -1 +0,0 @@
|
||||
brew "go"
|
||||
-641
@@ -1,641 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## 1.26.0 (2026-02-19)
|
||||
|
||||
Full Changelog: [v1.25.1...v1.26.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.25.1...v1.26.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** Add top-level cache control (automatic caching) ([75f9f70](https://github.com/anthropics/anthropic-sdk-go/commit/75f9f70045587c458ec2e3491b4eb88bc3329e9e))
|
||||
* **client:** add BetaToolRunner for automatic tool use loops ([#603](https://github.com/anthropics/anthropic-sdk-go/issues/603)) ([e44128a](https://github.com/anthropics/anthropic-sdk-go/commit/e44128a1a3c1d9b4710b4a024ace8121258b32b6))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **internal:** codegen related update ([6247d2f](https://github.com/anthropics/anthropic-sdk-go/commit/6247d2febe87242ee9d3ba49875ff62a5be9a626))
|
||||
|
||||
## 1.25.1 (2026-02-19)
|
||||
|
||||
Full Changelog: [v1.25.0...v1.25.1](https://github.com/anthropics/anthropic-sdk-go/compare/v1.25.0...v1.25.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **client:** use correct format specifier for header serialization ([9115a61](https://github.com/anthropics/anthropic-sdk-go/commit/9115a6154d0b1ba94370911822986b2ef8584e9a))
|
||||
|
||||
## 1.25.0 (2026-02-18)
|
||||
|
||||
Full Changelog: [v1.24.0...v1.25.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.24.0...v1.25.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** fix shared UserLocation and error code types ([cb98cd0](https://github.com/anthropics/anthropic-sdk-go/commit/cb98cd00c359c0181d7b39bdb057e7b06015aa33))
|
||||
|
||||
## 1.24.0 (2026-02-18)
|
||||
|
||||
Full Changelog: [v1.23.0...v1.24.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.23.0...v1.24.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** manual updates ([54d01f5](https://github.com/anthropics/anthropic-sdk-go/commit/54d01f5187ef9ec49f803edfe643bf1bf1e91072))
|
||||
|
||||
## 1.23.0 (2026-02-17)
|
||||
|
||||
Full Changelog: [v1.22.1...v1.23.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.22.1...v1.23.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** Releasing claude-sonnet-4-6 ([782d5a5](https://github.com/anthropics/anthropic-sdk-go/commit/782d5a5dc4c1f63cfef3afc5d257b08f8cf3fadc))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api:** fix spec errors ([15e6a5a](https://github.com/anthropics/anthropic-sdk-go/commit/15e6a5a0b4fb426f126f7b26b087709ea7ba00ac))
|
||||
* remove duplicate ServerToolUseBlock struct declaration ([#595](https://github.com/anthropics/anthropic-sdk-go/issues/595)) ([d4ece8a](https://github.com/anthropics/anthropic-sdk-go/commit/d4ece8ae310dd0369a5ea05671295ae2c23a53d9))
|
||||
|
||||
## 1.22.1 (2026-02-10)
|
||||
|
||||
Full Changelog: [v1.22.0...v1.22.1](https://github.com/anthropics/anthropic-sdk-go/compare/v1.22.0...v1.22.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **encoder:** correctly serialize NullStruct ([1435f8a](https://github.com/anthropics/anthropic-sdk-go/commit/1435f8ac4d272561c7e689cc6bb4e3794414ba57))
|
||||
|
||||
## 1.22.0 (2026-02-07)
|
||||
|
||||
Full Changelog: [v1.21.0...v1.22.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.21.0...v1.22.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** enabling fast-mode in claude-opus-4-6 ([ebe6433](https://github.com/anthropics/anthropic-sdk-go/commit/ebe6433768cab86dcc02b71159aaa347a8d473ec))
|
||||
|
||||
## 1.21.0 (2026-02-05)
|
||||
|
||||
Full Changelog: [v1.20.0...v1.21.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.20.0...v1.21.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** Release Claude Opus 4.6, adaptive thinking, and other features ([e899e64](https://github.com/anthropics/anthropic-sdk-go/commit/e899e64cd402eb004909d632e68acc4b0587f53c))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **ci:** remove claude-code-review workflow ([31db702](https://github.com/anthropics/anthropic-sdk-go/commit/31db70249f691b161f326f550dc26cdcce54dd30))
|
||||
|
||||
## 1.20.0 (2026-01-29)
|
||||
|
||||
Full Changelog: [v1.19.0...v1.20.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.19.0...v1.20.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** add support for Structured Outputs in the Messages API ([10c3821](https://github.com/anthropics/anthropic-sdk-go/commit/10c382188df98d7b045aec525bdc47f3df25d576))
|
||||
* **api:** migrate sending message format in output_config rather than output_format ([f996db4](https://github.com/anthropics/anthropic-sdk-go/commit/f996db402bc1f868b11d877014a6c51d977c557f))
|
||||
* **client:** add a convenient param.SetJSON helper ([427514e](https://github.com/anthropics/anthropic-sdk-go/commit/427514ea6dde81f4eb374967577b5a4cf380f627))
|
||||
* **encoder:** support bracket encoding form-data object members ([eaaeadf](https://github.com/anthropics/anthropic-sdk-go/commit/eaaeadf6dd67119ca4406f0fb0337c16d9011b8f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **accumulator:** revert to marshal accumulator on stop events ([#563](https://github.com/anthropics/anthropic-sdk-go/issues/563)) ([096a8a8](https://github.com/anthropics/anthropic-sdk-go/commit/096a8a8b20b530359c214e06272938bcf8a98c59))
|
||||
* **client:** retain streaming when user sets request body ([6d073fe](https://github.com/anthropics/anthropic-sdk-go/commit/6d073fe49f351c26c7f3fa8337e661c6a3600c68))
|
||||
* **docs:** add missing pointer prefix to api.md return types ([23aaf6d](https://github.com/anthropics/anthropic-sdk-go/commit/23aaf6de59f0c13c79dbe4fc1d764b47cfd83834))
|
||||
* **mcp:** correct code tool API endpoint ([6c8a083](https://github.com/anthropics/anthropic-sdk-go/commit/6c8a0831e6f084d316179a9288c4fa1c5420ea59))
|
||||
* rename param to avoid collision ([6d1cf75](https://github.com/anthropics/anthropic-sdk-go/commit/6d1cf75d5a407d5eb19c70e3778ab82bca74d0d5))
|
||||
* streaming endpoints should pass through errors correctly ([e584c87](https://github.com/anthropics/anthropic-sdk-go/commit/e584c87ec001ee8991ca17b8236a6ef3deb78ea7))
|
||||
* **to-param:** remove panics and add cases ([#524](https://github.com/anthropics/anthropic-sdk-go/issues/524)) ([f689816](https://github.com/anthropics/anthropic-sdk-go/commit/f6898163047854d39cec7c08ec5ab993bab463fc))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* add float64 to valid types for RegisterFieldValidator ([b6bec73](https://github.com/anthropics/anthropic-sdk-go/commit/b6bec73c5ed18698884b990fc3dc6398a3784177))
|
||||
* **ci:** Add Claude Code GitHub Workflow ([a151836](https://github.com/anthropics/anthropic-sdk-go/commit/a151836056343974d15eda64180fc776ba0f169d))
|
||||
* **client:** improve example values ([8af69b8](https://github.com/anthropics/anthropic-sdk-go/commit/8af69b851f4a60334ed75542c2eacbe69c01893c))
|
||||
* **client:** mark claude-3-5-haiku as deprecated ([dcac65c](https://github.com/anthropics/anthropic-sdk-go/commit/dcac65c8dd82f232c2997456319c16357874f37b))
|
||||
* elide duplicate aliases ([c8e2ee1](https://github.com/anthropics/anthropic-sdk-go/commit/c8e2ee14de53b5636eadccb2a890e4464e30b8d4))
|
||||
* **internal:** codegen related update ([931c976](https://github.com/anthropics/anthropic-sdk-go/commit/931c9769f1ff0557a8eff333463e1847b15f7953))
|
||||
* **internal:** update `actions/checkout` version ([3bd83ec](https://github.com/anthropics/anthropic-sdk-go/commit/3bd83eca53f1ec0b759c2568601286405821dcbc))
|
||||
* **internal:** use different example values for some enums ([f2d46b8](https://github.com/anthropics/anthropic-sdk-go/commit/f2d46b87de1a57ed1790cad3134b5e340f22fd73))
|
||||
|
||||
## 1.19.0 (2025-11-24)
|
||||
|
||||
Full Changelog: [v1.18.1...v1.19.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.18.1...v1.19.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** adds support for Claude Opus 4.5, Effort, Advance Tool Use Features, Autocompaction, and Computer Use v5 ([a03391c](https://github.com/anthropics/anthropic-sdk-go/commit/a03391cb00b8c78c79fd8bfe447f00d78f37db25))
|
||||
|
||||
## 1.18.1 (2025-11-19)
|
||||
|
||||
Full Changelog: [v1.18.0...v1.18.1](https://github.com/anthropics/anthropic-sdk-go/compare/v1.18.0...v1.18.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **structured outputs:** use correct beta header ([09ec0a6](https://github.com/anthropics/anthropic-sdk-go/commit/09ec0a647b1a108bb7c74e4c7b1016502ca781bb))
|
||||
|
||||
## 1.18.0 (2025-11-14)
|
||||
|
||||
Full Changelog: [v1.17.0...v1.18.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.17.0...v1.18.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** add support for structured outputs beta ([fb9cfb4](https://github.com/anthropics/anthropic-sdk-go/commit/fb9cfb4e4b571d5fec7da9874610aa8820aee80c))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* bump gjson version ([69b5e0e](https://github.com/anthropics/anthropic-sdk-go/commit/69b5e0e40757884bece66397fb6ca769f4e00118))
|
||||
|
||||
## 1.17.0 (2025-11-05)
|
||||
|
||||
Full Changelog: [v1.16.0...v1.17.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.16.0...v1.17.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **bedrock:** re-route beta headers through request body ([00a2bf3](https://github.com/anthropics/anthropic-sdk-go/commit/00a2bf35b34aa49f1514493cf0638b467c4f4eec))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **internal:** grammar fix (it's -> its) ([687bc29](https://github.com/anthropics/anthropic-sdk-go/commit/687bc299cacb84349eb2684df46994c06f9ba962))
|
||||
|
||||
## 1.16.0 (2025-10-29)
|
||||
|
||||
Full Changelog: [v1.15.0...v1.16.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.15.0...v1.16.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** add ability to clear thinking in context management ([6082754](https://github.com/anthropics/anthropic-sdk-go/commit/6082754e9b6a04570a93efdb5339853c71f1fe94))
|
||||
|
||||
## 1.15.0 (2025-10-28)
|
||||
|
||||
Full Changelog: [v1.14.0...v1.15.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.14.0...v1.15.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** adding support for agent skills ([5660b52](https://github.com/anthropics/anthropic-sdk-go/commit/5660b5252a4de07f3343c9089b148b16cda794d4))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **api:** mark older sonnet models as deprecated ([f13c5bd](https://github.com/anthropics/anthropic-sdk-go/commit/f13c5bd18ebb169c59913985537ca025634ef7eb))
|
||||
|
||||
## 1.14.0 (2025-10-15)
|
||||
|
||||
Full Changelog: [v1.13.0...v1.14.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.13.0...v1.14.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** manual updates ([3eac8aa](https://github.com/anthropics/anthropic-sdk-go/commit/3eac8aaee0dbb3f4a5e30b039d60503614365a82))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **client:** add context-management-2025-06-27 beta header ([eeba6fa](https://github.com/anthropics/anthropic-sdk-go/commit/eeba6fa95ca9eedf16897b413950fc5f80d0d8cb))
|
||||
* **client:** add model-context-window-exceeded-2025-08-26 beta header ([7d5a37d](https://github.com/anthropics/anthropic-sdk-go/commit/7d5a37d895b769739d23b6e91f6c0a806cade710))
|
||||
|
||||
## 1.13.0 (2025-09-29)
|
||||
|
||||
Full Changelog: [v1.12.0...v1.13.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.12.0...v1.13.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** adds support for Claude Sonnet 4.5 and context management features ([3d5d51a](https://github.com/anthropics/anthropic-sdk-go/commit/3d5d51ad6ee64b34c7cc361a9dfd6f45966987dd))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bugfix for setting JSON keys with special characters ([c868b92](https://github.com/anthropics/anthropic-sdk-go/commit/c868b921190f8d371cc93d12e019daf5a7463306))
|
||||
* **internal:** unmarshal correctly when there are multiple discriminators ([ecc3ce3](https://github.com/anthropics/anthropic-sdk-go/commit/ecc3ce31a9ed98b8f2b66b5e1489fce510528f77))
|
||||
* use slices.Concat instead of sometimes modifying r.Options ([88e7186](https://github.com/anthropics/anthropic-sdk-go/commit/88e7186cad944290498a3381c829df36d26a1cce))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* bump minimum go version to 1.22 ([87af8f3](https://github.com/anthropics/anthropic-sdk-go/commit/87af8f397ae68ce72a76a07a735d21495aad8799))
|
||||
* do not install brew dependencies in ./scripts/bootstrap by default ([c689348](https://github.com/anthropics/anthropic-sdk-go/commit/c689348cc4b5ec7ab3512261e4e3cc50d208a02c))
|
||||
* **internal:** fix tests ([bfc6eaf](https://github.com/anthropics/anthropic-sdk-go/commit/bfc6eafeff58664f0d6f155f96286f3993e60f89))
|
||||
* update more docs for 1.22 ([d67c50d](https://github.com/anthropics/anthropic-sdk-go/commit/d67c50d49082b4b28bdabc44943853431cd5205c))
|
||||
|
||||
## 1.12.0 (2025-09-10)
|
||||
|
||||
Full Changelog: [v1.11.0...v1.12.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.11.0...v1.12.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** adds support for web_fetch_20250910 tool ([6d5e237](https://github.com/anthropics/anthropic-sdk-go/commit/6d5e2370e14e1d125ebebcf741b721e88dc0e810))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* tmp ([07b65e9](https://github.com/anthropics/anthropic-sdk-go/commit/07b65e9b178a1c280fc96e3f2a7bf30bd9932329))
|
||||
|
||||
## 1.11.0 (2025-09-05)
|
||||
|
||||
Full Changelog: [v1.10.0...v1.11.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.10.0...v1.11.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** adds support for Documents in tool results ([7161c2c](https://github.com/anthropics/anthropic-sdk-go/commit/7161c2ce9843b80374186dc83fd84a8dfebda45f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **client:** fix issue in Go with nested document content params ([b442cc3](https://github.com/anthropics/anthropic-sdk-go/commit/b442cc3fd41ee53a18f8ccec868ae1057dae53a8))
|
||||
* use release please annotations on more places ([31a09b0](https://github.com/anthropics/anthropic-sdk-go/commit/31a09b07991cc92d38517c80320d154246779a76))
|
||||
|
||||
## 1.10.0 (2025-09-02)
|
||||
|
||||
Full Changelog: [v1.9.1...v1.10.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.9.1...v1.10.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** makes 1 hour TTL Cache Control generally available ([c28a9a3](https://github.com/anthropics/anthropic-sdk-go/commit/c28a9a3272acb1973f2a2fb768157ab27a8f440d))
|
||||
* **client:** adds support for code-execution-2025-08-26 tool ([066a126](https://github.com/anthropics/anthropic-sdk-go/commit/066a126a92a8e09f10742f13e0db36724a96c788))
|
||||
* use custom decoder for []ContentBlockParamUnion ([#464](https://github.com/anthropics/anthropic-sdk-go/issues/464)) ([4731597](https://github.com/anthropics/anthropic-sdk-go/commit/473159792468018c709da311d7ac27139cf851e6))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* close body before retrying ([c970e10](https://github.com/anthropics/anthropic-sdk-go/commit/c970e10ff45c04c38a5a2c87fe85a8c191e06f80))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* deprecate older claude-3-5 sonnet models ([#453](https://github.com/anthropics/anthropic-sdk-go/issues/453)) ([e49d59b](https://github.com/anthropics/anthropic-sdk-go/commit/e49d59b14be89dcfb858b565e5183ecf9c1e246b))
|
||||
|
||||
## 1.9.1 (2025-08-12)
|
||||
|
||||
Full Changelog: [v1.9.0...v1.9.1](https://github.com/anthropics/anthropic-sdk-go/compare/v1.9.0...v1.9.1)
|
||||
|
||||
## 1.9.0 (2025-08-12)
|
||||
|
||||
Full Changelog: [v1.8.0...v1.9.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.8.0...v1.9.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **betas:** add context-1m-2025-08-07 ([c086118](https://github.com/anthropics/anthropic-sdk-go/commit/c086118c9acd55ec711b29a08f165b358e56332b))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **internal:** detect breaking changes when removing endpoints ([91ea519](https://github.com/anthropics/anthropic-sdk-go/commit/91ea5197646ffd3d807610f11bab8726092e7a4b))
|
||||
* **internal:** update comment in script ([de412b0](https://github.com/anthropics/anthropic-sdk-go/commit/de412b007a097ce7d3231e0ccdf7d57572f78199))
|
||||
* update @stainless-api/prism-cli to v5.15.0 ([555556f](https://github.com/anthropics/anthropic-sdk-go/commit/555556f4ce77d406e904733b30c782039dacb837))
|
||||
|
||||
## 1.8.0 (2025-08-08)
|
||||
|
||||
Full Changelog: [v1.7.0...v1.8.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.7.0...v1.8.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** search result content blocks ([0907804](https://github.com/anthropics/anthropic-sdk-go/commit/0907804ae58405abc4f4c0acb76464da3abdd00b))
|
||||
* **client:** support optional json html escaping ([8da877c](https://github.com/anthropics/anthropic-sdk-go/commit/8da877cb04c62d081d36a1f8cb5eea7922a396ce))
|
||||
|
||||
## 1.7.0 (2025-08-05)
|
||||
|
||||
Full Changelog: [v1.6.2...v1.7.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.6.2...v1.7.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** add claude-opus-4-1-20250805 ([72c9d29](https://github.com/anthropics/anthropic-sdk-go/commit/72c9d29255cb59d11b132062df00889a63dd609e))
|
||||
* **api:** adds support for text_editor_20250728 tool ([be56278](https://github.com/anthropics/anthropic-sdk-go/commit/be56278e456ff5eb034852e17a4642be612e30a2))
|
||||
* **api:** removed older deprecated models ([88a397a](https://github.com/anthropics/anthropic-sdk-go/commit/88a397acb01a7557fbd6852f85ece295a7c2a2b7))
|
||||
* **docs:** add File Upload example ([bade71b](https://github.com/anthropics/anthropic-sdk-go/commit/bade71b64850e8fa4410c404f263d4252cdbb82d))
|
||||
* update streaming error message to say 'required' not 'recommended' ([0fb3d30](https://github.com/anthropics/anthropic-sdk-go/commit/0fb3d30814f8aead1237283a994f405c1103aff2))
|
||||
* update streaming error message to say 'required' not 'recommended' ([b23f6df](https://github.com/anthropics/anthropic-sdk-go/commit/b23f6df73098c6fe3aa599beb73973b699c4b2a4))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **client:** process custom base url ahead of time ([2165b1a](https://github.com/anthropics/anthropic-sdk-go/commit/2165b1ac1c78491be85fdc6b49c63ab027caeed6))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **client:** add TextEditor_20250429 tool ([20424fc](https://github.com/anthropics/anthropic-sdk-go/commit/20424fc340b4f10b208f5ba8ee2d2b4a6f9e546d))
|
||||
* **internal:** version bump ([e03b3bd](https://github.com/anthropics/anthropic-sdk-go/commit/e03b3bdd13e207925a9da2b12b830ce9bb6ed88b))
|
||||
|
||||
## 1.6.2 (2025-07-18)
|
||||
|
||||
Full Changelog: [v1.6.1...v1.6.2](https://github.com/anthropics/anthropic-sdk-go/compare/v1.6.1...v1.6.2)
|
||||
|
||||
### Chores
|
||||
|
||||
* **internal:** version bump ([defc645](https://github.com/anthropics/anthropic-sdk-go/commit/defc6458496679762e07ce8dc9838335e4bd8268))
|
||||
|
||||
## 1.6.1 (2025-07-18)
|
||||
|
||||
Full Changelog: [v1.6.0...v1.6.1](https://github.com/anthropics/anthropic-sdk-go/compare/v1.6.0...v1.6.1)
|
||||
|
||||
### Chores
|
||||
|
||||
* **internal:** version bump ([459dd39](https://github.com/anthropics/anthropic-sdk-go/commit/459dd391b281273af9027a23e39b78c422dace0b))
|
||||
|
||||
## 1.6.0 (2025-07-18)
|
||||
|
||||
Full Changelog: [v1.5.0...v1.6.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.5.0...v1.6.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **client:** expand max streaming buffer size ([8b206e2](https://github.com/anthropics/anthropic-sdk-go/commit/8b206e2267b83af7e9f7f56f029497bd403608fe))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api:** revert change to NewToolResultBlock ([b4167e7](https://github.com/anthropics/anthropic-sdk-go/commit/b4167e7b3bb80927b3f397c0b6fb00f7340272a0))
|
||||
* **client:** fix default timeout logic to match other languages ([47e47f5](https://github.com/anthropics/anthropic-sdk-go/commit/47e47f54f8bd1a58413c82137713bedf88e2d4d2))
|
||||
* **tests:** make sure to build examples in scripts/lint ([69bcb13](https://github.com/anthropics/anthropic-sdk-go/commit/69bcb139fcf661bff527d345e9876c26c784befc))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **api:** update BetaCitationSearchResultLocation ([5d040a7](https://github.com/anthropics/anthropic-sdk-go/commit/5d040a7698b11ee059c175ce4a806509a9ae8e5b))
|
||||
* **internal:** fix lint script for tests ([f54301d](https://github.com/anthropics/anthropic-sdk-go/commit/f54301d9f251fa6e409852605f2d301c50d3466d))
|
||||
* **internal:** restructure things to avoid conflicts ([5f1bead](https://github.com/anthropics/anthropic-sdk-go/commit/5f1bead6fd696504d63ebbbf21c1a55c707a3df7))
|
||||
* lint tests ([4a64d14](https://github.com/anthropics/anthropic-sdk-go/commit/4a64d14e7988ba0c2343d7abc65f15da41bafb24))
|
||||
* lint tests in subpackages ([4ae61a6](https://github.com/anthropics/anthropic-sdk-go/commit/4ae61a601cf94e459bc431e07c9b7e25557af493))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
* model in examples ([da9d5af](https://github.com/anthropics/anthropic-sdk-go/commit/da9d5af61544a6f25d9284ee6eee25f5d1364e8a))
|
||||
* model in examples ([fe2da16](https://github.com/anthropics/anthropic-sdk-go/commit/fe2da16e4bf05ee7029b1be33059bf3a4e76c300))
|
||||
|
||||
## 1.5.0 (2025-07-03)
|
||||
|
||||
Full Changelog: [v1.4.0...v1.5.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.4.0...v1.5.0)
|
||||
|
||||
### Features
|
||||
|
||||
* add RequestID to API errors ([884f13b](https://github.com/anthropics/anthropic-sdk-go/commit/884f13b87969c94bd3ed1343c17c84e69b676de8))
|
||||
* **api:** add support for Search Result Content Blocks ([1f6ab8a](https://github.com/anthropics/anthropic-sdk-go/commit/1f6ab8aa2f3a29ca92920545933fc028b4701d20))
|
||||
* **api:** api update ([27a18f2](https://github.com/anthropics/anthropic-sdk-go/commit/27a18f25697da82de75d5800a9077353bb5319a6))
|
||||
* **api:** manual updates ([926b094](https://github.com/anthropics/anthropic-sdk-go/commit/926b094724c0443e8c2d19fc2c885d296254c01a))
|
||||
* **client:** add debug log helper ([e427bb3](https://github.com/anthropics/anthropic-sdk-go/commit/e427bb35859880729e16cca16499accc3bb19a1b))
|
||||
* **client:** add escape hatch for null slice & maps ([9e3ded0](https://github.com/anthropics/anthropic-sdk-go/commit/9e3ded03652bfd8fc5e63095f0849995907537fb))
|
||||
* **vertex:** support global region endpoint ([3c0b86d](https://github.com/anthropics/anthropic-sdk-go/commit/3c0b86dc60bd05d12e854b8ec0fac79418532c78))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **client:** deprecate BetaBase64PDFBlock in favor of BetaRequestDocumentBlock ([5d8fd96](https://github.com/anthropics/anthropic-sdk-go/commit/5d8fd9661585c1894aeb4e80670d577ab1cc3582))
|
||||
* don't try to deserialize as json when ResponseBodyInto is []byte ([0e7ce7b](https://github.com/anthropics/anthropic-sdk-go/commit/0e7ce7b16f5af7afc94333cdef6958a08875a71d))
|
||||
* **pagination:** check if page data is empty in GetNextPage ([d64dc0a](https://github.com/anthropics/anthropic-sdk-go/commit/d64dc0a334da95f82a665f9cef9f6a2f58f39878))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **api:** mark claude-3-opus-20240229 as deprecated ([1472af8](https://github.com/anthropics/anthropic-sdk-go/commit/1472af8504ae2f48b562e4122e641b9207240d30))
|
||||
* **ci:** enable for pull requests ([cdb1340](https://github.com/anthropics/anthropic-sdk-go/commit/cdb134079026cfa467d5f0299ee5e551fb50628a))
|
||||
* **ci:** only run for pushes and fork pull requests ([d7d44ff](https://github.com/anthropics/anthropic-sdk-go/commit/d7d44ffb621e183f611fabe3ac6f0df06d99d459))
|
||||
* fix documentation of null map ([c79ab28](https://github.com/anthropics/anthropic-sdk-go/commit/c79ab28a977f1bbda336bfffdd9fdc7ee6adccaf))
|
||||
* **internal:** add breaking change detection ([49a1855](https://github.com/anthropics/anthropic-sdk-go/commit/49a1855d3d3f107ea69dc6c4e28a82dd36a9e2af))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
* simplify message creation syntax in README example ([#203](https://github.com/anthropics/anthropic-sdk-go/issues/203)) ([c4aef2e](https://github.com/anthropics/anthropic-sdk-go/commit/c4aef2e9c75a6cdfdfd8928bbc164b384051fc53))
|
||||
* update models and non-beta ([a7bc60e](https://github.com/anthropics/anthropic-sdk-go/commit/a7bc60e1beb087c6cc0843e99d3d3e4b51b1859d))
|
||||
|
||||
|
||||
### Refactors
|
||||
|
||||
* improve Error() method to avoid code duplication ([43651c2](https://github.com/anthropics/anthropic-sdk-go/commit/43651c2804801454d24674baf62e05fc9e27e366))
|
||||
|
||||
## 1.4.0 (2025-06-04)
|
||||
|
||||
Full Changelog: [v1.3.0...v1.4.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.3.0...v1.4.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **client:** allow overriding unions ([079149c](https://github.com/anthropics/anthropic-sdk-go/commit/079149c673981891ecd35906cd610f8d4a4b69a9))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **internal:** codegen related update ([853ba1f](https://github.com/anthropics/anthropic-sdk-go/commit/853ba1f46d2b6c476ee04d9c061368e708cc9e18))
|
||||
|
||||
## 1.3.0 (2025-06-03)
|
||||
|
||||
Full Changelog: [v1.2.2...v1.3.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.2.2...v1.3.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **client:** add support for new text_editor_20250429 tool ([b33c543](https://github.com/anthropics/anthropic-sdk-go/commit/b33c543f7dc3b74c3322b6f84c189b81f67b6154))
|
||||
|
||||
## 1.2.2 (2025-06-02)
|
||||
|
||||
Full Changelog: [v1.2.1...v1.2.2](https://github.com/anthropics/anthropic-sdk-go/compare/v1.2.1...v1.2.2)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **client:** access subunions properly ([f29c162](https://github.com/anthropics/anthropic-sdk-go/commit/f29c1627fe94c6371937659d02f1af7b55583d60))
|
||||
* fix error ([bbc002c](https://github.com/anthropics/anthropic-sdk-go/commit/bbc002ccbbf9df681201d9b8ba806c37338c0fd3))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* make go mod tidy continue on error ([ac184b4](https://github.com/anthropics/anthropic-sdk-go/commit/ac184b4f7afee4015d133a05ce819a8dac35be52))
|
||||
|
||||
## 1.2.1 (2025-05-23)
|
||||
|
||||
Full Changelog: [v1.2.0...v1.2.1](https://github.com/anthropics/anthropic-sdk-go/compare/v1.2.0...v1.2.1)
|
||||
|
||||
### Chores
|
||||
|
||||
* **examples:** clean up MCP example ([66f406a](https://github.com/anthropics/anthropic-sdk-go/commit/66f406a04b9756281e7716e9b635c3e3f29397fb))
|
||||
* **internal:** fix release workflows ([6a0ff4c](https://github.com/anthropics/anthropic-sdk-go/commit/6a0ff4cad1c1b4ab6435df80fccd945d6ce07be7))
|
||||
|
||||
## 1.2.0 (2025-05-22)
|
||||
|
||||
Full Changelog: [v1.1.0...v1.2.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.1.0...v1.2.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** add claude 4 models, files API, code execution tool, MCP connector and more ([b2e5cbf](https://github.com/anthropics/anthropic-sdk-go/commit/b2e5cbffd9d05228c2c2569974a6fa260c3f46be))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tests:** fix model testing for anthropic.CalculateNonStreamingTimeout ([9956842](https://github.com/anthropics/anthropic-sdk-go/commit/995684240b77284a4590b1b9ae34a85e525d1e52))
|
||||
|
||||
## 1.1.0 (2025-05-22)
|
||||
|
||||
Full Changelog: [v1.0.0...v1.1.0](https://github.com/anthropics/anthropic-sdk-go/compare/v1.0.0...v1.1.0)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** add claude 4 models, files API, code execution tool, MCP connector and more ([2740935](https://github.com/anthropics/anthropic-sdk-go/commit/2740935f444de2d46103a7c777ea75e7e214872e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tests:** fix model testing for anthropic.CalculateNonStreamingTimeout ([f1aa0a1](https://github.com/anthropics/anthropic-sdk-go/commit/f1aa0a1a32d1ca87b87a7d688daab31f2a36071c))
|
||||
|
||||
## 1.0.0 (2025-05-21)
|
||||
|
||||
Full Changelog: [v0.2.0-beta.4...v1.0.0](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-beta.4...v1.0.0)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **client:** rename variant constructors
|
||||
* **client:** remove is present
|
||||
|
||||
### Features
|
||||
|
||||
* **client:** improve variant constructor names ([227c96b](https://github.com/anthropics/anthropic-sdk-go/commit/227c96bf50e14827e112c31ad0f512354477a409))
|
||||
* **client:** rename variant constructors ([078fad6](https://github.com/anthropics/anthropic-sdk-go/commit/078fad6558642a20b5fb3e82186b03c2efc0ab47))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **client:** correctly set stream key for multipart ([f17bfe0](https://github.com/anthropics/anthropic-sdk-go/commit/f17bfe0aac0fb8228d9cad87ccca0deb7449a824))
|
||||
* **client:** don't panic on marshal with extra null field ([d67a151](https://github.com/anthropics/anthropic-sdk-go/commit/d67a151a6ef0870918c5eaf84ce996cb5b1860b7))
|
||||
* **client:** elide nil citations array ([09cadec](https://github.com/anthropics/anthropic-sdk-go/commit/09cadec3c076d74bda74e67c345a1aee1fdb7ce4))
|
||||
* **client:** fix bug with empty tool inputs and citation deltas in Accumulate ([f4ac348](https://github.com/anthropics/anthropic-sdk-go/commit/f4ac348658fb83485d6555c63f90920599c98d99))
|
||||
* **client:** increase max stream buffer size ([18a6ccf](https://github.com/anthropics/anthropic-sdk-go/commit/18a6ccf1961922a342467800c737fa000bdd254e))
|
||||
* **client:** remove is present ([385d99f](https://github.com/anthropics/anthropic-sdk-go/commit/385d99fa225c755d9af737425ad2ef4d66ad5ba9))
|
||||
* **client:** resolve naming collisions in union variants ([2cb6904](https://github.com/anthropics/anthropic-sdk-go/commit/2cb69048a6b583954934bc2926186564b5c74bf6))
|
||||
* **client:** use scanner for streaming ([82a2840](https://github.com/anthropics/anthropic-sdk-go/commit/82a2840ce0f8aa8bd63f7697c566f437c06bb132))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **examples:** remove fmt ([872e055](https://github.com/anthropics/anthropic-sdk-go/commit/872e0550171942c405786c7eedb23b8270f6e8de))
|
||||
* formatting ([1ce0ee8](https://github.com/anthropics/anthropic-sdk-go/commit/1ce0ee863c5df658909d81b138dc1ebedb78844a))
|
||||
* improve devcontainer setup ([9021490](https://github.com/anthropics/anthropic-sdk-go/commit/90214901d77ba57901e77d6ea31aafb06c120f2c))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
* upgrade security note to warning ([#346](https://github.com/anthropics/anthropic-sdk-go/issues/346)) ([83e70de](https://github.com/anthropics/anthropic-sdk-go/commit/83e70decfb5da14a1ecf78402302f7f0600515ea))
|
||||
|
||||
## 0.2.0-beta.4 (2025-05-18)
|
||||
|
||||
Full Changelog: [v0.2.0-beta.3...v0.2.0-beta.4](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-beta.3...v0.2.0-beta.4)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **client:** clearer array variant names
|
||||
* **client:** rename resp package
|
||||
* **client:** improve core function names
|
||||
* **client:** improve union variant names
|
||||
* **client:** improve param subunions & deduplicate types
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** adds web search capabilities to the Claude API ([9ca314a](https://github.com/anthropics/anthropic-sdk-go/commit/9ca314a74998f24b5f17427698a8fa709b103581))
|
||||
* **api:** extract ContentBlockDelta events into their own schemas ([#165](https://github.com/anthropics/anthropic-sdk-go/issues/165)) ([6d75486](https://github.com/anthropics/anthropic-sdk-go/commit/6d75486e9f524f5511f787181106a679e3414498))
|
||||
* **api:** manual updates ([d405f97](https://github.com/anthropics/anthropic-sdk-go/commit/d405f97373cd7ae863a7400441d1d79c85f0ddd5))
|
||||
* **api:** manual updates ([e1326cd](https://github.com/anthropics/anthropic-sdk-go/commit/e1326cdd756beb871e939af8be8b45fd3d5fdc9a))
|
||||
* **api:** manual updates ([a92a382](https://github.com/anthropics/anthropic-sdk-go/commit/a92a382976d595dd32208109b480bf26dbbdc00f))
|
||||
* **api:** manual updates ([59bd507](https://github.com/anthropics/anthropic-sdk-go/commit/59bd5071282403373ddca9333fafc9efc90a16d6))
|
||||
* **client:** add dynamic streaming buffer to handle large lines ([510e099](https://github.com/anthropics/anthropic-sdk-go/commit/510e099e19fa71411502650eb387f1fee79f5d0d))
|
||||
* **client:** add escape hatch to omit required param fields ([#175](https://github.com/anthropics/anthropic-sdk-go/issues/175)) ([6df8184](https://github.com/anthropics/anthropic-sdk-go/commit/6df8184947d6568260fa0bc22a89a27d10eaacd0))
|
||||
* **client:** add helper method to generate constant structs ([015e8bc](https://github.com/anthropics/anthropic-sdk-go/commit/015e8bc7f74582fb5a3d69021ad3d61e96d65b36))
|
||||
* **client:** add support for endpoint-specific base URLs in python ([44645c9](https://github.com/anthropics/anthropic-sdk-go/commit/44645c9fd0b883db4deeb88bfee6922ec9845ace))
|
||||
* **client:** add support for reading base URL from environment variable ([835e632](https://github.com/anthropics/anthropic-sdk-go/commit/835e6326b658cd40590cd8bbed0932ab219e6d2d))
|
||||
* **client:** clearer array variant names ([1fdea8f](https://github.com/anthropics/anthropic-sdk-go/commit/1fdea8f9fedc470a917d12607b3b7ebe3f0f6439))
|
||||
* **client:** experimental support for unmarshalling into param structs ([94c8fa4](https://github.com/anthropics/anthropic-sdk-go/commit/94c8fa41ecb4792cb7da043bde2c0f5ddafe84b0))
|
||||
* **client:** improve param subunions & deduplicate types ([8daacf6](https://github.com/anthropics/anthropic-sdk-go/commit/8daacf6866e8bc706ec29e17046e53d4ed100364))
|
||||
* **client:** make response union's AsAny method type safe ([#174](https://github.com/anthropics/anthropic-sdk-go/issues/174)) ([f410ed0](https://github.com/anthropics/anthropic-sdk-go/commit/f410ed025ee57a05b0cec8d72a1cb43d30e564a6))
|
||||
* **client:** rename resp package ([8e7d278](https://github.com/anthropics/anthropic-sdk-go/commit/8e7d2788e9be7b954d07de731e7b27ad2e2a9e8e))
|
||||
* **client:** support custom http clients ([#177](https://github.com/anthropics/anthropic-sdk-go/issues/177)) ([ff7a793](https://github.com/anthropics/anthropic-sdk-go/commit/ff7a793b43b99dc148b30e408edfdc19e19c28b2))
|
||||
* **client:** support more time formats ([af2df86](https://github.com/anthropics/anthropic-sdk-go/commit/af2df86f24acbe6b9cdcc4e055c3ff754303e0ef))
|
||||
* **client:** support param struct overrides ([#167](https://github.com/anthropics/anthropic-sdk-go/issues/167)) ([e0d5eb0](https://github.com/anthropics/anthropic-sdk-go/commit/e0d5eb098c6441e99d53c6d997c7bcca460a238b))
|
||||
* **client:** support unions in query and forms ([#171](https://github.com/anthropics/anthropic-sdk-go/issues/171)) ([6bf1ce3](https://github.com/anthropics/anthropic-sdk-go/commit/6bf1ce36f0155dba20afd4b63bf96c4527e2baa5))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **client:** clean up reader resources ([2234386](https://github.com/anthropics/anthropic-sdk-go/commit/223438673ade3be3435bebf7063fd34ddf3dfb8e))
|
||||
* **client:** correctly update body in WithJSONSet ([f531c77](https://github.com/anthropics/anthropic-sdk-go/commit/f531c77c15859b1f2e61d654f4d9956cdfafa082))
|
||||
* **client:** deduplicate stop reason type ([#155](https://github.com/anthropics/anthropic-sdk-go/issues/155)) ([0f985ad](https://github.com/anthropics/anthropic-sdk-go/commit/0f985ad54ef47849d7d478c84d34c7350a4349b5))
|
||||
* **client:** fix bug where types occasionally wouldn't generate ([8988713](https://github.com/anthropics/anthropic-sdk-go/commit/8988713904ce73d3c82de635d98da48b98532366))
|
||||
* **client:** improve core function names ([0a2777f](https://github.com/anthropics/anthropic-sdk-go/commit/0a2777fd597a5eb74bcf6b1da48a9ff1988059de))
|
||||
* **client:** improve union variant names ([92718fd](https://github.com/anthropics/anthropic-sdk-go/commit/92718fd4058fd8535fd888a56f83fc2d3ec505ef))
|
||||
* **client:** include path for type names in example code ([5bbe836](https://github.com/anthropics/anthropic-sdk-go/commit/5bbe83639793878aa0ea52e8ff06b1d9ee72ed7c))
|
||||
* **client:** resolve issue with optional multipart files ([e2af94c](https://github.com/anthropics/anthropic-sdk-go/commit/e2af94c840a8f9da566c781fc99c57084e490ec1))
|
||||
* **client:** return error on bad custom url instead of panic ([#169](https://github.com/anthropics/anthropic-sdk-go/issues/169)) ([b086b55](https://github.com/anthropics/anthropic-sdk-go/commit/b086b55f4886474282d4e2ea9ee3495cbf25ec6b))
|
||||
* **client:** support multipart encoding array formats ([#170](https://github.com/anthropics/anthropic-sdk-go/issues/170)) ([611a25a](https://github.com/anthropics/anthropic-sdk-go/commit/611a25a427fc5303bb311fa4a2fec836d55b0933))
|
||||
* **client:** time format encoding fix ([d589846](https://github.com/anthropics/anthropic-sdk-go/commit/d589846c1a08ad56d639d60736e2b8e190f7f2b1))
|
||||
* **client:** unmarshal responses properly ([8344a1c](https://github.com/anthropics/anthropic-sdk-go/commit/8344a1c58dd497abbed8e9e689efca544256eaa8))
|
||||
* **client:** unmarshal stream events into fresh memory ([#168](https://github.com/anthropics/anthropic-sdk-go/issues/168)) ([9cc1257](https://github.com/anthropics/anthropic-sdk-go/commit/9cc1257a67340e446ac415ec9ddddded24bb1f9a))
|
||||
* handle empty bodies in WithJSONSet ([0bad01e](https://github.com/anthropics/anthropic-sdk-go/commit/0bad01e40a2a4b5b376ba27513d7e16d604459d9))
|
||||
* **internal:** fix type changes ([d8ef353](https://github.com/anthropics/anthropic-sdk-go/commit/d8ef3531840ac1dc0541d3b1cf0015d1db29e2b6))
|
||||
* **pagination:** handle errors when applying options ([2381476](https://github.com/anthropics/anthropic-sdk-go/commit/2381476e64991e781b696890c98f78001e256b3b))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **ci:** add timeout thresholds for CI jobs ([335e9f0](https://github.com/anthropics/anthropic-sdk-go/commit/335e9f0af2275f1af21aa7062afb50bee81771b6))
|
||||
* **ci:** only use depot for staging repos ([6818451](https://github.com/anthropics/anthropic-sdk-go/commit/68184515143aa1e4473208f794fa593668c94df4))
|
||||
* **ci:** run on more branches and use depot runners ([b0ca09d](https://github.com/anthropics/anthropic-sdk-go/commit/b0ca09d1d39a8de390c47be804847a7647ca3c67))
|
||||
* **client:** use new opt conversion ([#184](https://github.com/anthropics/anthropic-sdk-go/issues/184)) ([58dc74f](https://github.com/anthropics/anthropic-sdk-go/commit/58dc74f951aa6a0eb4355a0213c8695bfa7cb0ed))
|
||||
* **docs:** doc improvements ([#173](https://github.com/anthropics/anthropic-sdk-go/issues/173)) ([aebe8f6](https://github.com/anthropics/anthropic-sdk-go/commit/aebe8f68afa3de4460cda6e4032c7859e13cda81))
|
||||
* **docs:** document pre-request options ([8f5eb18](https://github.com/anthropics/anthropic-sdk-go/commit/8f5eb188146bd46ba990558a7e2348c8697d6405))
|
||||
* **docs:** readme improvements ([#176](https://github.com/anthropics/anthropic-sdk-go/issues/176)) ([b5769ff](https://github.com/anthropics/anthropic-sdk-go/commit/b5769ffcf5ef5345659ae848b875227718ea2425))
|
||||
* **docs:** update file uploads in README ([#166](https://github.com/anthropics/anthropic-sdk-go/issues/166)) ([a4a36bf](https://github.com/anthropics/anthropic-sdk-go/commit/a4a36bfbefa5a166774c23d8c5428fb55c1b4abe))
|
||||
* **docs:** update respjson package name ([28910b5](https://github.com/anthropics/anthropic-sdk-go/commit/28910b57821cab670561a25bee413375187ed747))
|
||||
* **internal:** expand CI branch coverage ([#178](https://github.com/anthropics/anthropic-sdk-go/issues/178)) ([900e2df](https://github.com/anthropics/anthropic-sdk-go/commit/900e2df3eb2d3e1309d85fdcf807998f701bea8a))
|
||||
* **internal:** reduce CI branch coverage ([343f6c6](https://github.com/anthropics/anthropic-sdk-go/commit/343f6c6c295dc3d39f65aae481bc10969dbb5694))
|
||||
* **internal:** remove CI condition ([#160](https://github.com/anthropics/anthropic-sdk-go/issues/160)) ([adfa1e2](https://github.com/anthropics/anthropic-sdk-go/commit/adfa1e2e349842aa88262af70b209d1a59dbb419))
|
||||
* **internal:** update config ([#157](https://github.com/anthropics/anthropic-sdk-go/issues/157)) ([46f0194](https://github.com/anthropics/anthropic-sdk-go/commit/46f019497bd9533390c4b9f0ebee6863263ce009))
|
||||
* **readme:** improve formatting ([66be9bb](https://github.com/anthropics/anthropic-sdk-go/commit/66be9bbb17ccc9d878e79b3c39605da3e2846297))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
* remove or fix invalid readme examples ([142576c](https://github.com/anthropics/anthropic-sdk-go/commit/142576c73b4dab5b84a2bf2481506ad642ad31cc))
|
||||
* update documentation links to be more uniform ([457122b](https://github.com/anthropics/anthropic-sdk-go/commit/457122b79646dc17fa8752c98dbf4991edffc548))
|
||||
|
||||
## 0.2.0-beta.3 (2025-03-27)
|
||||
|
||||
Full Changelog: [v0.2.0-beta.2...v0.2.0-beta.3](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-beta.2...v0.2.0-beta.3)
|
||||
|
||||
### Chores
|
||||
|
||||
* add hash of OpenAPI spec/config inputs to .stats.yml ([#154](https://github.com/anthropics/anthropic-sdk-go/issues/154)) ([76b91b5](https://github.com/anthropics/anthropic-sdk-go/commit/76b91b56fbf42fe8982e7b861885db179b1bdcc5))
|
||||
* fix typos ([#152](https://github.com/anthropics/anthropic-sdk-go/issues/152)) ([1cf6a6a](https://github.com/anthropics/anthropic-sdk-go/commit/1cf6a6ae25231b88d2eedbe0758f1281cbe439d8))
|
||||
|
||||
## 0.2.0-beta.2 (2025-03-25)
|
||||
|
||||
Full Changelog: [v0.2.0-beta.1...v0.2.0-beta.2](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-beta.1...v0.2.0-beta.2)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **client:** use raw json for tool input ([1013c2b](https://github.com/anthropics/anthropic-sdk-go/commit/1013c2bdb87a27d2420dbe0dcadc57d1fe3589f2))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* add request options to client tests ([#150](https://github.com/anthropics/anthropic-sdk-go/issues/150)) ([7c70ae1](https://github.com/anthropics/anthropic-sdk-go/commit/7c70ae134a345aff775694abcad255c76e7dfcba))
|
||||
|
||||
## 0.2.0-beta.1 (2025-03-25)
|
||||
|
||||
Full Changelog: [v0.2.0-alpha.13...v0.2.0-beta.1](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.13...v0.2.0-beta.1)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **api:** migrate to v2
|
||||
|
||||
### Features
|
||||
|
||||
* add SKIP_BREW env var to ./scripts/bootstrap ([#137](https://github.com/anthropics/anthropic-sdk-go/issues/137)) ([4057111](https://github.com/anthropics/anthropic-sdk-go/commit/40571110129d5c66f171ead36f5d725663262bc4))
|
||||
* **api:** migrate to v2 ([fcd95eb](https://github.com/anthropics/anthropic-sdk-go/commit/fcd95eb8f45d0ffedcd1e47cd0879d7e66783540))
|
||||
* **client:** accept RFC6838 JSON content types ([#139](https://github.com/anthropics/anthropic-sdk-go/issues/139)) ([78d17cd](https://github.com/anthropics/anthropic-sdk-go/commit/78d17cd4122893ba62b1e14714a1da004c128344))
|
||||
* **client:** allow custom baseurls without trailing slash ([#135](https://github.com/anthropics/anthropic-sdk-go/issues/135)) ([9b30fce](https://github.com/anthropics/anthropic-sdk-go/commit/9b30fce0a71a35910315e02cd3a2f2afc1fd7962))
|
||||
* **client:** improve default client options support ([07f82a6](https://github.com/anthropics/anthropic-sdk-go/commit/07f82a6f9e07bf9aadf4ca150287887cb9e75bc4))
|
||||
* **client:** improve default client options support ([#142](https://github.com/anthropics/anthropic-sdk-go/issues/142)) ([f261355](https://github.com/anthropics/anthropic-sdk-go/commit/f261355e497748bcb112eecb67a95d7c7c5075c0))
|
||||
* **client:** support v2 ([#147](https://github.com/anthropics/anthropic-sdk-go/issues/147)) ([6b3af98](https://github.com/anthropics/anthropic-sdk-go/commit/6b3af98e02a9b6126bd715d43f83b8adf8b861e8))
|
||||
|
||||
|
||||
### Chores
|
||||
|
||||
* **docs:** clarify breaking changes ([#146](https://github.com/anthropics/anthropic-sdk-go/issues/146)) ([a2586b4](https://github.com/anthropics/anthropic-sdk-go/commit/a2586b4beb2b9a0ad252e90223fbb471e6c25bc1))
|
||||
* **internal:** codegen metadata ([ce0eca2](https://github.com/anthropics/anthropic-sdk-go/commit/ce0eca25c6a83fca9ececccb41faf04e74566e2d))
|
||||
* **internal:** remove extra empty newlines ([#143](https://github.com/anthropics/anthropic-sdk-go/issues/143)) ([2ed1584](https://github.com/anthropics/anthropic-sdk-go/commit/2ed1584c7d80fddf2ef5143eabbd33b8f1a4603d))
|
||||
|
||||
|
||||
### Refactors
|
||||
|
||||
* tidy up dependencies ([#140](https://github.com/anthropics/anthropic-sdk-go/issues/140)) ([289cc1b](https://github.com/anthropics/anthropic-sdk-go/commit/289cc1b007094421305dfc4ef01ae68bb2d50ee5))
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
## Setting up the environment
|
||||
|
||||
To set up the repository, run:
|
||||
|
||||
```sh
|
||||
$ ./scripts/bootstrap
|
||||
$ ./scripts/lint
|
||||
```
|
||||
|
||||
This will install all the required dependencies and build the SDK.
|
||||
|
||||
You can also [install go 1.22+ manually](https://go.dev/doc/install).
|
||||
|
||||
## Modifying/Adding code
|
||||
|
||||
Most of the SDK is generated code. Modifications to code will be persisted between generations, but may
|
||||
result in merge conflicts between manual patches and changes from the generator. The generator will never
|
||||
modify the contents of the `lib/` and `examples/` directories.
|
||||
|
||||
## Adding and running examples
|
||||
|
||||
All files in the `examples/` directory are not modified by the generator and can be freely edited or added to.
|
||||
|
||||
```go
|
||||
# add an example to examples/<your-example>/main.go
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```sh
|
||||
$ go run ./examples/<your-example>
|
||||
```
|
||||
|
||||
## Using the repository from source
|
||||
|
||||
To use a local version of this library from source in another project, edit the `go.mod` with a replace
|
||||
directive. This can be done through the CLI with the following:
|
||||
|
||||
```sh
|
||||
$ go mod edit -replace github.com/anthropics/anthropic-sdk-go=/path/to/anthropic-sdk-go
|
||||
```
|
||||
|
||||
## Running tests
|
||||
|
||||
Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests.
|
||||
|
||||
```sh
|
||||
$ ./scripts/mock
|
||||
```
|
||||
|
||||
```sh
|
||||
$ ./scripts/test
|
||||
```
|
||||
|
||||
## Formatting
|
||||
|
||||
This library uses the standard gofmt code formatter:
|
||||
|
||||
```sh
|
||||
$ ./scripts/format
|
||||
```
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
Copyright 2023 Anthropic, PBC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
-999
@@ -1,999 +0,0 @@
|
||||
# Anthropic Go API Library
|
||||
|
||||
<!-- x-release-please-start-version -->
|
||||
|
||||
<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go"><img src="https://pkg.go.dev/badge/github.com/anthropics/anthropic-sdk-go.svg" alt="Go Reference"></a>
|
||||
|
||||
<!-- x-release-please-end -->
|
||||
|
||||
The Anthropic Go library provides convenient access to the [Anthropic REST API](https://docs.anthropic.com/claude/reference/)
|
||||
from applications written in Go.
|
||||
|
||||
## Installation
|
||||
|
||||
<!-- x-release-please-start-version -->
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/anthropics/anthropic-sdk-go" // imported as anthropic
|
||||
)
|
||||
```
|
||||
|
||||
<!-- x-release-please-end -->
|
||||
|
||||
Or to pin the version:
|
||||
|
||||
<!-- x-release-please-start-version -->
|
||||
|
||||
```sh
|
||||
go get -u 'github.com/anthropics/[email protected]'
|
||||
```
|
||||
|
||||
<!-- x-release-please-end -->
|
||||
|
||||
## Requirements
|
||||
|
||||
This library requires Go 1.22+.
|
||||
|
||||
## Usage
|
||||
|
||||
The full API of this library can be found in [api.md](api.md).
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/anthropics/anthropic-sdk-go"
|
||||
"github.com/anthropics/anthropic-sdk-go/option"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := anthropic.NewClient(
|
||||
option.WithAPIKey("my-anthropic-api-key"), // defaults to os.LookupEnv("ANTHROPIC_API_KEY")
|
||||
)
|
||||
message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
|
||||
MaxTokens: 1024,
|
||||
Messages: []anthropic.MessageParam{
|
||||
anthropic.NewUserMessage(anthropic.NewTextBlock("What is a quaternion?")),
|
||||
},
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
fmt.Printf("%+v\n", message.Content)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Conversations</summary>
|
||||
|
||||
```go
|
||||
messages := []anthropic.MessageParam{
|
||||
anthropic.NewUserMessage(anthropic.NewTextBlock("What is my first name?")),
|
||||
}
|
||||
|
||||
message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
Messages: messages,
|
||||
MaxTokens: 1024,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%+v\n", message.Content)
|
||||
|
||||
messages = append(messages, message.ToParam())
|
||||
messages = append(messages, anthropic.NewUserMessage(
|
||||
anthropic.NewTextBlock("My full name is John Doe"),
|
||||
))
|
||||
|
||||
message, err = client.Messages.New(context.TODO(), anthropic.MessageNewParams{
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
Messages: messages,
|
||||
MaxTokens: 1024,
|
||||
})
|
||||
|
||||
fmt.Printf("%+v\n", message.Content)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>System prompts</summary>
|
||||
|
||||
```go
|
||||
message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
MaxTokens: 1024,
|
||||
System: []anthropic.TextBlockParam{
|
||||
{Text: "Be very serious at all times."},
|
||||
},
|
||||
Messages: messages,
|
||||
})
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Streaming</summary>
|
||||
|
||||
```go
|
||||
content := "What is a quaternion?"
|
||||
|
||||
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
MaxTokens: 1024,
|
||||
Messages: []anthropic.MessageParam{
|
||||
anthropic.NewUserMessage(anthropic.NewTextBlock(content)),
|
||||
},
|
||||
})
|
||||
|
||||
message := anthropic.Message{}
|
||||
for stream.Next() {
|
||||
event := stream.Current()
|
||||
err := message.Accumulate(event)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch eventVariant := event.AsAny().(type) {
|
||||
case anthropic.ContentBlockDeltaEvent:
|
||||
switch deltaVariant := eventVariant.Delta.AsAny().(type) {
|
||||
case anthropic.TextDelta:
|
||||
print(deltaVariant.Text)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if stream.Err() != nil {
|
||||
panic(stream.Err())
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Tool calling</summary>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/anthropics/anthropic-sdk-go"
|
||||
"github.com/invopop/jsonschema"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := anthropic.NewClient()
|
||||
|
||||
content := "Where is San Francisco?"
|
||||
|
||||
println("[user]: " + content)
|
||||
|
||||
messages := []anthropic.MessageParam{
|
||||
anthropic.NewUserMessage(anthropic.NewTextBlock(content)),
|
||||
}
|
||||
|
||||
toolParams := []anthropic.ToolParam{
|
||||
{
|
||||
Name: "get_coordinates",
|
||||
Description: anthropic.String("Accepts a place as an address, then returns the latitude and longitude coordinates."),
|
||||
InputSchema: GetCoordinatesInputSchema,
|
||||
},
|
||||
}
|
||||
tools := make([]anthropic.ToolUnionParam, len(toolParams))
|
||||
for i, toolParam := range toolParams {
|
||||
tools[i] = anthropic.ToolUnionParam{OfTool: &toolParam}
|
||||
}
|
||||
|
||||
for {
|
||||
message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
MaxTokens: 1024,
|
||||
Messages: messages,
|
||||
Tools: tools,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
print(color("[assistant]: "))
|
||||
for _, block := range message.Content {
|
||||
switch block := block.AsAny().(type) {
|
||||
case anthropic.TextBlock:
|
||||
println(block.Text)
|
||||
println()
|
||||
case anthropic.ToolUseBlock:
|
||||
inputJSON, _ := json.Marshal(block.Input)
|
||||
println(block.Name + ": " + string(inputJSON))
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
messages = append(messages, message.ToParam())
|
||||
toolResults := []anthropic.ContentBlockParamUnion{}
|
||||
|
||||
for _, block := range message.Content {
|
||||
switch variant := block.AsAny().(type) {
|
||||
case anthropic.ToolUseBlock:
|
||||
print(color("[user (" + block.Name + ")]: "))
|
||||
|
||||
var response any
|
||||
switch block.Name {
|
||||
case "get_coordinates":
|
||||
var input struct {
|
||||
Location string `json:"location"`
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
response = GetCoordinates(input.Location)
|
||||
}
|
||||
|
||||
b, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
println(string(b))
|
||||
|
||||
toolResults = append(toolResults, anthropic.NewToolResultBlock(block.ID, string(b), false))
|
||||
}
|
||||
|
||||
}
|
||||
if len(toolResults) == 0 {
|
||||
break
|
||||
}
|
||||
messages = append(messages, anthropic.NewUserMessage(toolResults...))
|
||||
}
|
||||
}
|
||||
|
||||
type GetCoordinatesInput struct {
|
||||
Location string `json:"location" jsonschema_description:"The location to look up."`
|
||||
}
|
||||
|
||||
var GetCoordinatesInputSchema = GenerateSchema[GetCoordinatesInput]()
|
||||
|
||||
type GetCoordinateResponse struct {
|
||||
Long float64 `json:"long"`
|
||||
Lat float64 `json:"lat"`
|
||||
}
|
||||
|
||||
func GetCoordinates(location string) GetCoordinateResponse {
|
||||
return GetCoordinateResponse{
|
||||
Long: -122.4194,
|
||||
Lat: 37.7749,
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateSchema[T any]() anthropic.ToolInputSchemaParam {
|
||||
reflector := jsonschema.Reflector{
|
||||
AllowAdditionalProperties: false,
|
||||
DoNotReference: true,
|
||||
}
|
||||
var v T
|
||||
|
||||
schema := reflector.Reflect(v)
|
||||
|
||||
return anthropic.ToolInputSchemaParam{
|
||||
Properties: schema.Properties,
|
||||
}
|
||||
}
|
||||
|
||||
func color(s string) string {
|
||||
return fmt.Sprintf("\033[1;%sm%s\033[0m", "33", s)
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Tool helpers</summary>
|
||||
|
||||
The SDK provides helper functions for defining tools and running automatic conversation loops. Here's a basic example:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/anthropics/anthropic-sdk-go"
|
||||
"github.com/anthropics/anthropic-sdk-go/toolrunner"
|
||||
)
|
||||
|
||||
// GetWeatherInput defines the tool input with jsonschema tags for automatic schema generation
|
||||
type GetWeatherInput struct {
|
||||
City string `json:"city" jsonschema:"required,description=The city name"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
client := anthropic.NewClient()
|
||||
|
||||
// Define a tool - the schema is generated automatically from the struct's jsonschema tags
|
||||
weatherTool, err := toolrunner.NewBetaToolFromJSONSchema(
|
||||
"get_weather",
|
||||
"Get weather for a city",
|
||||
func(ctx context.Context, input GetWeatherInput) (anthropic.BetaToolResultBlockParamContentUnion, error) {
|
||||
return anthropic.BetaToolResultBlockParamContentUnion{
|
||||
OfText: &anthropic.BetaTextBlockParam{
|
||||
Text: fmt.Sprintf("The weather in %s is sunny, 72°F", input.City),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create a tool runner that automatically handles the conversation loop
|
||||
runner := client.Beta.Messages.NewToolRunner([]anthropic.BetaTool{weatherTool}, anthropic.BetaToolRunnerParams{
|
||||
BetaMessageNewParams: anthropic.BetaMessageNewParams{
|
||||
Model: anthropic.ModelClaudeSonnet4_20250514,
|
||||
MaxTokens: 1024,
|
||||
Messages: []anthropic.BetaMessageParam{
|
||||
anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("What's the weather in Paris?")),
|
||||
},
|
||||
},
|
||||
MaxIterations: 5,
|
||||
})
|
||||
|
||||
// Run until Claude produces a final response
|
||||
message, err := runner.RunToCompletion(context.Background())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(message.Content[0].Text)
|
||||
}
|
||||
```
|
||||
|
||||
For more details, see [tools.md](tools.md).
|
||||
|
||||
</details>
|
||||
|
||||
### Request fields
|
||||
|
||||
The anthropic library uses the [`omitzero`](https://tip.golang.org/doc/go1.24#encodingjsonpkgencodingjson)
|
||||
semantics from the Go 1.24+ `encoding/json` release for request fields.
|
||||
|
||||
Required primitive fields (`int64`, `string`, etc.) feature the tag <code>\`json:"...,required"\`</code>. These
|
||||
fields are always serialized, even their zero values.
|
||||
|
||||
Optional primitive types are wrapped in a `param.Opt[T]`. These fields can be set with the provided constructors, `anthropic.String(string)`, `anthropic.Int(int64)`, etc.
|
||||
|
||||
Any `param.Opt[T]`, map, slice, struct or string enum uses the
|
||||
tag <code>\`json:"...,omitzero"\`</code>. Its zero value is considered omitted.
|
||||
|
||||
The `param.IsOmitted(any)` function can confirm the presence of any `omitzero` field.
|
||||
|
||||
```go
|
||||
p := anthropic.ExampleParams{
|
||||
ID: "id_xxx", // required property
|
||||
Name: anthropic.String("..."), // optional property
|
||||
|
||||
Point: anthropic.Point{
|
||||
X: 0, // required field will serialize as 0
|
||||
Y: anthropic.Int(1), // optional field will serialize as 1
|
||||
// ... omitted non-required fields will not be serialized
|
||||
},
|
||||
|
||||
Origin: anthropic.Origin{}, // the zero value of [Origin] is considered omitted
|
||||
}
|
||||
```
|
||||
|
||||
To send `null` instead of a `param.Opt[T]`, use `param.Null[T]()`.
|
||||
To send `null` instead of a struct `T`, use `param.NullStruct[T]()`.
|
||||
|
||||
```go
|
||||
p.Name = param.Null[string]() // 'null' instead of string
|
||||
p.Point = param.NullStruct[Point]() // 'null' instead of struct
|
||||
|
||||
param.IsNull(p.Name) // true
|
||||
param.IsNull(p.Point) // true
|
||||
```
|
||||
|
||||
Request structs contain a `.SetExtraFields(map[string]any)` method which can send non-conforming
|
||||
fields in the request body. Extra fields overwrite any struct fields with a matching
|
||||
key.
|
||||
|
||||
> [!WARNING]
|
||||
> For security reasons, only use `SetExtraFields` with trusted data.
|
||||
|
||||
To send a custom value instead of a struct, use `param.Override[T](value)`.
|
||||
|
||||
```go
|
||||
// In cases where the API specifies a given type,
|
||||
// but you want to send something else, use [SetExtraFields]:
|
||||
p.SetExtraFields(map[string]any{
|
||||
"x": 0.01, // send "x" as a float instead of int
|
||||
})
|
||||
|
||||
// Send a number instead of an object
|
||||
custom := param.Override[anthropic.FooParams](12)
|
||||
```
|
||||
|
||||
### Request unions
|
||||
|
||||
Unions are represented as a struct with fields prefixed by "Of" for each of its variants,
|
||||
only one field can be non-zero. The non-zero field will be serialized.
|
||||
|
||||
Sub-properties of the union can be accessed via methods on the union struct.
|
||||
These methods return a mutable pointer to the underlying data, if present.
|
||||
|
||||
```go
|
||||
// Only one field can be non-zero, use param.IsOmitted() to check if a field is set
|
||||
type AnimalUnionParam struct {
|
||||
OfCat *Cat `json:",omitzero,inline`
|
||||
OfDog *Dog `json:",omitzero,inline`
|
||||
}
|
||||
|
||||
animal := AnimalUnionParam{
|
||||
OfCat: &Cat{
|
||||
Name: "Whiskers",
|
||||
Owner: PersonParam{
|
||||
Address: AddressParam{Street: "3333 Coyote Hill Rd", Zip: 0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Mutating a field
|
||||
if address := animal.GetOwner().GetAddress(); address != nil {
|
||||
address.ZipCode = 94304
|
||||
}
|
||||
```
|
||||
|
||||
### Response objects
|
||||
|
||||
All fields in response structs are ordinary value types (not pointers or wrappers).
|
||||
Response structs also include a special `JSON` field containing metadata about
|
||||
each property.
|
||||
|
||||
```go
|
||||
type Animal struct {
|
||||
Name string `json:"name,nullable"`
|
||||
Owners int `json:"owners"`
|
||||
Age int `json:"age"`
|
||||
JSON struct {
|
||||
Name respjson.Field
|
||||
Owner respjson.Field
|
||||
Age respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
} `json:"-"`
|
||||
}
|
||||
```
|
||||
|
||||
To handle optional data, use the `.Valid()` method on the JSON field.
|
||||
`.Valid()` returns true if a field is not `null`, not present, or couldn't be marshaled.
|
||||
|
||||
If `.Valid()` is false, the corresponding field will simply be its zero value.
|
||||
|
||||
```go
|
||||
raw := `{"owners": 1, "name": null}`
|
||||
|
||||
var res Animal
|
||||
json.Unmarshal([]byte(raw), &res)
|
||||
|
||||
// Accessing regular fields
|
||||
|
||||
res.Owners // 1
|
||||
res.Name // ""
|
||||
res.Age // 0
|
||||
|
||||
// Optional field checks
|
||||
|
||||
res.JSON.Owners.Valid() // true
|
||||
res.JSON.Name.Valid() // false
|
||||
res.JSON.Age.Valid() // false
|
||||
|
||||
// Raw JSON values
|
||||
|
||||
res.JSON.Owners.Raw() // "1"
|
||||
res.JSON.Name.Raw() == "null" // true
|
||||
res.JSON.Name.Raw() == respjson.Null // true
|
||||
res.JSON.Age.Raw() == "" // true
|
||||
res.JSON.Age.Raw() == respjson.Omitted // true
|
||||
```
|
||||
|
||||
These `.JSON` structs also include an `ExtraFields` map containing
|
||||
any properties in the json response that were not specified
|
||||
in the struct. This can be useful for API features not yet
|
||||
present in the SDK.
|
||||
|
||||
```go
|
||||
body := res.JSON.ExtraFields["my_unexpected_field"].Raw()
|
||||
```
|
||||
|
||||
### Response Unions
|
||||
|
||||
In responses, unions are represented by a flattened struct containing all possible fields from each of the
|
||||
object variants.
|
||||
To convert it to a variant use the `.AsFooVariant()` method or the `.AsAny()` method if present.
|
||||
|
||||
If a response value union contains primitive values, primitive fields will be alongside
|
||||
the properties but prefixed with `Of` and feature the tag `json:"...,inline"`.
|
||||
|
||||
```go
|
||||
type AnimalUnion struct {
|
||||
// From variants [Dog], [Cat]
|
||||
Owner Person `json:"owner"`
|
||||
// From variant [Dog]
|
||||
DogBreed string `json:"dog_breed"`
|
||||
// From variant [Cat]
|
||||
CatBreed string `json:"cat_breed"`
|
||||
// ...
|
||||
|
||||
JSON struct {
|
||||
Owner respjson.Field
|
||||
// ...
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// If animal variant
|
||||
if animal.Owner.Address.ZipCode == "" {
|
||||
panic("missing zip code")
|
||||
}
|
||||
|
||||
// Switch on the variant
|
||||
switch variant := animal.AsAny().(type) {
|
||||
case Dog:
|
||||
case Cat:
|
||||
default:
|
||||
panic("unexpected type")
|
||||
}
|
||||
```
|
||||
|
||||
### RequestOptions
|
||||
|
||||
This library uses the functional options pattern. Functions defined in the
|
||||
`option` package return a `RequestOption`, which is a closure that mutates a
|
||||
`RequestConfig`. These options can be supplied to the client or at individual
|
||||
requests. For example:
|
||||
|
||||
```go
|
||||
client := anthropic.NewClient(
|
||||
// Adds a header to every request made by the client
|
||||
option.WithHeader("X-Some-Header", "custom_header_info"),
|
||||
)
|
||||
|
||||
client.Messages.New(context.TODO(), ...,
|
||||
// Override the header
|
||||
option.WithHeader("X-Some-Header", "some_other_custom_header_info"),
|
||||
// Add an undocumented field to the request body, using sjson syntax
|
||||
option.WithJSONSet("some.json.path", map[string]string{"my": "object"}),
|
||||
)
|
||||
```
|
||||
|
||||
The request option `option.WithDebugLog(nil)` may be helpful while debugging.
|
||||
|
||||
See the [full list of request options](https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/option).
|
||||
|
||||
### Pagination
|
||||
|
||||
This library provides some conveniences for working with paginated list endpoints.
|
||||
|
||||
You can use `.ListAutoPaging()` methods to iterate through items across all pages:
|
||||
|
||||
```go
|
||||
iter := client.Messages.Batches.ListAutoPaging(context.TODO(), anthropic.MessageBatchListParams{
|
||||
Limit: anthropic.Int(20),
|
||||
})
|
||||
// Automatically fetches more pages as needed.
|
||||
for iter.Next() {
|
||||
messageBatch := iter.Current()
|
||||
fmt.Printf("%+v\n", messageBatch)
|
||||
}
|
||||
if err := iter.Err(); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
```
|
||||
|
||||
Or you can use simple `.List()` methods to fetch a single page and receive a standard response object
|
||||
with additional helper methods like `.GetNextPage()`, e.g.:
|
||||
|
||||
```go
|
||||
page, err := client.Messages.Batches.List(context.TODO(), anthropic.MessageBatchListParams{
|
||||
Limit: anthropic.Int(20),
|
||||
})
|
||||
for page != nil {
|
||||
for _, batch := range page.Data {
|
||||
fmt.Printf("%+v\n", batch)
|
||||
}
|
||||
page, err = page.GetNextPage()
|
||||
}
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
```
|
||||
|
||||
### Errors
|
||||
|
||||
When the API returns a non-success status code, we return an error with type
|
||||
`*anthropic.Error`. This contains the `StatusCode`, `*http.Request`, and
|
||||
`*http.Response` values of the request, as well as the JSON of the error body
|
||||
(much like other response objects in the SDK). The error also includes the `RequestID`
|
||||
from the response headers, which is useful for troubleshooting with Anthropic support.
|
||||
|
||||
To handle errors, we recommend that you use the `errors.As` pattern:
|
||||
|
||||
```go
|
||||
_, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
|
||||
MaxTokens: 1024,
|
||||
Messages: []anthropic.MessageParam{{
|
||||
Content: []anthropic.ContentBlockParamUnion{{
|
||||
OfText: &anthropic.TextBlockParam{
|
||||
Text: "x",
|
||||
},
|
||||
}},
|
||||
Role: anthropic.MessageParamRoleUser,
|
||||
}},
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
})
|
||||
if err != nil {
|
||||
var apierr *anthropic.Error
|
||||
if errors.As(err, &apierr) {
|
||||
println("Request ID:", apierr.RequestID)
|
||||
println(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request
|
||||
println(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response
|
||||
}
|
||||
panic(err.Error()) // GET "/v1/messages": 400 Bad Request (Request-ID: req_xxx) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
When other errors occur, they are returned unwrapped; for example,
|
||||
if HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.
|
||||
|
||||
### Timeouts
|
||||
|
||||
Requests do not time out by default; use context to configure a timeout for a request lifecycle.
|
||||
|
||||
Note that if a request is [retried](#retries), the context timeout does not start over.
|
||||
To set a per-retry timeout, use `option.WithRequestTimeout()`.
|
||||
|
||||
```go
|
||||
// This sets the timeout for the request, including all the retries.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
defer cancel()
|
||||
client.Messages.New(
|
||||
ctx,
|
||||
anthropic.MessageNewParams{
|
||||
MaxTokens: 1024,
|
||||
Messages: []anthropic.MessageParam{{
|
||||
Content: []anthropic.ContentBlockParamUnion{{
|
||||
OfText: &anthropic.TextBlockParam{
|
||||
Text: "What is a quaternion?",
|
||||
},
|
||||
}},
|
||||
Role: anthropic.MessageParamRoleUser,
|
||||
}},
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
},
|
||||
// This sets the per-retry timeout
|
||||
option.WithRequestTimeout(20*time.Second),
|
||||
)
|
||||
```
|
||||
|
||||
### Long Requests
|
||||
|
||||
> [!IMPORTANT]
|
||||
> We highly encourage you use the streaming Messages API for longer running requests.
|
||||
|
||||
We do not recommend setting a large `MaxTokens` value without using streaming as some networks may drop idle connections after a certain period of time, which
|
||||
can cause the request to fail or [timeout](#timeouts) without receiving a response from Anthropic.
|
||||
|
||||
This SDK will also return an error if a non-streaming request is expected to be above roughly 10 minutes long.
|
||||
Calling `.Messages.NewStreaming()` or [setting a custom timeout](#timeouts) disables this error.
|
||||
|
||||
### File uploads
|
||||
|
||||
Request parameters that correspond to file uploads in multipart requests are typed as
|
||||
`io.Reader`. The contents of the `io.Reader` will by default be sent as a multipart form
|
||||
part with the file name of "anonymous_file" and content-type of "application/octet-stream", so we
|
||||
recommend always specifyig a custom content-type with the `anthropic.File(reader io.Reader, filename string, contentType string)`
|
||||
helper we provide to easily wrap any `io.Reader` with the appropriate file name and content type.
|
||||
|
||||
```go
|
||||
// A file from the file system
|
||||
file, err := os.Open("/path/to/file.json")
|
||||
anthropic.BetaFileUploadParams{
|
||||
File: anthropic.File(file, "custom-name.json", "application/json"),
|
||||
Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaFilesAPI2025_04_14},
|
||||
}
|
||||
|
||||
// A file from a string
|
||||
anthropic.BetaFileUploadParams{
|
||||
File: anthropic.File(strings.NewReader("my file contents"), "custom-name.json", "application/json"),
|
||||
Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaFilesAPI2025_04_14},
|
||||
}
|
||||
```
|
||||
|
||||
The file name and content-type can also be customized by implementing `Name() string` or `ContentType()
|
||||
string` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a
|
||||
file returned by `os.Open` will be sent with the file name on disk.
|
||||
|
||||
### Retries
|
||||
|
||||
Certain errors will be automatically retried 2 times by default, with a short exponential backoff.
|
||||
We retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,
|
||||
and >=500 Internal errors.
|
||||
|
||||
You can use the `WithMaxRetries` option to configure or disable this:
|
||||
|
||||
```go
|
||||
// Configure the default for all requests:
|
||||
client := anthropic.NewClient(
|
||||
option.WithMaxRetries(0), // default is 2
|
||||
)
|
||||
|
||||
// Override per-request:
|
||||
client.Messages.New(
|
||||
context.TODO(),
|
||||
anthropic.MessageNewParams{
|
||||
MaxTokens: 1024,
|
||||
Messages: []anthropic.MessageParam{{
|
||||
Content: []anthropic.ContentBlockParamUnion{{
|
||||
OfText: &anthropic.TextBlockParam{
|
||||
Text: "What is a quaternion?",
|
||||
},
|
||||
}},
|
||||
Role: anthropic.MessageParamRoleUser,
|
||||
}},
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
},
|
||||
option.WithMaxRetries(5),
|
||||
)
|
||||
```
|
||||
|
||||
### Accessing raw response data (e.g. response headers)
|
||||
|
||||
You can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when
|
||||
you need to examine response headers, status codes, or other details.
|
||||
|
||||
```go
|
||||
// Create a variable to store the HTTP response
|
||||
var response *http.Response
|
||||
message, err := client.Messages.New(
|
||||
context.TODO(),
|
||||
anthropic.MessageNewParams{
|
||||
MaxTokens: 1024,
|
||||
Messages: []anthropic.MessageParam{{
|
||||
Content: []anthropic.ContentBlockParamUnion{{
|
||||
OfText: &anthropic.TextBlockParam{
|
||||
Text: "x",
|
||||
},
|
||||
}},
|
||||
Role: anthropic.MessageParamRoleUser,
|
||||
}},
|
||||
Model: anthropic.ModelClaudeSonnet4_5_20250929,
|
||||
},
|
||||
option.WithResponseInto(&response),
|
||||
)
|
||||
if err != nil {
|
||||
// handle error
|
||||
}
|
||||
fmt.Printf("%+v\n", message)
|
||||
|
||||
fmt.Printf("Status Code: %d\n", response.StatusCode)
|
||||
fmt.Printf("Headers: %+#v\n", response.Header)
|
||||
```
|
||||
|
||||
### Making custom/undocumented requests
|
||||
|
||||
This library is typed for convenient access to the documented API. If you need to access undocumented
|
||||
endpoints, params, or response properties, the library can still be used.
|
||||
|
||||
#### Undocumented endpoints
|
||||
|
||||
To make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.
|
||||
`RequestOptions` on the client, such as retries, will be respected when making these requests.
|
||||
|
||||
```go
|
||||
var (
|
||||
// params can be an io.Reader, a []byte, an encoding/json serializable object,
|
||||
// or a "…Params" struct defined in this library.
|
||||
params map[string]any
|
||||
|
||||
// result can be an []byte, *http.Response, a encoding/json deserializable object,
|
||||
// or a model defined in this library.
|
||||
result *http.Response
|
||||
)
|
||||
err := client.Post(context.Background(), "/unspecified", params, &result)
|
||||
if err != nil {
|
||||
…
|
||||
}
|
||||
```
|
||||
|
||||
#### Undocumented request params
|
||||
|
||||
To make requests using undocumented parameters, you may use either the `option.WithQuerySet()`
|
||||
or the `option.WithJSONSet()` methods.
|
||||
|
||||
```go
|
||||
params := FooNewParams{
|
||||
ID: "id_xxxx",
|
||||
Data: FooNewParamsData{
|
||||
FirstName: anthropic.String("John"),
|
||||
},
|
||||
}
|
||||
client.Foo.New(context.Background(), params, option.WithJSONSet("data.last_name", "Doe"))
|
||||
```
|
||||
|
||||
#### Undocumented response properties
|
||||
|
||||
To access undocumented response properties, you may either access the raw JSON of the response as a string
|
||||
with `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with
|
||||
`result.JSON.Foo.Raw()`.
|
||||
|
||||
Any fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.
|
||||
|
||||
### Middleware
|
||||
|
||||
We provide `option.WithMiddleware` which applies the given
|
||||
middleware to requests.
|
||||
|
||||
```go
|
||||
func Logger(req *http.Request, next option.MiddlewareNext) (res *http.Response, err error) {
|
||||
// Before the request
|
||||
start := time.Now()
|
||||
LogReq(req)
|
||||
|
||||
// Forward the request to the next handler
|
||||
res, err = next(req)
|
||||
|
||||
// Handle stuff after the request
|
||||
end := time.Now()
|
||||
LogRes(res, err, start - end)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
client := anthropic.NewClient(
|
||||
option.WithMiddleware(Logger),
|
||||
)
|
||||
```
|
||||
|
||||
When multiple middlewares are provided as variadic arguments, the middlewares
|
||||
are applied left to right. If `option.WithMiddleware` is given
|
||||
multiple times, for example first in the client then the method, the
|
||||
middleware in the client will run first and the middleware given in the method
|
||||
will run next.
|
||||
|
||||
You may also replace the default `http.Client` with
|
||||
`option.WithHTTPClient(client)`. Only one http client is
|
||||
accepted (this overwrites any previous client) and receives requests after any
|
||||
middleware has been applied.
|
||||
|
||||
## Amazon Bedrock
|
||||
|
||||
To use this library with [Amazon Bedrock](https://aws.amazon.com/bedrock/claude/),
|
||||
use the bedrock request option `bedrock.WithLoadDefaultConfig(…)` which reads the
|
||||
[default config](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html).
|
||||
|
||||
Importing the `bedrock` library also globally registers a decoder for `application/vnd.amazon.eventstream` for
|
||||
streaming.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/anthropics/anthropic-sdk-go"
|
||||
"github.com/anthropics/anthropic-sdk-go/bedrock"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := anthropic.NewClient(
|
||||
bedrock.WithLoadDefaultConfig(context.Background()),
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
If you already have an `aws.Config`, you can also use it directly with `bedrock.WithConfig(cfg)`.
|
||||
|
||||
### Bearer Token Authentication
|
||||
|
||||
You can also authenticate with Bedrock using bearer tokens instead of AWS credentials. This is useful in corporate environments where teams need access to Bedrock without managing AWS credentials, IAM roles, or account-level permissions.
|
||||
|
||||
The simplest approach is to set the `AWS_BEARER_TOKEN_BEDROCK` environment variable:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anthropics/anthropic-sdk-go"
|
||||
"github.com/anthropics/anthropic-sdk-go/bedrock"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Automatically uses AWS_BEARER_TOKEN_BEDROCK from the environment.
|
||||
// Region defaults to us-east-1 or uses AWS_REGION if set.
|
||||
client := anthropic.NewClient(
|
||||
bedrock.WithLoadDefaultConfig(context.Background()),
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
To provide a token programmatically, use `bedrock.WithConfig` with a `BearerAuthTokenProvider`:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anthropics/anthropic-sdk-go"
|
||||
"github.com/anthropics/anthropic-sdk-go/bedrock"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := aws.Config{
|
||||
Region: "us-west-2",
|
||||
BearerAuthTokenProvider: bedrock.NewStaticBearerTokenProvider("your-bearer-token"),
|
||||
}
|
||||
client := anthropic.NewClient(
|
||||
bedrock.WithConfig(cfg),
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Read more about Anthropic and Amazon Bedrock [here](https://docs.anthropic.com/en/api/claude-on-amazon-bedrock) and about Bedrock API keys [here](https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys-use.html).
|
||||
|
||||
## Google Vertex AI
|
||||
|
||||
To use this library with [Google Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude),
|
||||
use the request option `vertex.WithGoogleAuth(…)` which reads the
|
||||
[Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials).
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anthropics/anthropic-sdk-go"
|
||||
"github.com/anthropics/anthropic-sdk-go/vertex"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := anthropic.NewClient(
|
||||
vertex.WithGoogleAuth(context.Background(), "us-central1", "id-xxx"),
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
If you already have `*google.Credentials`, you can also use it directly with
|
||||
`vertex.WithCredentials(ctx, region, projectId, creds)`.
|
||||
|
||||
Read more about Anthropic and Google Vertex [here](https://docs.anthropic.com/en/api/claude-on-vertex-ai).
|
||||
|
||||
## Semantic versioning
|
||||
|
||||
This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
|
||||
|
||||
1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_
|
||||
2. Changes that we do not expect to impact the vast majority of users in practice.
|
||||
|
||||
We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
|
||||
|
||||
We are keen for your feedback; please open an [issue](https://www.github.com/anthropics/anthropic-sdk-go/issues) with questions, bugs, or suggestions.
|
||||
|
||||
## Contributing
|
||||
|
||||
See [the contributing documentation](./CONTRIBUTING.md).
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken.
|
||||
|
||||
To report a security issue, please contact the Stainless team at security@stainless.com.
|
||||
|
||||
## Responsible Disclosure
|
||||
|
||||
We appreciate the efforts of security researchers and individuals who help us maintain the security of
|
||||
SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible
|
||||
disclosure practices by allowing us a reasonable amount of time to investigate and address the issue
|
||||
before making any information public.
|
||||
|
||||
## Reporting Non-SDK Related Security Issues
|
||||
|
||||
If you encounter security issues that are not directly related to SDKs but pertain to the services
|
||||
or products provided by Anthropic, please follow the respective company's security reporting guidelines.
|
||||
|
||||
### Anthropic Terms and Policies
|
||||
|
||||
Please contact support@anthropic.com for any questions or concerns regarding the security of our services.
|
||||
|
||||
---
|
||||
|
||||
Thank you for helping us keep the SDKs and systems they interact with secure.
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/apierror"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/param"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/shared"
|
||||
)
|
||||
|
||||
// aliased to make [param.APIUnion] private when embedding
|
||||
type paramUnion = param.APIUnion
|
||||
|
||||
// aliased to make [param.APIObject] private when embedding
|
||||
type paramObj = param.APIObject
|
||||
|
||||
type Error = apierror.Error
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type APIErrorObject = shared.APIErrorObject
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type AuthenticationError = shared.AuthenticationError
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type BillingError = shared.BillingError
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type ErrorObjectUnion = shared.ErrorObjectUnion
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type ErrorResponse = shared.ErrorResponse
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type GatewayTimeoutError = shared.GatewayTimeoutError
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type InvalidRequestError = shared.InvalidRequestError
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type NotFoundError = shared.NotFoundError
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type OverloadedError = shared.OverloadedError
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type PermissionError = shared.PermissionError
|
||||
|
||||
// This is an alias to an internal type.
|
||||
type RateLimitError = shared.RateLimitError
|
||||
|
||||
// Backward-compatible type aliases for renamed types.
|
||||
// These ensure existing code continues to compile after
|
||||
// UserLocation and ErrorCode types were consolidated.
|
||||
|
||||
type WebSearchToolRequestErrorErrorCode = WebSearchToolResultErrorCode
|
||||
type WebSearchToolResultErrorErrorCode = WebSearchToolResultErrorCode
|
||||
type WebSearchTool20250305UserLocationParam = UserLocationParam
|
||||
type WebSearchTool20260209UserLocationParam = UserLocationParam
|
||||
|
||||
const WebSearchToolRequestErrorErrorCodeInvalidToolInput = WebSearchToolResultErrorCodeInvalidToolInput
|
||||
const WebSearchToolRequestErrorErrorCodeUnavailable = WebSearchToolResultErrorCodeUnavailable
|
||||
const WebSearchToolRequestErrorErrorCodeMaxUsesExceeded = WebSearchToolResultErrorCodeMaxUsesExceeded
|
||||
const WebSearchToolRequestErrorErrorCodeTooManyRequests = WebSearchToolResultErrorCodeTooManyRequests
|
||||
const WebSearchToolRequestErrorErrorCodeQueryTooLong = WebSearchToolResultErrorCodeQueryTooLong
|
||||
const WebSearchToolRequestErrorErrorCodeRequestTooLarge = WebSearchToolResultErrorCodeRequestTooLarge
|
||||
const WebSearchToolResultErrorErrorCodeInvalidToolInput = WebSearchToolResultErrorCodeInvalidToolInput
|
||||
const WebSearchToolResultErrorErrorCodeUnavailable = WebSearchToolResultErrorCodeUnavailable
|
||||
const WebSearchToolResultErrorErrorCodeMaxUsesExceeded = WebSearchToolResultErrorCodeMaxUsesExceeded
|
||||
const WebSearchToolResultErrorErrorCodeTooManyRequests = WebSearchToolResultErrorCodeTooManyRequests
|
||||
const WebSearchToolResultErrorErrorCodeQueryTooLong = WebSearchToolResultErrorCodeQueryTooLong
|
||||
const WebSearchToolResultErrorErrorCodeRequestTooLarge = WebSearchToolResultErrorCodeRequestTooLarge
|
||||
-545
@@ -1,545 +0,0 @@
|
||||
# Shared Response Types
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#APIErrorObject">APIErrorObject</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#AuthenticationError">AuthenticationError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#BillingError">BillingError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#ErrorObjectUnion">ErrorObjectUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#ErrorResponse">ErrorResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#GatewayTimeoutError">GatewayTimeoutError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#InvalidRequestError">InvalidRequestError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#NotFoundError">NotFoundError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#OverloadedError">OverloadedError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#PermissionError">PermissionError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/shared#RateLimitError">RateLimitError</a>
|
||||
|
||||
# Messages
|
||||
|
||||
Params Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#Base64ImageSourceParam">Base64ImageSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#Base64PDFSourceParam">Base64PDFSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionOutputBlockParam">BashCodeExecutionOutputBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionResultBlockParam">BashCodeExecutionResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionToolResultBlockParam">BashCodeExecutionToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionToolResultErrorCode">BashCodeExecutionToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionToolResultErrorParam">BashCodeExecutionToolResultErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CacheControlEphemeralParam">CacheControlEphemeralParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationCharLocationParam">CitationCharLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationContentBlockLocationParam">CitationContentBlockLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationPageLocationParam">CitationPageLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationSearchResultLocationParam">CitationSearchResultLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationWebSearchResultLocationParam">CitationWebSearchResultLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationsConfigParam">CitationsConfigParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionOutputBlockParam">CodeExecutionOutputBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionResultBlockParam">CodeExecutionResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionTool20250522Param">CodeExecutionTool20250522Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionTool20250825Param">CodeExecutionTool20250825Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionTool20260120Param">CodeExecutionTool20260120Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionToolResultBlockParam">CodeExecutionToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionToolResultBlockParamContentUnion">CodeExecutionToolResultBlockParamContentUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionToolResultErrorCode">CodeExecutionToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionToolResultErrorParam">CodeExecutionToolResultErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ContainerUploadBlockParam">ContainerUploadBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ContentBlockParamUnion">ContentBlockParamUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ContentBlockSourceParam">ContentBlockSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ContentBlockSourceContentItemUnionParam">ContentBlockSourceContentItemUnionParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#DirectCallerParam">DirectCallerParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#DocumentBlockParam">DocumentBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#EncryptedCodeExecutionResultBlockParam">EncryptedCodeExecutionResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ImageBlockParam">ImageBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#JSONOutputFormatParam">JSONOutputFormatParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MemoryTool20250818Param">MemoryTool20250818Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageCountTokensToolUnionParam">MessageCountTokensToolUnionParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageParam">MessageParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MetadataParam">MetadataParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#Model">Model</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#OutputConfigParam">OutputConfigParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#PlainTextSourceParam">PlainTextSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#RedactedThinkingBlockParam">RedactedThinkingBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#SearchResultBlockParam">SearchResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ServerToolCallerParam">ServerToolCallerParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ServerToolCaller20260120Param">ServerToolCaller20260120Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ServerToolUseBlockParam">ServerToolUseBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextBlockParam">TextBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextCitationParamUnion">TextCitationParamUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionCreateResultBlockParam">TextEditorCodeExecutionCreateResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionStrReplaceResultBlockParam">TextEditorCodeExecutionStrReplaceResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionToolResultBlockParam">TextEditorCodeExecutionToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionToolResultErrorCode">TextEditorCodeExecutionToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionToolResultErrorParam">TextEditorCodeExecutionToolResultErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionViewResultBlockParam">TextEditorCodeExecutionViewResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ThinkingBlockParam">ThinkingBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ThinkingConfigAdaptiveParam">ThinkingConfigAdaptiveParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ThinkingConfigDisabledParam">ThinkingConfigDisabledParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ThinkingConfigEnabledParam">ThinkingConfigEnabledParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ThinkingConfigParamUnion">ThinkingConfigParamUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolParam">ToolParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolBash20250124Param">ToolBash20250124Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolChoiceUnionParam">ToolChoiceUnionParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolChoiceAnyParam">ToolChoiceAnyParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolChoiceAutoParam">ToolChoiceAutoParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolChoiceNoneParam">ToolChoiceNoneParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolChoiceToolParam">ToolChoiceToolParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolReferenceBlockParam">ToolReferenceBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolResultBlockParam">ToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolBm25_20251119Param">ToolSearchToolBm25_20251119Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolRegex20251119Param">ToolSearchToolRegex20251119Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolResultBlockParam">ToolSearchToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolResultErrorCode">ToolSearchToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolResultErrorParam">ToolSearchToolResultErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolSearchResultBlockParam">ToolSearchToolSearchResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolTextEditor20250124Param">ToolTextEditor20250124Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolTextEditor20250429Param">ToolTextEditor20250429Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolTextEditor20250728Param">ToolTextEditor20250728Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolUnionParam">ToolUnionParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolUseBlockParam">ToolUseBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#URLImageSourceParam">URLImageSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#URLPDFSourceParam">URLPDFSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#UserLocationParam">UserLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchBlockParam">WebFetchBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchTool20250910Param">WebFetchTool20250910Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchTool20260209Param">WebFetchTool20260209Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchToolResultBlockParam">WebFetchToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchToolResultErrorBlockParam">WebFetchToolResultErrorBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchToolResultErrorCode">WebFetchToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchResultBlockParam">WebSearchResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchTool20250305Param">WebSearchTool20250305Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchTool20260209Param">WebSearchTool20260209Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchToolRequestErrorParam">WebSearchToolRequestErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchToolResultBlockParam">WebSearchToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchToolResultBlockParamContentUnion">WebSearchToolResultBlockParamContentUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchToolResultErrorCode">WebSearchToolResultErrorCode</a>
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#Base64PDFSource">Base64PDFSource</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionOutputBlock">BashCodeExecutionOutputBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionResultBlock">BashCodeExecutionResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionToolResultBlock">BashCodeExecutionToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionToolResultError">BashCodeExecutionToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BashCodeExecutionToolResultErrorCode">BashCodeExecutionToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CacheCreation">CacheCreation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationCharLocation">CitationCharLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationContentBlockLocation">CitationContentBlockLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationPageLocation">CitationPageLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationsConfig">CitationsConfig</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationsDelta">CitationsDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationsSearchResultLocation">CitationsSearchResultLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CitationsWebSearchResultLocation">CitationsWebSearchResultLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionOutputBlock">CodeExecutionOutputBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionResultBlock">CodeExecutionResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionToolResultBlock">CodeExecutionToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionToolResultBlockContentUnion">CodeExecutionToolResultBlockContentUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionToolResultError">CodeExecutionToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#CodeExecutionToolResultErrorCode">CodeExecutionToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#Container">Container</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ContainerUploadBlock">ContainerUploadBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ContentBlockUnion">ContentBlockUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#DirectCaller">DirectCaller</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#DocumentBlock">DocumentBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#EncryptedCodeExecutionResultBlock">EncryptedCodeExecutionResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#InputJSONDelta">InputJSONDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#Message">Message</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageDeltaUsage">MessageDeltaUsage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageTokensCount">MessageTokensCount</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#Model">Model</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#PlainTextSource">PlainTextSource</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#RawContentBlockDeltaUnion">RawContentBlockDeltaUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ContentBlockDeltaEvent">ContentBlockDeltaEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ContentBlockStartEvent">ContentBlockStartEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ContentBlockStopEvent">ContentBlockStopEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageDeltaEvent">MessageDeltaEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageStartEvent">MessageStartEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageStopEvent">MessageStopEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageStreamEventUnion">MessageStreamEventUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#RedactedThinkingBlock">RedactedThinkingBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ServerToolCaller">ServerToolCaller</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ServerToolCaller20260120">ServerToolCaller20260120</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ServerToolUsage">ServerToolUsage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ServerToolUseBlock">ServerToolUseBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#SignatureDelta">SignatureDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#StopReason">StopReason</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextBlock">TextBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextCitationUnion">TextCitationUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextDelta">TextDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionCreateResultBlock">TextEditorCodeExecutionCreateResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionStrReplaceResultBlock">TextEditorCodeExecutionStrReplaceResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionToolResultBlock">TextEditorCodeExecutionToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionToolResultError">TextEditorCodeExecutionToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionToolResultErrorCode">TextEditorCodeExecutionToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#TextEditorCodeExecutionViewResultBlock">TextEditorCodeExecutionViewResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ThinkingBlock">ThinkingBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ThinkingDelta">ThinkingDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolReferenceBlock">ToolReferenceBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolResultBlock">ToolSearchToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolResultError">ToolSearchToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolResultErrorCode">ToolSearchToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolSearchToolSearchResultBlock">ToolSearchToolSearchResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ToolUseBlock">ToolUseBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#Usage">Usage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchBlock">WebFetchBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchToolResultBlock">WebFetchToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchToolResultErrorBlock">WebFetchToolResultErrorBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebFetchToolResultErrorCode">WebFetchToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchResultBlock">WebSearchResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchToolResultBlock">WebSearchToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchToolResultBlockContentUnion">WebSearchToolResultBlockContentUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchToolResultError">WebSearchToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#WebSearchToolResultErrorCode">WebSearchToolResultErrorCode</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="post /v1/messages">client.Messages.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageNewParams">MessageNewParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#Message">Message</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /v1/messages/count_tokens">client.Messages.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageService.CountTokens">CountTokens</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageCountTokensParams">MessageCountTokensParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageTokensCount">MessageTokensCount</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
## Batches
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#DeletedMessageBatch">DeletedMessageBatch</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatch">MessageBatch</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchCanceledResult">MessageBatchCanceledResult</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchErroredResult">MessageBatchErroredResult</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchExpiredResult">MessageBatchExpiredResult</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchIndividualResponse">MessageBatchIndividualResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchRequestCounts">MessageBatchRequestCounts</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchResultUnion">MessageBatchResultUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchSucceededResult">MessageBatchSucceededResult</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="post /v1/messages/batches">client.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchNewParams">MessageBatchNewParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatch">MessageBatch</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/messages/batches/{message_batch_id}">client.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, messageBatchID <a href="https://pkg.go.dev/builtin#string">string</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatch">MessageBatch</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/messages/batches">client.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchListParams">MessageBatchListParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination#Page">Page</a>[<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatch">MessageBatch</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="delete /v1/messages/batches/{message_batch_id}">client.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, messageBatchID <a href="https://pkg.go.dev/builtin#string">string</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#DeletedMessageBatch">DeletedMessageBatch</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /v1/messages/batches/{message_batch_id}/cancel">client.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchService.Cancel">Cancel</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, messageBatchID <a href="https://pkg.go.dev/builtin#string">string</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatch">MessageBatch</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/messages/batches/{message_batch_id}/results">client.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchService.Results">Results</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, messageBatchID <a href="https://pkg.go.dev/builtin#string">string</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#MessageBatchIndividualResponse">MessageBatchIndividualResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
# Models
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ModelInfo">ModelInfo</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="get /v1/models/{model_id}">client.Models.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ModelService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, modelID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ModelGetParams">ModelGetParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ModelInfo">ModelInfo</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/models">client.Models.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ModelService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ModelListParams">ModelListParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination#Page">Page</a>[<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#ModelInfo">ModelInfo</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
# Beta
|
||||
|
||||
Params Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#AnthropicBeta">AnthropicBeta</a>
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaAPIError">BetaAPIError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaAuthenticationError">BetaAuthenticationError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBillingError">BetaBillingError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaErrorUnion">BetaErrorUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaErrorResponse">BetaErrorResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaGatewayTimeoutError">BetaGatewayTimeoutError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaInvalidRequestError">BetaInvalidRequestError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaNotFoundError">BetaNotFoundError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaOverloadedError">BetaOverloadedError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaPermissionError">BetaPermissionError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRateLimitError">BetaRateLimitError</a>
|
||||
|
||||
## Models
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaModelInfo">BetaModelInfo</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="get /v1/models/{model_id}?beta=true">client.Beta.Models.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaModelService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, modelID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaModelGetParams">BetaModelGetParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaModelInfo">BetaModelInfo</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/models?beta=true">client.Beta.Models.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaModelService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaModelListParams">BetaModelListParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination#Page">Page</a>[<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaModelInfo">BetaModelInfo</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
## Messages
|
||||
|
||||
Params Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaAllThinkingTurnsParam">BetaAllThinkingTurnsParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBase64ImageSourceParam">BetaBase64ImageSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBase64PDFSourceParam">BetaBase64PDFSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBashCodeExecutionOutputBlockParam">BetaBashCodeExecutionOutputBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBashCodeExecutionResultBlockParam">BetaBashCodeExecutionResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBashCodeExecutionToolResultBlockParam">BetaBashCodeExecutionToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBashCodeExecutionToolResultErrorParam">BetaBashCodeExecutionToolResultErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCacheControlEphemeralParam">BetaCacheControlEphemeralParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationCharLocationParam">BetaCitationCharLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationContentBlockLocationParam">BetaCitationContentBlockLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationPageLocationParam">BetaCitationPageLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationSearchResultLocationParam">BetaCitationSearchResultLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationWebSearchResultLocationParam">BetaCitationWebSearchResultLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationsConfigParam">BetaCitationsConfigParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaClearThinking20251015EditParam">BetaClearThinking20251015EditParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaClearToolUses20250919EditParam">BetaClearToolUses20250919EditParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionOutputBlockParam">BetaCodeExecutionOutputBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionResultBlockParam">BetaCodeExecutionResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionTool20250522Param">BetaCodeExecutionTool20250522Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionTool20250825Param">BetaCodeExecutionTool20250825Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionTool20260120Param">BetaCodeExecutionTool20260120Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionToolResultBlockParam">BetaCodeExecutionToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionToolResultBlockParamContentUnion">BetaCodeExecutionToolResultBlockParamContentUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionToolResultErrorCode">BetaCodeExecutionToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionToolResultErrorParam">BetaCodeExecutionToolResultErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCompact20260112EditParam">BetaCompact20260112EditParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCompactionBlockParam">BetaCompactionBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContainerParams">BetaContainerParams</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContainerUploadBlockParam">BetaContainerUploadBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContentBlockParamUnion">BetaContentBlockParamUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContentBlockSourceParam">BetaContentBlockSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContentBlockSourceContentUnionParam">BetaContentBlockSourceContentUnionParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContextManagementConfigParam">BetaContextManagementConfigParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaDirectCallerParam">BetaDirectCallerParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaEncryptedCodeExecutionResultBlockParam">BetaEncryptedCodeExecutionResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileDocumentSourceParam">BetaFileDocumentSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileImageSourceParam">BetaFileImageSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaImageBlockParam">BetaImageBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaInputTokensClearAtLeastParam">BetaInputTokensClearAtLeastParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaInputTokensTriggerParam">BetaInputTokensTriggerParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaJSONOutputFormatParam">BetaJSONOutputFormatParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMCPToolConfigParam">BetaMCPToolConfigParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMCPToolDefaultConfigParam">BetaMCPToolDefaultConfigParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMCPToolUseBlockParam">BetaMCPToolUseBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMCPToolsetParam">BetaMCPToolsetParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMemoryTool20250818Param">BetaMemoryTool20250818Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageParam">BetaMessageParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMetadataParam">BetaMetadataParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaOutputConfigParam">BetaOutputConfigParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaPlainTextSourceParam">BetaPlainTextSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRedactedThinkingBlockParam">BetaRedactedThinkingBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRequestDocumentBlockParam">BetaRequestDocumentBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRequestMCPServerToolConfigurationParam">BetaRequestMCPServerToolConfigurationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRequestMCPServerURLDefinitionParam">BetaRequestMCPServerURLDefinitionParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRequestMCPToolResultBlockParam">BetaRequestMCPToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSearchResultBlockParam">BetaSearchResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaServerToolCallerParam">BetaServerToolCallerParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaServerToolCaller20260120Param">BetaServerToolCaller20260120Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaServerToolUseBlockParam">BetaServerToolUseBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillParams">BetaSkillParams</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextBlockParam">BetaTextBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextCitationParamUnion">BetaTextCitationParamUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionCreateResultBlockParam">BetaTextEditorCodeExecutionCreateResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionStrReplaceResultBlockParam">BetaTextEditorCodeExecutionStrReplaceResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionToolResultBlockParam">BetaTextEditorCodeExecutionToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionToolResultErrorParam">BetaTextEditorCodeExecutionToolResultErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionViewResultBlockParam">BetaTextEditorCodeExecutionViewResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaThinkingBlockParam">BetaThinkingBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaThinkingConfigAdaptiveParam">BetaThinkingConfigAdaptiveParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaThinkingConfigDisabledParam">BetaThinkingConfigDisabledParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaThinkingConfigEnabledParam">BetaThinkingConfigEnabledParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaThinkingConfigParamUnion">BetaThinkingConfigParamUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaThinkingTurnsParam">BetaThinkingTurnsParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolParam">BetaToolParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolBash20241022Param">BetaToolBash20241022Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolBash20250124Param">BetaToolBash20250124Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolChoiceUnionParam">BetaToolChoiceUnionParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolChoiceAnyParam">BetaToolChoiceAnyParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolChoiceAutoParam">BetaToolChoiceAutoParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolChoiceNoneParam">BetaToolChoiceNoneParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolChoiceToolParam">BetaToolChoiceToolParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolComputerUse20241022Param">BetaToolComputerUse20241022Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolComputerUse20250124Param">BetaToolComputerUse20250124Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolComputerUse20251124Param">BetaToolComputerUse20251124Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolReferenceBlockParam">BetaToolReferenceBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolResultBlockParam">BetaToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolSearchToolBm25_20251119Param">BetaToolSearchToolBm25_20251119Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolSearchToolRegex20251119Param">BetaToolSearchToolRegex20251119Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolSearchToolResultBlockParam">BetaToolSearchToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolSearchToolResultErrorParam">BetaToolSearchToolResultErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolSearchToolSearchResultBlockParam">BetaToolSearchToolSearchResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolTextEditor20241022Param">BetaToolTextEditor20241022Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolTextEditor20250124Param">BetaToolTextEditor20250124Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolTextEditor20250429Param">BetaToolTextEditor20250429Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolTextEditor20250728Param">BetaToolTextEditor20250728Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolUnionParam">BetaToolUnionParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolUseBlockParam">BetaToolUseBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolUsesKeepParam">BetaToolUsesKeepParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolUsesTriggerParam">BetaToolUsesTriggerParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaURLImageSourceParam">BetaURLImageSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaURLPDFSourceParam">BetaURLPDFSourceParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaUserLocationParam">BetaUserLocationParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchBlockParam">BetaWebFetchBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchTool20250910Param">BetaWebFetchTool20250910Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchTool20260209Param">BetaWebFetchTool20260209Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchToolResultBlockParam">BetaWebFetchToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchToolResultErrorBlockParam">BetaWebFetchToolResultErrorBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchToolResultErrorCode">BetaWebFetchToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchResultBlockParam">BetaWebSearchResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchTool20250305Param">BetaWebSearchTool20250305Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchTool20260209Param">BetaWebSearchTool20260209Param</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchToolRequestErrorParam">BetaWebSearchToolRequestErrorParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchToolResultBlockParam">BetaWebSearchToolResultBlockParam</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchToolResultBlockParamContentUnion">BetaWebSearchToolResultBlockParamContentUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchToolResultErrorCode">BetaWebSearchToolResultErrorCode</a>
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBase64PDFSource">BetaBase64PDFSource</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBashCodeExecutionOutputBlock">BetaBashCodeExecutionOutputBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBashCodeExecutionResultBlock">BetaBashCodeExecutionResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBashCodeExecutionToolResultBlock">BetaBashCodeExecutionToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaBashCodeExecutionToolResultError">BetaBashCodeExecutionToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCacheCreation">BetaCacheCreation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationCharLocation">BetaCitationCharLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationConfig">BetaCitationConfig</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationContentBlockLocation">BetaCitationContentBlockLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationPageLocation">BetaCitationPageLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationSearchResultLocation">BetaCitationSearchResultLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationsDelta">BetaCitationsDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCitationsWebSearchResultLocation">BetaCitationsWebSearchResultLocation</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaClearThinking20251015EditResponse">BetaClearThinking20251015EditResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaClearToolUses20250919EditResponse">BetaClearToolUses20250919EditResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionOutputBlock">BetaCodeExecutionOutputBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionResultBlock">BetaCodeExecutionResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionToolResultBlock">BetaCodeExecutionToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionToolResultBlockContentUnion">BetaCodeExecutionToolResultBlockContentUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionToolResultError">BetaCodeExecutionToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCodeExecutionToolResultErrorCode">BetaCodeExecutionToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCompactionBlock">BetaCompactionBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCompactionContentBlockDelta">BetaCompactionContentBlockDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCompactionIterationUsage">BetaCompactionIterationUsage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContainer">BetaContainer</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContainerUploadBlock">BetaContainerUploadBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContentBlockUnion">BetaContentBlockUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaContextManagementResponse">BetaContextManagementResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaCountTokensContextManagementResponse">BetaCountTokensContextManagementResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaDirectCaller">BetaDirectCaller</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaDocumentBlock">BetaDocumentBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaEncryptedCodeExecutionResultBlock">BetaEncryptedCodeExecutionResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaInputJSONDelta">BetaInputJSONDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaIterationsUsage">BetaIterationsUsage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMCPToolResultBlock">BetaMCPToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMCPToolUseBlock">BetaMCPToolUseBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMemoryTool20250818CommandUnion">BetaMemoryTool20250818CommandUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMemoryTool20250818CreateCommand">BetaMemoryTool20250818CreateCommand</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMemoryTool20250818DeleteCommand">BetaMemoryTool20250818DeleteCommand</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMemoryTool20250818InsertCommand">BetaMemoryTool20250818InsertCommand</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMemoryTool20250818RenameCommand">BetaMemoryTool20250818RenameCommand</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMemoryTool20250818StrReplaceCommand">BetaMemoryTool20250818StrReplaceCommand</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMemoryTool20250818ViewCommand">BetaMemoryTool20250818ViewCommand</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessage">BetaMessage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageDeltaUsage">BetaMessageDeltaUsage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageIterationUsage">BetaMessageIterationUsage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageTokensCount">BetaMessageTokensCount</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaPlainTextSource">BetaPlainTextSource</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRawContentBlockDeltaUnion">BetaRawContentBlockDeltaUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRawContentBlockDeltaEvent">BetaRawContentBlockDeltaEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRawContentBlockStartEvent">BetaRawContentBlockStartEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRawContentBlockStopEvent">BetaRawContentBlockStopEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRawMessageDeltaEvent">BetaRawMessageDeltaEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRawMessageStartEvent">BetaRawMessageStartEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRawMessageStopEvent">BetaRawMessageStopEvent</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRawMessageStreamEventUnion">BetaRawMessageStreamEventUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaRedactedThinkingBlock">BetaRedactedThinkingBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaServerToolCaller">BetaServerToolCaller</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaServerToolCaller20260120">BetaServerToolCaller20260120</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaServerToolUsage">BetaServerToolUsage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaServerToolUseBlock">BetaServerToolUseBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSignatureDelta">BetaSignatureDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkill">BetaSkill</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaStopReason">BetaStopReason</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextBlock">BetaTextBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextCitationUnion">BetaTextCitationUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextDelta">BetaTextDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionCreateResultBlock">BetaTextEditorCodeExecutionCreateResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionStrReplaceResultBlock">BetaTextEditorCodeExecutionStrReplaceResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionToolResultBlock">BetaTextEditorCodeExecutionToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionToolResultError">BetaTextEditorCodeExecutionToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaTextEditorCodeExecutionViewResultBlock">BetaTextEditorCodeExecutionViewResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaThinkingBlock">BetaThinkingBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaThinkingDelta">BetaThinkingDelta</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolReferenceBlock">BetaToolReferenceBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolSearchToolResultBlock">BetaToolSearchToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolSearchToolResultError">BetaToolSearchToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolSearchToolSearchResultBlock">BetaToolSearchToolSearchResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaToolUseBlock">BetaToolUseBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaUsage">BetaUsage</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchBlock">BetaWebFetchBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchToolResultBlock">BetaWebFetchToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchToolResultErrorBlock">BetaWebFetchToolResultErrorBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebFetchToolResultErrorCode">BetaWebFetchToolResultErrorCode</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchResultBlock">BetaWebSearchResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchToolResultBlock">BetaWebSearchToolResultBlock</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchToolResultBlockContentUnion">BetaWebSearchToolResultBlockContentUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchToolResultError">BetaWebSearchToolResultError</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaWebSearchToolResultErrorCode">BetaWebSearchToolResultErrorCode</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="post /v1/messages?beta=true">client.Beta.Messages.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageNewParams">BetaMessageNewParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessage">BetaMessage</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /v1/messages/count_tokens?beta=true">client.Beta.Messages.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageService.CountTokens">CountTokens</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageCountTokensParams">BetaMessageCountTokensParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageTokensCount">BetaMessageTokensCount</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
### Batches
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaDeletedMessageBatch">BetaDeletedMessageBatch</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatch">BetaMessageBatch</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchCanceledResult">BetaMessageBatchCanceledResult</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchErroredResult">BetaMessageBatchErroredResult</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchExpiredResult">BetaMessageBatchExpiredResult</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchIndividualResponse">BetaMessageBatchIndividualResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchRequestCounts">BetaMessageBatchRequestCounts</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchResultUnion">BetaMessageBatchResultUnion</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchSucceededResult">BetaMessageBatchSucceededResult</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="post /v1/messages/batches?beta=true">client.Beta.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchNewParams">BetaMessageBatchNewParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatch">BetaMessageBatch</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/messages/batches/{message_batch_id}?beta=true">client.Beta.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, messageBatchID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchGetParams">BetaMessageBatchGetParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatch">BetaMessageBatch</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/messages/batches?beta=true">client.Beta.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchListParams">BetaMessageBatchListParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination#Page">Page</a>[<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatch">BetaMessageBatch</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="delete /v1/messages/batches/{message_batch_id}?beta=true">client.Beta.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, messageBatchID <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchDeleteParams">BetaMessageBatchDeleteParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaDeletedMessageBatch">BetaDeletedMessageBatch</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /v1/messages/batches/{message_batch_id}/cancel?beta=true">client.Beta.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchService.Cancel">Cancel</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, messageBatchID <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchCancelParams">BetaMessageBatchCancelParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatch">BetaMessageBatch</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/messages/batches/{message_batch_id}/results?beta=true">client.Beta.Messages.Batches.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchService.Results">Results</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, messageBatchID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchResultsParams">BetaMessageBatchResultsParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaMessageBatchIndividualResponse">BetaMessageBatchIndividualResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
## Files
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#DeletedFile">DeletedFile</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#FileMetadata">FileMetadata</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="get /v1/files?beta=true">client.Beta.Files.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileListParams">BetaFileListParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination#Page">Page</a>[<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#FileMetadata">FileMetadata</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="delete /v1/files/{file_id}?beta=true">client.Beta.Files.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fileID <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileDeleteParams">BetaFileDeleteParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#DeletedFile">DeletedFile</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/files/{file_id}/content?beta=true">client.Beta.Files.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileService.Download">Download</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fileID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileDownloadParams">BetaFileDownloadParams</a>) (\*http.Response, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/files/{file_id}?beta=true">client.Beta.Files.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileService.GetMetadata">GetMetadata</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fileID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileGetMetadataParams">BetaFileGetMetadataParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#FileMetadata">FileMetadata</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /v1/files?beta=true">client.Beta.Files.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileService.Upload">Upload</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaFileUploadParams">BetaFileUploadParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#FileMetadata">FileMetadata</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
## Skills
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillNewResponse">BetaSkillNewResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillGetResponse">BetaSkillGetResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillListResponse">BetaSkillListResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillDeleteResponse">BetaSkillDeleteResponse</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="post /v1/skills?beta=true">client.Beta.Skills.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillNewParams">BetaSkillNewParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillNewResponse">BetaSkillNewResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/skills/{skill_id}?beta=true">client.Beta.Skills.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, skillID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillGetParams">BetaSkillGetParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillGetResponse">BetaSkillGetResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/skills?beta=true">client.Beta.Skills.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillListParams">BetaSkillListParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination#PageCursor">PageCursor</a>[<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillListResponse">BetaSkillListResponse</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="delete /v1/skills/{skill_id}?beta=true">client.Beta.Skills.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, skillID <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillDeleteParams">BetaSkillDeleteParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillDeleteResponse">BetaSkillDeleteResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
### Versions
|
||||
|
||||
Response Types:
|
||||
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionNewResponse">BetaSkillVersionNewResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionGetResponse">BetaSkillVersionGetResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionListResponse">BetaSkillVersionListResponse</a>
|
||||
- <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionDeleteResponse">BetaSkillVersionDeleteResponse</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="post /v1/skills/{skill_id}/versions?beta=true">client.Beta.Skills.Versions.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, skillID <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionNewParams">BetaSkillVersionNewParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionNewResponse">BetaSkillVersionNewResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/skills/{skill_id}/versions/{version}?beta=true">client.Beta.Skills.Versions.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, version <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionGetParams">BetaSkillVersionGetParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionGetResponse">BetaSkillVersionGetResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="get /v1/skills/{skill_id}/versions?beta=true">client.Beta.Skills.Versions.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, skillID <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionListParams">BetaSkillVersionListParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go/packages/pagination#PageCursor">PageCursor</a>[<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionListResponse">BetaSkillVersionListResponse</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="delete /v1/skills/{skill_id}/versions/{version}?beta=true">client.Beta.Skills.Versions.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, version <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionDeleteParams">BetaSkillVersionDeleteParams</a>) (\*<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go">anthropic</a>.<a href="https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#BetaSkillVersionDeleteResponse">BetaSkillVersionDeleteResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
-295
@@ -1,295 +0,0 @@
|
||||
package bedrock
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream"
|
||||
"github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream/eventstreamapi"
|
||||
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/smithy-go/auth/bearer"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/requestconfig"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/option"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/ssestream"
|
||||
)
|
||||
|
||||
const DefaultVersion = "bedrock-2023-05-31"
|
||||
|
||||
var DefaultEndpoints = map[string]bool{
|
||||
"/v1/complete": true,
|
||||
"/v1/messages": true,
|
||||
}
|
||||
|
||||
func NewStaticBearerTokenProvider(token string) *bearer.StaticTokenProvider {
|
||||
return &bearer.StaticTokenProvider{
|
||||
Token: bearer.Token{
|
||||
Value: token,
|
||||
CanExpire: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type eventstreamChunk struct {
|
||||
Bytes string `json:"bytes"`
|
||||
P string `json:"p"`
|
||||
}
|
||||
|
||||
type eventstreamDecoder struct {
|
||||
eventstream.Decoder
|
||||
|
||||
rc io.ReadCloser
|
||||
evt ssestream.Event
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *eventstreamDecoder) Close() error {
|
||||
return e.rc.Close()
|
||||
}
|
||||
|
||||
func (e *eventstreamDecoder) Err() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func (e *eventstreamDecoder) Next() bool {
|
||||
if e.err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
msg, err := e.Decoder.Decode(e.rc, nil)
|
||||
if err != nil {
|
||||
e.err = err
|
||||
return false
|
||||
}
|
||||
|
||||
messageType := msg.Headers.Get(eventstreamapi.MessageTypeHeader)
|
||||
if messageType == nil {
|
||||
e.err = fmt.Errorf("%s event header not present", eventstreamapi.MessageTypeHeader)
|
||||
return false
|
||||
}
|
||||
|
||||
switch messageType.String() {
|
||||
case eventstreamapi.EventMessageType:
|
||||
eventType := msg.Headers.Get(eventstreamapi.EventTypeHeader)
|
||||
if eventType == nil {
|
||||
e.err = fmt.Errorf("%s event header not present", eventstreamapi.EventTypeHeader)
|
||||
return false
|
||||
}
|
||||
|
||||
if eventType.String() == "chunk" {
|
||||
chunk := eventstreamChunk{}
|
||||
err = json.Unmarshal(msg.Payload, &chunk)
|
||||
if err != nil {
|
||||
e.err = err
|
||||
return false
|
||||
}
|
||||
decoded, err := base64.StdEncoding.DecodeString(chunk.Bytes)
|
||||
if err != nil {
|
||||
e.err = err
|
||||
return false
|
||||
}
|
||||
e.evt = ssestream.Event{
|
||||
Type: gjson.GetBytes(decoded, "type").String(),
|
||||
Data: decoded,
|
||||
}
|
||||
}
|
||||
|
||||
case eventstreamapi.ExceptionMessageType:
|
||||
// See https://github.com/aws/aws-sdk-go-v2/blob/885de40869f9bcee29ad11d60967aa0f1b571d46/service/iotsitewise/deserializers.go#L15511C1-L15567C2
|
||||
exceptionType := msg.Headers.Get(eventstreamapi.ExceptionTypeHeader)
|
||||
if exceptionType == nil {
|
||||
e.err = fmt.Errorf("%s event header not present", eventstreamapi.ExceptionTypeHeader)
|
||||
return false
|
||||
}
|
||||
|
||||
// See https://github.com/aws/aws-sdk-go-v2/blob/885de40869f9bcee29ad11d60967aa0f1b571d46/aws/protocol/restjson/decoder_util.go#L15-L48k
|
||||
var errInfo struct {
|
||||
Code string
|
||||
Type string `json:"__type"`
|
||||
Message string
|
||||
}
|
||||
err = json.Unmarshal(msg.Payload, &errInfo)
|
||||
if err != nil && err != io.EOF {
|
||||
e.err = fmt.Errorf("received exception %s: parsing exception payload failed: %w", exceptionType.String(), err)
|
||||
return false
|
||||
}
|
||||
|
||||
errorCode := "UnknownError"
|
||||
errorMessage := errorCode
|
||||
if ev := exceptionType.String(); len(ev) > 0 {
|
||||
errorCode = ev
|
||||
} else if len(errInfo.Code) > 0 {
|
||||
errorCode = errInfo.Code
|
||||
} else if len(errInfo.Type) > 0 {
|
||||
errorCode = errInfo.Type
|
||||
}
|
||||
|
||||
if len(errInfo.Message) > 0 {
|
||||
errorMessage = errInfo.Message
|
||||
}
|
||||
e.err = fmt.Errorf("received exception %s: %s", errorCode, errorMessage)
|
||||
return false
|
||||
|
||||
case eventstreamapi.ErrorMessageType:
|
||||
errorCode := "UnknownError"
|
||||
errorMessage := errorCode
|
||||
if header := msg.Headers.Get(eventstreamapi.ErrorCodeHeader); header != nil {
|
||||
errorCode = header.String()
|
||||
}
|
||||
if header := msg.Headers.Get(eventstreamapi.ErrorMessageHeader); header != nil {
|
||||
errorMessage = header.String()
|
||||
}
|
||||
e.err = fmt.Errorf("received error %s: %s", errorCode, errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *eventstreamDecoder) Event() ssestream.Event {
|
||||
return e.evt
|
||||
}
|
||||
|
||||
var _ ssestream.Decoder = &eventstreamDecoder{}
|
||||
|
||||
func init() {
|
||||
ssestream.RegisterDecoder("application/vnd.amazon.eventstream", func(rc io.ReadCloser) ssestream.Decoder {
|
||||
return &eventstreamDecoder{rc: rc}
|
||||
})
|
||||
}
|
||||
|
||||
// WithLoadDefaultConfig returns a request option which loads the default config for Amazon and registers
|
||||
// middleware that intercepts request to the Messages API so that this SDK can be used with Amazon Bedrock.
|
||||
//
|
||||
// If you already have an [aws.Config], it is recommended that you instead call [WithConfig] directly.
|
||||
func WithLoadDefaultConfig(ctx context.Context, optFns ...func(*config.LoadOptions) error) option.RequestOption {
|
||||
cfg, err := config.LoadDefaultConfig(ctx, optFns...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return WithConfig(cfg)
|
||||
}
|
||||
|
||||
// WithConfig returns a request option that uses the provided config and registers middleware to
|
||||
// intercept requests to the Messages API, enabling this SDK to work with Amazon Bedrock.
|
||||
//
|
||||
// Authentication is determined as follows: if the AWS_BEARER_TOKEN_BEDROCK environment variable is
|
||||
// set, it is used for bearer token authentication. Otherwise, if cfg.BearerAuthTokenProvider is set,
|
||||
// it is used. If neither is available, cfg.Credentials is used for AWS SigV4 signing and must be set.
|
||||
func WithConfig(cfg aws.Config) option.RequestOption {
|
||||
var credentialErr error
|
||||
|
||||
if cfg.BearerAuthTokenProvider == nil {
|
||||
if token := os.Getenv("AWS_BEARER_TOKEN_BEDROCK"); token != "" {
|
||||
cfg.BearerAuthTokenProvider = NewStaticBearerTokenProvider(token)
|
||||
}
|
||||
} else if cfg.BearerAuthTokenProvider == nil && cfg.Credentials == nil {
|
||||
credentialErr = fmt.Errorf("expected AWS credentials to be set")
|
||||
}
|
||||
|
||||
signer := v4.NewSigner()
|
||||
middleware := bedrockMiddleware(signer, cfg)
|
||||
|
||||
return requestconfig.RequestOptionFunc(func(rc *requestconfig.RequestConfig) error {
|
||||
if credentialErr != nil {
|
||||
return credentialErr
|
||||
}
|
||||
return rc.Apply(
|
||||
option.WithBaseURL(fmt.Sprintf("https://bedrock-runtime.%s.amazonaws.com", cfg.Region)),
|
||||
option.WithMiddleware(middleware),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
func bedrockMiddleware(signer *v4.Signer, cfg aws.Config) option.Middleware {
|
||||
return func(r *http.Request, next option.MiddlewareNext) (res *http.Response, err error) {
|
||||
var body []byte
|
||||
if r.Body != nil {
|
||||
body, err = io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
if !gjson.GetBytes(body, "anthropic_version").Exists() {
|
||||
body, _ = sjson.SetBytes(body, "anthropic_version", DefaultVersion)
|
||||
}
|
||||
|
||||
// pull the betas off of the header (if set) and put them in the body
|
||||
if betaHeader := r.Header.Values("anthropic-beta"); len(betaHeader) > 0 {
|
||||
r.Header.Del("anthropic-beta")
|
||||
body, err = sjson.SetBytes(body, "anthropic_beta", betaHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if r.Method == http.MethodPost && DefaultEndpoints[r.URL.Path] {
|
||||
model := gjson.GetBytes(body, "model").String()
|
||||
stream := gjson.GetBytes(body, "stream").Bool()
|
||||
|
||||
body, _ = sjson.DeleteBytes(body, "model")
|
||||
body, _ = sjson.DeleteBytes(body, "stream")
|
||||
|
||||
var method string
|
||||
if stream {
|
||||
method = "invoke-with-response-stream"
|
||||
} else {
|
||||
method = "invoke"
|
||||
}
|
||||
|
||||
r.URL.Path = fmt.Sprintf("/model/%s/%s", model, method)
|
||||
r.URL.RawPath = fmt.Sprintf("/model/%s/%s", url.QueryEscape(model), method)
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(body)
|
||||
r.Body = io.NopCloser(reader)
|
||||
r.GetBody = func() (io.ReadCloser, error) {
|
||||
_, err := reader.Seek(0, 0)
|
||||
return io.NopCloser(reader), err
|
||||
}
|
||||
r.ContentLength = int64(len(body))
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
switch {
|
||||
case os.Getenv("AWS_BEARER_TOKEN_BEDROCK") != "":
|
||||
r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("AWS_BEARER_TOKEN_BEDROCK")))
|
||||
case cfg.Credentials != nil:
|
||||
credentials, err := cfg.Credentials.Retrieve(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hash := sha256.Sum256(body)
|
||||
err = signer.SignHTTP(ctx, credentials, r, hex.EncodeToString(hash[:]), "bedrock", cfg.Region, time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case cfg.BearerAuthTokenProvider != nil:
|
||||
token, err := cfg.BearerAuthTokenProvider.RetrieveBearerToken(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token.Value))
|
||||
default:
|
||||
return nil, fmt.Errorf("no credentials or bearer token provider given")
|
||||
}
|
||||
|
||||
return next(r)
|
||||
}
|
||||
}
|
||||
-374
@@ -1,374 +0,0 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/apijson"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/option"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/respjson"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/shared/constant"
|
||||
)
|
||||
|
||||
// BetaService contains methods and other services that help with interacting with
|
||||
// the anthropic API.
|
||||
//
|
||||
// Note, unlike clients, this service does not read variables from the environment
|
||||
// automatically. You should not instantiate this service directly, and instead use
|
||||
// the [NewBetaService] method instead.
|
||||
type BetaService struct {
|
||||
Options []option.RequestOption
|
||||
Models BetaModelService
|
||||
Messages BetaMessageService
|
||||
Files BetaFileService
|
||||
Skills BetaSkillService
|
||||
}
|
||||
|
||||
// NewBetaService generates a new service that applies the given options to each
|
||||
// request. These options are applied after the parent client's options (if there
|
||||
// is one), and before any request-specific options.
|
||||
func NewBetaService(opts ...option.RequestOption) (r BetaService) {
|
||||
r = BetaService{}
|
||||
r.Options = opts
|
||||
r.Models = NewBetaModelService(opts...)
|
||||
r.Messages = NewBetaMessageService(opts...)
|
||||
r.Files = NewBetaFileService(opts...)
|
||||
r.Skills = NewBetaSkillService(opts...)
|
||||
return
|
||||
}
|
||||
|
||||
type AnthropicBeta = string
|
||||
|
||||
const (
|
||||
AnthropicBetaMessageBatches2024_09_24 AnthropicBeta = "message-batches-2024-09-24"
|
||||
AnthropicBetaPromptCaching2024_07_31 AnthropicBeta = "prompt-caching-2024-07-31"
|
||||
AnthropicBetaComputerUse2024_10_22 AnthropicBeta = "computer-use-2024-10-22"
|
||||
AnthropicBetaComputerUse2025_01_24 AnthropicBeta = "computer-use-2025-01-24"
|
||||
AnthropicBetaPDFs2024_09_25 AnthropicBeta = "pdfs-2024-09-25"
|
||||
AnthropicBetaTokenCounting2024_11_01 AnthropicBeta = "token-counting-2024-11-01"
|
||||
AnthropicBetaTokenEfficientTools2025_02_19 AnthropicBeta = "token-efficient-tools-2025-02-19"
|
||||
AnthropicBetaOutput128k2025_02_19 AnthropicBeta = "output-128k-2025-02-19"
|
||||
AnthropicBetaFilesAPI2025_04_14 AnthropicBeta = "files-api-2025-04-14"
|
||||
AnthropicBetaMCPClient2025_04_04 AnthropicBeta = "mcp-client-2025-04-04"
|
||||
AnthropicBetaMCPClient2025_11_20 AnthropicBeta = "mcp-client-2025-11-20"
|
||||
AnthropicBetaDevFullThinking2025_05_14 AnthropicBeta = "dev-full-thinking-2025-05-14"
|
||||
AnthropicBetaInterleavedThinking2025_05_14 AnthropicBeta = "interleaved-thinking-2025-05-14"
|
||||
AnthropicBetaCodeExecution2025_05_22 AnthropicBeta = "code-execution-2025-05-22"
|
||||
AnthropicBetaExtendedCacheTTL2025_04_11 AnthropicBeta = "extended-cache-ttl-2025-04-11"
|
||||
AnthropicBetaContext1m2025_08_07 AnthropicBeta = "context-1m-2025-08-07"
|
||||
AnthropicBetaContextManagement2025_06_27 AnthropicBeta = "context-management-2025-06-27"
|
||||
AnthropicBetaModelContextWindowExceeded2025_08_26 AnthropicBeta = "model-context-window-exceeded-2025-08-26"
|
||||
AnthropicBetaSkills2025_10_02 AnthropicBeta = "skills-2025-10-02"
|
||||
AnthropicBetaFastMode2026_02_01 AnthropicBeta = "fast-mode-2026-02-01"
|
||||
)
|
||||
|
||||
type BetaAPIError struct {
|
||||
Message string `json:"message,required"`
|
||||
Type constant.APIError `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaAPIError) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaAPIError) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaAuthenticationError struct {
|
||||
Message string `json:"message,required"`
|
||||
Type constant.AuthenticationError `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaAuthenticationError) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaAuthenticationError) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaBillingError struct {
|
||||
Message string `json:"message,required"`
|
||||
Type constant.BillingError `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaBillingError) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaBillingError) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
// BetaErrorUnion contains all possible properties and values from
|
||||
// [BetaInvalidRequestError], [BetaAuthenticationError], [BetaBillingError],
|
||||
// [BetaPermissionError], [BetaNotFoundError], [BetaRateLimitError],
|
||||
// [BetaGatewayTimeoutError], [BetaAPIError], [BetaOverloadedError].
|
||||
//
|
||||
// Use the [BetaErrorUnion.AsAny] method to switch on the variant.
|
||||
//
|
||||
// Use the methods beginning with 'As' to cast the union to one of its variants.
|
||||
type BetaErrorUnion struct {
|
||||
Message string `json:"message"`
|
||||
// Any of "invalid_request_error", "authentication_error", "billing_error",
|
||||
// "permission_error", "not_found_error", "rate_limit_error", "timeout_error",
|
||||
// "api_error", "overloaded_error".
|
||||
Type string `json:"type"`
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// anyBetaError is implemented by each variant of [BetaErrorUnion] to add type
|
||||
// safety for the return type of [BetaErrorUnion.AsAny]
|
||||
type anyBetaError interface {
|
||||
implBetaErrorUnion()
|
||||
}
|
||||
|
||||
func (BetaInvalidRequestError) implBetaErrorUnion() {}
|
||||
func (BetaAuthenticationError) implBetaErrorUnion() {}
|
||||
func (BetaBillingError) implBetaErrorUnion() {}
|
||||
func (BetaPermissionError) implBetaErrorUnion() {}
|
||||
func (BetaNotFoundError) implBetaErrorUnion() {}
|
||||
func (BetaRateLimitError) implBetaErrorUnion() {}
|
||||
func (BetaGatewayTimeoutError) implBetaErrorUnion() {}
|
||||
func (BetaAPIError) implBetaErrorUnion() {}
|
||||
func (BetaOverloadedError) implBetaErrorUnion() {}
|
||||
|
||||
// Use the following switch statement to find the correct variant
|
||||
//
|
||||
// switch variant := BetaErrorUnion.AsAny().(type) {
|
||||
// case anthropic.BetaInvalidRequestError:
|
||||
// case anthropic.BetaAuthenticationError:
|
||||
// case anthropic.BetaBillingError:
|
||||
// case anthropic.BetaPermissionError:
|
||||
// case anthropic.BetaNotFoundError:
|
||||
// case anthropic.BetaRateLimitError:
|
||||
// case anthropic.BetaGatewayTimeoutError:
|
||||
// case anthropic.BetaAPIError:
|
||||
// case anthropic.BetaOverloadedError:
|
||||
// default:
|
||||
// fmt.Errorf("no variant present")
|
||||
// }
|
||||
func (u BetaErrorUnion) AsAny() anyBetaError {
|
||||
switch u.Type {
|
||||
case "invalid_request_error":
|
||||
return u.AsInvalidRequestError()
|
||||
case "authentication_error":
|
||||
return u.AsAuthenticationError()
|
||||
case "billing_error":
|
||||
return u.AsBillingError()
|
||||
case "permission_error":
|
||||
return u.AsPermissionError()
|
||||
case "not_found_error":
|
||||
return u.AsNotFoundError()
|
||||
case "rate_limit_error":
|
||||
return u.AsRateLimitError()
|
||||
case "timeout_error":
|
||||
return u.AsTimeoutError()
|
||||
case "api_error":
|
||||
return u.AsAPIError()
|
||||
case "overloaded_error":
|
||||
return u.AsOverloadedError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u BetaErrorUnion) AsInvalidRequestError() (v BetaInvalidRequestError) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return
|
||||
}
|
||||
|
||||
func (u BetaErrorUnion) AsAuthenticationError() (v BetaAuthenticationError) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return
|
||||
}
|
||||
|
||||
func (u BetaErrorUnion) AsBillingError() (v BetaBillingError) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return
|
||||
}
|
||||
|
||||
func (u BetaErrorUnion) AsPermissionError() (v BetaPermissionError) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return
|
||||
}
|
||||
|
||||
func (u BetaErrorUnion) AsNotFoundError() (v BetaNotFoundError) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return
|
||||
}
|
||||
|
||||
func (u BetaErrorUnion) AsRateLimitError() (v BetaRateLimitError) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return
|
||||
}
|
||||
|
||||
func (u BetaErrorUnion) AsTimeoutError() (v BetaGatewayTimeoutError) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return
|
||||
}
|
||||
|
||||
func (u BetaErrorUnion) AsAPIError() (v BetaAPIError) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return
|
||||
}
|
||||
|
||||
func (u BetaErrorUnion) AsOverloadedError() (v BetaOverloadedError) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (u BetaErrorUnion) RawJSON() string { return u.JSON.raw }
|
||||
|
||||
func (r *BetaErrorUnion) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaErrorResponse struct {
|
||||
Error BetaErrorUnion `json:"error,required"`
|
||||
RequestID string `json:"request_id,required"`
|
||||
Type constant.Error `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Error respjson.Field
|
||||
RequestID respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaErrorResponse) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaErrorResponse) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaGatewayTimeoutError struct {
|
||||
Message string `json:"message,required"`
|
||||
Type constant.TimeoutError `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaGatewayTimeoutError) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaGatewayTimeoutError) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaInvalidRequestError struct {
|
||||
Message string `json:"message,required"`
|
||||
Type constant.InvalidRequestError `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaInvalidRequestError) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaInvalidRequestError) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaNotFoundError struct {
|
||||
Message string `json:"message,required"`
|
||||
Type constant.NotFoundError `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaNotFoundError) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaNotFoundError) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaOverloadedError struct {
|
||||
Message string `json:"message,required"`
|
||||
Type constant.OverloadedError `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaOverloadedError) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaOverloadedError) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaPermissionError struct {
|
||||
Message string `json:"message,required"`
|
||||
Type constant.PermissionError `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaPermissionError) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaPermissionError) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaRateLimitError struct {
|
||||
Message string `json:"message,required"`
|
||||
Type constant.RateLimitError `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaRateLimitError) RawJSON() string { return r.JSON.raw }
|
||||
func (r *BetaRateLimitError) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
-273
@@ -1,273 +0,0 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/apiform"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/apijson"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/apiquery"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/requestconfig"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/option"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/pagination"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/param"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/respjson"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/shared/constant"
|
||||
)
|
||||
|
||||
// BetaFileService contains methods and other services that help with interacting
|
||||
// with the anthropic API.
|
||||
//
|
||||
// Note, unlike clients, this service does not read variables from the environment
|
||||
// automatically. You should not instantiate this service directly, and instead use
|
||||
// the [NewBetaFileService] method instead.
|
||||
type BetaFileService struct {
|
||||
Options []option.RequestOption
|
||||
}
|
||||
|
||||
// NewBetaFileService generates a new service that applies the given options to
|
||||
// each request. These options are applied after the parent client's options (if
|
||||
// there is one), and before any request-specific options.
|
||||
func NewBetaFileService(opts ...option.RequestOption) (r BetaFileService) {
|
||||
r = BetaFileService{}
|
||||
r.Options = opts
|
||||
return r
|
||||
}
|
||||
|
||||
// List Files
|
||||
func (r *BetaFileService) List(ctx context.Context, params BetaFileListParams, opts ...option.RequestOption) (res *pagination.Page[FileMetadata], err error) {
|
||||
var raw *http.Response
|
||||
for _, v := range params.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14"), option.WithResponseInto(&raw)}, opts...)
|
||||
path := "v1/files?beta=true"
|
||||
cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = cfg.Execute()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.SetPageConfig(cfg, raw)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// List Files
|
||||
func (r *BetaFileService) ListAutoPaging(ctx context.Context, params BetaFileListParams, opts ...option.RequestOption) *pagination.PageAutoPager[FileMetadata] {
|
||||
return pagination.NewPageAutoPager(r.List(ctx, params, opts...))
|
||||
}
|
||||
|
||||
// Delete File
|
||||
func (r *BetaFileService) Delete(ctx context.Context, fileID string, body BetaFileDeleteParams, opts ...option.RequestOption) (res *DeletedFile, err error) {
|
||||
for _, v := range body.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14")}, opts...)
|
||||
if fileID == "" {
|
||||
err = errors.New("missing required file_id parameter")
|
||||
return res, err
|
||||
}
|
||||
path := fmt.Sprintf("v1/files/%s?beta=true", fileID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &res, opts...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Download File
|
||||
func (r *BetaFileService) Download(ctx context.Context, fileID string, query BetaFileDownloadParams, opts ...option.RequestOption) (res *http.Response, err error) {
|
||||
for _, v := range query.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14"), option.WithHeader("Accept", "application/binary")}, opts...)
|
||||
if fileID == "" {
|
||||
err = errors.New("missing required file_id parameter")
|
||||
return res, err
|
||||
}
|
||||
path := fmt.Sprintf("v1/files/%s/content?beta=true", fileID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Get File Metadata
|
||||
func (r *BetaFileService) GetMetadata(ctx context.Context, fileID string, query BetaFileGetMetadataParams, opts ...option.RequestOption) (res *FileMetadata, err error) {
|
||||
for _, v := range query.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14")}, opts...)
|
||||
if fileID == "" {
|
||||
err = errors.New("missing required file_id parameter")
|
||||
return res, err
|
||||
}
|
||||
path := fmt.Sprintf("v1/files/%s?beta=true", fileID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Upload File
|
||||
func (r *BetaFileService) Upload(ctx context.Context, params BetaFileUploadParams, opts ...option.RequestOption) (res *FileMetadata, err error) {
|
||||
for _, v := range params.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "files-api-2025-04-14")}, opts...)
|
||||
path := "v1/files?beta=true"
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
type DeletedFile struct {
|
||||
// ID of the deleted file.
|
||||
ID string `json:"id,required"`
|
||||
// Deleted object type.
|
||||
//
|
||||
// For file deletion, this is always `"file_deleted"`.
|
||||
//
|
||||
// Any of "file_deleted".
|
||||
Type DeletedFileType `json:"type"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
ID respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r DeletedFile) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *DeletedFile) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
// Deleted object type.
|
||||
//
|
||||
// For file deletion, this is always `"file_deleted"`.
|
||||
type DeletedFileType string
|
||||
|
||||
const (
|
||||
DeletedFileTypeFileDeleted DeletedFileType = "file_deleted"
|
||||
)
|
||||
|
||||
type FileMetadata struct {
|
||||
// Unique object identifier.
|
||||
//
|
||||
// The format and length of IDs may change over time.
|
||||
ID string `json:"id,required"`
|
||||
// RFC 3339 datetime string representing when the file was created.
|
||||
CreatedAt time.Time `json:"created_at,required" format:"date-time"`
|
||||
// Original filename of the uploaded file.
|
||||
Filename string `json:"filename,required"`
|
||||
// MIME type of the file.
|
||||
MimeType string `json:"mime_type,required"`
|
||||
// Size of the file in bytes.
|
||||
SizeBytes int64 `json:"size_bytes,required"`
|
||||
// Object type.
|
||||
//
|
||||
// For files, this is always `"file"`.
|
||||
Type constant.File `json:"type,required"`
|
||||
// Whether the file can be downloaded.
|
||||
Downloadable bool `json:"downloadable"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
ID respjson.Field
|
||||
CreatedAt respjson.Field
|
||||
Filename respjson.Field
|
||||
MimeType respjson.Field
|
||||
SizeBytes respjson.Field
|
||||
Type respjson.Field
|
||||
Downloadable respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r FileMetadata) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *FileMetadata) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaFileListParams struct {
|
||||
// ID of the object to use as a cursor for pagination. When provided, returns the
|
||||
// page of results immediately after this object.
|
||||
AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
|
||||
// ID of the object to use as a cursor for pagination. When provided, returns the
|
||||
// page of results immediately before this object.
|
||||
BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
|
||||
// Number of items to return per page.
|
||||
//
|
||||
// Defaults to `20`. Ranges from `1` to `1000`.
|
||||
Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
// URLQuery serializes [BetaFileListParams]'s query parameters as `url.Values`.
|
||||
func (r BetaFileListParams) URLQuery() (v url.Values, err error) {
|
||||
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||
})
|
||||
}
|
||||
|
||||
type BetaFileDeleteParams struct {
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
type BetaFileDownloadParams struct {
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
type BetaFileGetMetadataParams struct {
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
type BetaFileUploadParams struct {
|
||||
// The file to upload
|
||||
File io.Reader `json:"file,omitzero,required" format:"binary"`
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
func (r BetaFileUploadParams) MarshalMultipart() (data []byte, contentType string, err error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
writer := multipart.NewWriter(buf)
|
||||
err = apiform.MarshalRoot(r, writer)
|
||||
if err == nil {
|
||||
err = apiform.WriteExtras(writer, r.ExtraFields())
|
||||
}
|
||||
if err != nil {
|
||||
writer.Close()
|
||||
return nil, "", err
|
||||
}
|
||||
err = writer.Close()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return buf.Bytes(), writer.FormDataContentType(), nil
|
||||
}
|
||||
-11734
File diff suppressed because it is too large.
Load diff
-925
@@ -1,925 +0,0 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/apijson"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/apiquery"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/requestconfig"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/option"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/jsonl"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/pagination"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/param"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/respjson"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/shared/constant"
|
||||
)
|
||||
|
||||
// BetaMessageBatchService contains methods and other services that help with
|
||||
// interacting with the anthropic API.
|
||||
//
|
||||
// Note, unlike clients, this service does not read variables from the environment
|
||||
// automatically. You should not instantiate this service directly, and instead use
|
||||
// the [NewBetaMessageBatchService] method instead.
|
||||
type BetaMessageBatchService struct {
|
||||
Options []option.RequestOption
|
||||
}
|
||||
|
||||
// NewBetaMessageBatchService generates a new service that applies the given
|
||||
// options to each request. These options are applied after the parent client's
|
||||
// options (if there is one), and before any request-specific options.
|
||||
func NewBetaMessageBatchService(opts ...option.RequestOption) (r BetaMessageBatchService) {
|
||||
r = BetaMessageBatchService{}
|
||||
r.Options = opts
|
||||
return r
|
||||
}
|
||||
|
||||
// Send a batch of Message creation requests.
|
||||
//
|
||||
// The Message Batches API can be used to process multiple Messages API requests at
|
||||
// once. Once a Message Batch is created, it begins processing immediately. Batches
|
||||
// can take up to 24 hours to complete.
|
||||
//
|
||||
// Learn more about the Message Batches API in our
|
||||
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
|
||||
func (r *BetaMessageBatchService) New(ctx context.Context, params BetaMessageBatchNewParams, opts ...option.RequestOption) (res *BetaMessageBatch, err error) {
|
||||
for _, v := range params.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24")}, opts...)
|
||||
path := "v1/messages/batches?beta=true"
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// This endpoint is idempotent and can be used to poll for Message Batch
|
||||
// completion. To access the results of a Message Batch, make a request to the
|
||||
// `results_url` field in the response.
|
||||
//
|
||||
// Learn more about the Message Batches API in our
|
||||
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
|
||||
func (r *BetaMessageBatchService) Get(ctx context.Context, messageBatchID string, query BetaMessageBatchGetParams, opts ...option.RequestOption) (res *BetaMessageBatch, err error) {
|
||||
for _, v := range query.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24")}, opts...)
|
||||
if messageBatchID == "" {
|
||||
err = errors.New("missing required message_batch_id parameter")
|
||||
return res, err
|
||||
}
|
||||
path := fmt.Sprintf("v1/messages/batches/%s?beta=true", messageBatchID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// List all Message Batches within a Workspace. Most recently created batches are
|
||||
// returned first.
|
||||
//
|
||||
// Learn more about the Message Batches API in our
|
||||
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
|
||||
func (r *BetaMessageBatchService) List(ctx context.Context, params BetaMessageBatchListParams, opts ...option.RequestOption) (res *pagination.Page[BetaMessageBatch], err error) {
|
||||
var raw *http.Response
|
||||
for _, v := range params.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24"), option.WithResponseInto(&raw)}, opts...)
|
||||
path := "v1/messages/batches?beta=true"
|
||||
cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = cfg.Execute()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.SetPageConfig(cfg, raw)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// List all Message Batches within a Workspace. Most recently created batches are
|
||||
// returned first.
|
||||
//
|
||||
// Learn more about the Message Batches API in our
|
||||
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
|
||||
func (r *BetaMessageBatchService) ListAutoPaging(ctx context.Context, params BetaMessageBatchListParams, opts ...option.RequestOption) *pagination.PageAutoPager[BetaMessageBatch] {
|
||||
return pagination.NewPageAutoPager(r.List(ctx, params, opts...))
|
||||
}
|
||||
|
||||
// Delete a Message Batch.
|
||||
//
|
||||
// Message Batches can only be deleted once they've finished processing. If you'd
|
||||
// like to delete an in-progress batch, you must first cancel it.
|
||||
//
|
||||
// Learn more about the Message Batches API in our
|
||||
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
|
||||
func (r *BetaMessageBatchService) Delete(ctx context.Context, messageBatchID string, body BetaMessageBatchDeleteParams, opts ...option.RequestOption) (res *BetaDeletedMessageBatch, err error) {
|
||||
for _, v := range body.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24")}, opts...)
|
||||
if messageBatchID == "" {
|
||||
err = errors.New("missing required message_batch_id parameter")
|
||||
return res, err
|
||||
}
|
||||
path := fmt.Sprintf("v1/messages/batches/%s?beta=true", messageBatchID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &res, opts...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Batches may be canceled any time before processing ends. Once cancellation is
|
||||
// initiated, the batch enters a `canceling` state, at which time the system may
|
||||
// complete any in-progress, non-interruptible requests before finalizing
|
||||
// cancellation.
|
||||
//
|
||||
// The number of canceled requests is specified in `request_counts`. To determine
|
||||
// which requests were canceled, check the individual results within the batch.
|
||||
// Note that cancellation may not result in any canceled requests if they were
|
||||
// non-interruptible.
|
||||
//
|
||||
// Learn more about the Message Batches API in our
|
||||
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
|
||||
func (r *BetaMessageBatchService) Cancel(ctx context.Context, messageBatchID string, body BetaMessageBatchCancelParams, opts ...option.RequestOption) (res *BetaMessageBatch, err error) {
|
||||
for _, v := range body.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24")}, opts...)
|
||||
if messageBatchID == "" {
|
||||
err = errors.New("missing required message_batch_id parameter")
|
||||
return res, err
|
||||
}
|
||||
path := fmt.Sprintf("v1/messages/batches/%s/cancel?beta=true", messageBatchID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Streams the results of a Message Batch as a `.jsonl` file.
|
||||
//
|
||||
// Each line in the file is a JSON object containing the result of a single request
|
||||
// in the Message Batch. Results are not guaranteed to be in the same order as
|
||||
// requests. Use the `custom_id` field to match results to requests.
|
||||
//
|
||||
// Learn more about the Message Batches API in our
|
||||
// [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
|
||||
func (r *BetaMessageBatchService) ResultsStreaming(ctx context.Context, messageBatchID string, query BetaMessageBatchResultsParams, opts ...option.RequestOption) (stream *jsonl.Stream[BetaMessageBatchIndividualResponse]) {
|
||||
var (
|
||||
raw *http.Response
|
||||
err error
|
||||
)
|
||||
for _, v := range query.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithHeader("anthropic-beta", "message-batches-2024-09-24"), option.WithHeader("Accept", "application/x-jsonl")}, opts...)
|
||||
if messageBatchID == "" {
|
||||
err = errors.New("missing required message_batch_id parameter")
|
||||
return stream
|
||||
}
|
||||
path := fmt.Sprintf("v1/messages/batches/%s/results?beta=true", messageBatchID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &raw, opts...)
|
||||
return jsonl.NewStream[BetaMessageBatchIndividualResponse](raw, err)
|
||||
}
|
||||
|
||||
type BetaDeletedMessageBatch struct {
|
||||
// ID of the Message Batch.
|
||||
ID string `json:"id,required"`
|
||||
// Deleted object type.
|
||||
//
|
||||
// For Message Batches, this is always `"message_batch_deleted"`.
|
||||
Type constant.MessageBatchDeleted `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
ID respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaDeletedMessageBatch) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *BetaDeletedMessageBatch) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaMessageBatch struct {
|
||||
// Unique object identifier.
|
||||
//
|
||||
// The format and length of IDs may change over time.
|
||||
ID string `json:"id,required"`
|
||||
// RFC 3339 datetime string representing the time at which the Message Batch was
|
||||
// archived and its results became unavailable.
|
||||
ArchivedAt time.Time `json:"archived_at,required" format:"date-time"`
|
||||
// RFC 3339 datetime string representing the time at which cancellation was
|
||||
// initiated for the Message Batch. Specified only if cancellation was initiated.
|
||||
CancelInitiatedAt time.Time `json:"cancel_initiated_at,required" format:"date-time"`
|
||||
// RFC 3339 datetime string representing the time at which the Message Batch was
|
||||
// created.
|
||||
CreatedAt time.Time `json:"created_at,required" format:"date-time"`
|
||||
// RFC 3339 datetime string representing the time at which processing for the
|
||||
// Message Batch ended. Specified only once processing ends.
|
||||
//
|
||||
// Processing ends when every request in a Message Batch has either succeeded,
|
||||
// errored, canceled, or expired.
|
||||
EndedAt time.Time `json:"ended_at,required" format:"date-time"`
|
||||
// RFC 3339 datetime string representing the time at which the Message Batch will
|
||||
// expire and end processing, which is 24 hours after creation.
|
||||
ExpiresAt time.Time `json:"expires_at,required" format:"date-time"`
|
||||
// Processing status of the Message Batch.
|
||||
//
|
||||
// Any of "in_progress", "canceling", "ended".
|
||||
ProcessingStatus BetaMessageBatchProcessingStatus `json:"processing_status,required"`
|
||||
// Tallies requests within the Message Batch, categorized by their status.
|
||||
//
|
||||
// Requests start as `processing` and move to one of the other statuses only once
|
||||
// processing of the entire batch ends. The sum of all values always matches the
|
||||
// total number of requests in the batch.
|
||||
RequestCounts BetaMessageBatchRequestCounts `json:"request_counts,required"`
|
||||
// URL to a `.jsonl` file containing the results of the Message Batch requests.
|
||||
// Specified only once processing ends.
|
||||
//
|
||||
// Results in the file are not guaranteed to be in the same order as requests. Use
|
||||
// the `custom_id` field to match results to requests.
|
||||
ResultsURL string `json:"results_url,required"`
|
||||
// Object type.
|
||||
//
|
||||
// For Message Batches, this is always `"message_batch"`.
|
||||
Type constant.MessageBatch `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
ID respjson.Field
|
||||
ArchivedAt respjson.Field
|
||||
CancelInitiatedAt respjson.Field
|
||||
CreatedAt respjson.Field
|
||||
EndedAt respjson.Field
|
||||
ExpiresAt respjson.Field
|
||||
ProcessingStatus respjson.Field
|
||||
RequestCounts respjson.Field
|
||||
ResultsURL respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaMessageBatch) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *BetaMessageBatch) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
// Processing status of the Message Batch.
|
||||
type BetaMessageBatchProcessingStatus string
|
||||
|
||||
const (
|
||||
BetaMessageBatchProcessingStatusInProgress BetaMessageBatchProcessingStatus = "in_progress"
|
||||
BetaMessageBatchProcessingStatusCanceling BetaMessageBatchProcessingStatus = "canceling"
|
||||
BetaMessageBatchProcessingStatusEnded BetaMessageBatchProcessingStatus = "ended"
|
||||
)
|
||||
|
||||
type BetaMessageBatchCanceledResult struct {
|
||||
Type constant.Canceled `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaMessageBatchCanceledResult) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *BetaMessageBatchCanceledResult) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaMessageBatchErroredResult struct {
|
||||
Error BetaErrorResponse `json:"error,required"`
|
||||
Type constant.Errored `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Error respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaMessageBatchErroredResult) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *BetaMessageBatchErroredResult) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaMessageBatchExpiredResult struct {
|
||||
Type constant.Expired `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaMessageBatchExpiredResult) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *BetaMessageBatchExpiredResult) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
// This is a single line in the response `.jsonl` file and does not represent the
|
||||
// response as a whole.
|
||||
type BetaMessageBatchIndividualResponse struct {
|
||||
// Developer-provided ID created for each request in a Message Batch. Useful for
|
||||
// matching results to requests, as results may be given out of request order.
|
||||
//
|
||||
// Must be unique for each request within the Message Batch.
|
||||
CustomID string `json:"custom_id,required"`
|
||||
// Processing result for this request.
|
||||
//
|
||||
// Contains a Message output if processing was successful, an error response if
|
||||
// processing failed, or the reason why processing was not attempted, such as
|
||||
// cancellation or expiration.
|
||||
Result BetaMessageBatchResultUnion `json:"result,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
CustomID respjson.Field
|
||||
Result respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaMessageBatchIndividualResponse) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *BetaMessageBatchIndividualResponse) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaMessageBatchRequestCounts struct {
|
||||
// Number of requests in the Message Batch that have been canceled.
|
||||
//
|
||||
// This is zero until processing of the entire Message Batch has ended.
|
||||
Canceled int64 `json:"canceled,required"`
|
||||
// Number of requests in the Message Batch that encountered an error.
|
||||
//
|
||||
// This is zero until processing of the entire Message Batch has ended.
|
||||
Errored int64 `json:"errored,required"`
|
||||
// Number of requests in the Message Batch that have expired.
|
||||
//
|
||||
// This is zero until processing of the entire Message Batch has ended.
|
||||
Expired int64 `json:"expired,required"`
|
||||
// Number of requests in the Message Batch that are processing.
|
||||
Processing int64 `json:"processing,required"`
|
||||
// Number of requests in the Message Batch that have completed successfully.
|
||||
//
|
||||
// This is zero until processing of the entire Message Batch has ended.
|
||||
Succeeded int64 `json:"succeeded,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Canceled respjson.Field
|
||||
Errored respjson.Field
|
||||
Expired respjson.Field
|
||||
Processing respjson.Field
|
||||
Succeeded respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaMessageBatchRequestCounts) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *BetaMessageBatchRequestCounts) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
// BetaMessageBatchResultUnion contains all possible properties and values from
|
||||
// [BetaMessageBatchSucceededResult], [BetaMessageBatchErroredResult],
|
||||
// [BetaMessageBatchCanceledResult], [BetaMessageBatchExpiredResult].
|
||||
//
|
||||
// Use the [BetaMessageBatchResultUnion.AsAny] method to switch on the variant.
|
||||
//
|
||||
// Use the methods beginning with 'As' to cast the union to one of its variants.
|
||||
type BetaMessageBatchResultUnion struct {
|
||||
// This field is from variant [BetaMessageBatchSucceededResult].
|
||||
Message BetaMessage `json:"message"`
|
||||
// Any of "succeeded", "errored", "canceled", "expired".
|
||||
Type string `json:"type"`
|
||||
// This field is from variant [BetaMessageBatchErroredResult].
|
||||
Error BetaErrorResponse `json:"error"`
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
Error respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// anyBetaMessageBatchResult is implemented by each variant of
|
||||
// [BetaMessageBatchResultUnion] to add type safety for the return type of
|
||||
// [BetaMessageBatchResultUnion.AsAny]
|
||||
type anyBetaMessageBatchResult interface {
|
||||
implBetaMessageBatchResultUnion()
|
||||
}
|
||||
|
||||
func (BetaMessageBatchSucceededResult) implBetaMessageBatchResultUnion() {}
|
||||
func (BetaMessageBatchErroredResult) implBetaMessageBatchResultUnion() {}
|
||||
func (BetaMessageBatchCanceledResult) implBetaMessageBatchResultUnion() {}
|
||||
func (BetaMessageBatchExpiredResult) implBetaMessageBatchResultUnion() {}
|
||||
|
||||
// Use the following switch statement to find the correct variant
|
||||
//
|
||||
// switch variant := BetaMessageBatchResultUnion.AsAny().(type) {
|
||||
// case anthropic.BetaMessageBatchSucceededResult:
|
||||
// case anthropic.BetaMessageBatchErroredResult:
|
||||
// case anthropic.BetaMessageBatchCanceledResult:
|
||||
// case anthropic.BetaMessageBatchExpiredResult:
|
||||
// default:
|
||||
// fmt.Errorf("no variant present")
|
||||
// }
|
||||
func (u BetaMessageBatchResultUnion) AsAny() anyBetaMessageBatchResult {
|
||||
switch u.Type {
|
||||
case "succeeded":
|
||||
return u.AsSucceeded()
|
||||
case "errored":
|
||||
return u.AsErrored()
|
||||
case "canceled":
|
||||
return u.AsCanceled()
|
||||
case "expired":
|
||||
return u.AsExpired()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u BetaMessageBatchResultUnion) AsSucceeded() (v BetaMessageBatchSucceededResult) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u BetaMessageBatchResultUnion) AsErrored() (v BetaMessageBatchErroredResult) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u BetaMessageBatchResultUnion) AsCanceled() (v BetaMessageBatchCanceledResult) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u BetaMessageBatchResultUnion) AsExpired() (v BetaMessageBatchExpiredResult) {
|
||||
apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
|
||||
return v
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (u BetaMessageBatchResultUnion) RawJSON() string { return u.JSON.raw }
|
||||
|
||||
func (r *BetaMessageBatchResultUnion) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaMessageBatchSucceededResult struct {
|
||||
Message BetaMessage `json:"message,required"`
|
||||
Type constant.Succeeded `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
Message respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaMessageBatchSucceededResult) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *BetaMessageBatchSucceededResult) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaMessageBatchNewParams struct {
|
||||
// List of requests for prompt completion. Each is an individual request to create
|
||||
// a Message.
|
||||
Requests []BetaMessageBatchNewParamsRequest `json:"requests,omitzero,required"`
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
func (r BetaMessageBatchNewParams) MarshalJSON() (data []byte, err error) {
|
||||
type shadow BetaMessageBatchNewParams
|
||||
return param.MarshalObject(r, (*shadow)(&r))
|
||||
}
|
||||
|
||||
func (r *BetaMessageBatchNewParams) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
// The properties CustomID, Params are required.
|
||||
type BetaMessageBatchNewParamsRequest struct {
|
||||
// Developer-provided ID created for each request in a Message Batch. Useful for
|
||||
// matching results to requests, as results may be given out of request order.
|
||||
//
|
||||
// Must be unique for each request within the Message Batch.
|
||||
CustomID string `json:"custom_id,required"`
|
||||
// Messages API creation parameters for the individual request.
|
||||
//
|
||||
// See the [Messages API reference](https://docs.claude.com/en/api/messages) for
|
||||
// full documentation on available parameters.
|
||||
Params BetaMessageBatchNewParamsRequestParams `json:"params,omitzero,required"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
func (r BetaMessageBatchNewParamsRequest) MarshalJSON() (data []byte, err error) {
|
||||
type shadow BetaMessageBatchNewParamsRequest
|
||||
return param.MarshalObject(r, (*shadow)(&r))
|
||||
}
|
||||
|
||||
func (r *BetaMessageBatchNewParamsRequest) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
// Messages API creation parameters for the individual request.
|
||||
//
|
||||
// See the [Messages API reference](https://docs.claude.com/en/api/messages) for
|
||||
// full documentation on available parameters.
|
||||
//
|
||||
// The properties MaxTokens, Messages, Model are required.
|
||||
type BetaMessageBatchNewParamsRequestParams struct {
|
||||
// The maximum number of tokens to generate before stopping.
|
||||
//
|
||||
// Note that our models may stop _before_ reaching this maximum. This parameter
|
||||
// only specifies the absolute maximum number of tokens to generate.
|
||||
//
|
||||
// Different models have different maximum values for this parameter. See
|
||||
// [models](https://docs.claude.com/en/docs/models-overview) for details.
|
||||
MaxTokens int64 `json:"max_tokens,required"`
|
||||
// Input messages.
|
||||
//
|
||||
// Our models are trained to operate on alternating `user` and `assistant`
|
||||
// conversational turns. When creating a new `Message`, you specify the prior
|
||||
// conversational turns with the `messages` parameter, and the model then generates
|
||||
// the next `Message` in the conversation. Consecutive `user` or `assistant` turns
|
||||
// in your request will be combined into a single turn.
|
||||
//
|
||||
// Each input message must be an object with a `role` and `content`. You can
|
||||
// specify a single `user`-role message, or you can include multiple `user` and
|
||||
// `assistant` messages.
|
||||
//
|
||||
// If the final message uses the `assistant` role, the response content will
|
||||
// continue immediately from the content in that message. This can be used to
|
||||
// constrain part of the model's response.
|
||||
//
|
||||
// Example with a single `user` message:
|
||||
//
|
||||
// ```json
|
||||
// [{ "role": "user", "content": "Hello, Claude" }]
|
||||
// ```
|
||||
//
|
||||
// Example with multiple conversational turns:
|
||||
//
|
||||
// ```json
|
||||
// [
|
||||
//
|
||||
// { "role": "user", "content": "Hello there." },
|
||||
// { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
|
||||
// { "role": "user", "content": "Can you explain LLMs in plain English?" }
|
||||
//
|
||||
// ]
|
||||
// ```
|
||||
//
|
||||
// Example with a partially-filled response from Claude:
|
||||
//
|
||||
// ```json
|
||||
// [
|
||||
//
|
||||
// {
|
||||
// "role": "user",
|
||||
// "content": "What's the Greek name for Sun? (A) Sol (B) Helios (C) Sun"
|
||||
// },
|
||||
// { "role": "assistant", "content": "The best answer is (" }
|
||||
//
|
||||
// ]
|
||||
// ```
|
||||
//
|
||||
// Each input message `content` may be either a single `string` or an array of
|
||||
// content blocks, where each block has a specific `type`. Using a `string` for
|
||||
// `content` is shorthand for an array of one content block of type `"text"`. The
|
||||
// following input messages are equivalent:
|
||||
//
|
||||
// ```json
|
||||
// { "role": "user", "content": "Hello, Claude" }
|
||||
// ```
|
||||
//
|
||||
// ```json
|
||||
// { "role": "user", "content": [{ "type": "text", "text": "Hello, Claude" }] }
|
||||
// ```
|
||||
//
|
||||
// See [input examples](https://docs.claude.com/en/api/messages-examples).
|
||||
//
|
||||
// Note that if you want to include a
|
||||
// [system prompt](https://docs.claude.com/en/docs/system-prompts), you can use the
|
||||
// top-level `system` parameter — there is no `"system"` role for input messages in
|
||||
// the Messages API.
|
||||
//
|
||||
// There is a limit of 100,000 messages in a single request.
|
||||
Messages []BetaMessageParam `json:"messages,omitzero,required"`
|
||||
// The model that will complete your prompt.\n\nSee
|
||||
// [models](https://docs.anthropic.com/en/docs/models-overview) for additional
|
||||
// details and options.
|
||||
Model Model `json:"model,omitzero,required"`
|
||||
// Specifies the geographic region for inference processing. If not specified, the
|
||||
// workspace's `default_inference_geo` is used.
|
||||
InferenceGeo param.Opt[string] `json:"inference_geo,omitzero"`
|
||||
// Whether to incrementally stream the response using server-sent events.
|
||||
//
|
||||
// See [streaming](https://docs.claude.com/en/api/messages-streaming) for details.
|
||||
Stream param.Opt[bool] `json:"stream,omitzero"`
|
||||
// Amount of randomness injected into the response.
|
||||
//
|
||||
// Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0`
|
||||
// for analytical / multiple choice, and closer to `1.0` for creative and
|
||||
// generative tasks.
|
||||
//
|
||||
// Note that even with `temperature` of `0.0`, the results will not be fully
|
||||
// deterministic.
|
||||
Temperature param.Opt[float64] `json:"temperature,omitzero"`
|
||||
// Only sample from the top K options for each subsequent token.
|
||||
//
|
||||
// Used to remove "long tail" low probability responses.
|
||||
// [Learn more technical details here](https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277).
|
||||
//
|
||||
// Recommended for advanced use cases only. You usually only need to use
|
||||
// `temperature`.
|
||||
TopK param.Opt[int64] `json:"top_k,omitzero"`
|
||||
// Use nucleus sampling.
|
||||
//
|
||||
// In nucleus sampling, we compute the cumulative distribution over all the options
|
||||
// for each subsequent token in decreasing probability order and cut it off once it
|
||||
// reaches a particular probability specified by `top_p`. You should either alter
|
||||
// `temperature` or `top_p`, but not both.
|
||||
//
|
||||
// Recommended for advanced use cases only. You usually only need to use
|
||||
// `temperature`.
|
||||
TopP param.Opt[float64] `json:"top_p,omitzero"`
|
||||
// Container identifier for reuse across requests.
|
||||
Container BetaMessageBatchNewParamsRequestParamsContainerUnion `json:"container,omitzero"`
|
||||
// The inference speed mode for this request. `"fast"` enables high
|
||||
// output-tokens-per-second inference.
|
||||
//
|
||||
// Any of "standard", "fast".
|
||||
Speed string `json:"speed,omitzero"`
|
||||
// Top-level cache control automatically applies a cache_control marker to the last
|
||||
// cacheable block in the request.
|
||||
CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"`
|
||||
// Context management configuration.
|
||||
//
|
||||
// This allows you to control how Claude manages context across multiple requests,
|
||||
// such as whether to clear function results or not.
|
||||
ContextManagement BetaContextManagementConfigParam `json:"context_management,omitzero"`
|
||||
// MCP servers to be utilized in this request
|
||||
MCPServers []BetaRequestMCPServerURLDefinitionParam `json:"mcp_servers,omitzero"`
|
||||
// An object describing metadata about the request.
|
||||
Metadata BetaMetadataParam `json:"metadata,omitzero"`
|
||||
// Configuration options for the model's output, such as the output format.
|
||||
OutputConfig BetaOutputConfigParam `json:"output_config,omitzero"`
|
||||
// Deprecated: Use `output_config.format` instead. See
|
||||
// [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)
|
||||
//
|
||||
// A schema to specify Claude's output format in responses. This parameter will be
|
||||
// removed in a future release.
|
||||
//
|
||||
// Deprecated: deprecated
|
||||
OutputFormat BetaJSONOutputFormatParam `json:"output_format,omitzero"`
|
||||
// Determines whether to use priority capacity (if available) or standard capacity
|
||||
// for this request.
|
||||
//
|
||||
// Anthropic offers different levels of service for your API requests. See
|
||||
// [service-tiers](https://docs.claude.com/en/api/service-tiers) for details.
|
||||
//
|
||||
// Any of "auto", "standard_only".
|
||||
ServiceTier string `json:"service_tier,omitzero"`
|
||||
// Custom text sequences that will cause the model to stop generating.
|
||||
//
|
||||
// Our models will normally stop when they have naturally completed their turn,
|
||||
// which will result in a response `stop_reason` of `"end_turn"`.
|
||||
//
|
||||
// If you want the model to stop generating when it encounters custom strings of
|
||||
// text, you can use the `stop_sequences` parameter. If the model encounters one of
|
||||
// the custom sequences, the response `stop_reason` value will be `"stop_sequence"`
|
||||
// and the response `stop_sequence` value will contain the matched stop sequence.
|
||||
StopSequences []string `json:"stop_sequences,omitzero"`
|
||||
// System prompt.
|
||||
//
|
||||
// A system prompt is a way of providing context and instructions to Claude, such
|
||||
// as specifying a particular goal or role. See our
|
||||
// [guide to system prompts](https://docs.claude.com/en/docs/system-prompts).
|
||||
System []BetaTextBlockParam `json:"system,omitzero"`
|
||||
// Configuration for enabling Claude's extended thinking.
|
||||
//
|
||||
// When enabled, responses include `thinking` content blocks showing Claude's
|
||||
// thinking process before the final answer. Requires a minimum budget of 1,024
|
||||
// tokens and counts towards your `max_tokens` limit.
|
||||
//
|
||||
// See
|
||||
// [extended thinking](https://docs.claude.com/en/docs/build-with-claude/extended-thinking)
|
||||
// for details.
|
||||
Thinking BetaThinkingConfigParamUnion `json:"thinking,omitzero"`
|
||||
// How the model should use the provided tools. The model can use a specific tool,
|
||||
// any available tool, decide by itself, or not use tools at all.
|
||||
ToolChoice BetaToolChoiceUnionParam `json:"tool_choice,omitzero"`
|
||||
// Definitions of tools that the model may use.
|
||||
//
|
||||
// If you include `tools` in your API request, the model may return `tool_use`
|
||||
// content blocks that represent the model's use of those tools. You can then run
|
||||
// those tools using the tool input generated by the model and then optionally
|
||||
// return results back to the model using `tool_result` content blocks.
|
||||
//
|
||||
// There are two types of tools: **client tools** and **server tools**. The
|
||||
// behavior described below applies to client tools. For
|
||||
// [server tools](https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview#server-tools),
|
||||
// see their individual documentation as each has its own behavior (e.g., the
|
||||
// [web search tool](https://docs.claude.com/en/docs/agents-and-tools/tool-use/web-search-tool)).
|
||||
//
|
||||
// Each tool definition includes:
|
||||
//
|
||||
// - `name`: Name of the tool.
|
||||
// - `description`: Optional, but strongly-recommended description of the tool.
|
||||
// - `input_schema`: [JSON schema](https://json-schema.org/draft/2020-12) for the
|
||||
// tool `input` shape that the model will produce in `tool_use` output content
|
||||
// blocks.
|
||||
//
|
||||
// For example, if you defined `tools` as:
|
||||
//
|
||||
// ```json
|
||||
// [
|
||||
//
|
||||
// {
|
||||
// "name": "get_stock_price",
|
||||
// "description": "Get the current stock price for a given ticker symbol.",
|
||||
// "input_schema": {
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "ticker": {
|
||||
// "type": "string",
|
||||
// "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
|
||||
// }
|
||||
// },
|
||||
// "required": ["ticker"]
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ]
|
||||
// ```
|
||||
//
|
||||
// And then asked the model "What's the S&P 500 at today?", the model might produce
|
||||
// `tool_use` content blocks in the response like this:
|
||||
//
|
||||
// ```json
|
||||
// [
|
||||
//
|
||||
// {
|
||||
// "type": "tool_use",
|
||||
// "id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
|
||||
// "name": "get_stock_price",
|
||||
// "input": { "ticker": "^GSPC" }
|
||||
// }
|
||||
//
|
||||
// ]
|
||||
// ```
|
||||
//
|
||||
// You might then run your `get_stock_price` tool with `{"ticker": "^GSPC"}` as an
|
||||
// input, and return the following back to the model in a subsequent `user`
|
||||
// message:
|
||||
//
|
||||
// ```json
|
||||
// [
|
||||
//
|
||||
// {
|
||||
// "type": "tool_result",
|
||||
// "tool_use_id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
|
||||
// "content": "259.75 USD"
|
||||
// }
|
||||
//
|
||||
// ]
|
||||
// ```
|
||||
//
|
||||
// Tools can be used for workflows that include running client-side tools and
|
||||
// functions, or more generally whenever you want the model to produce a particular
|
||||
// JSON structure of output.
|
||||
//
|
||||
// See our [guide](https://docs.claude.com/en/docs/tool-use) for more details.
|
||||
Tools []BetaToolUnionParam `json:"tools,omitzero"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
func (r BetaMessageBatchNewParamsRequestParams) MarshalJSON() (data []byte, err error) {
|
||||
type shadow BetaMessageBatchNewParamsRequestParams
|
||||
return param.MarshalObject(r, (*shadow)(&r))
|
||||
}
|
||||
|
||||
func (r *BetaMessageBatchNewParamsRequestParams) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func init() {
|
||||
apijson.RegisterFieldValidator[BetaMessageBatchNewParamsRequestParams](
|
||||
"service_tier", "auto", "standard_only",
|
||||
)
|
||||
apijson.RegisterFieldValidator[BetaMessageBatchNewParamsRequestParams](
|
||||
"speed", "standard", "fast",
|
||||
)
|
||||
}
|
||||
|
||||
// Only one field can be non-zero.
|
||||
//
|
||||
// Use [param.IsOmitted] to confirm if a field is set.
|
||||
type BetaMessageBatchNewParamsRequestParamsContainerUnion struct {
|
||||
OfContainers *BetaContainerParams `json:",omitzero,inline"`
|
||||
OfString param.Opt[string] `json:",omitzero,inline"`
|
||||
paramUnion
|
||||
}
|
||||
|
||||
func (u BetaMessageBatchNewParamsRequestParamsContainerUnion) MarshalJSON() ([]byte, error) {
|
||||
return param.MarshalUnion(u, u.OfContainers, u.OfString)
|
||||
}
|
||||
func (u *BetaMessageBatchNewParamsRequestParamsContainerUnion) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, u)
|
||||
}
|
||||
|
||||
func (u *BetaMessageBatchNewParamsRequestParamsContainerUnion) asAny() any {
|
||||
if !param.IsOmitted(u.OfContainers) {
|
||||
return u.OfContainers
|
||||
} else if !param.IsOmitted(u.OfString) {
|
||||
return &u.OfString.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type BetaMessageBatchGetParams struct {
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
type BetaMessageBatchListParams struct {
|
||||
// ID of the object to use as a cursor for pagination. When provided, returns the
|
||||
// page of results immediately after this object.
|
||||
AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
|
||||
// ID of the object to use as a cursor for pagination. When provided, returns the
|
||||
// page of results immediately before this object.
|
||||
BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
|
||||
// Number of items to return per page.
|
||||
//
|
||||
// Defaults to `20`. Ranges from `1` to `1000`.
|
||||
Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
// URLQuery serializes [BetaMessageBatchListParams]'s query parameters as
|
||||
// `url.Values`.
|
||||
func (r BetaMessageBatchListParams) URLQuery() (v url.Values, err error) {
|
||||
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||
})
|
||||
}
|
||||
|
||||
type BetaMessageBatchDeleteParams struct {
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
type BetaMessageBatchCancelParams struct {
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
type BetaMessageBatchResultsParams struct {
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
-459
@@ -1,459 +0,0 @@
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/paramutil"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/param"
|
||||
)
|
||||
|
||||
// Accumulate builds up the Message incrementally from a MessageStreamEvent. The Message then can be used as
|
||||
// any other Message, except with the caveat that the Message.JSON field which normally can be used to inspect
|
||||
// the JSON sent over the network may not be populated fully.
|
||||
//
|
||||
// message := anthropic.Message{}
|
||||
// for stream.Next() {
|
||||
// event := stream.Current()
|
||||
// message.Accumulate(event)
|
||||
// }
|
||||
func (acc *BetaMessage) Accumulate(event BetaRawMessageStreamEventUnion) error {
|
||||
if acc == nil {
|
||||
return fmt.Errorf("accumulate: cannot accumulate into nil Message")
|
||||
}
|
||||
|
||||
switch event := event.AsAny().(type) {
|
||||
case BetaRawMessageStartEvent:
|
||||
*acc = event.Message
|
||||
case BetaRawMessageDeltaEvent:
|
||||
acc.StopReason = event.Delta.StopReason
|
||||
acc.StopSequence = event.Delta.StopSequence
|
||||
acc.Usage.OutputTokens = event.Usage.OutputTokens
|
||||
acc.Usage.Iterations = event.Usage.Iterations
|
||||
acc.ContextManagement = event.ContextManagement
|
||||
case BetaRawContentBlockStartEvent:
|
||||
acc.Content = append(acc.Content, BetaContentBlockUnion{})
|
||||
err := acc.Content[len(acc.Content)-1].UnmarshalJSON([]byte(event.ContentBlock.RawJSON()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case BetaRawContentBlockDeltaEvent:
|
||||
if len(acc.Content) == 0 {
|
||||
return fmt.Errorf("received event of type %s but there was no content block", event.Type)
|
||||
}
|
||||
cb := &acc.Content[len(acc.Content)-1]
|
||||
switch delta := event.Delta.AsAny().(type) {
|
||||
case BetaTextDelta:
|
||||
cb.Text += delta.Text
|
||||
case BetaInputJSONDelta:
|
||||
if len(delta.PartialJSON) != 0 {
|
||||
if string(cb.Input) == "{}" {
|
||||
cb.Input = []byte(delta.PartialJSON)
|
||||
} else {
|
||||
cb.Input = append(cb.Input, []byte(delta.PartialJSON)...)
|
||||
}
|
||||
}
|
||||
case BetaThinkingDelta:
|
||||
cb.Thinking += delta.Thinking
|
||||
case BetaSignatureDelta:
|
||||
cb.Signature += delta.Signature
|
||||
case BetaCitationsDelta:
|
||||
citation := BetaTextCitationUnion{}
|
||||
err := citation.UnmarshalJSON([]byte(delta.Citation.RawJSON()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not unmarshal citation delta into citation type: %w", err)
|
||||
}
|
||||
cb.Citations = append(cb.Citations, citation)
|
||||
case BetaCompactionContentBlockDelta:
|
||||
cb.Content.OfString = delta.Content
|
||||
}
|
||||
case BetaRawMessageStopEvent:
|
||||
// Re-marshal the accumulated message to update JSON.raw so that AsAny()
|
||||
// returns the accumulated data rather than the original stream data
|
||||
accJSON, err := json.Marshal(acc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error converting accumulated message to JSON: %w", err)
|
||||
}
|
||||
acc.JSON.raw = string(accJSON)
|
||||
case BetaRawContentBlockStopEvent:
|
||||
// Re-marshal the content block to update JSON.raw so that AsAny()
|
||||
// returns the accumulated data rather than the original stream data
|
||||
if len(acc.Content) == 0 {
|
||||
return fmt.Errorf("received event of type %s but there was no content block", event.Type)
|
||||
}
|
||||
contentBlock := &acc.Content[len(acc.Content)-1]
|
||||
cbJSON, err := json.Marshal(contentBlock)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error converting content block to JSON: %w", err)
|
||||
}
|
||||
contentBlock.JSON.raw = string(cbJSON)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Param converters
|
||||
|
||||
func (r BetaContentBlockUnion) ToParam() BetaContentBlockParamUnion {
|
||||
return r.AsAny().toParamUnion()
|
||||
}
|
||||
|
||||
func (variant BetaTextBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfText: &p}
|
||||
}
|
||||
|
||||
func (variant BetaToolUseBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfToolUse: &p}
|
||||
}
|
||||
|
||||
func (variant BetaThinkingBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfThinking: &p}
|
||||
}
|
||||
|
||||
func (variant BetaRedactedThinkingBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfRedactedThinking: &p}
|
||||
}
|
||||
|
||||
func (variant BetaWebSearchToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfWebSearchToolResult: &p}
|
||||
}
|
||||
|
||||
func (variant BetaBashCodeExecutionToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfBashCodeExecutionToolResult: &p}
|
||||
}
|
||||
|
||||
func (variant BetaCodeExecutionToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfCodeExecutionToolResult: &p}
|
||||
}
|
||||
|
||||
func (variant BetaContainerUploadBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfContainerUpload: &p}
|
||||
}
|
||||
|
||||
func (variant BetaMCPToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfMCPToolResult: &p}
|
||||
}
|
||||
|
||||
func (variant BetaMCPToolUseBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfMCPToolUse: &p}
|
||||
}
|
||||
|
||||
func (variant BetaServerToolUseBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfServerToolUse: &p}
|
||||
}
|
||||
|
||||
func (variant BetaTextEditorCodeExecutionToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfTextEditorCodeExecutionToolResult: &p}
|
||||
}
|
||||
|
||||
func (variant BetaWebFetchToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfWebFetchToolResult: &p}
|
||||
}
|
||||
|
||||
func (variant BetaToolSearchToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfToolSearchToolResult: &p}
|
||||
}
|
||||
|
||||
func (variant BetaCompactionBlock) toParamUnion() BetaContentBlockParamUnion {
|
||||
p := variant.ToParam()
|
||||
return BetaContentBlockParamUnion{OfCompaction: &p}
|
||||
}
|
||||
|
||||
func (r BetaMessage) ToParam() BetaMessageParam {
|
||||
var p BetaMessageParam
|
||||
p.Role = BetaMessageParamRole(r.Role)
|
||||
p.Content = make([]BetaContentBlockParamUnion, len(r.Content))
|
||||
for i, c := range r.Content {
|
||||
contentParams := c.ToParam()
|
||||
p.Content[i] = contentParams
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaRedactedThinkingBlock) ToParam() BetaRedactedThinkingBlockParam {
|
||||
var p BetaRedactedThinkingBlockParam
|
||||
p.Type = r.Type
|
||||
p.Data = r.Data
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaTextBlock) ToParam() BetaTextBlockParam {
|
||||
var p BetaTextBlockParam
|
||||
p.Type = r.Type
|
||||
p.Text = r.Text
|
||||
|
||||
// Distinguish between a nil and zero length slice, since some compatible
|
||||
// APIs may not require citations.
|
||||
if r.Citations != nil {
|
||||
p.Citations = make([]BetaTextCitationParamUnion, 0, len(r.Citations))
|
||||
}
|
||||
for _, citation := range r.Citations {
|
||||
p.Citations = append(p.Citations, citation.AsAny().toParamUnion())
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaCitationCharLocation) toParamUnion() BetaTextCitationParamUnion {
|
||||
var citationParam BetaCitationCharLocationParam
|
||||
citationParam.Type = r.Type
|
||||
citationParam.DocumentTitle = paramutil.ToOpt(r.DocumentTitle, r.JSON.DocumentTitle)
|
||||
citationParam.CitedText = r.CitedText
|
||||
citationParam.DocumentIndex = r.DocumentIndex
|
||||
citationParam.EndCharIndex = r.EndCharIndex
|
||||
citationParam.StartCharIndex = r.StartCharIndex
|
||||
return BetaTextCitationParamUnion{OfCharLocation: &citationParam}
|
||||
}
|
||||
|
||||
func (citationVariant BetaCitationPageLocation) toParamUnion() BetaTextCitationParamUnion {
|
||||
var citationParam BetaCitationPageLocationParam
|
||||
citationParam.Type = citationVariant.Type
|
||||
citationParam.DocumentTitle = paramutil.ToOpt(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle)
|
||||
citationParam.DocumentIndex = citationVariant.DocumentIndex
|
||||
citationParam.EndPageNumber = citationVariant.EndPageNumber
|
||||
citationParam.StartPageNumber = citationVariant.StartPageNumber
|
||||
return BetaTextCitationParamUnion{OfPageLocation: &citationParam}
|
||||
}
|
||||
|
||||
func (citationVariant BetaCitationContentBlockLocation) toParamUnion() BetaTextCitationParamUnion {
|
||||
var citationParam BetaCitationContentBlockLocationParam
|
||||
citationParam.Type = citationVariant.Type
|
||||
citationParam.DocumentTitle = paramutil.ToOpt(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle)
|
||||
citationParam.CitedText = citationVariant.CitedText
|
||||
citationParam.DocumentIndex = citationVariant.DocumentIndex
|
||||
citationParam.EndBlockIndex = citationVariant.EndBlockIndex
|
||||
citationParam.StartBlockIndex = citationVariant.StartBlockIndex
|
||||
return BetaTextCitationParamUnion{OfContentBlockLocation: &citationParam}
|
||||
}
|
||||
|
||||
func (citationVariant BetaCitationsWebSearchResultLocation) toParamUnion() BetaTextCitationParamUnion {
|
||||
var citationParam BetaCitationWebSearchResultLocationParam
|
||||
citationParam.Type = citationVariant.Type
|
||||
citationParam.CitedText = citationVariant.CitedText
|
||||
citationParam.Title = paramutil.ToOpt(citationVariant.Title, citationVariant.JSON.Title)
|
||||
return BetaTextCitationParamUnion{OfWebSearchResultLocation: &citationParam}
|
||||
}
|
||||
|
||||
func (citationVariant BetaCitationSearchResultLocation) toParamUnion() BetaTextCitationParamUnion {
|
||||
var citationParam BetaCitationSearchResultLocationParam
|
||||
citationParam.Type = citationVariant.Type
|
||||
citationParam.CitedText = citationVariant.CitedText
|
||||
citationParam.Title = paramutil.ToOpt(citationVariant.Title, citationVariant.JSON.Title)
|
||||
citationParam.EndBlockIndex = citationVariant.EndBlockIndex
|
||||
citationParam.StartBlockIndex = citationVariant.StartBlockIndex
|
||||
citationParam.Source = citationVariant.Source
|
||||
return BetaTextCitationParamUnion{OfSearchResultLocation: &citationParam}
|
||||
}
|
||||
|
||||
func (r BetaThinkingBlock) ToParam() BetaThinkingBlockParam {
|
||||
var p BetaThinkingBlockParam
|
||||
p.Type = r.Type
|
||||
p.Signature = r.Signature
|
||||
p.Thinking = r.Thinking
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaToolUseBlock) ToParam() BetaToolUseBlockParam {
|
||||
var p BetaToolUseBlockParam
|
||||
p.Type = r.Type
|
||||
p.ID = r.ID
|
||||
p.Input = r.Input
|
||||
p.Name = r.Name
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaWebSearchResultBlock) ToParam() BetaWebSearchResultBlockParam {
|
||||
var p BetaWebSearchResultBlockParam
|
||||
p.Type = r.Type
|
||||
p.EncryptedContent = r.EncryptedContent
|
||||
p.Title = r.Title
|
||||
p.URL = r.URL
|
||||
p.PageAge = paramutil.ToOpt(r.PageAge, r.JSON.PageAge)
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaWebSearchToolResultBlock) ToParam() BetaWebSearchToolResultBlockParam {
|
||||
var p BetaWebSearchToolResultBlockParam
|
||||
p.Type = r.Type
|
||||
p.ToolUseID = r.ToolUseID
|
||||
|
||||
if len(r.Content.OfBetaWebSearchResultBlockArray) > 0 {
|
||||
for _, block := range r.Content.OfBetaWebSearchResultBlockArray {
|
||||
p.Content.OfResultBlock = append(p.Content.OfResultBlock, block.ToParam())
|
||||
}
|
||||
} else {
|
||||
p.Content.OfError = &BetaWebSearchToolRequestErrorParam{
|
||||
Type: r.Content.Type,
|
||||
ErrorCode: r.Content.ErrorCode,
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaWebFetchToolResultBlock) ToParam() BetaWebFetchToolResultBlockParam {
|
||||
var p BetaWebFetchToolResultBlockParam
|
||||
p.Type = r.Type
|
||||
p.ToolUseID = r.ToolUseID
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaMCPToolUseBlock) ToParam() BetaMCPToolUseBlockParam {
|
||||
var p BetaMCPToolUseBlockParam
|
||||
p.Type = r.Type
|
||||
p.ID = r.ID
|
||||
p.Input = r.Input
|
||||
p.Name = r.Name
|
||||
p.ServerName = r.ServerName
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaContainerUploadBlock) ToParam() BetaContainerUploadBlockParam {
|
||||
var p BetaContainerUploadBlockParam
|
||||
p.Type = r.Type
|
||||
p.FileID = r.FileID
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaServerToolUseBlock) ToParam() BetaServerToolUseBlockParam {
|
||||
var p BetaServerToolUseBlockParam
|
||||
p.Type = r.Type
|
||||
p.ID = r.ID
|
||||
p.Input = r.Input
|
||||
p.Name = BetaServerToolUseBlockParamName(r.Name)
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaTextEditorCodeExecutionToolResultBlock) ToParam() BetaTextEditorCodeExecutionToolResultBlockParam {
|
||||
var p BetaTextEditorCodeExecutionToolResultBlockParam
|
||||
p.Type = r.Type
|
||||
p.ToolUseID = r.ToolUseID
|
||||
if r.Content.JSON.ErrorCode.Valid() {
|
||||
p.Content.OfRequestTextEditorCodeExecutionToolResultError = &BetaTextEditorCodeExecutionToolResultErrorParam{
|
||||
ErrorCode: BetaTextEditorCodeExecutionToolResultErrorParamErrorCode(r.Content.ErrorCode),
|
||||
ErrorMessage: paramutil.ToOpt(r.Content.ErrorMessage, r.Content.JSON.ErrorMessage),
|
||||
}
|
||||
} else {
|
||||
p.Content = param.Override[BetaTextEditorCodeExecutionToolResultBlockParamContentUnion](r.Content.RawJSON())
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaMCPToolResultBlock) ToParam() BetaRequestMCPToolResultBlockParam {
|
||||
var p BetaRequestMCPToolResultBlockParam
|
||||
p.Type = r.Type
|
||||
p.ToolUseID = r.ToolUseID
|
||||
if r.Content.JSON.OfString.Valid() {
|
||||
p.Content.OfString = paramutil.ToOpt(r.Content.OfString, r.Content.JSON.OfString)
|
||||
} else {
|
||||
for _, block := range r.Content.OfBetaMCPToolResultBlockContent {
|
||||
p.Content.OfBetaMCPToolResultBlockContent = append(p.Content.OfBetaMCPToolResultBlockContent, block.ToParam())
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaBashCodeExecutionToolResultBlock) ToParam() BetaBashCodeExecutionToolResultBlockParam {
|
||||
var p BetaBashCodeExecutionToolResultBlockParam
|
||||
p.Type = r.Type
|
||||
p.ToolUseID = r.ToolUseID
|
||||
|
||||
if r.Content.JSON.ErrorCode.Valid() {
|
||||
p.Content.OfRequestBashCodeExecutionToolResultError = &BetaBashCodeExecutionToolResultErrorParam{
|
||||
ErrorCode: BetaBashCodeExecutionToolResultErrorParamErrorCode(r.Content.ErrorCode),
|
||||
}
|
||||
} else {
|
||||
requestBashContentResult := &BetaBashCodeExecutionResultBlockParam{
|
||||
ReturnCode: r.Content.ReturnCode,
|
||||
Stderr: r.Content.Stderr,
|
||||
Stdout: r.Content.Stdout,
|
||||
}
|
||||
for _, block := range r.Content.Content {
|
||||
requestBashContentResult.Content = append(requestBashContentResult.Content, block.ToParam())
|
||||
}
|
||||
p.Content.OfRequestBashCodeExecutionResultBlock = requestBashContentResult
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaBashCodeExecutionOutputBlock) ToParam() BetaBashCodeExecutionOutputBlockParam {
|
||||
var p BetaBashCodeExecutionOutputBlockParam
|
||||
p.Type = r.Type
|
||||
p.FileID = r.FileID
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaCodeExecutionToolResultBlock) ToParam() BetaCodeExecutionToolResultBlockParam {
|
||||
var p BetaCodeExecutionToolResultBlockParam
|
||||
p.Type = r.Type
|
||||
p.ToolUseID = r.ToolUseID
|
||||
if r.Content.JSON.ErrorCode.Valid() {
|
||||
p.Content.OfError = &BetaCodeExecutionToolResultErrorParam{
|
||||
ErrorCode: r.Content.ErrorCode,
|
||||
}
|
||||
} else {
|
||||
p.Content.OfResultBlock = &BetaCodeExecutionResultBlockParam{
|
||||
ReturnCode: r.Content.ReturnCode,
|
||||
Stderr: r.Content.Stderr,
|
||||
Stdout: r.Content.Stdout,
|
||||
}
|
||||
for _, block := range r.Content.Content {
|
||||
p.Content.OfResultBlock.Content = append(p.Content.OfResultBlock.Content, block.ToParam())
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaCodeExecutionOutputBlock) ToParam() BetaCodeExecutionOutputBlockParam {
|
||||
var p BetaCodeExecutionOutputBlockParam
|
||||
p.Type = r.Type
|
||||
p.FileID = r.FileID
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaToolSearchToolResultBlock) ToParam() BetaToolSearchToolResultBlockParam {
|
||||
var p BetaToolSearchToolResultBlockParam
|
||||
p.Type = r.Type
|
||||
p.ToolUseID = r.ToolUseID
|
||||
if r.Content.JSON.ErrorCode.Valid() {
|
||||
p.Content.OfRequestToolSearchToolResultError = &BetaToolSearchToolResultErrorParam{
|
||||
ErrorCode: BetaToolSearchToolResultErrorParamErrorCode(r.Content.ErrorCode),
|
||||
}
|
||||
} else {
|
||||
p.Content.OfRequestToolSearchToolSearchResultBlock = &BetaToolSearchToolSearchResultBlockParam{}
|
||||
for _, block := range r.Content.ToolReferences {
|
||||
p.Content.OfRequestToolSearchToolSearchResultBlock.ToolReferences = append(
|
||||
p.Content.OfRequestToolSearchToolSearchResultBlock.ToolReferences,
|
||||
block.ToParam(),
|
||||
)
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaToolReferenceBlock) ToParam() BetaToolReferenceBlockParam {
|
||||
var p BetaToolReferenceBlockParam
|
||||
p.Type = r.Type
|
||||
p.ToolName = r.ToolName
|
||||
return p
|
||||
}
|
||||
|
||||
func (r BetaCompactionBlock) ToParam() BetaCompactionBlockParam {
|
||||
var p BetaCompactionBlockParam
|
||||
p.Type = r.Type
|
||||
p.Content = param.NewOpt(r.Content)
|
||||
return p
|
||||
}
|
||||
-151
@@ -1,151 +0,0 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
package anthropic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/apijson"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/apiquery"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/internal/requestconfig"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/option"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/pagination"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/param"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/packages/respjson"
|
||||
"github.com/charmbracelet/anthropic-sdk-go/shared/constant"
|
||||
)
|
||||
|
||||
// BetaModelService contains methods and other services that help with interacting
|
||||
// with the anthropic API.
|
||||
//
|
||||
// Note, unlike clients, this service does not read variables from the environment
|
||||
// automatically. You should not instantiate this service directly, and instead use
|
||||
// the [NewBetaModelService] method instead.
|
||||
type BetaModelService struct {
|
||||
Options []option.RequestOption
|
||||
}
|
||||
|
||||
// NewBetaModelService generates a new service that applies the given options to
|
||||
// each request. These options are applied after the parent client's options (if
|
||||
// there is one), and before any request-specific options.
|
||||
func NewBetaModelService(opts ...option.RequestOption) (r BetaModelService) {
|
||||
r = BetaModelService{}
|
||||
r.Options = opts
|
||||
return r
|
||||
}
|
||||
|
||||
// Get a specific model.
|
||||
//
|
||||
// The Models API response can be used to determine information about a specific
|
||||
// model or resolve a model alias to a model ID.
|
||||
func (r *BetaModelService) Get(ctx context.Context, modelID string, query BetaModelGetParams, opts ...option.RequestOption) (res *BetaModelInfo, err error) {
|
||||
for _, v := range query.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
if modelID == "" {
|
||||
err = errors.New("missing required model_id parameter")
|
||||
return res, err
|
||||
}
|
||||
path := fmt.Sprintf("v1/models/%s?beta=true", modelID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// List available models.
|
||||
//
|
||||
// The Models API response can be used to determine which models are available for
|
||||
// use in the API. More recently released models are listed first.
|
||||
func (r *BetaModelService) List(ctx context.Context, params BetaModelListParams, opts ...option.RequestOption) (res *pagination.Page[BetaModelInfo], err error) {
|
||||
var raw *http.Response
|
||||
for _, v := range params.Betas {
|
||||
opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%v", v)))
|
||||
}
|
||||
opts = slices.Concat(r.Options, opts)
|
||||
opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
|
||||
path := "v1/models?beta=true"
|
||||
cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = cfg.Execute()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.SetPageConfig(cfg, raw)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// List available models.
|
||||
//
|
||||
// The Models API response can be used to determine which models are available for
|
||||
// use in the API. More recently released models are listed first.
|
||||
func (r *BetaModelService) ListAutoPaging(ctx context.Context, params BetaModelListParams, opts ...option.RequestOption) *pagination.PageAutoPager[BetaModelInfo] {
|
||||
return pagination.NewPageAutoPager(r.List(ctx, params, opts...))
|
||||
}
|
||||
|
||||
type BetaModelInfo struct {
|
||||
// Unique model identifier.
|
||||
ID string `json:"id,required"`
|
||||
// RFC 3339 datetime string representing the time at which the model was released.
|
||||
// May be set to an epoch value if the release date is unknown.
|
||||
CreatedAt time.Time `json:"created_at,required" format:"date-time"`
|
||||
// A human-readable name for the model.
|
||||
DisplayName string `json:"display_name,required"`
|
||||
// Object type.
|
||||
//
|
||||
// For Models, this is always `"model"`.
|
||||
Type constant.Model `json:"type,required"`
|
||||
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
|
||||
JSON struct {
|
||||
ID respjson.Field
|
||||
CreatedAt respjson.Field
|
||||
DisplayName respjson.Field
|
||||
Type respjson.Field
|
||||
ExtraFields map[string]respjson.Field
|
||||
raw string
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// Returns the unmodified JSON received from the API
|
||||
func (r BetaModelInfo) RawJSON() string { return r.JSON.raw }
|
||||
|
||||
func (r *BetaModelInfo) UnmarshalJSON(data []byte) error {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
type BetaModelGetParams struct {
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
type BetaModelListParams struct {
|
||||
// ID of the object to use as a cursor for pagination. When provided, returns the
|
||||
// page of results immediately after this object.
|
||||
AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
|
||||
// ID of the object to use as a cursor for pagination. When provided, returns the
|
||||
// page of results immediately before this object.
|
||||
BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
|
||||
// Number of items to return per page.
|
||||
//
|
||||
// Defaults to `20`. Ranges from `1` to `1000`.
|
||||
Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
|
||||
// Optional header to specify the beta version(s) you want to use.
|
||||
Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"`
|
||||
paramObj
|
||||
}
|
||||
|
||||
// URLQuery serializes [BetaModelListParams]'s query parameters as `url.Values`.
|
||||
func (r BetaModelListParams) URLQuery() (v url.Values, err error) {
|
||||
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||
})
|
||||
}
|
||||
Loaded 100 of 546 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user