Created
April 22, 2025 18:56
-
-
Save trjordan/a10772a79a202f5de58bbf1056b223d4 to your computer and use it in GitHub Desktop.
Anthropic alpha 13 to beta 3 diff
This file has been truncated, but you can view the full file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml | |
| index 9ff53ed..8077d60 100644 | |
| --- a/.github/workflows/ci.yml | |
| +++ b/.github/workflows/ci.yml | |
| @@ -42,4 +42,3 @@ jobs: | |
| - name: Run tests | |
| run: ./scripts/test | |
| - | |
| diff --git a/.release-please-manifest.json b/.release-please-manifest.json | |
| index ecfd70b..bee6b5e 100644 | |
| --- a/.release-please-manifest.json | |
| +++ b/.release-please-manifest.json | |
| @@ -1,3 +1,3 @@ | |
| { | |
| - ".": "0.2.0-alpha.13" | |
| -} | |
| \ No newline at end of file | |
| + ".": "0.2.0-beta.3" | |
| +} | |
| diff --git a/.stats.yml b/.stats.yml | |
| index 756a363..2c1bac2 100644 | |
| --- a/.stats.yml | |
| +++ b/.stats.yml | |
| @@ -1,2 +1,4 @@ | |
| configured_endpoints: 21 | |
| openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/anthropic-fd7537a41646cd9253c04f350436c5471e4762750fce8ca8f1909a3052d98608.yml | |
| +openapi_spec_hash: d2d7ec2a7a35a1ed2443c3b690c802c4 | |
| +config_hash: 92dd03fd872d52f9707c9e7a7953c3d1 | |
| diff --git a/CHANGELOG.md b/CHANGELOG.md | |
| index dc6bdaa..18d08a3 100644 | |
| --- a/CHANGELOG.md | |
| +++ b/CHANGELOG.md | |
| @@ -1,319 +1,53 @@ | |
| # Changelog | |
| -## 0.2.0-alpha.13 (2025-02-28) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.12...v0.2.0-alpha.13](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.12...v0.2.0-alpha.13) | |
| - | |
| -### Features | |
| - | |
| -* **api:** add support for disabling tool calls ([#133](https://github.com/anthropics/anthropic-sdk-go/issues/133)) ([90f7490](https://github.com/anthropics/anthropic-sdk-go/commit/90f7490774321fdbcadea60c4390244afd5b4c3d)) | |
| - | |
| - | |
| -### Documentation | |
| - | |
| -* update URLs from stainlessapi.com to stainless.com ([#131](https://github.com/anthropics/anthropic-sdk-go/issues/131)) ([334be2b](https://github.com/anthropics/anthropic-sdk-go/commit/334be2b932571846203e0019ee3fe5b551d42c96)) | |
| - | |
| -## 0.2.0-alpha.12 (2025-02-27) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.11...v0.2.0-alpha.12](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.11...v0.2.0-alpha.12) | |
| - | |
| -### Features | |
| - | |
| -* **api:** add URL source blocks for images and PDFs ([#129](https://github.com/anthropics/anthropic-sdk-go/issues/129)) ([589f5dc](https://github.com/anthropics/anthropic-sdk-go/commit/589f5dc44bdcfbec7269dcd0ad94baf72c3876b3)) | |
| - | |
| - | |
| -### Bug Fixes | |
| - | |
| -* Preserve Thinking and Signature fields in Message.ToParam() method ([#128](https://github.com/anthropics/anthropic-sdk-go/issues/128)) ([b67c786](https://github.com/anthropics/anthropic-sdk-go/commit/b67c786b64d3a3903a0dcdc50ceac07fc4a6396a)) | |
| - | |
| - | |
| -### Chores | |
| - | |
| -* **internal:** update spec ([#124](https://github.com/anthropics/anthropic-sdk-go/issues/124)) ([3b3bdad](https://github.com/anthropics/anthropic-sdk-go/commit/3b3bdad4b5038278d26ed1c82e0a37259326c049)) | |
| - | |
| -## 0.2.0-alpha.11 (2025-02-24) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.10...v0.2.0-alpha.11](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.10...v0.2.0-alpha.11) | |
| - | |
| -### Features | |
| - | |
| -* **api:** add claude-3.7 + support for thinking ([cc7ddcc](https://github.com/anthropics/anthropic-sdk-go/commit/cc7ddcc83a2aeabc17037035b42e94d59679d9e3)) | |
| -* **client:** send `X-Stainless-Timeout` header ([#114](https://github.com/anthropics/anthropic-sdk-go/issues/114)) ([66f2aec](https://github.com/anthropics/anthropic-sdk-go/commit/66f2aec50b2abf200eaca7fd6636c64059bc884b)) | |
| -* **pagination:** avoid fetching when has_more: false ([#118](https://github.com/anthropics/anthropic-sdk-go/issues/118)) ([6d90a30](https://github.com/anthropics/anthropic-sdk-go/commit/6d90a300dd0553b92b2f555cc11bc4a134593b90)) | |
| - | |
| - | |
| -### Bug Fixes | |
| - | |
| -* **client:** don't truncate manually specified filenames ([#121](https://github.com/anthropics/anthropic-sdk-go/issues/121)) ([ce64cf5](https://github.com/anthropics/anthropic-sdk-go/commit/ce64cf54d299d5d3d7b707024ea5ca65c4bd5b56)) | |
| -* do not call path.Base on ContentType ([#120](https://github.com/anthropics/anthropic-sdk-go/issues/120)) ([5f20f48](https://github.com/anthropics/anthropic-sdk-go/commit/5f20f48a882546e5e25492a543a7cc56be3eb7dc)) | |
| -* fix early cancel when RequestTimeout is provided for streaming requests ([#119](https://github.com/anthropics/anthropic-sdk-go/issues/119)) ([20af10e](https://github.com/anthropics/anthropic-sdk-go/commit/20af10e556caa9dd1691fee0c68aab528d61bc87)) | |
| -* fix unicode encoding for json ([#111](https://github.com/anthropics/anthropic-sdk-go/issues/111)) ([699e5cd](https://github.com/anthropics/anthropic-sdk-go/commit/699e5cd7a37a20b48824d0b1b978b28df1d8afbf)) | |
| -* **stream:** ensure .Close() doesn't panic ([#113](https://github.com/anthropics/anthropic-sdk-go/issues/113)) ([2125563](https://github.com/anthropics/anthropic-sdk-go/commit/2125563ac0bf773e0795ce51933e535854a30a0e)) | |
| -* update stream error handling ([#117](https://github.com/anthropics/anthropic-sdk-go/issues/117)) ([40d1ea2](https://github.com/anthropics/anthropic-sdk-go/commit/40d1ea2589b3df6111c8cf000f49ec46ede7a7a4)) | |
| - | |
| - | |
| -### Chores | |
| - | |
| -* add UnionUnmarshaler for responses that are interfaces ([#116](https://github.com/anthropics/anthropic-sdk-go/issues/116)) ([93f533c](https://github.com/anthropics/anthropic-sdk-go/commit/93f533c1c940b1dd6264886344902239a268634a)) | |
| -* **api:** update openapi spec url ([#108](https://github.com/anthropics/anthropic-sdk-go/issues/108)) ([8f291ed](https://github.com/anthropics/anthropic-sdk-go/commit/8f291ed434cd1cd0eb7f82a2e8b39b9e97744f6e)) | |
| -* **docs:** add docstring explaining streaming pattern ([#115](https://github.com/anthropics/anthropic-sdk-go/issues/115)) ([862c3d4](https://github.com/anthropics/anthropic-sdk-go/commit/862c3d41e8d19ad4b0e9d2d228719c930e6f7d18)) | |
| -* **internal:** fix devcontainers setup ([#123](https://github.com/anthropics/anthropic-sdk-go/issues/123)) ([6f9dcc1](https://github.com/anthropics/anthropic-sdk-go/commit/6f9dcc103ee4dfeeda6a5c78e3d461d0c3ddab0b)) | |
| - | |
| - | |
| -### Documentation | |
| - | |
| -* document raw responses ([#112](https://github.com/anthropics/anthropic-sdk-go/issues/112)) ([1cf3aee](https://github.com/anthropics/anthropic-sdk-go/commit/1cf3aee0a28edc06e0e19723f94290b80074d6ce)) | |
| - | |
| -## 0.2.0-alpha.10 (2025-01-28) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.9...v0.2.0-alpha.10](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.9...v0.2.0-alpha.10) | |
| - | |
| -### Bug Fixes | |
| - | |
| -* fix interface implementation stub names for unions ([#106](https://github.com/anthropics/anthropic-sdk-go/issues/106)) ([0ac5655](https://github.com/anthropics/anthropic-sdk-go/commit/0ac5655d4033ec3d6448ecf89216b048bccbbd85)) | |
| - | |
| - | |
| -### Chores | |
| - | |
| -* **api:** deprecate some models ([#105](https://github.com/anthropics/anthropic-sdk-go/issues/105)) ([f1e30cc](https://github.com/anthropics/anthropic-sdk-go/commit/f1e30ccd3ace4165bf0653cf5251b1fc06a1e78a)) | |
| -* **docs:** updates ([#103](https://github.com/anthropics/anthropic-sdk-go/issues/103)) ([c264f59](https://github.com/anthropics/anthropic-sdk-go/commit/c264f59fc3f58a0233f8c801436cccc0f4eeef6c)) | |
| -* refactor client tests ([#107](https://github.com/anthropics/anthropic-sdk-go/issues/107)) ([f02b038](https://github.com/anthropics/anthropic-sdk-go/commit/f02b038063ab0095cc3497cbe1c3f585cb471817)) | |
| - | |
| -## 0.2.0-alpha.9 (2025-01-23) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.8...v0.2.0-alpha.9](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.8...v0.2.0-alpha.9) | |
| - | |
| -### Features | |
| - | |
| -* **api:** add citations ([#101](https://github.com/anthropics/anthropic-sdk-go/issues/101)) ([59fd065](https://github.com/anthropics/anthropic-sdk-go/commit/59fd065fe106db20527f37e4ecdc6cc771c10418)) | |
| -* **api:** add message batch delete endpoint ([#81](https://github.com/anthropics/anthropic-sdk-go/issues/81)) ([b3a63e7](https://github.com/anthropics/anthropic-sdk-go/commit/b3a63e7cbf73d06141750cf126af25412b12061d)) | |
| -* **client:** support results endpoint ([#98](https://github.com/anthropics/anthropic-sdk-go/issues/98)) ([380054f](https://github.com/anthropics/anthropic-sdk-go/commit/380054fc5608380cdc054a181d83558ee7c5b946)) | |
| - | |
| - | |
| -### Bug Fixes | |
| - | |
| -* fix apijson.Port for embedded structs ([#95](https://github.com/anthropics/anthropic-sdk-go/issues/95)) ([5c3a7f7](https://github.com/anthropics/anthropic-sdk-go/commit/5c3a7f7f4d2694b8b52a0c4a36701a489a58dcf0)) | |
| -* fix apijson.Port for embedded structs ([#97](https://github.com/anthropics/anthropic-sdk-go/issues/97)) ([55a3365](https://github.com/anthropics/anthropic-sdk-go/commit/55a3365c873b6b385d27f2315e370fa40736778e)) | |
| -* fix header parameter value ([#90](https://github.com/anthropics/anthropic-sdk-go/issues/90)) ([d52699a](https://github.com/anthropics/anthropic-sdk-go/commit/d52699aa2036162f6842a3115eb754b6870260e1)) | |
| -* prevent niche naming conflicts for string enums with different casing ([#100](https://github.com/anthropics/anthropic-sdk-go/issues/100)) ([3af5fe8](https://github.com/anthropics/anthropic-sdk-go/commit/3af5fe8993928a6985022cdbea6bfe220a6d6be5)) | |
| -* support array query parameters ([#89](https://github.com/anthropics/anthropic-sdk-go/issues/89)) ([d728bcc](https://github.com/anthropics/anthropic-sdk-go/commit/d728bcc9d69414bb3ba577e504e1285f0eb22bc5)) | |
| +## 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 | |
| -* bump license year ([#88](https://github.com/anthropics/anthropic-sdk-go/issues/88)) ([c8ddc6b](https://github.com/anthropics/anthropic-sdk-go/commit/c8ddc6b1364485e299e050423e459023e2d65b46)) | |
| -* **internal:** remove unused field ([#94](https://github.com/anthropics/anthropic-sdk-go/issues/94)) ([b98d12a](https://github.com/anthropics/anthropic-sdk-go/commit/b98d12a3991ae2f1d714833a71ec90dedc552661)) | |
| -* **internal:** rename `streaming.go` ([#96](https://github.com/anthropics/anthropic-sdk-go/issues/96)) ([ce8ac0f](https://github.com/anthropics/anthropic-sdk-go/commit/ce8ac0fe762132d230241f021eeb0cd4215f271b)) | |
| -* **internal:** update examples ([#91](https://github.com/anthropics/anthropic-sdk-go/issues/91)) ([9717662](https://github.com/anthropics/anthropic-sdk-go/commit/97176628489158be07baf1747ba39f15429d3a39)) | |
| - | |
| +* 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)) | |
| -### Documentation | |
| +## 0.2.0-beta.2 (2025-03-25) | |
| -* **readme:** fix misplaced period ([#93](https://github.com/anthropics/anthropic-sdk-go/issues/93)) ([953d510](https://github.com/anthropics/anthropic-sdk-go/commit/953d5104b1460b749b776a6ba4df90d2604c06cd)) | |
| - | |
| -## 0.2.0-alpha.8 (2024-12-19) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.7...v0.2.0-alpha.8](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.7...v0.2.0-alpha.8) | |
| +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 | |
| -* **bedrock:** handle exceptions messages in bedrock stream ([7786f8f](https://github.com/anthropics/anthropic-sdk-go/commit/7786f8f7f97d073b79f5e1faaec1a6de285001c2)) | |
| +* **client:** use raw json for tool input ([1013c2b](https://github.com/anthropics/anthropic-sdk-go/commit/1013c2bdb87a27d2420dbe0dcadc57d1fe3589f2)) | |
| ### Chores | |
| -* bump testing data uri ([#79](https://github.com/anthropics/anthropic-sdk-go/issues/79)) ([0dc9c88](https://github.com/anthropics/anthropic-sdk-go/commit/0dc9c8811f211cdd25eb5451aa88f258591fb9bd)) | |
| - | |
| -## 0.2.0-alpha.7 (2024-12-17) | |
| +* 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)) | |
| -Full Changelog: [v0.2.0-alpha.6...v0.2.0-alpha.7](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.6...v0.2.0-alpha.7) | |
| - | |
| -### Bug Fixes | |
| +## 0.2.0-beta.1 (2025-03-25) | |
| -* **vertex:** remove `anthropic_version` deletion for token counting ([15987ac](https://github.com/anthropics/anthropic-sdk-go/commit/15987ac82378e0e0d28878f91e2ddca8f6fb5ab9)) | |
| +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) | |
| -## 0.2.0-alpha.6 (2024-12-17) | |
| +### ⚠ BREAKING CHANGES | |
| -Full Changelog: [v0.2.0-alpha.5...v0.2.0-alpha.6](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.5...v0.2.0-alpha.6) | |
| +* **api:** migrate to v2 | |
| ### Features | |
| -* **api:** general availability updates ([#74](https://github.com/anthropics/anthropic-sdk-go/issues/74)) ([0c19b86](https://github.com/anthropics/anthropic-sdk-go/commit/0c19b86f4d0f8496d551f3b707bfb8834b98b315)) | |
| -* **vertex:** add support for token counting ([86e085b](https://github.com/anthropics/anthropic-sdk-go/commit/86e085b0452926491ec11b2c77abec4c0a733d3b)) | |
| - | |
| - | |
| -### Bug Fixes | |
| - | |
| -* **messages:** correct batch params type ([2a39e4b](https://github.com/anthropics/anthropic-sdk-go/commit/2a39e4b9af65f0318374f88c2aef150b69df7107)) | |
| -* replace `MessageParamContentUnion` with `ContentBlockParamUnion` to fix go script ([#70](https://github.com/anthropics/anthropic-sdk-go/issues/70)) ([5d32a5f](https://github.com/anthropics/anthropic-sdk-go/commit/5d32a5f2be05c31932451d8033e954cd71c9fbc8)) | |
| -* **tests:** correct input schema type ([6514952](https://github.com/anthropics/anthropic-sdk-go/commit/6514952ac492f3f7ceed1c5726dfbc7b5b3f72db)) | |
| - | |
| - | |
| -### Chores | |
| - | |
| -* **api:** update spec version ([#72](https://github.com/anthropics/anthropic-sdk-go/issues/72)) ([854416b](https://github.com/anthropics/anthropic-sdk-go/commit/854416b61b37fff95bca34d7c91035fb11aef921)) | |
| -* **internal:** update spec ([#73](https://github.com/anthropics/anthropic-sdk-go/issues/73)) ([6da0443](https://github.com/anthropics/anthropic-sdk-go/commit/6da04433a0cdf00600080f45d41cfd92064e7471)) | |
| - | |
| - | |
| -### Documentation | |
| - | |
| -* **examples:** use claude 3 sonnet more ([c02fdac](https://github.com/anthropics/anthropic-sdk-go/commit/c02fdac54687c966a8641be10035c0f389bddfe0)) | |
| - | |
| -## 0.2.0-alpha.5 (2024-12-01) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.4...v0.2.0-alpha.5](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.4...v0.2.0-alpha.5) | |
| - | |
| -### Bug Fixes | |
| - | |
| -* **api:** escape key values when encoding maps ([#56](https://github.com/anthropics/anthropic-sdk-go/issues/56)) ([fa49eb8](https://github.com/anthropics/anthropic-sdk-go/commit/fa49eb8c4f8d6fa7e45ec4e7eb457a87218349c4)) | |
| -* **client:** no panic on missing BaseURL ([#61](https://github.com/anthropics/anthropic-sdk-go/issues/61)) ([7438b15](https://github.com/anthropics/anthropic-sdk-go/commit/7438b15855bd6b5902d62fdbf02f143544eee986)) | |
| -* correct required fields for flattened unions ([#59](https://github.com/anthropics/anthropic-sdk-go/issues/59)) ([735c07c](https://github.com/anthropics/anthropic-sdk-go/commit/735c07c66a3bbf54bff97db7fe5290d7635c0774)) | |
| -* forward error and close for bedrock decoder ([#66](https://github.com/anthropics/anthropic-sdk-go/issues/66)) ([5f6f6fd](https://github.com/anthropics/anthropic-sdk-go/commit/5f6f6fd822b029dffd90aa49b06add0661251de0)) | |
| -* **types:** remove anthropic-instant-1.2 model ([#57](https://github.com/anthropics/anthropic-sdk-go/issues/57)) ([23fbc37](https://github.com/anthropics/anthropic-sdk-go/commit/23fbc3752122462a1e29e15327b1736072032ba3)) | |
| +* 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 | |
| -* **api:** update spec version ([#62](https://github.com/anthropics/anthropic-sdk-go/issues/62)) ([1526051](https://github.com/anthropics/anthropic-sdk-go/commit/1526051561d4e1fe7792d90f0c2299036fedbc21)) | |
| -* **ci:** remove unneeded workflow ([#55](https://github.com/anthropics/anthropic-sdk-go/issues/55)) ([0181fc2](https://github.com/anthropics/anthropic-sdk-go/commit/0181fc2796bc5fea1a21e2744257900caef8ee72)) | |
| -* fix references to content block param types ([dea6478](https://github.com/anthropics/anthropic-sdk-go/commit/dea647890542036c1ed4cc55409002fd2e00adb6)) | |
| -* **tests:** limit array example length ([#64](https://github.com/anthropics/anthropic-sdk-go/issues/64)) ([9fb231b](https://github.com/anthropics/anthropic-sdk-go/commit/9fb231b806af753b6c9aae82c023e087c2ecaefb)) | |
| - | |
| - | |
| -### Documentation | |
| - | |
| -* add missing docs for some enums ([#54](https://github.com/anthropics/anthropic-sdk-go/issues/54)) ([56db6b8](https://github.com/anthropics/anthropic-sdk-go/commit/56db6b832d0e0454895b6d4ab43d32bd6b7418b4)) | |
| +* **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 | |
| -* sort fields for squashed union structs ([#51](https://github.com/anthropics/anthropic-sdk-go/issues/51)) ([a9874d1](https://github.com/anthropics/anthropic-sdk-go/commit/a9874d193998572a28475781dd8de296d4021bf2)) | |
| - | |
| -## 0.2.0-alpha.4 (2024-11-04) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.3...v0.2.0-alpha.4](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.3...v0.2.0-alpha.4) | |
| - | |
| -### Features | |
| - | |
| -* **api:** add message token counting & PDFs support ([#45](https://github.com/anthropics/anthropic-sdk-go/issues/45)) ([775de6d](https://github.com/anthropics/anthropic-sdk-go/commit/775de6d75c61cd3a6b3d63fdf129b1564b1f147c)) | |
| -* **api:** add new haiku model ([#48](https://github.com/anthropics/anthropic-sdk-go/issues/48)) ([8cb9d59](https://github.com/anthropics/anthropic-sdk-go/commit/8cb9d59b13d12a70866a579dca8cc965e33eeba5)) | |
| - | |
| - | |
| -### Bug Fixes | |
| - | |
| -* **types:** add missing token-counting-2024-11-01 ([#47](https://github.com/anthropics/anthropic-sdk-go/issues/47)) ([bc46a6e](https://github.com/anthropics/anthropic-sdk-go/commit/bc46a6e648f9ad804b119eff977e050843efb7f6)) | |
| -* **types:** correct claude-3-5-haiku-20241022 name ([#50](https://github.com/anthropics/anthropic-sdk-go/issues/50)) ([f0016bb](https://github.com/anthropics/anthropic-sdk-go/commit/f0016bbb272fd65fcc42f0b664e3ab45a665e673)) | |
| - | |
| - | |
| -### Chores | |
| - | |
| -* **internal:** update spec version ([#40](https://github.com/anthropics/anthropic-sdk-go/issues/40)) ([b41d55f](https://github.com/anthropics/anthropic-sdk-go/commit/b41d55f13b57553bd6e639ae359c5c6f0a9031bb)) | |
| - | |
| -## 0.2.0-alpha.3 (2024-10-22) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.2...v0.2.0-alpha.3](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.2...v0.2.0-alpha.3) | |
| - | |
| -### Features | |
| - | |
| -* **api:** add new model and `computer-use-2024-10-22` beta ([#37](https://github.com/anthropics/anthropic-sdk-go/issues/37)) ([a520abe](https://github.com/anthropics/anthropic-sdk-go/commit/a520abeedd326cea2161166cd2259345c15a82e4)) | |
| - | |
| - | |
| -### Chores | |
| - | |
| -* **api:** add title ([#34](https://github.com/anthropics/anthropic-sdk-go/issues/34)) ([2b96326](https://github.com/anthropics/anthropic-sdk-go/commit/2b96326e58bb7179d21476f9ce1a550664f13a38)) | |
| -* **internal:** update spec ([#36](https://github.com/anthropics/anthropic-sdk-go/issues/36)) ([a735bf7](https://github.com/anthropics/anthropic-sdk-go/commit/a735bf7e7872c8cc3ee08e57167860270e6cdba6)) | |
| - | |
| -## 0.2.0-alpha.2 (2024-10-17) | |
| - | |
| -Full Changelog: [v0.2.0-alpha.1...v0.2.0-alpha.2](https://github.com/anthropics/anthropic-sdk-go/compare/v0.2.0-alpha.1...v0.2.0-alpha.2) | |
| - | |
| -### Features | |
| - | |
| -* move pagination package from internal to packages ([#33](https://github.com/anthropics/anthropic-sdk-go/issues/33)) ([ee3edb1](https://github.com/anthropics/anthropic-sdk-go/commit/ee3edb16dcd406435ade212cb7553f75b161e297)) | |
| - | |
| - | |
| -### Bug Fixes | |
| - | |
| -* **beta:** merge betas param with the default value ([#32](https://github.com/anthropics/anthropic-sdk-go/issues/32)) ([9191ae0](https://github.com/anthropics/anthropic-sdk-go/commit/9191ae0b8a47c3c6ea9dfbb5073f1e66f5b4e1d8)) | |
| - | |
| - | |
| -### Chores | |
| - | |
| -* fix GetNextPage docstring ([#29](https://github.com/anthropics/anthropic-sdk-go/issues/29)) ([acf8009](https://github.com/anthropics/anthropic-sdk-go/commit/acf8009c886ec27cc07665b0377a2a3b3493c336)) | |
| -* **internal:** update spec URL ([#31](https://github.com/anthropics/anthropic-sdk-go/issues/31)) ([240f1c3](https://github.com/anthropics/anthropic-sdk-go/commit/240f1c3d7e4dc145988d2f8d11e45ccfd255861e)) | |
| - | |
| -## 0.2.0-alpha.1 (2024-10-08) | |
| - | |
| -Full Changelog: [v0.1.0-alpha.2...v0.2.0-alpha.1](https://github.com/anthropics/anthropic-sdk-go/compare/v0.1.0-alpha.2...v0.2.0-alpha.1) | |
| - | |
| -### Features | |
| - | |
| -* **api:** add message batches api ([#28](https://github.com/anthropics/anthropic-sdk-go/issues/28)) ([169eb3c](https://github.com/anthropics/anthropic-sdk-go/commit/169eb3c83d39126b4f9ec3a8d7f70c06466d9ef6)) | |
| - | |
| - | |
| -### Bug Fixes | |
| - | |
| -* **beta:** pass beta header by default ([#27](https://github.com/anthropics/anthropic-sdk-go/issues/27)) ([c79ba68](https://github.com/anthropics/anthropic-sdk-go/commit/c79ba6826c452ca1eeefd34db1638722fa942082)) | |
| - | |
| - | |
| -### Refactors | |
| - | |
| -* **types:** improve metadata type names ([#26](https://github.com/anthropics/anthropic-sdk-go/issues/26)) ([95f0266](https://github.com/anthropics/anthropic-sdk-go/commit/95f0266f62ba90590db68f1f98e41d80ea8f5388)) | |
| -* **types:** improve tool type names ([#23](https://github.com/anthropics/anthropic-sdk-go/issues/23)) ([79e4d75](https://github.com/anthropics/anthropic-sdk-go/commit/79e4d75d26bbf2339841d27696477817c01a55fc)) | |
| - | |
| -## 0.1.0-alpha.2 (2024-10-04) | |
| - | |
| -Full Changelog: [v0.1.0-alpha.1...v0.1.0-alpha.2](https://github.com/anthropics/anthropic-sdk-go/compare/v0.1.0-alpha.1...v0.1.0-alpha.2) | |
| - | |
| -### Features | |
| - | |
| -* **api:** support disabling parallel tool use ([#22](https://github.com/anthropics/anthropic-sdk-go/issues/22)) ([1d8c00b](https://github.com/anthropics/anthropic-sdk-go/commit/1d8c00b317536d77a26f74d0008e1a4760b17d2e)) | |
| -* **client:** send retry count header ([#19](https://github.com/anthropics/anthropic-sdk-go/issues/19)) ([d1c8ea1](https://github.com/anthropics/anthropic-sdk-go/commit/d1c8ea1f84d05002705ac7aa4d47a5ba13c388e9)) | |
| -* improve error message ([#15](https://github.com/anthropics/anthropic-sdk-go/issues/15)) ([98d1ffd](https://github.com/anthropics/anthropic-sdk-go/commit/98d1ffd29f97e85ea543f36ce104c341e729a7d2)) | |
| - | |
| - | |
| -### Bug Fixes | |
| - | |
| -* **requestconfig:** copy over more fields when cloning ([#17](https://github.com/anthropics/anthropic-sdk-go/issues/17)) ([d5e7415](https://github.com/anthropics/anthropic-sdk-go/commit/d5e741578ac0ff88db3b04564810321b18f4dd40)) | |
| - | |
| - | |
| -### Chores | |
| - | |
| -* **ci:** add CODEOWNERS file ([#12](https://github.com/anthropics/anthropic-sdk-go/issues/12)) ([71c33b8](https://github.com/anthropics/anthropic-sdk-go/commit/71c33b841dece97e77f04ea4feae3d586b59b0d6)) | |
| - | |
| - | |
| -### Documentation | |
| - | |
| -* improve and reference contributing documentation ([#21](https://github.com/anthropics/anthropic-sdk-go/issues/21)) ([7288df1](https://github.com/anthropics/anthropic-sdk-go/commit/7288df1e1e62401487bee0685f77119bae5287ee)) | |
| -* update CONTRIBUTING.md ([#18](https://github.com/anthropics/anthropic-sdk-go/issues/18)) ([dcfcbf8](https://github.com/anthropics/anthropic-sdk-go/commit/dcfcbf8d07e3d7a7d6b6398d60724f38eca050a4)) | |
| - | |
| -## 0.1.0-alpha.1 (2024-08-14) | |
| - | |
| -Full Changelog: [v0.0.1-alpha.0...v0.1.0-alpha.1](https://github.com/anthropics/anthropic-sdk-go/compare/v0.0.1-alpha.0...v0.1.0-alpha.1) | |
| - | |
| -### Features | |
| - | |
| -* **api:** add prompt caching beta ([#11](https://github.com/anthropics/anthropic-sdk-go/issues/11)) ([78f8c72](https://github.com/anthropics/anthropic-sdk-go/commit/78f8c7266dd98ef5f76d258f485ee284b7a0e590)) | |
| -* publish ([5ff0ff8](https://github.com/anthropics/anthropic-sdk-go/commit/5ff0ff8cc5706c39a6dde75ae69d11c892ef8bb3)) | |
| -* simplify system prompt ([#3](https://github.com/anthropics/anthropic-sdk-go/issues/3)) ([cd3fcef](https://github.com/anthropics/anthropic-sdk-go/commit/cd3fcefad20baef3c28375adf16ab266f97e7d94)) | |
| -* simplify system prompt ([#4](https://github.com/anthropics/anthropic-sdk-go/issues/4)) ([85e1b34](https://github.com/anthropics/anthropic-sdk-go/commit/85e1b349619e7dd26c06ed0d9f566ddbbe80db2a)) | |
| - | |
| - | |
| -### Bug Fixes | |
| - | |
| -* deserialization of struct unions that implement json.Unmarshaler ([#6](https://github.com/anthropics/anthropic-sdk-go/issues/6)) ([a883a3a](https://github.com/anthropics/anthropic-sdk-go/commit/a883a3a8232dfca1ce8a139047a0356a3fd6015f)) | |
| -* handle nil pagination responses when HTTP status is 200 ([#2](https://github.com/anthropics/anthropic-sdk-go/issues/2)) ([2bb2325](https://github.com/anthropics/anthropic-sdk-go/commit/2bb232557a9f75d58b7e7145c69771c927574dd3)) | |
| -* message accumulation with union content block ([09457cb](https://github.com/anthropics/anthropic-sdk-go/commit/09457cb2ef8019cc23bcdefa0d3102e642d64b3d)) | |
| - | |
| - | |
| -### Chores | |
| - | |
| -* add back custom code ([106c404](https://github.com/anthropics/anthropic-sdk-go/commit/106c40466382daaa403e7f472647248e14d939d7)) | |
| -* bump Go to v1.21 ([#7](https://github.com/anthropics/anthropic-sdk-go/issues/7)) ([928ed50](https://github.com/anthropics/anthropic-sdk-go/commit/928ed50c83154eb4f56575cf9f405a132000888e)) | |
| -* **ci:** bump prism mock server version ([#5](https://github.com/anthropics/anthropic-sdk-go/issues/5)) ([0b326c6](https://github.com/anthropics/anthropic-sdk-go/commit/0b326c6b18effa222b8b03a17c1e562d0aedce1d)) | |
| -* **examples:** minor formatting changes ([#8](https://github.com/anthropics/anthropic-sdk-go/issues/8)) ([4195c55](https://github.com/anthropics/anthropic-sdk-go/commit/4195c5541a1a517a3890bfe43eb84e3ddc496bfe)) | |
| - | |
| - | |
| -### Documentation | |
| - | |
| -* add examples to README ([df47298](https://github.com/anthropics/anthropic-sdk-go/commit/df4729897b782faeaa6a0795359ecf20b4a833ca)) | |
| +* tidy up dependencies ([#140](https://github.com/anthropics/anthropic-sdk-go/issues/140)) ([289cc1b](https://github.com/anthropics/anthropic-sdk-go/commit/289cc1b007094421305dfc4ef01ae68bb2d50ee5)) | |
| diff --git a/MIGRATION.md b/MIGRATION.md | |
| new file mode 100644 | |
| index 0000000..1bf985c | |
| --- /dev/null | |
| +++ b/MIGRATION.md | |
| @@ -0,0 +1,284 @@ | |
| +# Anthropic Go Migration Guide | |
| + | |
| +<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> | |
| + | |
| +This SDK includes breaking changes to improve the ergonomics of constructing parameters and accessing responses. | |
| + | |
| +To reduce verbosity, the `anthropic.F(...)` and `param.Field[T]` have been removed. | |
| +All calls to `anthropic.F(...)` can be deleted. | |
| + | |
| +The SDK now uses the <code>\`json:"...,omitzero"\`</code> struct tag to omit fields. Nested structs, arrays and maps | |
| +can be declared like normal. | |
| + | |
| +The old SDK used interfaces for unions in requests, which required | |
| +a type assertion to access variants and fields. The new design uses | |
| +structs with a field for each variant, wherein only one field can be set. | |
| +These struct unions also expose 'Get' methods to access and mutate subfields | |
| +which may be shared by multiple variants. | |
| + | |
| +# Request parameters | |
| + | |
| +## Required primitives parameters serialize their zero values (`string`, `int64`, etc.) | |
| + | |
| +> [!CAUTION] | |
| +> | |
| +> **This change can cause new behavior in existing code, without compiler warnings.** | |
| + | |
| +While migrating, ensure that all required fields are explicitly set. A required primitive | |
| +field `Age` will use the <code>\`json:"age,required"\`</code> struct tag without `omitzero`. | |
| + | |
| +If a required primitive field is not set, the zero value will be serialized. | |
| +This was not the case in with `param.Field[T]`. | |
| + | |
| +```diff | |
| +type FooParams struct { | |
| +- Age param.Field[int64] `json:"age,required"` | |
| +- Name param.Field[string] `json:"name"` | |
| ++ Age int64 `json:"age,required"` // <== Notice no omitzero | |
| ++ Name param.Opt[string] `json:"name,omitzero"` | |
| +} | |
| +``` | |
| + | |
| +<table> | |
| +<tr> | |
| +<th>Previous</th> | |
| +<th>New</th> | |
| +</tr> | |
| +<tr> | |
| +<td> | |
| + | |
| +```go | |
| +_ = FooParams{ | |
| + Name: anthropic.String("Jerry") | |
| +} | |
| +`{"name": "Jerry"}` // (after serialization) | |
| +``` | |
| + | |
| +</td> | |
| +<td> | |
| + | |
| +```go | |
| +_ = FooParams{ | |
| + Name: anthropic.String("Jerry") | |
| +} | |
| +`{"name": "Jerry", "age": 0}` // <== Notice the age field | |
| +``` | |
| + | |
| +</td> | |
| +</tr> | |
| +</table> | |
| + | |
| +The required field `"age"` is now present as `0`. Fields without the <code>\`json:"...,omitzero"\`</code> struct tag | |
| +are always serialized, including their zero values. | |
| + | |
| +## Transition from `param.Field[T]` to `omitzero` | |
| + | |
| +The `anthropic.F(...)` function and `param.Field[T]` type are no longer present in the new SDK. | |
| + | |
| +To represent omitted fields, the SDK uses <a href="https://pkg.go.dev/encoding/json#Marshal"><code>\`json:"...,omitzero"\`</code> semantics</a> from Go 1.24+ for JSON encoding[^1]. `omitzero` always omits fields | |
| +with zero values. | |
| + | |
| +In all cases other than optional primitives, `anthropic.F()` can simply be removed. | |
| +For optional primitive types, such as `param.Opt[string]`, you can use `anthropic.String(string)` to construct the value. | |
| +Similar functions exist for other primitive types like `anthropic.Int(int)`, `anthropic.Bool(bool)`, etc. | |
| + | |
| +`omitzero` is used for fields whose type is either a struct, slice, map, string enum, | |
| +or wrapped optional primitive (e.g. `param.Opt[T]`). Required primitive fields don't use `omitzero`. | |
| + | |
| +**Example User Code: Constructing a request** | |
| + | |
| +```diff | |
| +foo = FooParams{ | |
| +- RequiredString: anthropic.String("hello"), | |
| ++ RequiredString: "hello", | |
| + | |
| +- OptionalString: anthropic.String("hi"), | |
| ++ OptionalString: anthropic.String("hi"), | |
| + | |
| +- Array: anthropic.F([]BarParam{ | |
| +- BarParam{Prop: ... } | |
| +- }), | |
| ++ Array: []BarParam{ | |
| ++ BarParam{Prop: ... } | |
| ++ }, | |
| + | |
| +- RequiredObject: anthropic.F(BarParam{ ... }), | |
| ++ RequiredObject: BarParam{ ... }, | |
| + | |
| +- OptionalObject: anthropic.F(BarParam{ ... }), | |
| ++ OptionalObject: BarParam{ ... }, | |
| + | |
| +- StringEnum: anthropic.F[BazEnum]("baz-ok"), | |
| ++ StringEnum: "baz-ok", | |
| +} | |
| +``` | |
| + | |
| +**Internal SDK Code: Fields of a request struct:** | |
| + | |
| +```diff | |
| +type FooParams struct { | |
| +- RequiredString param.Field[string] `json:"required_string,required"` | |
| ++ RequiredString string `json:"required_string,required"` | |
| + | |
| +- OptionalString param.Field[string] `json:"optional_string"` | |
| ++ OptionalString param.Opt[string] `json:"optional_string,omitzero"` | |
| + | |
| +- Array param.Field[[]BarParam] `json"array"` | |
| ++ Array []BarParam `json"array,omitzero"` | |
| + | |
| +- Map param.Field[map[string]BarParam] `json"map"` | |
| ++ Map map[string]BarParam `json"map,omitzero"` | |
| + | |
| +- RequiredObject param.Field[BarParam] `json:"required_object,required"` | |
| ++ RequiredObject BarParam `json:"required_object,omitzero,required"` | |
| + | |
| +- OptionalObject param.Field[BarParam] `json:"optional_object"` | |
| ++ OptionalObject BarParam `json:"optional_object,omitzero"` | |
| + | |
| +- StringEnum param.Field[BazEnum] `json:"string_enum"` | |
| ++ StringEnum BazEnum `json:"string_enum,omitzero"` | |
| +} | |
| +``` | |
| + | |
| +## Request Unions: Removing interfaces and moving to structs | |
| + | |
| +For a type `AnimalUnionParam` which could be either a `CatParam | DogParam`. | |
| + | |
| +<table> | |
| +<tr><th>Previous</th> <th>New</th></tr> | |
| +<tr> | |
| +<td> | |
| + | |
| +```go | |
| +type AnimalParam interface { | |
| + ImplAnimalParam() | |
| +} | |
| + | |
| +func (Dog) ImplAnimalParam() {} | |
| +func (Cat) ImplAnimalParam() {} | |
| +``` | |
| + | |
| +</td> | |
| +<td> | |
| + | |
| +```go | |
| +type AnimalUnionParam struct { | |
| + OfCat *Cat `json:",omitzero,inline` | |
| + OfDog *Dog `json:",omitzero,inline` | |
| +} | |
| +``` | |
| + | |
| +</td> | |
| +</tr> | |
| + | |
| +<tr style="background:rgb(209, 217, 224)"> | |
| +<td> | |
| + | |
| +```go | |
| +var dog AnimalParam = DogParam{ | |
| + Name: "spot", ... | |
| +} | |
| +var cat AnimalParam = CatParam{ | |
| + Name: "whiskers", ... | |
| +} | |
| +``` | |
| + | |
| +</td> | |
| +<td> | |
| + | |
| +```go | |
| +dog := AnimalUnionParam{ | |
| + OfDog: &DogParam{Name: "spot", ... }, | |
| +} | |
| +cat := AnimalUnionParam{ | |
| + OfCat: &CatParam{Name: "whiskers", ... }, | |
| +} | |
| +``` | |
| + | |
| +</td> | |
| +</tr> | |
| + | |
| +<tr> | |
| +<td> | |
| + | |
| +```go | |
| +var name string | |
| +switch v := animal.(type) { | |
| +case Dog: | |
| + name = v.Name | |
| +case Cat: | |
| + name = v.Name | |
| +} | |
| +``` | |
| + | |
| +</td> | |
| +<td> | |
| + | |
| +```go | |
| +// Accessing fields | |
| +var name *string = animal.GetName() | |
| +``` | |
| + | |
| +</td> | |
| +</tr> | |
| +</table> | |
| + | |
| +## Sending explicit `null` values | |
| + | |
| +The old SDK had a function `param.Null[T]()` which could set `param.Field[T]` to `null`. | |
| + | |
| +The new SDK uses `param.NullOpt[T]()` for to set a `param.Opt[T]` to `null`, | |
| +and `param.NullObj[T]()` to set a param struct `T` to `null`. | |
| + | |
| +```diff | |
| +- var nullObj param.Field[BarParam] = param.Null[BarParam]() | |
| ++ var nullObj BarParam = param.NullObj[BarParam]() | |
| + | |
| +- var nullPrimitive param.Field[int64] = param.Null[int64]() | |
| ++ var nullPrimitive param.Opt[int64] = param.NullOpt[int64]() | |
| +``` | |
| + | |
| +## Sending custom values | |
| + | |
| +The `anthropic.Raw[T](any)` function has been removed. All request structs now support a | |
| +`.WithExtraField(map[string]any)` method to customize the fields. | |
| + | |
| +```diff | |
| +foo := FooParams{ | |
| + A: param.String("hello"), | |
| +- B: param.Raw[string](12) // sending `12` instead of a string | |
| +} | |
| ++ foo.WithExtraFields(map[string]any{ | |
| ++ "B": 12, | |
| ++ }) | |
| +``` | |
| + | |
| +# Response Properties | |
| + | |
| +## Checking for presence of optional fields | |
| + | |
| +The `.IsNull()` method has been changed to `.IsPresent()` to better reflect its behavior. | |
| + | |
| +```diff | |
| +- if !resp.Foo.JSON.Bar.IsNull() { | |
| ++ if resp.Foo.JSON.Bar.IsPresent() { | |
| + println("bar is present:", resp.Foo.Bar) | |
| +} | |
| +``` | |
| + | |
| +| Previous | New | Returns true for values | | |
| +| -------------- | ------------------- | ----------------------- | | |
| +| `.IsNull()` | `!.IsPresent()` | `null` or Omitted | | |
| +| `.IsMissing()` | `.Raw() == ""` | Omitted | | |
| +| | `.IsExplicitNull()` | `null` | | |
| + | |
| +## Checking Raw JSON of a response | |
| + | |
| +The `.RawJSON()` method has moved to the parent of the `.JSON` property. | |
| + | |
| +```diff | |
| +- resp.Foo.JSON.RawJSON() | |
| ++ resp.Foo.RawJSON() | |
| +``` | |
| + | |
| +[^1]: The SDK doesn't require Go 1.24, despite supporting the `omitzero` feature | |
| diff --git a/README.md b/README.md | |
| index 6a5dbf4..f437e49 100644 | |
| --- a/README.md | |
| +++ b/README.md | |
| @@ -5,6 +5,10 @@ | |
| The Anthropic Go library provides convenient access to [the Anthropic REST | |
| API](https://docs.anthropic.com/claude/reference/) from applications written in Go. The full API of this library can be found in [api.md](api.md). | |
| +> [!WARNING] | |
| +> The latest version of this package uses a new design with significant breaking changes. | |
| +> Please refer to the [migration guide](./MIGRATION.md) for more information on how to update your code. | |
| + | |
| ## Installation | |
| <!-- x-release-please-start-version --> | |
| @@ -22,7 +26,7 @@ Or to pin the version: | |
| <!-- x-release-please-start-version --> | |
| ```sh | |
| -go get -u 'github.com/anthropics/[email protected]' | |
| +go get -u 'github.com/anthropics/[email protected]' | |
| ``` | |
| <!-- x-release-please-end --> | |
| @@ -51,11 +55,14 @@ func main() { | |
| option.WithAPIKey("my-anthropic-api-key"), // defaults to os.LookupEnv("ANTHROPIC_API_KEY") | |
| ) | |
| message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| - anthropic.NewUserMessage(anthropic.NewTextBlock("What is a quaternion?")), | |
| - }), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?"}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if err != nil { | |
| panic(err.Error()) | |
| @@ -70,25 +77,32 @@ func main() { | |
| ```go | |
| messages := []anthropic.MessageParam{ | |
| - anthropic.NewUserMessage(anthropic.NewTextBlock("What is my first name?")), | |
| + anthropic.NewUserMessage(anthropic.NewTextBlock("What is my first name?")), | |
| } | |
| message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - Model: anthropic.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - Messages: anthropic.F(messages), | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + 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"), | |
| + anthropic.NewTextBlock("My full name is John Doe"), | |
| )) | |
| message, err = client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - Model: anthropic.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - Messages: anthropic.F(messages), | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + Messages: messages, | |
| + MaxTokens: 1024, | |
| }) | |
| + | |
| +fmt.Printf("%+v\n", message.Content) | |
| ``` | |
| </details> | |
| @@ -97,17 +111,13 @@ message, err = client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| <summary>System prompts</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.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - MaxTokens: anthropic.Int(1024), | |
| - System: anthropic.F([]anthropic.TextBlockParam{ | |
| - anthropic.NewTextBlock("Be very serious at all times."), | |
| - }), | |
| - Messages: anthropic.F(messages), | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + MaxTokens: 1024, | |
| + System: []anthropic.TextBlockParam{ | |
| + {Text: "Be very serious at all times."}, | |
| + }, | |
| + Messages: messages, | |
| }) | |
| ``` | |
| @@ -117,29 +127,36 @@ message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| <summary>Streaming</summary> | |
| ```go | |
| +content := "What is a quaternion?" | |
| + | |
| stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{ | |
| - Model: anthropic.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| - anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| - }), | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{ | |
| + anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| + }, | |
| }) | |
| message := anthropic.Message{} | |
| for stream.Next() { | |
| - event := stream.Current() | |
| - message.Accumulate(event) | |
| - | |
| - switch delta := event.Delta.(type) { | |
| - case anthropic.ContentBlockDeltaEventDelta: | |
| - if delta.Text != "" { | |
| - print(delta.Text) | |
| - } | |
| - } | |
| -} | |
| - | |
| -if stream.Err() != nil { | |
| - panic(stream.Err()) | |
| + 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()) | |
| + } | |
| } | |
| ``` | |
| @@ -156,8 +173,8 @@ import ( | |
| "encoding/json" | |
| "fmt" | |
| - "github.com/invopop/jsonschema" | |
| "github.com/anthropics/anthropic-sdk-go" | |
| + "github.com/invopop/jsonschema" | |
| ) | |
| func main() { | |
| @@ -171,20 +188,24 @@ func main() { | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| } | |
| - tools := []anthropic.ToolParam{ | |
| + toolParams := []anthropic.ToolParam{ | |
| { | |
| - Name: anthropic.F("get_coordinates"), | |
| - Description: anthropic.F("Accepts a place as an address, then returns the latitude and longitude coordinates."), | |
| - InputSchema: anthropic.F(GetCoordinatesInputSchema), | |
| + 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.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F(messages), | |
| - Tools: anthropic.F(tools), | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + MaxTokens: 1024, | |
| + Messages: messages, | |
| + Tools: tools, | |
| }) | |
| if err != nil { | |
| @@ -193,29 +214,37 @@ func main() { | |
| print(color("[assistant]: ")) | |
| for _, block := range message.Content { | |
| - switch block := block.AsUnion().(type) { | |
| + switch block := block.AsAny().(type) { | |
| case anthropic.TextBlock: | |
| println(block.Text) | |
| + println() | |
| case anthropic.ToolUseBlock: | |
| - println(block.Name + ": " + string(block.Input)) | |
| + inputJSON, _ := json.Marshal(block.Input) | |
| + println(block.Name + ": " + string(inputJSON)) | |
| + println() | |
| } | |
| } | |
| messages = append(messages, message.ToParam()) | |
| - toolResults := []anthropic.MessageParamContentUnion{} | |
| + toolResults := []anthropic.ContentBlockParamUnion{} | |
| for _, block := range message.Content { | |
| - if block.Type == anthropic.ContentBlockTypeToolUse { | |
| - print("[user (" + block.Name + ")]: ") | |
| + switch variant := block.AsAny().(type) { | |
| + case anthropic.ToolUseBlock: | |
| + print(color("[user (" + block.Name + ")]: ")) | |
| var response interface{} | |
| switch block.Name { | |
| case "get_coordinates": | |
| - input := GetCoordinatesInput{} | |
| - err := json.Unmarshal(block.Input, &input) | |
| + 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) | |
| } | |
| @@ -224,8 +253,11 @@ func main() { | |
| panic(err) | |
| } | |
| + println(string(b)) | |
| + | |
| toolResults = append(toolResults, anthropic.NewToolResultBlock(block.ID, string(b), false)) | |
| } | |
| + | |
| } | |
| if len(toolResults) == 0 { | |
| break | |
| @@ -252,13 +284,22 @@ func GetCoordinates(location string) GetCoordinateResponse { | |
| } | |
| } | |
| -func GenerateSchema[T any]() interface{} { | |
| +func GenerateSchema[T any]() anthropic.ToolInputSchemaParam { | |
| reflector := jsonschema.Reflector{ | |
| AllowAdditionalProperties: false, | |
| DoNotReference: true, | |
| } | |
| var v T | |
| - return reflector.Reflect(v) | |
| + | |
| + 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) | |
| } | |
| ``` | |
| @@ -266,31 +307,82 @@ func GenerateSchema[T any]() interface{} { | |
| ### Request fields | |
| -All request parameters are wrapped in a generic `Field` type, | |
| -which we use to distinguish zero values from null or omitted 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]`. Use the provided constructors set `param.Opt[T]` fields such as `anthropic.String(string)`, `anthropic.Int(int64)`, etc. | |
| + | |
| +Optional primitives, maps, slices and structs and string enums (represented as `string`) always feature the | |
| +tag <code>\`json:"...,omitzero"\`</code>. Their zero values are considered omitted. | |
| -This prevents accidentally sending a zero value if you forget a required parameter, | |
| -and enables explicitly sending `null`, `false`, `''`, or `0` on optional parameters. | |
| -Any field not specified is not sent. | |
| +Any non-nil slice of length zero will serialize as an empty JSON array, `"[]"`. Similarly, any non-nil map with length zero with serialize as an empty JSON object, `"{}"`. | |
| -To construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`. | |
| -To send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example: | |
| +To send `null` instead of an `param.Opt[T]`, use `param.NullOpt[T]()`. | |
| +To send `null` instead of a struct, use `param.NullObj[T]()`, where `T` is a struct. | |
| +To send a custom value instead of a struct, use `param.OverrideObj[T](value)`. | |
| + | |
| +To override request structs contain a `.WithExtraFields(map[string]any)` method which can be used to | |
| +send non-conforming fields in the request body. Extra fields overwrite any struct fields with a matching | |
| +key, so only use with trusted data. | |
| ```go | |
| params := FooParams{ | |
| - Name: anthropic.F("hello"), | |
| + ID: "id_xxx", // required property | |
| + Name: anthropic.String("hello"), // optional property | |
| + Description: param.NullOpt[string](), // explicit null 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 | |
| + }), | |
| - // Explicitly send `"description": null` | |
| - Description: anthropic.Null[string](), | |
| + Origin: anthropic.Origin{}, // the zero value of [Origin] is considered omitted | |
| +} | |
| - Point: anthropic.F(anthropic.Point{ | |
| - X: anthropic.Int(0), | |
| - Y: anthropic.Int(1), | |
| +// In cases where the API specifies a given type, | |
| +// but you want to send something else, use [WithExtraFields]: | |
| +params.WithExtraFields(map[string]any{ | |
| + "x": 0.01, // send "x" as a float instead of int | |
| +}) | |
| - // In cases where the API specifies a given type, | |
| - // but you want to send something else, use `Raw`: | |
| - Z: anthropic.Raw[int64](0.01), // sends a float | |
| - }), | |
| +// Send a number instead of an object | |
| +custom := param.OverrideObj[anthropic.FooParams](12) | |
| +``` | |
| + | |
| +When available, use the `.IsPresent()` method to check if an optional parameter is not omitted or `null`. | |
| +Otherwise, the `param.IsOmitted(any)` function can confirm the presence of any `omitzero` field. | |
| + | |
| +### Request unions | |
| + | |
| +Unions are represented as a struct with fields prefixed by "Of" for each of it's 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 | |
| } | |
| ``` | |
| @@ -306,14 +398,14 @@ information about each property, which you can use like so: | |
| ```go | |
| if res.Name == "" { | |
| - // true if `"name"` is either not present or explicitly null | |
| - res.JSON.Name.IsNull() | |
| + // true if `"name"` was unmarshalled successfully | |
| + res.JSON.Name.IsPresent() | |
| - // true if the `"name"` key was not present in the response JSON at all | |
| - res.JSON.Name.IsMissing() | |
| + res.JSON.Name.IsExplicitNull() // true if `"name"` is explicitly null | |
| + res.JSON.Name.Raw() == "" // true if `"name"` field does not exist | |
| // When the API returns data that cannot be coerced to the expected type: | |
| - if res.JSON.Name.IsInvalid() { | |
| + if !res.JSON.Name.IsPresent() && res.JSON.Name.Raw() != "" { | |
| raw := res.JSON.Name.Raw() | |
| legacyName := struct{ | |
| @@ -326,7 +418,7 @@ if res.Name == "" { | |
| } | |
| ``` | |
| -These `.JSON` structs also include an `Extras` map containing | |
| +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. | |
| @@ -335,6 +427,49 @@ present in the SDK. | |
| 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 { | |
| + OfString string `json:",inline"` | |
| + Name string `json:"name"` | |
| + Owner Person `json:"owner"` | |
| + // ... | |
| + JSON struct { | |
| + OfString resp.Field | |
| + Name resp.Field | |
| + Owner resp.Field | |
| + // ... | |
| + } | |
| +} | |
| + | |
| +// If animal variant | |
| +if animal.Owner.Address.JSON.ZipCode == "" { | |
| + panic("missing zip code") | |
| +} | |
| + | |
| +// If string variant | |
| +if !animal.OfString == "" { | |
| + panic("expected a name") | |
| +} | |
| + | |
| +// Switch on the variant | |
| +switch variant := animalOrName.AsAny().(type) { | |
| +case string: | |
| +case Dog: | |
| +case Cat: | |
| +default: | |
| + panic("unexpected type") | |
| +} | |
| +``` | |
| + | |
| ### RequestOptions | |
| This library uses the functional options pattern. Functions defined in the | |
| @@ -366,7 +501,7 @@ You can use `.ListAutoPaging()` methods to iterate through items across all page | |
| ```go | |
| iter := client.Beta.Messages.Batches.ListAutoPaging(context.TODO(), anthropic.BetaMessageBatchListParams{ | |
| - Limit: anthropic.F(int64(20)), | |
| + Limit: anthropic.Int(20), | |
| }) | |
| // Automatically fetches more pages as needed. | |
| for iter.Next() { | |
| @@ -383,7 +518,7 @@ with additional helper methods like `.GetNextPage()`, e.g.: | |
| ```go | |
| page, err := client.Beta.Messages.Batches.List(context.TODO(), anthropic.BetaMessageBatchListParams{ | |
| - Limit: anthropic.F(int64(20)), | |
| + Limit: anthropic.Int(20), | |
| }) | |
| for page != nil { | |
| for _, batch := range page.Data { | |
| @@ -407,8 +542,16 @@ To handle errors, we recommend that you use the `errors.As` pattern: | |
| ```go | |
| _, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| @@ -437,11 +580,14 @@ defer cancel() | |
| client.Messages.New( | |
| ctx, | |
| anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| - anthropic.NewUserMessage(anthropic.NewTextBlock("What is a quaternion?")), | |
| - }), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?"}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }, | |
| // This sets the per-retry timeout | |
| option.WithRequestTimeout(20*time.Second), | |
| @@ -462,7 +608,7 @@ Calling `.Messages.NewStreaming()` or [setting a custom timeout](#timeouts) disa | |
| ### File uploads | |
| Request parameters that correspond to file uploads in multipart requests are typed as | |
| -`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form | |
| +`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". | |
| The file name and content-type can be customized by implementing `Name() string` or `ContentType() | |
| @@ -490,11 +636,14 @@ client := anthropic.NewClient( | |
| client.Messages.New( | |
| context.TODO(), | |
| anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| - anthropic.NewUserMessage(anthropic.NewTextBlock("What is a quaternion?")), | |
| - }), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?"}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }, | |
| option.WithMaxRetries(5), | |
| ) | |
| @@ -511,12 +660,16 @@ var response *http.Response | |
| message, err := client.Messages.New( | |
| context.TODO(), | |
| anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }, | |
| option.WithResponseInto(&response), | |
| ) | |
| @@ -541,17 +694,17 @@ To make requests to undocumented endpoints, you can use `client.Get`, `client.Po | |
| ```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]interface{} | |
| + // params can be an io.Reader, a []byte, an encoding/json serializable object, | |
| + // or a "…Params" struct defined in this library. | |
| + params map[string]interface{} | |
| - // result can be an []byte, *http.Response, a encoding/json deserializable object, | |
| - // or a model defined in this library. | |
| - result *http.Response | |
| + // 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 { | |
| - … | |
| + … | |
| } | |
| ``` | |
| @@ -562,10 +715,10 @@ or the `option.WithJSONSet()` methods. | |
| ```go | |
| params := FooNewParams{ | |
| - ID: anthropic.F("id_xxxx"), | |
| - Data: anthropic.F(FooNewParamsData{ | |
| - FirstName: anthropic.F("John"), | |
| - }), | |
| + ID: "id_xxxx", | |
| + Data: FooNewParamsData{ | |
| + FirstName: anthropic.String("John"), | |
| + }, | |
| } | |
| client.Foo.New(context.Background(), params, option.WithJSONSet("data.last_name", "Doe")) | |
| ``` | |
| @@ -596,7 +749,7 @@ func Logger(req *http.Request, next option.MiddlewareNext) (res *http.Response, | |
| end := time.Now() | |
| LogRes(res, err, start - end) | |
| - return res, err | |
| + return res, err | |
| } | |
| client := anthropic.NewClient( | |
| @@ -661,7 +814,7 @@ import ( | |
| func main() { | |
| client := anthropic.NewClient( | |
| - vertex.WithGoogleAuth(context.Background(), "us-central1", "stainless-399616"), | |
| + vertex.WithGoogleAuth(context.Background(), "us-central1", "id-xxx"), | |
| ) | |
| } | |
| ``` | |
| diff --git a/aliases.go b/aliases.go | |
| index 0205358..da74b40 100644 | |
| --- a/aliases.go | |
| +++ b/aliases.go | |
| @@ -4,130 +4,37 @@ package anthropic | |
| import ( | |
| "github.com/anthropics/anthropic-sdk-go/internal/apierror" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| "github.com/anthropics/anthropic-sdk-go/shared" | |
| ) | |
| -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 APIErrorObjectType = shared.APIErrorObjectType | |
| - | |
| -// This is an alias to an internal value. | |
| -const APIErrorObjectTypeAPIError = shared.APIErrorObjectTypeAPIError | |
| - | |
| -// This is an alias to an internal type. | |
| -type AuthenticationError = shared.AuthenticationError | |
| - | |
| -// This is an alias to an internal type. | |
| -type AuthenticationErrorType = shared.AuthenticationErrorType | |
| - | |
| -// This is an alias to an internal value. | |
| -const AuthenticationErrorTypeAuthenticationError = shared.AuthenticationErrorTypeAuthenticationError | |
| - | |
| -// This is an alias to an internal type. | |
| -type BillingError = shared.BillingError | |
| +// aliased to make [param.APIUnion] private when embedding | |
| +type paramUnion = param.APIUnion | |
| -// This is an alias to an internal type. | |
| -type BillingErrorType = shared.BillingErrorType | |
| +// aliased to make [param.APIObject] private when embedding | |
| +type paramObj = param.APIObject | |
| -// This is an alias to an internal value. | |
| -const BillingErrorTypeBillingError = shared.BillingErrorTypeBillingError | |
| +type Error = apierror.Error | |
| // This is an alias to an internal type. | |
| -type ErrorObject = shared.ErrorObject | |
| +type APIErrorObject = shared.APIErrorObject | |
| // This is an alias to an internal type. | |
| -type ErrorObjectType = shared.ErrorObjectType | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorObjectTypeInvalidRequestError = shared.ErrorObjectTypeInvalidRequestError | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorObjectTypeAuthenticationError = shared.ErrorObjectTypeAuthenticationError | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorObjectTypeBillingError = shared.ErrorObjectTypeBillingError | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorObjectTypePermissionError = shared.ErrorObjectTypePermissionError | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorObjectTypeNotFoundError = shared.ErrorObjectTypeNotFoundError | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorObjectTypeRateLimitError = shared.ErrorObjectTypeRateLimitError | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorObjectTypeTimeoutError = shared.ErrorObjectTypeTimeoutError | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorObjectTypeAPIError = shared.ErrorObjectTypeAPIError | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorObjectTypeOverloadedError = shared.ErrorObjectTypeOverloadedError | |
| +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 ErrorResponseType = shared.ErrorResponseType | |
| - | |
| -// This is an alias to an internal value. | |
| -const ErrorResponseTypeError = shared.ErrorResponseTypeError | |
| - | |
| // This is an alias to an internal type. | |
| type GatewayTimeoutError = shared.GatewayTimeoutError | |
| -// This is an alias to an internal type. | |
| -type GatewayTimeoutErrorType = shared.GatewayTimeoutErrorType | |
| - | |
| -// This is an alias to an internal value. | |
| -const GatewayTimeoutErrorTypeTimeoutError = shared.GatewayTimeoutErrorTypeTimeoutError | |
| - | |
| -// This is an alias to an internal type. | |
| -type InvalidRequestError = shared.InvalidRequestError | |
| - | |
| -// This is an alias to an internal type. | |
| -type InvalidRequestErrorType = shared.InvalidRequestErrorType | |
| - | |
| -// This is an alias to an internal value. | |
| -const InvalidRequestErrorTypeInvalidRequestError = shared.InvalidRequestErrorTypeInvalidRequestError | |
| - | |
| -// This is an alias to an internal type. | |
| -type NotFoundError = shared.NotFoundError | |
| - | |
| -// This is an alias to an internal type. | |
| -type NotFoundErrorType = shared.NotFoundErrorType | |
| - | |
| -// This is an alias to an internal value. | |
| -const NotFoundErrorTypeNotFoundError = shared.NotFoundErrorTypeNotFoundError | |
| - | |
| -// This is an alias to an internal type. | |
| -type OverloadedError = shared.OverloadedError | |
| - | |
| -// This is an alias to an internal type. | |
| -type OverloadedErrorType = shared.OverloadedErrorType | |
| - | |
| -// This is an alias to an internal value. | |
| -const OverloadedErrorTypeOverloadedError = shared.OverloadedErrorTypeOverloadedError | |
| - | |
| -// This is an alias to an internal type. | |
| -type PermissionError = shared.PermissionError | |
| - | |
| -// This is an alias to an internal type. | |
| -type PermissionErrorType = shared.PermissionErrorType | |
| - | |
| -// This is an alias to an internal value. | |
| -const PermissionErrorTypePermissionError = shared.PermissionErrorTypePermissionError | |
| - | |
| -// This is an alias to an internal type. | |
| -type RateLimitError = shared.RateLimitError | |
| - | |
| -// This is an alias to an internal type. | |
| -type RateLimitErrorType = shared.RateLimitErrorType | |
| - | |
| -// This is an alias to an internal value. | |
| -const RateLimitErrorTypeRateLimitError = shared.RateLimitErrorTypeRateLimitError | |
| +func toParam[T comparable](value T, meta resp.Field) param.Opt[T] { | |
| + if meta.IsPresent() { | |
| + return param.NewOpt(value) | |
| + } | |
| + if meta.IsExplicitNull() { | |
| + return param.NullOpt[T]() | |
| + } | |
| + return param.Opt[T]{} | |
| +} | |
| diff --git a/api.md b/api.md | |
| index 4f9239a..674ae97 100644 | |
| --- a/api.md | |
| +++ b/api.md | |
| @@ -3,7 +3,7 @@ | |
| - <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#ErrorObject">ErrorObject</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> | |
| @@ -49,7 +49,7 @@ 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#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#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#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#ToolUnionUnionParam">ToolUnionUnionParam</a> | |
| +- <a href="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> | |
| @@ -60,7 +60,7 @@ 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#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#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#ContentBlock">ContentBlock</a> | |
| +- <a href="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#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> | |
| @@ -72,11 +72,11 @@ 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#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#MessageStreamEvent">MessageStreamEvent</a> | |
| +- <a href="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#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#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#TextCitation">TextCitation</a> | |
| +- <a href="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#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> | |
| @@ -99,7 +99,7 @@ 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#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#MessageBatchResult">MessageBatchResult</a> | |
| +- <a href="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: | |
| @@ -133,7 +133,7 @@ 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#BetaError">BetaError</a> | |
| +- <a href="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> | |
| @@ -192,7 +192,7 @@ 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#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#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#BetaToolUnionUnionParam">BetaToolUnionUnionParam</a> | |
| +- <a href="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#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> | |
| @@ -203,7 +203,7 @@ 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#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#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#BetaContentBlock">BetaContentBlock</a> | |
| +- <a href="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#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#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> | |
| @@ -214,11 +214,11 @@ 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#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#BetaRawMessageStreamEvent">BetaRawMessageStreamEvent</a> | |
| +- <a href="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#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#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#BetaTextCitation">BetaTextCitation</a> | |
| +- <a href="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#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> | |
| @@ -241,7 +241,7 @@ 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#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#BetaMessageBatchResult">BetaMessageBatchResult</a> | |
| +- <a href="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: | |
| diff --git a/bedrock/bedrock.go b/bedrock/bedrock.go | |
| index d535321..57b0008 100644 | |
| --- a/bedrock/bedrock.go | |
| +++ b/bedrock/bedrock.go | |
| @@ -180,12 +180,12 @@ func WithConfig(cfg aws.Config) option.RequestOption { | |
| signer := v4.NewSigner() | |
| middleware := bedrockMiddleware(signer, cfg) | |
| - return func(rc *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(rc *requestconfig.RequestConfig) error { | |
| 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 { | |
| diff --git a/bedrock/bedrock_test.go b/bedrock/bedrock_test.go | |
| deleted file mode 100644 | |
| index 2f98f2b..0000000 | |
| --- a/bedrock/bedrock_test.go | |
| +++ /dev/null | |
| @@ -1,38 +0,0 @@ | |
| -package bedrock | |
| - | |
| -import ( | |
| - "context" | |
| - "errors" | |
| - "net/http" | |
| - "testing" | |
| - | |
| - "github.com/anthropics/anthropic-sdk-go" | |
| - "github.com/anthropics/anthropic-sdk-go/option" | |
| -) | |
| - | |
| -func TestBedrockError(t *testing.T) { | |
| - expectedErr := errors.New("simulated network error") | |
| - | |
| - client := anthropic.NewClient( | |
| - option.WithMiddleware(func(r *http.Request, next option.MiddlewareNext) (*http.Response, error) { | |
| - return nil, expectedErr | |
| - }), | |
| - ) | |
| - | |
| - // Attempt to make a request | |
| - stream := client.Messages.NewStreaming(context.Background(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| - anthropic.NewUserMessage(anthropic.NewTextBlock("test message")), | |
| - }), | |
| - Model: anthropic.F("anthropic.claude-3-sonnet-20240229-v1:0"), | |
| - }) | |
| - | |
| - for stream.Next() { | |
| - stream.Current() | |
| - } | |
| - | |
| - if stream.Err() != expectedErr { | |
| - t.Fatal() | |
| - } | |
| -} | |
| diff --git a/beta.go b/beta.go | |
| index 9b01387..7abc9ec 100644 | |
| --- a/beta.go | |
| +++ b/beta.go | |
| @@ -3,11 +3,12 @@ | |
| package anthropic | |
| import ( | |
| - "reflect" | |
| + "encoding/json" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apijson" | |
| "github.com/anthropics/anthropic-sdk-go/option" | |
| - "github.com/tidwall/gjson" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| + "github.com/anthropics/anthropic-sdk-go/shared/constant" | |
| ) | |
| // BetaService contains methods and other services that help with interacting with | |
| @@ -18,15 +19,15 @@ import ( | |
| // the [NewBetaService] method instead. | |
| type BetaService struct { | |
| Options []option.RequestOption | |
| - Models *BetaModelService | |
| - Messages *BetaMessageService | |
| + Models BetaModelService | |
| + Messages BetaMessageService | |
| } | |
| // 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{} | |
| +func NewBetaService(opts ...option.RequestOption) (r BetaService) { | |
| + r = BetaService{} | |
| r.Options = opts | |
| r.Models = NewBetaModelService(opts...) | |
| r.Messages = NewBetaMessageService(opts...) | |
| @@ -47,509 +48,303 @@ const ( | |
| ) | |
| type BetaAPIError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaAPIErrorType `json:"type,required"` | |
| - JSON betaAPIErrorJSON `json:"-"` | |
| -} | |
| - | |
| -// betaAPIErrorJSON contains the JSON metadata for the struct [BetaAPIError] | |
| -type betaAPIErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaAPIError) UnmarshalJSON(data []byte) (err error) { | |
| + Message string `json:"message,required"` | |
| + Type constant.APIError `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaAPIErrorJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaAPIError) implementsBetaError() {} | |
| - | |
| -type BetaAPIErrorType string | |
| - | |
| -const ( | |
| - BetaAPIErrorTypeAPIError BetaAPIErrorType = "api_error" | |
| -) | |
| - | |
| -func (r BetaAPIErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaAPIErrorTypeAPIError: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaAuthenticationError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaAuthenticationErrorType `json:"type,required"` | |
| - JSON betaAuthenticationErrorJSON `json:"-"` | |
| -} | |
| - | |
| -// betaAuthenticationErrorJSON contains the JSON metadata for the struct | |
| -// [BetaAuthenticationError] | |
| -type betaAuthenticationErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaAuthenticationError) UnmarshalJSON(data []byte) (err error) { | |
| + Message string `json:"message,required"` | |
| + Type constant.AuthenticationError `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaAuthenticationErrorJSON) RawJSON() string { | |
| - return r.raw | |
| +type BetaBillingError struct { | |
| + Message string `json:"message,required"` | |
| + Type constant.BillingError `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r BetaAuthenticationError) implementsBetaError() {} | |
| - | |
| -type BetaAuthenticationErrorType string | |
| - | |
| -const ( | |
| - BetaAuthenticationErrorTypeAuthenticationError BetaAuthenticationErrorType = "authentication_error" | |
| -) | |
| - | |
| -func (r BetaAuthenticationErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaAuthenticationErrorTypeAuthenticationError: | |
| - return true | |
| +// 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 resp.Field | |
| + Type resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := BetaErrorUnion.AsAny().(type) { | |
| +// case BetaInvalidRequestError: | |
| +// case BetaAuthenticationError: | |
| +// case BetaBillingError: | |
| +// case BetaPermissionError: | |
| +// case BetaNotFoundError: | |
| +// case BetaRateLimitError: | |
| +// case BetaGatewayTimeoutError: | |
| +// case BetaAPIError: | |
| +// case BetaOverloadedError: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u BetaErrorUnion) AsAny() any { | |
| + 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.AsGatewayTimeoutError() | |
| + case "api_error": | |
| + return u.AsAPIError() | |
| + case "overloaded_error": | |
| + return u.AsOverloadedError() | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaBillingError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaBillingErrorType `json:"type,required"` | |
| - JSON betaBillingErrorJSON `json:"-"` | |
| +func (u BetaErrorUnion) AsInvalidRequestError() (v BetaInvalidRequestError) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// betaBillingErrorJSON contains the JSON metadata for the struct | |
| -// [BetaBillingError] | |
| -type betaBillingErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func (u BetaErrorUnion) AsAuthenticationError() (v BetaAuthenticationError) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r *BetaBillingError) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +func (u BetaErrorUnion) AsBillingError() (v BetaBillingError) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r betaBillingErrorJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u BetaErrorUnion) AsPermissionError() (v BetaPermissionError) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r BetaBillingError) implementsBetaError() {} | |
| - | |
| -type BetaBillingErrorType string | |
| - | |
| -const ( | |
| - BetaBillingErrorTypeBillingError BetaBillingErrorType = "billing_error" | |
| -) | |
| - | |
| -func (r BetaBillingErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaBillingErrorTypeBillingError: | |
| - return true | |
| - } | |
| - return false | |
| +func (u BetaErrorUnion) AsNotFoundError() (v BetaNotFoundError) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaErrorType `json:"type,required"` | |
| - JSON betaErrorJSON `json:"-"` | |
| - union BetaErrorUnion | |
| +func (u BetaErrorUnion) AsRateLimitError() (v BetaRateLimitError) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// betaErrorJSON contains the JSON metadata for the struct [BetaError] | |
| -type betaErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func (u BetaErrorUnion) AsGatewayTimeoutError() (v BetaGatewayTimeoutError) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r betaErrorJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u BetaErrorUnion) AsAPIError() (v BetaAPIError) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r *BetaError) UnmarshalJSON(data []byte) (err error) { | |
| - *r = BetaError{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| +func (u BetaErrorUnion) AsOverloadedError() (v BetaOverloadedError) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// AsUnion returns a [BetaErrorUnion] interface which you can cast to the specific | |
| -// types for more type safety. | |
| -// | |
| -// Possible runtime types of the union are [BetaInvalidRequestError], | |
| -// [BetaAuthenticationError], [BetaBillingError], [BetaPermissionError], | |
| -// [BetaNotFoundError], [BetaRateLimitError], [BetaGatewayTimeoutError], | |
| -// [BetaAPIError], [BetaOverloadedError]. | |
| -func (r BetaError) AsUnion() BetaErrorUnion { | |
| - return r.union | |
| -} | |
| - | |
| -// Union satisfied by [BetaInvalidRequestError], [BetaAuthenticationError], | |
| -// [BetaBillingError], [BetaPermissionError], [BetaNotFoundError], | |
| -// [BetaRateLimitError], [BetaGatewayTimeoutError], [BetaAPIError] or | |
| -// [BetaOverloadedError]. | |
| -type BetaErrorUnion interface { | |
| - implementsBetaError() | |
| -} | |
| - | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*BetaErrorUnion)(nil)).Elem(), | |
| - "type", | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaInvalidRequestError{}), | |
| - DiscriminatorValue: "invalid_request_error", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaAuthenticationError{}), | |
| - DiscriminatorValue: "authentication_error", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaBillingError{}), | |
| - DiscriminatorValue: "billing_error", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaPermissionError{}), | |
| - DiscriminatorValue: "permission_error", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaNotFoundError{}), | |
| - DiscriminatorValue: "not_found_error", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaRateLimitError{}), | |
| - DiscriminatorValue: "rate_limit_error", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaGatewayTimeoutError{}), | |
| - DiscriminatorValue: "timeout_error", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaAPIError{}), | |
| - DiscriminatorValue: "api_error", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaOverloadedError{}), | |
| - DiscriminatorValue: "overloaded_error", | |
| - }, | |
| - ) | |
| -} | |
| - | |
| -type BetaErrorType string | |
| - | |
| -const ( | |
| - BetaErrorTypeInvalidRequestError BetaErrorType = "invalid_request_error" | |
| - BetaErrorTypeAuthenticationError BetaErrorType = "authentication_error" | |
| - BetaErrorTypeBillingError BetaErrorType = "billing_error" | |
| - BetaErrorTypePermissionError BetaErrorType = "permission_error" | |
| - BetaErrorTypeNotFoundError BetaErrorType = "not_found_error" | |
| - BetaErrorTypeRateLimitError BetaErrorType = "rate_limit_error" | |
| - BetaErrorTypeTimeoutError BetaErrorType = "timeout_error" | |
| - BetaErrorTypeAPIError BetaErrorType = "api_error" | |
| - BetaErrorTypeOverloadedError BetaErrorType = "overloaded_error" | |
| -) | |
| +// Returns the unmodified JSON received from the API | |
| +func (u BetaErrorUnion) RawJSON() string { return u.JSON.raw } | |
| -func (r BetaErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaErrorTypeInvalidRequestError, BetaErrorTypeAuthenticationError, BetaErrorTypeBillingError, BetaErrorTypePermissionError, BetaErrorTypeNotFoundError, BetaErrorTypeRateLimitError, BetaErrorTypeTimeoutError, BetaErrorTypeAPIError, BetaErrorTypeOverloadedError: | |
| - return true | |
| - } | |
| - return false | |
| +func (r *BetaErrorUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| type BetaErrorResponse struct { | |
| - Error BetaError `json:"error,required"` | |
| - Type BetaErrorResponseType `json:"type,required"` | |
| - JSON betaErrorResponseJSON `json:"-"` | |
| -} | |
| - | |
| -// betaErrorResponseJSON contains the JSON metadata for the struct | |
| -// [BetaErrorResponse] | |
| -type betaErrorResponseJSON struct { | |
| - Error apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaErrorResponse) UnmarshalJSON(data []byte) (err error) { | |
| + Error BetaErrorUnion `json:"error,required"` | |
| + Type constant.Error `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Error resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaErrorResponseJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -type BetaErrorResponseType string | |
| - | |
| -const ( | |
| - BetaErrorResponseTypeError BetaErrorResponseType = "error" | |
| -) | |
| - | |
| -func (r BetaErrorResponseType) IsKnown() bool { | |
| - switch r { | |
| - case BetaErrorResponseTypeError: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaGatewayTimeoutError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaGatewayTimeoutErrorType `json:"type,required"` | |
| - JSON betaGatewayTimeoutErrorJSON `json:"-"` | |
| -} | |
| - | |
| -// betaGatewayTimeoutErrorJSON contains the JSON metadata for the struct | |
| -// [BetaGatewayTimeoutError] | |
| -type betaGatewayTimeoutErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaGatewayTimeoutError) UnmarshalJSON(data []byte) (err error) { | |
| + Message string `json:"message,required"` | |
| + Type constant.TimeoutError `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaGatewayTimeoutErrorJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaGatewayTimeoutError) implementsBetaError() {} | |
| - | |
| -type BetaGatewayTimeoutErrorType string | |
| - | |
| -const ( | |
| - BetaGatewayTimeoutErrorTypeTimeoutError BetaGatewayTimeoutErrorType = "timeout_error" | |
| -) | |
| - | |
| -func (r BetaGatewayTimeoutErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaGatewayTimeoutErrorTypeTimeoutError: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaInvalidRequestError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaInvalidRequestErrorType `json:"type,required"` | |
| - JSON betaInvalidRequestErrorJSON `json:"-"` | |
| -} | |
| - | |
| -// betaInvalidRequestErrorJSON contains the JSON metadata for the struct | |
| -// [BetaInvalidRequestError] | |
| -type betaInvalidRequestErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaInvalidRequestError) UnmarshalJSON(data []byte) (err error) { | |
| + Message string `json:"message,required"` | |
| + Type constant.InvalidRequestError `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaInvalidRequestErrorJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaInvalidRequestError) implementsBetaError() {} | |
| - | |
| -type BetaInvalidRequestErrorType string | |
| - | |
| -const ( | |
| - BetaInvalidRequestErrorTypeInvalidRequestError BetaInvalidRequestErrorType = "invalid_request_error" | |
| -) | |
| - | |
| -func (r BetaInvalidRequestErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaInvalidRequestErrorTypeInvalidRequestError: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaNotFoundError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaNotFoundErrorType `json:"type,required"` | |
| - JSON betaNotFoundErrorJSON `json:"-"` | |
| -} | |
| - | |
| -// betaNotFoundErrorJSON contains the JSON metadata for the struct | |
| -// [BetaNotFoundError] | |
| -type betaNotFoundErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaNotFoundError) UnmarshalJSON(data []byte) (err error) { | |
| + Message string `json:"message,required"` | |
| + Type constant.NotFoundError `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaNotFoundErrorJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaNotFoundError) implementsBetaError() {} | |
| - | |
| -type BetaNotFoundErrorType string | |
| - | |
| -const ( | |
| - BetaNotFoundErrorTypeNotFoundError BetaNotFoundErrorType = "not_found_error" | |
| -) | |
| - | |
| -func (r BetaNotFoundErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaNotFoundErrorTypeNotFoundError: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaOverloadedError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaOverloadedErrorType `json:"type,required"` | |
| - JSON betaOverloadedErrorJSON `json:"-"` | |
| -} | |
| - | |
| -// betaOverloadedErrorJSON contains the JSON metadata for the struct | |
| -// [BetaOverloadedError] | |
| -type betaOverloadedErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaOverloadedError) UnmarshalJSON(data []byte) (err error) { | |
| + Message string `json:"message,required"` | |
| + Type constant.OverloadedError `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaOverloadedErrorJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaOverloadedError) implementsBetaError() {} | |
| - | |
| -type BetaOverloadedErrorType string | |
| - | |
| -const ( | |
| - BetaOverloadedErrorTypeOverloadedError BetaOverloadedErrorType = "overloaded_error" | |
| -) | |
| - | |
| -func (r BetaOverloadedErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaOverloadedErrorTypeOverloadedError: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaPermissionError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaPermissionErrorType `json:"type,required"` | |
| - JSON betaPermissionErrorJSON `json:"-"` | |
| -} | |
| - | |
| -// betaPermissionErrorJSON contains the JSON metadata for the struct | |
| -// [BetaPermissionError] | |
| -type betaPermissionErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaPermissionError) UnmarshalJSON(data []byte) (err error) { | |
| + Message string `json:"message,required"` | |
| + Type constant.PermissionError `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaPermissionErrorJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaPermissionError) implementsBetaError() {} | |
| - | |
| -type BetaPermissionErrorType string | |
| - | |
| -const ( | |
| - BetaPermissionErrorTypePermissionError BetaPermissionErrorType = "permission_error" | |
| -) | |
| - | |
| -func (r BetaPermissionErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaPermissionErrorTypePermissionError: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaRateLimitError struct { | |
| - Message string `json:"message,required"` | |
| - Type BetaRateLimitErrorType `json:"type,required"` | |
| - JSON betaRateLimitErrorJSON `json:"-"` | |
| -} | |
| - | |
| -// betaRateLimitErrorJSON contains the JSON metadata for the struct | |
| -// [BetaRateLimitError] | |
| -type betaRateLimitErrorJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaRateLimitError) UnmarshalJSON(data []byte) (err error) { | |
| + Message string `json:"message,required"` | |
| + Type constant.RateLimitError `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| - | |
| -func (r betaRateLimitErrorJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaRateLimitError) implementsBetaError() {} | |
| - | |
| -type BetaRateLimitErrorType string | |
| - | |
| -const ( | |
| - BetaRateLimitErrorTypeRateLimitError BetaRateLimitErrorType = "rate_limit_error" | |
| -) | |
| - | |
| -func (r BetaRateLimitErrorType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRateLimitErrorTypeRateLimitError: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| diff --git a/betamessage.go b/betamessage.go | |
| index 8e8a4b0..e03467c 100644 | |
| --- a/betamessage.go | |
| +++ b/betamessage.go | |
| @@ -4,15 +4,18 @@ package anthropic | |
| import ( | |
| "context" | |
| + "encoding/json" | |
| "fmt" | |
| "net/http" | |
| "reflect" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apijson" | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| "github.com/anthropics/anthropic-sdk-go/internal/requestconfig" | |
| "github.com/anthropics/anthropic-sdk-go/option" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| "github.com/anthropics/anthropic-sdk-go/packages/ssestream" | |
| + "github.com/anthropics/anthropic-sdk-go/shared/constant" | |
| "github.com/tidwall/gjson" | |
| ) | |
| @@ -24,14 +27,14 @@ import ( | |
| // the [NewBetaMessageService] method instead. | |
| type BetaMessageService struct { | |
| Options []option.RequestOption | |
| - Batches *BetaMessageBatchService | |
| + Batches BetaMessageBatchService | |
| } | |
| // NewBetaMessageService 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 NewBetaMessageService(opts ...option.RequestOption) (r *BetaMessageService) { | |
| - r = &BetaMessageService{} | |
| +func NewBetaMessageService(opts ...option.RequestOption) (r BetaMessageService) { | |
| + r = BetaMessageService{} | |
| r.Options = opts | |
| r.Batches = NewBetaMessageBatchService(opts...) | |
| return | |
| @@ -47,23 +50,12 @@ func NewBetaMessageService(opts ...option.RequestOption) (r *BetaMessageService) | |
| // | |
| // Note: If you choose to set a timeout for this request, we recommend 10 minutes. | |
| func (r *BetaMessageService) New(ctx context.Context, params BetaMessageNewParams, opts ...option.RequestOption) (res *BetaMessage, err error) { | |
| - for _, v := range params.Betas.Value { | |
| + for _, v := range params.Betas { | |
| opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%s", v))) | |
| } | |
| opts = append(r.Options[:], opts...) | |
| path := "v1/messages?beta=true" | |
| - | |
| - cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodPost, path, params, &res, opts...) | |
| - if err != nil { | |
| - return | |
| - } | |
| - | |
| - err = checkLongRequest(ctx, cfg, int(params.MaxTokens.Value)) | |
| - if err != nil { | |
| - return | |
| - } | |
| - | |
| - err = cfg.Execute() | |
| + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...) | |
| return | |
| } | |
| @@ -76,19 +68,19 @@ func (r *BetaMessageService) New(ctx context.Context, params BetaMessageNewParam | |
| // Learn more about the Messages API in our [user guide](/en/docs/initial-setup) | |
| // | |
| // Note: If you choose to set a timeout for this request, we recommend 10 minutes. | |
| -func (r *BetaMessageService) NewStreaming(ctx context.Context, params BetaMessageNewParams, opts ...option.RequestOption) (stream *ssestream.Stream[BetaRawMessageStreamEvent]) { | |
| +func (r *BetaMessageService) NewStreaming(ctx context.Context, params BetaMessageNewParams, opts ...option.RequestOption) (stream *ssestream.Stream[BetaRawMessageStreamEventUnion]) { | |
| var ( | |
| raw *http.Response | |
| err error | |
| ) | |
| - for _, v := range params.Betas.Value { | |
| + for _, v := range params.Betas { | |
| opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%s", v))) | |
| } | |
| opts = append(r.Options[:], opts...) | |
| opts = append([]option.RequestOption{option.WithJSONSet("stream", true)}, opts...) | |
| path := "v1/messages?beta=true" | |
| err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &raw, opts...) | |
| - return ssestream.NewStream[BetaRawMessageStreamEvent](ssestream.NewDecoder(raw), err) | |
| + return ssestream.NewStream[BetaRawMessageStreamEventUnion](ssestream.NewDecoder(raw), err) | |
| } | |
| // Count the number of tokens in a Message. | |
| @@ -99,7 +91,7 @@ func (r *BetaMessageService) NewStreaming(ctx context.Context, params BetaMessag | |
| // Learn more about token counting in our | |
| // [user guide](/en/docs/build-with-claude/token-counting) | |
| func (r *BetaMessageService) CountTokens(ctx context.Context, params BetaMessageCountTokensParams, opts ...option.RequestOption) (res *BetaMessageTokensCount, err error) { | |
| - for _, v := range params.Betas.Value { | |
| + for _, v := range params.Betas { | |
| opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%s", v))) | |
| } | |
| opts = append(r.Options[:], opts...) | |
| @@ -108,18 +100,24 @@ func (r *BetaMessageService) CountTokens(ctx context.Context, params BetaMessage | |
| return | |
| } | |
| +// The properties Data, MediaType, Type are required. | |
| type BetaBase64ImageSourceParam struct { | |
| - Data param.Field[string] `json:"data,required" format:"byte"` | |
| - MediaType param.Field[BetaBase64ImageSourceMediaType] `json:"media_type,required"` | |
| - Type param.Field[BetaBase64ImageSourceType] `json:"type,required"` | |
| + Data string `json:"data,required" format:"byte"` | |
| + // Any of "image/jpeg", "image/png", "image/gif", "image/webp". | |
| + MediaType BetaBase64ImageSourceMediaType `json:"media_type,omitzero,required"` | |
| + // This field can be elided, and will marshal its zero value as "base64". | |
| + Type constant.Base64 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaBase64ImageSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaBase64ImageSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaBase64ImageSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r BetaBase64ImageSourceParam) implementsBetaImageBlockParamSourceUnion() {} | |
| - | |
| type BetaBase64ImageSourceMediaType string | |
| const ( | |
| @@ -129,864 +127,1121 @@ const ( | |
| BetaBase64ImageSourceMediaTypeImageWebP BetaBase64ImageSourceMediaType = "image/webp" | |
| ) | |
| -func (r BetaBase64ImageSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaBase64ImageSourceMediaTypeImageJPEG, BetaBase64ImageSourceMediaTypeImagePNG, BetaBase64ImageSourceMediaTypeImageGIF, BetaBase64ImageSourceMediaTypeImageWebP: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaBase64ImageSourceType string | |
| - | |
| -const ( | |
| - BetaBase64ImageSourceTypeBase64 BetaBase64ImageSourceType = "base64" | |
| -) | |
| - | |
| -func (r BetaBase64ImageSourceType) IsKnown() bool { | |
| - switch r { | |
| - case BetaBase64ImageSourceTypeBase64: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| +// The properties Source, Type are required. | |
| type BetaBase64PDFBlockParam struct { | |
| - Source param.Field[BetaBase64PDFBlockSourceUnionParam] `json:"source,required"` | |
| - Type param.Field[BetaBase64PDFBlockType] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| - Citations param.Field[BetaCitationsConfigParam] `json:"citations"` | |
| - Context param.Field[string] `json:"context"` | |
| - Title param.Field[string] `json:"title"` | |
| -} | |
| - | |
| + Source BetaBase64PDFBlockSourceUnionParam `json:"source,omitzero,required"` | |
| + Context param.Opt[string] `json:"context,omitzero"` | |
| + Title param.Opt[string] `json:"title,omitzero"` | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + Citations BetaCitationsConfigParam `json:"citations,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "document". | |
| + Type constant.Document `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaBase64PDFBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaBase64PDFBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaBase64PDFBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r BetaBase64PDFBlockParam) implementsBetaContentBlockParamUnion() {} | |
| - | |
| -type BetaBase64PDFBlockSourceParam struct { | |
| - Type param.Field[BetaBase64PDFBlockSourceType] `json:"type,required"` | |
| - Content param.Field[interface{}] `json:"content"` | |
| - Data param.Field[string] `json:"data" format:"byte"` | |
| - MediaType param.Field[BetaBase64PDFBlockSourceMediaType] `json:"media_type"` | |
| - URL param.Field[string] `json:"url"` | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaBase64PDFBlockSourceUnionParam struct { | |
| + OfBase64PDFSource *BetaBase64PDFSourceParam `json:",omitzero,inline"` | |
| + OfPlainTextSource *BetaPlainTextSourceParam `json:",omitzero,inline"` | |
| + OfContentBlockSource *BetaContentBlockSourceParam `json:",omitzero,inline"` | |
| + OfUrlpdfSource *BetaURLPDFSourceParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -func (r BetaBase64PDFBlockSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaBase64PDFBlockSourceUnionParam) IsPresent() bool { | |
| + return !param.IsOmitted(u) && !u.IsNull() | |
| } | |
| - | |
| -func (r BetaBase64PDFBlockSourceParam) implementsBetaBase64PDFBlockSourceUnionParam() {} | |
| - | |
| -// Satisfied by [BetaBase64PDFSourceParam], [BetaPlainTextSourceParam], | |
| -// [BetaContentBlockSourceParam], [BetaURLPDFSourceParam], | |
| -// [BetaBase64PDFBlockSourceParam]. | |
| -type BetaBase64PDFBlockSourceUnionParam interface { | |
| - implementsBetaBase64PDFBlockSourceUnionParam() | |
| +func (u BetaBase64PDFBlockSourceUnionParam) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaBase64PDFBlockSourceUnionParam](u.OfBase64PDFSource, u.OfPlainTextSource, u.OfContentBlockSource, u.OfUrlpdfSource) | |
| } | |
| -type BetaBase64PDFBlockSourceType string | |
| - | |
| -const ( | |
| - BetaBase64PDFBlockSourceTypeBase64 BetaBase64PDFBlockSourceType = "base64" | |
| - BetaBase64PDFBlockSourceTypeText BetaBase64PDFBlockSourceType = "text" | |
| - BetaBase64PDFBlockSourceTypeContent BetaBase64PDFBlockSourceType = "content" | |
| - BetaBase64PDFBlockSourceTypeURL BetaBase64PDFBlockSourceType = "url" | |
| -) | |
| - | |
| -func (r BetaBase64PDFBlockSourceType) IsKnown() bool { | |
| - switch r { | |
| - case BetaBase64PDFBlockSourceTypeBase64, BetaBase64PDFBlockSourceTypeText, BetaBase64PDFBlockSourceTypeContent, BetaBase64PDFBlockSourceTypeURL: | |
| - return true | |
| +func (u *BetaBase64PDFBlockSourceUnionParam) asAny() any { | |
| + if !param.IsOmitted(u.OfBase64PDFSource) { | |
| + return u.OfBase64PDFSource | |
| + } else if !param.IsOmitted(u.OfPlainTextSource) { | |
| + return u.OfPlainTextSource | |
| + } else if !param.IsOmitted(u.OfContentBlockSource) { | |
| + return u.OfContentBlockSource | |
| + } else if !param.IsOmitted(u.OfUrlpdfSource) { | |
| + return u.OfUrlpdfSource | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaBase64PDFBlockSourceMediaType string | |
| - | |
| -const ( | |
| - BetaBase64PDFBlockSourceMediaTypeApplicationPDF BetaBase64PDFBlockSourceMediaType = "application/pdf" | |
| - BetaBase64PDFBlockSourceMediaTypeTextPlain BetaBase64PDFBlockSourceMediaType = "text/plain" | |
| -) | |
| - | |
| -func (r BetaBase64PDFBlockSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaBase64PDFBlockSourceMediaTypeApplicationPDF, BetaBase64PDFBlockSourceMediaTypeTextPlain: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaBase64PDFBlockSourceUnionParam) GetContent() *BetaContentBlockSourceContentUnionParam { | |
| + if vt := u.OfContentBlockSource; vt != nil { | |
| + return &vt.Content | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaBase64PDFBlockType string | |
| - | |
| -const ( | |
| - BetaBase64PDFBlockTypeDocument BetaBase64PDFBlockType = "document" | |
| -) | |
| - | |
| -func (r BetaBase64PDFBlockType) IsKnown() bool { | |
| - switch r { | |
| - case BetaBase64PDFBlockTypeDocument: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaBase64PDFBlockSourceUnionParam) GetURL() *string { | |
| + if vt := u.OfUrlpdfSource; vt != nil { | |
| + return &vt.URL | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaBase64PDFSourceParam struct { | |
| - Data param.Field[string] `json:"data,required" format:"byte"` | |
| - MediaType param.Field[BetaBase64PDFSourceMediaType] `json:"media_type,required"` | |
| - Type param.Field[BetaBase64PDFSourceType] `json:"type,required"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaBase64PDFBlockSourceUnionParam) GetData() *string { | |
| + if vt := u.OfBase64PDFSource; vt != nil { | |
| + return (*string)(&vt.Data) | |
| + } else if vt := u.OfPlainTextSource; vt != nil { | |
| + return (*string)(&vt.Data) | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaBase64PDFSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaBase64PDFBlockSourceUnionParam) GetMediaType() *string { | |
| + if vt := u.OfBase64PDFSource; vt != nil { | |
| + return (*string)(&vt.MediaType) | |
| + } else if vt := u.OfPlainTextSource; vt != nil { | |
| + return (*string)(&vt.MediaType) | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaBase64PDFSourceParam) implementsBetaBase64PDFBlockSourceUnionParam() {} | |
| - | |
| -type BetaBase64PDFSourceMediaType string | |
| - | |
| -const ( | |
| - BetaBase64PDFSourceMediaTypeApplicationPDF BetaBase64PDFSourceMediaType = "application/pdf" | |
| -) | |
| - | |
| -func (r BetaBase64PDFSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaBase64PDFSourceMediaTypeApplicationPDF: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaBase64PDFBlockSourceUnionParam) GetType() *string { | |
| + if vt := u.OfBase64PDFSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfPlainTextSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfContentBlockSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfUrlpdfSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaBase64PDFSourceType string | |
| +func init() { | |
| + apijson.RegisterUnion[BetaBase64PDFBlockSourceUnionParam]( | |
| + "type", | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaBase64PDFSourceParam{}), | |
| + DiscriminatorValue: "base64", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaPlainTextSourceParam{}), | |
| + DiscriminatorValue: "text", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaContentBlockSourceParam{}), | |
| + DiscriminatorValue: "content", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaURLPDFSourceParam{}), | |
| + DiscriminatorValue: "url", | |
| + }, | |
| + ) | |
| +} | |
| -const ( | |
| - BetaBase64PDFSourceTypeBase64 BetaBase64PDFSourceType = "base64" | |
| -) | |
| +// The properties Data, MediaType, Type are required. | |
| +type BetaBase64PDFSourceParam struct { | |
| + Data string `json:"data,required" format:"byte"` | |
| + // This field can be elided, and will marshal its zero value as "application/pdf". | |
| + MediaType constant.ApplicationPDF `json:"media_type,required"` | |
| + // This field can be elided, and will marshal its zero value as "base64". | |
| + Type constant.Base64 `json:"type,required"` | |
| + paramObj | |
| +} | |
| -func (r BetaBase64PDFSourceType) IsKnown() bool { | |
| - switch r { | |
| - case BetaBase64PDFSourceTypeBase64: | |
| - return true | |
| - } | |
| - return false | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaBase64PDFSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r BetaBase64PDFSourceParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaBase64PDFSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The property Type is required. | |
| type BetaCacheControlEphemeralParam struct { | |
| - Type param.Field[BetaCacheControlEphemeralType] `json:"type,required"` | |
| + // This field can be elided, and will marshal its zero value as "ephemeral". | |
| + Type constant.Ephemeral `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaCacheControlEphemeralParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaCacheControlEphemeralParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaCacheControlEphemeralParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -type BetaCacheControlEphemeralType string | |
| - | |
| -const ( | |
| - BetaCacheControlEphemeralTypeEphemeral BetaCacheControlEphemeralType = "ephemeral" | |
| -) | |
| +type BetaCitationCharLocation struct { | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + DocumentTitle string `json:"document_title,required"` | |
| + EndCharIndex int64 `json:"end_char_index,required"` | |
| + StartCharIndex int64 `json:"start_char_index,required"` | |
| + Type constant.CharLocation `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndCharIndex resp.Field | |
| + StartCharIndex resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaCitationCharLocation) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaCitationCharLocation) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r BetaCacheControlEphemeralType) IsKnown() bool { | |
| - switch r { | |
| - case BetaCacheControlEphemeralTypeEphemeral: | |
| - return true | |
| - } | |
| - return false | |
| +// The properties CitedText, DocumentIndex, DocumentTitle, EndCharIndex, | |
| +// StartCharIndex, Type are required. | |
| +type BetaCitationCharLocationParam struct { | |
| + DocumentTitle param.Opt[string] `json:"document_title,omitzero,required"` | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + EndCharIndex int64 `json:"end_char_index,required"` | |
| + StartCharIndex int64 `json:"start_char_index,required"` | |
| + // This field can be elided, and will marshal its zero value as "char_location". | |
| + Type constant.CharLocation `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaCitationCharLocationParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r BetaCitationCharLocationParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaCitationCharLocationParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -type BetaCitationCharLocation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - EndCharIndex int64 `json:"end_char_index,required"` | |
| - StartCharIndex int64 `json:"start_char_index,required"` | |
| - Type BetaCitationCharLocationType `json:"type,required"` | |
| - JSON betaCitationCharLocationJSON `json:"-"` | |
| -} | |
| - | |
| -// betaCitationCharLocationJSON contains the JSON metadata for the struct | |
| -// [BetaCitationCharLocation] | |
| -type betaCitationCharLocationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - EndCharIndex apijson.Field | |
| - StartCharIndex apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaCitationCharLocation) UnmarshalJSON(data []byte) (err error) { | |
| +type BetaCitationContentBlockLocation struct { | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + DocumentTitle string `json:"document_title,required"` | |
| + EndBlockIndex int64 `json:"end_block_index,required"` | |
| + StartBlockIndex int64 `json:"start_block_index,required"` | |
| + Type constant.ContentBlockLocation `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndBlockIndex resp.Field | |
| + StartBlockIndex resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaCitationContentBlockLocation) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaCitationContentBlockLocation) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaCitationCharLocationJSON) RawJSON() string { | |
| - return r.raw | |
| +// The properties CitedText, DocumentIndex, DocumentTitle, EndBlockIndex, | |
| +// StartBlockIndex, Type are required. | |
| +type BetaCitationContentBlockLocationParam struct { | |
| + DocumentTitle param.Opt[string] `json:"document_title,omitzero,required"` | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + EndBlockIndex int64 `json:"end_block_index,required"` | |
| + StartBlockIndex int64 `json:"start_block_index,required"` | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "content_block_location". | |
| + Type constant.ContentBlockLocation `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaCitationContentBlockLocationParam) IsPresent() bool { | |
| + return !param.IsOmitted(f) && !f.IsNull() | |
| +} | |
| +func (r BetaCitationContentBlockLocationParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaCitationContentBlockLocationParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r BetaCitationCharLocation) implementsBetaCitationsDeltaCitation() {} | |
| +type BetaCitationPageLocation struct { | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + DocumentTitle string `json:"document_title,required"` | |
| + EndPageNumber int64 `json:"end_page_number,required"` | |
| + StartPageNumber int64 `json:"start_page_number,required"` | |
| + Type constant.PageLocation `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndPageNumber resp.Field | |
| + StartPageNumber resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaCitationPageLocation) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaCitationPageLocation) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r BetaCitationCharLocation) implementsBetaTextCitation() {} | |
| +// The properties CitedText, DocumentIndex, DocumentTitle, EndPageNumber, | |
| +// StartPageNumber, Type are required. | |
| +type BetaCitationPageLocationParam struct { | |
| + DocumentTitle param.Opt[string] `json:"document_title,omitzero,required"` | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + EndPageNumber int64 `json:"end_page_number,required"` | |
| + StartPageNumber int64 `json:"start_page_number,required"` | |
| + // This field can be elided, and will marshal its zero value as "page_location". | |
| + Type constant.PageLocation `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaCitationPageLocationParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r BetaCitationPageLocationParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaCitationPageLocationParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| +} | |
| -type BetaCitationCharLocationType string | |
| +type BetaCitationsConfigParam struct { | |
| + Enabled param.Opt[bool] `json:"enabled,omitzero"` | |
| + paramObj | |
| +} | |
| -const ( | |
| - BetaCitationCharLocationTypeCharLocation BetaCitationCharLocationType = "char_location" | |
| -) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaCitationsConfigParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r BetaCitationsConfigParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaCitationsConfigParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| +} | |
| -func (r BetaCitationCharLocationType) IsKnown() bool { | |
| - switch r { | |
| - case BetaCitationCharLocationTypeCharLocation: | |
| - return true | |
| - } | |
| - return false | |
| +type BetaCitationsDelta struct { | |
| + Citation BetaCitationsDeltaCitationUnion `json:"citation,required"` | |
| + Type constant.CitationsDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Citation resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaCitationsDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaCitationsDelta) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -type BetaCitationCharLocationParam struct { | |
| - CitedText param.Field[string] `json:"cited_text,required"` | |
| - DocumentIndex param.Field[int64] `json:"document_index,required"` | |
| - DocumentTitle param.Field[string] `json:"document_title,required"` | |
| - EndCharIndex param.Field[int64] `json:"end_char_index,required"` | |
| - StartCharIndex param.Field[int64] `json:"start_char_index,required"` | |
| - Type param.Field[BetaCitationCharLocationParamType] `json:"type,required"` | |
| +// BetaCitationsDeltaCitationUnion contains all possible properties and values from | |
| +// [BetaCitationCharLocation], [BetaCitationPageLocation], | |
| +// [BetaCitationContentBlockLocation]. | |
| +// | |
| +// Use the [BetaCitationsDeltaCitationUnion.AsAny] method to switch on the variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type BetaCitationsDeltaCitationUnion struct { | |
| + CitedText string `json:"cited_text"` | |
| + DocumentIndex int64 `json:"document_index"` | |
| + DocumentTitle string `json:"document_title"` | |
| + // This field is from variant [BetaCitationCharLocation]. | |
| + EndCharIndex int64 `json:"end_char_index"` | |
| + // This field is from variant [BetaCitationCharLocation]. | |
| + StartCharIndex int64 `json:"start_char_index"` | |
| + // Any of "char_location", "page_location", "content_block_location". | |
| + Type string `json:"type"` | |
| + // This field is from variant [BetaCitationPageLocation]. | |
| + EndPageNumber int64 `json:"end_page_number"` | |
| + // This field is from variant [BetaCitationPageLocation]. | |
| + StartPageNumber int64 `json:"start_page_number"` | |
| + // This field is from variant [BetaCitationContentBlockLocation]. | |
| + EndBlockIndex int64 `json:"end_block_index"` | |
| + // This field is from variant [BetaCitationContentBlockLocation]. | |
| + StartBlockIndex int64 `json:"start_block_index"` | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndCharIndex resp.Field | |
| + StartCharIndex resp.Field | |
| + Type resp.Field | |
| + EndPageNumber resp.Field | |
| + StartPageNumber resp.Field | |
| + EndBlockIndex resp.Field | |
| + StartBlockIndex resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := BetaCitationsDeltaCitationUnion.AsAny().(type) { | |
| +// case BetaCitationCharLocation: | |
| +// case BetaCitationPageLocation: | |
| +// case BetaCitationContentBlockLocation: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u BetaCitationsDeltaCitationUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "char_location": | |
| + return u.AsResponseCharLocationCitation() | |
| + case "page_location": | |
| + return u.AsResponsePageLocationCitation() | |
| + case "content_block_location": | |
| + return u.AsResponseContentBlockLocationCitation() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +func (u BetaCitationsDeltaCitationUnion) AsResponseCharLocationCitation() (v BetaCitationCharLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r BetaCitationCharLocationParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +func (u BetaCitationsDeltaCitationUnion) AsResponsePageLocationCitation() (v BetaCitationPageLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r BetaCitationCharLocationParam) implementsBetaTextCitationParamUnion() {} | |
| +func (u BetaCitationsDeltaCitationUnion) AsResponseContentBlockLocationCitation() (v BetaCitationContentBlockLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| +} | |
| -type BetaCitationCharLocationParamType string | |
| +// Returns the unmodified JSON received from the API | |
| +func (u BetaCitationsDeltaCitationUnion) RawJSON() string { return u.JSON.raw } | |
| -const ( | |
| - BetaCitationCharLocationParamTypeCharLocation BetaCitationCharLocationParamType = "char_location" | |
| -) | |
| +func (r *BetaCitationsDeltaCitationUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r BetaCitationCharLocationParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaCitationCharLocationParamTypeCharLocation: | |
| - return true | |
| - } | |
| - return false | |
| +// BetaContentBlockUnion contains all possible properties and values from | |
| +// [BetaTextBlock], [BetaToolUseBlock], [BetaThinkingBlock], | |
| +// [BetaRedactedThinkingBlock]. | |
| +// | |
| +// Use the [BetaContentBlockUnion.AsAny] method to switch on the variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type BetaContentBlockUnion struct { | |
| + // This field is from variant [BetaTextBlock]. | |
| + Citations []BetaTextCitationUnion `json:"citations"` | |
| + // This field is from variant [BetaTextBlock]. | |
| + Text string `json:"text"` | |
| + // Any of "text", "tool_use", "thinking", "redacted_thinking". | |
| + Type string `json:"type"` | |
| + // This field is from variant [BetaToolUseBlock]. | |
| + ID string `json:"id"` | |
| + // This field is from variant [BetaToolUseBlock]. | |
| + Input interface{} `json:"input"` | |
| + // This field is from variant [BetaToolUseBlock]. | |
| + Name string `json:"name"` | |
| + // This field is from variant [BetaThinkingBlock]. | |
| + Signature string `json:"signature"` | |
| + // This field is from variant [BetaThinkingBlock]. | |
| + Thinking string `json:"thinking"` | |
| + // This field is from variant [BetaRedactedThinkingBlock]. | |
| + Data string `json:"data"` | |
| + JSON struct { | |
| + Citations resp.Field | |
| + Text resp.Field | |
| + Type resp.Field | |
| + ID resp.Field | |
| + Input resp.Field | |
| + Name resp.Field | |
| + Signature resp.Field | |
| + Thinking resp.Field | |
| + Data resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +func (r BetaContentBlockUnion) ToParam() BetaContentBlockParamUnion { | |
| + switch variant := r.AsAny().(type) { | |
| + case BetaTextBlock: | |
| + p := variant.ToParam() | |
| + return BetaContentBlockParamUnion{OfRequestTextBlock: &p} | |
| + case BetaToolUseBlock: | |
| + p := variant.ToParam() | |
| + return BetaContentBlockParamUnion{OfRequestToolUseBlock: &p} | |
| + case BetaThinkingBlock: | |
| + p := variant.ToParam() | |
| + return BetaContentBlockParamUnion{OfRequestThinkingBlock: &p} | |
| + case BetaRedactedThinkingBlock: | |
| + p := variant.ToParam() | |
| + return BetaContentBlockParamUnion{OfRequestRedactedThinkingBlock: &p} | |
| + } | |
| + return BetaContentBlockParamUnion{} | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := BetaContentBlockUnion.AsAny().(type) { | |
| +// case BetaTextBlock: | |
| +// case BetaToolUseBlock: | |
| +// case BetaThinkingBlock: | |
| +// case BetaRedactedThinkingBlock: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u BetaContentBlockUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "text": | |
| + return u.AsResponseTextBlock() | |
| + case "tool_use": | |
| + return u.AsResponseToolUseBlock() | |
| + case "thinking": | |
| + return u.AsResponseThinkingBlock() | |
| + case "redacted_thinking": | |
| + return u.AsResponseRedactedThinkingBlock() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +func (u BetaContentBlockUnion) AsResponseTextBlock() (v BetaTextBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaCitationContentBlockLocation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - EndBlockIndex int64 `json:"end_block_index,required"` | |
| - StartBlockIndex int64 `json:"start_block_index,required"` | |
| - Type BetaCitationContentBlockLocationType `json:"type,required"` | |
| - JSON betaCitationContentBlockLocationJSON `json:"-"` | |
| -} | |
| - | |
| -// betaCitationContentBlockLocationJSON contains the JSON metadata for the struct | |
| -// [BetaCitationContentBlockLocation] | |
| -type betaCitationContentBlockLocationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - EndBlockIndex apijson.Field | |
| - StartBlockIndex apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaCitationContentBlockLocation) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +func (u BetaContentBlockUnion) AsResponseToolUseBlock() (v BetaToolUseBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r betaCitationContentBlockLocationJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u BetaContentBlockUnion) AsResponseThinkingBlock() (v BetaThinkingBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r BetaCitationContentBlockLocation) implementsBetaCitationsDeltaCitation() {} | |
| +func (u BetaContentBlockUnion) AsResponseRedactedThinkingBlock() (v BetaRedactedThinkingBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| +} | |
| -func (r BetaCitationContentBlockLocation) implementsBetaTextCitation() {} | |
| +// Returns the unmodified JSON received from the API | |
| +func (u BetaContentBlockUnion) RawJSON() string { return u.JSON.raw } | |
| -type BetaCitationContentBlockLocationType string | |
| +func (r *BetaContentBlockUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -const ( | |
| - BetaCitationContentBlockLocationTypeContentBlockLocation BetaCitationContentBlockLocationType = "content_block_location" | |
| -) | |
| +func BetaContentBlockParamOfRequestTextBlock(text string) BetaContentBlockParamUnion { | |
| + var variant BetaTextBlockParam | |
| + variant.Text = text | |
| + return BetaContentBlockParamUnion{OfRequestTextBlock: &variant} | |
| +} | |
| -func (r BetaCitationContentBlockLocationType) IsKnown() bool { | |
| - switch r { | |
| - case BetaCitationContentBlockLocationTypeContentBlockLocation: | |
| - return true | |
| +func BetaContentBlockParamOfRequestImageBlock[ | |
| + T BetaBase64ImageSourceParam | BetaURLImageSourceParam, | |
| +](source T) BetaContentBlockParamUnion { | |
| + var variant BetaImageBlockParam | |
| + switch v := any(source).(type) { | |
| + case BetaBase64ImageSourceParam: | |
| + variant.Source.OfBase64ImageSource = &v | |
| + case BetaURLImageSourceParam: | |
| + variant.Source.OfURLImageSource = &v | |
| } | |
| - return false | |
| + return BetaContentBlockParamUnion{OfRequestImageBlock: &variant} | |
| } | |
| -type BetaCitationContentBlockLocationParam struct { | |
| - CitedText param.Field[string] `json:"cited_text,required"` | |
| - DocumentIndex param.Field[int64] `json:"document_index,required"` | |
| - DocumentTitle param.Field[string] `json:"document_title,required"` | |
| - EndBlockIndex param.Field[int64] `json:"end_block_index,required"` | |
| - StartBlockIndex param.Field[int64] `json:"start_block_index,required"` | |
| - Type param.Field[BetaCitationContentBlockLocationParamType] `json:"type,required"` | |
| +func BetaContentBlockParamOfRequestToolUseBlock(id string, input interface{}, name string) BetaContentBlockParamUnion { | |
| + var variant BetaToolUseBlockParam | |
| + variant.ID = id | |
| + variant.Input = input | |
| + variant.Name = name | |
| + return BetaContentBlockParamUnion{OfRequestToolUseBlock: &variant} | |
| } | |
| -func (r BetaCitationContentBlockLocationParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +func BetaContentBlockParamOfRequestToolResultBlock(toolUseID string) BetaContentBlockParamUnion { | |
| + var variant BetaToolResultBlockParam | |
| + variant.ToolUseID = toolUseID | |
| + return BetaContentBlockParamUnion{OfRequestToolResultBlock: &variant} | |
| } | |
| -func (r BetaCitationContentBlockLocationParam) implementsBetaTextCitationParamUnion() {} | |
| - | |
| -type BetaCitationContentBlockLocationParamType string | |
| - | |
| -const ( | |
| - BetaCitationContentBlockLocationParamTypeContentBlockLocation BetaCitationContentBlockLocationParamType = "content_block_location" | |
| -) | |
| - | |
| -func (r BetaCitationContentBlockLocationParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaCitationContentBlockLocationParamTypeContentBlockLocation: | |
| - return true | |
| +func BetaContentBlockParamOfRequestDocumentBlock[ | |
| + T BetaBase64PDFSourceParam | BetaPlainTextSourceParam | BetaContentBlockSourceParam | BetaURLPDFSourceParam, | |
| +](source T) BetaContentBlockParamUnion { | |
| + var variant BetaBase64PDFBlockParam | |
| + switch v := any(source).(type) { | |
| + case BetaBase64PDFSourceParam: | |
| + variant.Source.OfBase64PDFSource = &v | |
| + case BetaPlainTextSourceParam: | |
| + variant.Source.OfPlainTextSource = &v | |
| + case BetaContentBlockSourceParam: | |
| + variant.Source.OfContentBlockSource = &v | |
| + case BetaURLPDFSourceParam: | |
| + variant.Source.OfUrlpdfSource = &v | |
| } | |
| - return false | |
| + return BetaContentBlockParamUnion{OfRequestDocumentBlock: &variant} | |
| } | |
| -type BetaCitationPageLocation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - EndPageNumber int64 `json:"end_page_number,required"` | |
| - StartPageNumber int64 `json:"start_page_number,required"` | |
| - Type BetaCitationPageLocationType `json:"type,required"` | |
| - JSON betaCitationPageLocationJSON `json:"-"` | |
| -} | |
| - | |
| -// betaCitationPageLocationJSON contains the JSON metadata for the struct | |
| -// [BetaCitationPageLocation] | |
| -type betaCitationPageLocationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - EndPageNumber apijson.Field | |
| - StartPageNumber apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaCitationPageLocation) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +func BetaContentBlockParamOfRequestThinkingBlock(signature string, thinking string) BetaContentBlockParamUnion { | |
| + var variant BetaThinkingBlockParam | |
| + variant.Signature = signature | |
| + variant.Thinking = thinking | |
| + return BetaContentBlockParamUnion{OfRequestThinkingBlock: &variant} | |
| } | |
| -func (r betaCitationPageLocationJSON) RawJSON() string { | |
| - return r.raw | |
| +func BetaContentBlockParamOfRequestRedactedThinkingBlock(data string) BetaContentBlockParamUnion { | |
| + var variant BetaRedactedThinkingBlockParam | |
| + variant.Data = data | |
| + return BetaContentBlockParamUnion{OfRequestRedactedThinkingBlock: &variant} | |
| } | |
| -func (r BetaCitationPageLocation) implementsBetaCitationsDeltaCitation() {} | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaContentBlockParamUnion struct { | |
| + OfRequestTextBlock *BetaTextBlockParam `json:",omitzero,inline"` | |
| + OfRequestImageBlock *BetaImageBlockParam `json:",omitzero,inline"` | |
| + OfRequestToolUseBlock *BetaToolUseBlockParam `json:",omitzero,inline"` | |
| + OfRequestToolResultBlock *BetaToolResultBlockParam `json:",omitzero,inline"` | |
| + OfRequestDocumentBlock *BetaBase64PDFBlockParam `json:",omitzero,inline"` | |
| + OfRequestThinkingBlock *BetaThinkingBlockParam `json:",omitzero,inline"` | |
| + OfRequestRedactedThinkingBlock *BetaRedactedThinkingBlockParam `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| -func (r BetaCitationPageLocation) implementsBetaTextCitation() {} | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaContentBlockParamUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u BetaContentBlockParamUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaContentBlockParamUnion](u.OfRequestTextBlock, | |
| + u.OfRequestImageBlock, | |
| + u.OfRequestToolUseBlock, | |
| + u.OfRequestToolResultBlock, | |
| + u.OfRequestDocumentBlock, | |
| + u.OfRequestThinkingBlock, | |
| + u.OfRequestRedactedThinkingBlock) | |
| +} | |
| -type BetaCitationPageLocationType string | |
| +func (u *BetaContentBlockParamUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfRequestTextBlock) { | |
| + return u.OfRequestTextBlock | |
| + } else if !param.IsOmitted(u.OfRequestImageBlock) { | |
| + return u.OfRequestImageBlock | |
| + } else if !param.IsOmitted(u.OfRequestToolUseBlock) { | |
| + return u.OfRequestToolUseBlock | |
| + } else if !param.IsOmitted(u.OfRequestToolResultBlock) { | |
| + return u.OfRequestToolResultBlock | |
| + } else if !param.IsOmitted(u.OfRequestDocumentBlock) { | |
| + return u.OfRequestDocumentBlock | |
| + } else if !param.IsOmitted(u.OfRequestThinkingBlock) { | |
| + return u.OfRequestThinkingBlock | |
| + } else if !param.IsOmitted(u.OfRequestRedactedThinkingBlock) { | |
| + return u.OfRequestRedactedThinkingBlock | |
| + } | |
| + return nil | |
| +} | |
| -const ( | |
| - BetaCitationPageLocationTypePageLocation BetaCitationPageLocationType = "page_location" | |
| -) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetText() *string { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return &vt.Text | |
| + } | |
| + return nil | |
| +} | |
| -func (r BetaCitationPageLocationType) IsKnown() bool { | |
| - switch r { | |
| - case BetaCitationPageLocationTypePageLocation: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetID() *string { | |
| + if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return &vt.ID | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaCitationPageLocationParam struct { | |
| - CitedText param.Field[string] `json:"cited_text,required"` | |
| - DocumentIndex param.Field[int64] `json:"document_index,required"` | |
| - DocumentTitle param.Field[string] `json:"document_title,required"` | |
| - EndPageNumber param.Field[int64] `json:"end_page_number,required"` | |
| - StartPageNumber param.Field[int64] `json:"start_page_number,required"` | |
| - Type param.Field[BetaCitationPageLocationParamType] `json:"type,required"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetInput() *interface{} { | |
| + if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return &vt.Input | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaCitationPageLocationParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetName() *string { | |
| + if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return &vt.Name | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaCitationPageLocationParam) implementsBetaTextCitationParamUnion() {} | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetToolUseID() *string { | |
| + if vt := u.OfRequestToolResultBlock; vt != nil { | |
| + return &vt.ToolUseID | |
| + } | |
| + return nil | |
| +} | |
| -type BetaCitationPageLocationParamType string | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetContent() *[]BetaToolResultBlockParamContentUnion { | |
| + if vt := u.OfRequestToolResultBlock; vt != nil { | |
| + return &vt.Content | |
| + } | |
| + return nil | |
| +} | |
| -const ( | |
| - BetaCitationPageLocationParamTypePageLocation BetaCitationPageLocationParamType = "page_location" | |
| -) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetIsError() *bool { | |
| + if vt := u.OfRequestToolResultBlock; vt != nil && vt.IsError.IsPresent() { | |
| + return &vt.IsError.Value | |
| + } | |
| + return nil | |
| +} | |
| -func (r BetaCitationPageLocationParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaCitationPageLocationParamTypePageLocation: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetContext() *string { | |
| + if vt := u.OfRequestDocumentBlock; vt != nil && vt.Context.IsPresent() { | |
| + return &vt.Context.Value | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaCitationsConfigParam struct { | |
| - Enabled param.Field[bool] `json:"enabled"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetTitle() *string { | |
| + if vt := u.OfRequestDocumentBlock; vt != nil && vt.Title.IsPresent() { | |
| + return &vt.Title.Value | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaCitationsConfigParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetSignature() *string { | |
| + if vt := u.OfRequestThinkingBlock; vt != nil { | |
| + return &vt.Signature | |
| + } | |
| + return nil | |
| } | |
| -type BetaCitationsDelta struct { | |
| - Citation BetaCitationsDeltaCitation `json:"citation,required"` | |
| - Type BetaCitationsDeltaType `json:"type,required"` | |
| - JSON betaCitationsDeltaJSON `json:"-"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetThinking() *string { | |
| + if vt := u.OfRequestThinkingBlock; vt != nil { | |
| + return &vt.Thinking | |
| + } | |
| + return nil | |
| } | |
| -// betaCitationsDeltaJSON contains the JSON metadata for the struct | |
| -// [BetaCitationsDelta] | |
| -type betaCitationsDeltaJSON struct { | |
| - Citation apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetData() *string { | |
| + if vt := u.OfRequestRedactedThinkingBlock; vt != nil { | |
| + return &vt.Data | |
| + } | |
| + return nil | |
| } | |
| -func (r *BetaCitationsDelta) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaContentBlockParamUnion) GetType() *string { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestImageBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestToolResultBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestDocumentBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestThinkingBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestRedactedThinkingBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| -func (r betaCitationsDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| +// Returns a pointer to the underlying variant's CacheControl property, if present. | |
| +func (u BetaContentBlockParamUnion) GetCacheControl() *BetaCacheControlEphemeralParam { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestImageBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestToolResultBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestDocumentBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaCitationsDelta) implementsBetaRawContentBlockDeltaEventDelta() {} | |
| +// Returns a subunion which exports methods to access subproperties | |
| +// | |
| +// Or use AsAny() to get the underlying value | |
| +func (u BetaContentBlockParamUnion) GetCitations() (res betaContentBlockParamUnionCitations) { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + res.ofBetaTextBlockCitations = &vt.Citations | |
| + } else if vt := u.OfRequestDocumentBlock; vt != nil { | |
| + res.ofBetaCitationsConfig = &vt.Citations | |
| + } | |
| + return | |
| +} | |
| -type BetaCitationsDeltaCitation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - Type BetaCitationsDeltaCitationType `json:"type,required"` | |
| - EndBlockIndex int64 `json:"end_block_index"` | |
| - EndCharIndex int64 `json:"end_char_index"` | |
| - EndPageNumber int64 `json:"end_page_number"` | |
| - StartBlockIndex int64 `json:"start_block_index"` | |
| - StartCharIndex int64 `json:"start_char_index"` | |
| - StartPageNumber int64 `json:"start_page_number"` | |
| - JSON betaCitationsDeltaCitationJSON `json:"-"` | |
| - union BetaCitationsDeltaCitationUnion | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type betaContentBlockParamUnionCitations struct { | |
| + ofBetaTextBlockCitations *[]BetaTextCitationParamUnion | |
| + ofBetaCitationsConfig *BetaCitationsConfigParam | |
| } | |
| -// betaCitationsDeltaCitationJSON contains the JSON metadata for the struct | |
| -// [BetaCitationsDeltaCitation] | |
| -type betaCitationsDeltaCitationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - Type apijson.Field | |
| - EndBlockIndex apijson.Field | |
| - EndCharIndex apijson.Field | |
| - EndPageNumber apijson.Field | |
| - StartBlockIndex apijson.Field | |
| - StartCharIndex apijson.Field | |
| - StartPageNumber apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +// Use the following switch statement to get the type of the union: | |
| +// | |
| +// switch u.AsAny().(type) { | |
| +// case *[]anthropic.BetaTextCitationParamUnion: | |
| +// case *anthropic.BetaCitationsConfigParam: | |
| +// default: | |
| +// fmt.Errorf("not present") | |
| +// } | |
| +func (u betaContentBlockParamUnionCitations) AsAny() any { | |
| + if !param.IsOmitted(u.ofBetaTextBlockCitations) { | |
| + return u.ofBetaTextBlockCitations | |
| + } else if !param.IsOmitted(u.ofBetaCitationsConfig) { | |
| + return u.ofBetaCitationsConfig | |
| + } | |
| + return nil | |
| } | |
| -func (r betaCitationsDeltaCitationJSON) RawJSON() string { | |
| - return r.raw | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u betaContentBlockParamUnionCitations) GetEnabled() *bool { | |
| + if vt := u.ofBetaCitationsConfig; vt != nil && vt.Enabled.IsPresent() { | |
| + return &vt.Enabled.Value | |
| + } | |
| + return nil | |
| } | |
| -func (r *BetaCitationsDeltaCitation) UnmarshalJSON(data []byte) (err error) { | |
| - *r = BetaCitationsDeltaCitation{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| +// Returns a subunion which exports methods to access subproperties | |
| +// | |
| +// Or use AsAny() to get the underlying value | |
| +func (u BetaContentBlockParamUnion) GetSource() (res betaContentBlockParamUnionSource) { | |
| + if vt := u.OfRequestImageBlock; vt != nil { | |
| + res.ofBetaImageBlockSource = &vt.Source | |
| + } else if vt := u.OfRequestDocumentBlock; vt != nil { | |
| + res.ofBetaBase64PDFBlockSourceUnion = &vt.Source | |
| } | |
| - return apijson.Port(r.union, &r) | |
| + return | |
| } | |
| -// AsUnion returns a [BetaCitationsDeltaCitationUnion] interface which you can cast | |
| -// to the specific types for more type safety. | |
| +// Only one field can be non-zero. | |
| // | |
| -// Possible runtime types of the union are [BetaCitationCharLocation], | |
| -// [BetaCitationPageLocation], [BetaCitationContentBlockLocation]. | |
| -func (r BetaCitationsDeltaCitation) AsUnion() BetaCitationsDeltaCitationUnion { | |
| - return r.union | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type betaContentBlockParamUnionSource struct { | |
| + ofBetaImageBlockSource *BetaImageBlockParamSourceUnion | |
| + ofBetaBase64PDFBlockSourceUnion *BetaBase64PDFBlockSourceUnionParam | |
| } | |
| -// Union satisfied by [BetaCitationCharLocation], [BetaCitationPageLocation] or | |
| -// [BetaCitationContentBlockLocation]. | |
| -type BetaCitationsDeltaCitationUnion interface { | |
| - implementsBetaCitationsDeltaCitation() | |
| +// Use the following switch statement to get the type of the union: | |
| +// | |
| +// switch u.AsAny().(type) { | |
| +// case *anthropic.BetaBase64ImageSourceParam: | |
| +// case *anthropic.BetaURLImageSourceParam: | |
| +// case *anthropic.BetaBase64PDFSourceParam: | |
| +// case *anthropic.BetaPlainTextSourceParam: | |
| +// case *anthropic.BetaContentBlockSourceParam: | |
| +// case *anthropic.BetaURLPDFSourceParam: | |
| +// default: | |
| +// fmt.Errorf("not present") | |
| +// } | |
| +func (u betaContentBlockParamUnionSource) AsAny() any { | |
| + if !param.IsOmitted(u.ofBetaImageBlockSource) { | |
| + return u.ofBetaImageBlockSource.asAny() | |
| + } else if !param.IsOmitted(u.ofBetaBase64PDFBlockSourceUnion) { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.asAny() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u betaContentBlockParamUnionSource) GetContent() *BetaContentBlockSourceContentUnionParam { | |
| + if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetContent() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u betaContentBlockParamUnionSource) GetData() *string { | |
| + if u.ofBetaImageBlockSource != nil { | |
| + return u.ofBetaImageBlockSource.GetData() | |
| + } else if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetData() | |
| + } else if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetData() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u betaContentBlockParamUnionSource) GetMediaType() *string { | |
| + if u.ofBetaImageBlockSource != nil { | |
| + return u.ofBetaImageBlockSource.GetMediaType() | |
| + } else if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetMediaType() | |
| + } else if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetMediaType() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u betaContentBlockParamUnionSource) GetType() *string { | |
| + if u.ofBetaImageBlockSource != nil { | |
| + return u.ofBetaImageBlockSource.GetType() | |
| + } else if u.ofBetaImageBlockSource != nil { | |
| + return u.ofBetaImageBlockSource.GetType() | |
| + } else if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetType() | |
| + } else if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetType() | |
| + } else if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetType() | |
| + } else if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetType() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u betaContentBlockParamUnionSource) GetURL() *string { | |
| + if u.ofBetaImageBlockSource != nil { | |
| + return u.ofBetaImageBlockSource.GetURL() | |
| + } else if u.ofBetaBase64PDFBlockSourceUnion != nil { | |
| + return u.ofBetaBase64PDFBlockSourceUnion.GetURL() | |
| + } | |
| + return nil | |
| } | |
| func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*BetaCitationsDeltaCitationUnion)(nil)).Elem(), | |
| + apijson.RegisterUnion[BetaContentBlockParamUnion]( | |
| "type", | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaCitationCharLocation{}), | |
| - DiscriminatorValue: "char_location", | |
| + Type: reflect.TypeOf(BetaTextBlockParam{}), | |
| + DiscriminatorValue: "text", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaCitationPageLocation{}), | |
| - DiscriminatorValue: "page_location", | |
| + Type: reflect.TypeOf(BetaImageBlockParam{}), | |
| + DiscriminatorValue: "image", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaCitationContentBlockLocation{}), | |
| - DiscriminatorValue: "content_block_location", | |
| + Type: reflect.TypeOf(BetaToolUseBlockParam{}), | |
| + DiscriminatorValue: "tool_use", | |
| }, | |
| - ) | |
| -} | |
| - | |
| -type BetaCitationsDeltaCitationType string | |
| - | |
| -const ( | |
| - BetaCitationsDeltaCitationTypeCharLocation BetaCitationsDeltaCitationType = "char_location" | |
| - BetaCitationsDeltaCitationTypePageLocation BetaCitationsDeltaCitationType = "page_location" | |
| - BetaCitationsDeltaCitationTypeContentBlockLocation BetaCitationsDeltaCitationType = "content_block_location" | |
| -) | |
| - | |
| -func (r BetaCitationsDeltaCitationType) IsKnown() bool { | |
| - switch r { | |
| - case BetaCitationsDeltaCitationTypeCharLocation, BetaCitationsDeltaCitationTypePageLocation, BetaCitationsDeltaCitationTypeContentBlockLocation: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaCitationsDeltaType string | |
| - | |
| -const ( | |
| - BetaCitationsDeltaTypeCitationsDelta BetaCitationsDeltaType = "citations_delta" | |
| -) | |
| - | |
| -func (r BetaCitationsDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaCitationsDeltaTypeCitationsDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaContentBlock struct { | |
| - Type BetaContentBlockType `json:"type,required"` | |
| - ID string `json:"id"` | |
| - // This field can have the runtime type of [[]BetaTextCitation]. | |
| - Citations interface{} `json:"citations"` | |
| - Data string `json:"data"` | |
| - // This field can have the runtime type of [interface{}]. | |
| - Input interface{} `json:"input"` | |
| - Name string `json:"name"` | |
| - Signature string `json:"signature"` | |
| - Text string `json:"text"` | |
| - Thinking string `json:"thinking"` | |
| - JSON betaContentBlockJSON `json:"-"` | |
| - union BetaContentBlockUnion | |
| -} | |
| - | |
| -// betaContentBlockJSON contains the JSON metadata for the struct | |
| -// [BetaContentBlock] | |
| -type betaContentBlockJSON struct { | |
| - Type apijson.Field | |
| - ID apijson.Field | |
| - Citations apijson.Field | |
| - Data apijson.Field | |
| - Input apijson.Field | |
| - Name apijson.Field | |
| - Signature apijson.Field | |
| - Text apijson.Field | |
| - Thinking apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r betaContentBlockJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r *BetaContentBlock) UnmarshalJSON(data []byte) (err error) { | |
| - *r = BetaContentBlock{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| -} | |
| - | |
| -// AsUnion returns a [BetaContentBlockUnion] interface which you can cast to the | |
| -// specific types for more type safety. | |
| -// | |
| -// Possible runtime types of the union are [BetaTextBlock], [BetaToolUseBlock], | |
| -// [BetaThinkingBlock], [BetaRedactedThinkingBlock]. | |
| -func (r BetaContentBlock) AsUnion() BetaContentBlockUnion { | |
| - return r.union | |
| -} | |
| - | |
| -// Union satisfied by [BetaTextBlock], [BetaToolUseBlock], [BetaThinkingBlock] or | |
| -// [BetaRedactedThinkingBlock]. | |
| -type BetaContentBlockUnion interface { | |
| - implementsBetaContentBlock() | |
| -} | |
| - | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*BetaContentBlockUnion)(nil)).Elem(), | |
| - "type", | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaTextBlock{}), | |
| - DiscriminatorValue: "text", | |
| + Type: reflect.TypeOf(BetaToolResultBlockParam{}), | |
| + DiscriminatorValue: "tool_result", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaToolUseBlock{}), | |
| - DiscriminatorValue: "tool_use", | |
| + Type: reflect.TypeOf(BetaBase64PDFBlockParam{}), | |
| + DiscriminatorValue: "document", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaThinkingBlock{}), | |
| + Type: reflect.TypeOf(BetaThinkingBlockParam{}), | |
| DiscriminatorValue: "thinking", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaRedactedThinkingBlock{}), | |
| + Type: reflect.TypeOf(BetaRedactedThinkingBlockParam{}), | |
| DiscriminatorValue: "redacted_thinking", | |
| }, | |
| ) | |
| } | |
| -type BetaContentBlockType string | |
| - | |
| -const ( | |
| - BetaContentBlockTypeText BetaContentBlockType = "text" | |
| - BetaContentBlockTypeToolUse BetaContentBlockType = "tool_use" | |
| - BetaContentBlockTypeThinking BetaContentBlockType = "thinking" | |
| - BetaContentBlockTypeRedactedThinking BetaContentBlockType = "redacted_thinking" | |
| -) | |
| - | |
| -func (r BetaContentBlockType) IsKnown() bool { | |
| - switch r { | |
| - case BetaContentBlockTypeText, BetaContentBlockTypeToolUse, BetaContentBlockTypeThinking, BetaContentBlockTypeRedactedThinking: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaContentBlockParam struct { | |
| - Type param.Field[BetaContentBlockParamType] `json:"type,required"` | |
| - ID param.Field[string] `json:"id"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| - Citations param.Field[interface{}] `json:"citations"` | |
| - Content param.Field[interface{}] `json:"content"` | |
| - Context param.Field[string] `json:"context"` | |
| - Data param.Field[string] `json:"data"` | |
| - Input param.Field[interface{}] `json:"input"` | |
| - IsError param.Field[bool] `json:"is_error"` | |
| - Name param.Field[string] `json:"name"` | |
| - Signature param.Field[string] `json:"signature"` | |
| - Source param.Field[interface{}] `json:"source"` | |
| - Text param.Field[string] `json:"text"` | |
| - Thinking param.Field[string] `json:"thinking"` | |
| - Title param.Field[string] `json:"title"` | |
| - ToolUseID param.Field[string] `json:"tool_use_id"` | |
| -} | |
| - | |
| -func (r BetaContentBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaContentBlockParam) implementsBetaContentBlockParamUnion() {} | |
| - | |
| -// Satisfied by [BetaTextBlockParam], [BetaImageBlockParam], | |
| -// [BetaToolUseBlockParam], [BetaToolResultBlockParam], [BetaBase64PDFBlockParam], | |
| -// [BetaThinkingBlockParam], [BetaRedactedThinkingBlockParam], | |
| -// [BetaContentBlockParam]. | |
| -type BetaContentBlockParamUnion interface { | |
| - implementsBetaContentBlockParamUnion() | |
| -} | |
| - | |
| -type BetaContentBlockParamType string | |
| - | |
| -const ( | |
| - BetaContentBlockParamTypeText BetaContentBlockParamType = "text" | |
| - BetaContentBlockParamTypeImage BetaContentBlockParamType = "image" | |
| - BetaContentBlockParamTypeToolUse BetaContentBlockParamType = "tool_use" | |
| - BetaContentBlockParamTypeToolResult BetaContentBlockParamType = "tool_result" | |
| - BetaContentBlockParamTypeDocument BetaContentBlockParamType = "document" | |
| - BetaContentBlockParamTypeThinking BetaContentBlockParamType = "thinking" | |
| - BetaContentBlockParamTypeRedactedThinking BetaContentBlockParamType = "redacted_thinking" | |
| -) | |
| - | |
| -func (r BetaContentBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaContentBlockParamTypeText, BetaContentBlockParamTypeImage, BetaContentBlockParamTypeToolUse, BetaContentBlockParamTypeToolResult, BetaContentBlockParamTypeDocument, BetaContentBlockParamTypeThinking, BetaContentBlockParamTypeRedactedThinking: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| +// The properties Content, Type are required. | |
| type BetaContentBlockSourceParam struct { | |
| - Content param.Field[BetaContentBlockSourceContentUnionParam] `json:"content,required"` | |
| - Type param.Field[BetaContentBlockSourceType] `json:"type,required"` | |
| + Content BetaContentBlockSourceContentUnionParam `json:"content,omitzero,required"` | |
| + // This field can be elided, and will marshal its zero value as "content". | |
| + Type constant.Content `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaContentBlockSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaContentBlockSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaContentBlockSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r BetaContentBlockSourceParam) implementsBetaBase64PDFBlockSourceUnionParam() {} | |
| - | |
| -// Satisfied by [shared.UnionString], | |
| -// [BetaContentBlockSourceContentBetaContentBlockSourceContentParam]. | |
| -type BetaContentBlockSourceContentUnionParam interface { | |
| - ImplementsBetaContentBlockSourceContentUnionParam() | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaContentBlockSourceContentUnionParam struct { | |
| + OfString param.Opt[string] `json:",omitzero,inline"` | |
| + OfBetaContentBlockSourceContent []BetaContentBlockSourceContentUnionParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -type BetaContentBlockSourceContentBetaContentBlockSourceContentParam []BetaContentBlockSourceContentUnionParam | |
| - | |
| -func (r BetaContentBlockSourceContentBetaContentBlockSourceContentParam) ImplementsBetaContentBlockSourceContentUnionParam() { | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaContentBlockSourceContentUnionParam) IsPresent() bool { | |
| + return !param.IsOmitted(u) && !u.IsNull() | |
| +} | |
| +func (u BetaContentBlockSourceContentUnionParam) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaContentBlockSourceContentUnionParam](u.OfString, u.OfBetaContentBlockSourceContent) | |
| } | |
| -type BetaContentBlockSourceType string | |
| - | |
| -const ( | |
| - BetaContentBlockSourceTypeContent BetaContentBlockSourceType = "content" | |
| -) | |
| - | |
| -func (r BetaContentBlockSourceType) IsKnown() bool { | |
| - switch r { | |
| - case BetaContentBlockSourceTypeContent: | |
| - return true | |
| +func (u *BetaContentBlockSourceContentUnionParam) asAny() any { | |
| + if !param.IsOmitted(u.OfString) { | |
| + return &u.OfString.Value | |
| + } else if !param.IsOmitted(u.OfBetaContentBlockSourceContent) { | |
| + return &u.OfBetaContentBlockSourceContent | |
| } | |
| - return false | |
| + return nil | |
| } | |
| +// The properties Source, Type are required. | |
| type BetaImageBlockParam struct { | |
| - Source param.Field[BetaImageBlockParamSourceUnion] `json:"source,required"` | |
| - Type param.Field[BetaImageBlockParamType] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| + Source BetaImageBlockParamSourceUnion `json:"source,omitzero,required"` | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "image". | |
| + Type constant.Image `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaImageBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaImageBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaImageBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r BetaImageBlockParam) implementsBetaContentBlockParamUnion() {} | |
| - | |
| -func (r BetaImageBlockParam) implementsBetaContentBlockSourceContentUnionParam() {} | |
| - | |
| -func (r BetaImageBlockParam) implementsBetaToolResultBlockParamContentUnion() {} | |
| - | |
| -type BetaImageBlockParamSource struct { | |
| - Type param.Field[BetaImageBlockParamSourceType] `json:"type,required"` | |
| - Data param.Field[string] `json:"data" format:"byte"` | |
| - MediaType param.Field[BetaImageBlockParamSourceMediaType] `json:"media_type"` | |
| - URL param.Field[string] `json:"url"` | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaImageBlockParamSourceUnion struct { | |
| + OfBase64ImageSource *BetaBase64ImageSourceParam `json:",omitzero,inline"` | |
| + OfURLImageSource *BetaURLImageSourceParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -func (r BetaImageBlockParamSource) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaImageBlockParamSourceUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u BetaImageBlockParamSourceUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaImageBlockParamSourceUnion](u.OfBase64ImageSource, u.OfURLImageSource) | |
| } | |
| -func (r BetaImageBlockParamSource) implementsBetaImageBlockParamSourceUnion() {} | |
| - | |
| -// Satisfied by [BetaBase64ImageSourceParam], [BetaURLImageSourceParam], | |
| -// [BetaImageBlockParamSource]. | |
| -type BetaImageBlockParamSourceUnion interface { | |
| - implementsBetaImageBlockParamSourceUnion() | |
| +func (u *BetaImageBlockParamSourceUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfBase64ImageSource) { | |
| + return u.OfBase64ImageSource | |
| + } else if !param.IsOmitted(u.OfURLImageSource) { | |
| + return u.OfURLImageSource | |
| + } | |
| + return nil | |
| } | |
| -type BetaImageBlockParamSourceType string | |
| - | |
| -const ( | |
| - BetaImageBlockParamSourceTypeBase64 BetaImageBlockParamSourceType = "base64" | |
| - BetaImageBlockParamSourceTypeURL BetaImageBlockParamSourceType = "url" | |
| -) | |
| - | |
| -func (r BetaImageBlockParamSourceType) IsKnown() bool { | |
| - switch r { | |
| - case BetaImageBlockParamSourceTypeBase64, BetaImageBlockParamSourceTypeURL: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaImageBlockParamSourceUnion) GetData() *string { | |
| + if vt := u.OfBase64ImageSource; vt != nil { | |
| + return &vt.Data | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaImageBlockParamSourceMediaType string | |
| - | |
| -const ( | |
| - BetaImageBlockParamSourceMediaTypeImageJPEG BetaImageBlockParamSourceMediaType = "image/jpeg" | |
| - BetaImageBlockParamSourceMediaTypeImagePNG BetaImageBlockParamSourceMediaType = "image/png" | |
| - BetaImageBlockParamSourceMediaTypeImageGIF BetaImageBlockParamSourceMediaType = "image/gif" | |
| - BetaImageBlockParamSourceMediaTypeImageWebP BetaImageBlockParamSourceMediaType = "image/webp" | |
| -) | |
| - | |
| -func (r BetaImageBlockParamSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaImageBlockParamSourceMediaTypeImageJPEG, BetaImageBlockParamSourceMediaTypeImagePNG, BetaImageBlockParamSourceMediaTypeImageGIF, BetaImageBlockParamSourceMediaTypeImageWebP: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaImageBlockParamSourceUnion) GetMediaType() *string { | |
| + if vt := u.OfBase64ImageSource; vt != nil { | |
| + return (*string)(&vt.MediaType) | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaImageBlockParamType string | |
| - | |
| -const ( | |
| - BetaImageBlockParamTypeImage BetaImageBlockParamType = "image" | |
| -) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaImageBlockParamSourceUnion) GetURL() *string { | |
| + if vt := u.OfURLImageSource; vt != nil { | |
| + return &vt.URL | |
| + } | |
| + return nil | |
| +} | |
| -func (r BetaImageBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaImageBlockParamTypeImage: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaImageBlockParamSourceUnion) GetType() *string { | |
| + if vt := u.OfBase64ImageSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfURLImageSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaInputJSONDelta struct { | |
| - PartialJSON string `json:"partial_json,required"` | |
| - Type BetaInputJSONDeltaType `json:"type,required"` | |
| - JSON betaInputJSONDeltaJSON `json:"-"` | |
| -} | |
| - | |
| -// betaInputJSONDeltaJSON contains the JSON metadata for the struct | |
| -// [BetaInputJSONDelta] | |
| -type betaInputJSONDeltaJSON struct { | |
| - PartialJSON apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func init() { | |
| + apijson.RegisterUnion[BetaImageBlockParamSourceUnion]( | |
| + "type", | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaBase64ImageSourceParam{}), | |
| + DiscriminatorValue: "base64", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaURLImageSourceParam{}), | |
| + DiscriminatorValue: "url", | |
| + }, | |
| + ) | |
| } | |
| -func (r *BetaInputJSONDelta) UnmarshalJSON(data []byte) (err error) { | |
| +type BetaInputJSONDelta struct { | |
| + PartialJSON string `json:"partial_json,required"` | |
| + Type constant.InputJSONDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + PartialJSON resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaInputJSONDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaInputJSONDelta) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaInputJSONDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaInputJSONDelta) implementsBetaRawContentBlockDeltaEventDelta() {} | |
| - | |
| -type BetaInputJSONDeltaType string | |
| - | |
| -const ( | |
| - BetaInputJSONDeltaTypeInputJSONDelta BetaInputJSONDeltaType = "input_json_delta" | |
| -) | |
| - | |
| -func (r BetaInputJSONDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaInputJSONDeltaTypeInputJSONDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaMessage struct { | |
| // Unique object identifier. | |
| // | |
| @@ -1026,7 +1281,7 @@ type BetaMessage struct { | |
| // ```json | |
| // [{ "type": "text", "text": "B)" }] | |
| // ``` | |
| - Content []BetaContentBlock `json:"content,required"` | |
| + Content []BetaContentBlockUnion `json:"content,required"` | |
| // The model that will complete your prompt.\n\nSee | |
| // [models](https://docs.anthropic.com/en/docs/models-overview) for additional | |
| // details and options. | |
| @@ -1034,7 +1289,7 @@ type BetaMessage struct { | |
| // Conversational role of the generated message. | |
| // | |
| // This will always be `"assistant"`. | |
| - Role BetaMessageRole `json:"role,required"` | |
| + Role constant.Assistant `json:"role,required"` | |
| // The reason that we stopped. | |
| // | |
| // This may be one the following values: | |
| @@ -1046,16 +1301,18 @@ type BetaMessage struct { | |
| // | |
| // In non-streaming mode this value is always non-null. In streaming mode, it is | |
| // null in the `message_start` event and non-null otherwise. | |
| - StopReason BetaMessageStopReason `json:"stop_reason,required,nullable"` | |
| + // | |
| + // Any of "end_turn", "max_tokens", "stop_sequence", "tool_use". | |
| + StopReason BetaMessageStopReason `json:"stop_reason,required"` | |
| // Which custom stop sequence was generated, if any. | |
| // | |
| // This value will be a non-null string if one of your custom stop sequences was | |
| // generated. | |
| - StopSequence string `json:"stop_sequence,required,nullable"` | |
| + StopSequence string `json:"stop_sequence,required"` | |
| // Object type. | |
| // | |
| // For Messages, this is always `"message"`. | |
| - Type BetaMessageType `json:"type,required"` | |
| + Type constant.Message `json:"type,required"` | |
| // Billing and rate-limit usage. | |
| // | |
| // Anthropic's API bills and rate-limits by token counts, as tokens represent the | |
| @@ -1071,47 +1328,38 @@ type BetaMessage struct { | |
| // | |
| // Total input tokens in a request is the summation of `input_tokens`, | |
| // `cache_creation_input_tokens`, and `cache_read_input_tokens`. | |
| - Usage BetaUsage `json:"usage,required"` | |
| - JSON betaMessageJSON `json:"-"` | |
| -} | |
| - | |
| -// betaMessageJSON contains the JSON metadata for the struct [BetaMessage] | |
| -type betaMessageJSON struct { | |
| - ID apijson.Field | |
| - Content apijson.Field | |
| - Model apijson.Field | |
| - Role apijson.Field | |
| - StopReason apijson.Field | |
| - StopSequence apijson.Field | |
| - Type apijson.Field | |
| - Usage apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaMessage) UnmarshalJSON(data []byte) (err error) { | |
| + Usage BetaUsage `json:"usage,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + Content resp.Field | |
| + Model resp.Field | |
| + Role resp.Field | |
| + StopReason resp.Field | |
| + StopSequence resp.Field | |
| + Type resp.Field | |
| + Usage resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaMessage) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaMessage) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaMessageJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -// Conversational role of the generated message. | |
| -// | |
| -// This will always be `"assistant"`. | |
| -type BetaMessageRole string | |
| - | |
| -const ( | |
| - BetaMessageRoleAssistant BetaMessageRole = "assistant" | |
| -) | |
| - | |
| -func (r BetaMessageRole) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageRoleAssistant: | |
| - return true | |
| +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 false | |
| + return p | |
| } | |
| // The reason that we stopped. | |
| @@ -1134,60 +1382,38 @@ const ( | |
| BetaMessageStopReasonToolUse BetaMessageStopReason = "tool_use" | |
| ) | |
| -func (r BetaMessageStopReason) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageStopReasonEndTurn, BetaMessageStopReasonMaxTokens, BetaMessageStopReasonStopSequence, BetaMessageStopReasonToolUse: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -// Object type. | |
| -// | |
| -// For Messages, this is always `"message"`. | |
| -type BetaMessageType string | |
| - | |
| -const ( | |
| - BetaMessageTypeMessage BetaMessageType = "message" | |
| -) | |
| - | |
| -func (r BetaMessageType) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageTypeMessage: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaMessageDeltaUsage struct { | |
| // The cumulative number of output tokens which were used. | |
| - OutputTokens int64 `json:"output_tokens,required"` | |
| - JSON betaMessageDeltaUsageJSON `json:"-"` | |
| -} | |
| - | |
| -// betaMessageDeltaUsageJSON contains the JSON metadata for the struct | |
| -// [BetaMessageDeltaUsage] | |
| -type betaMessageDeltaUsageJSON struct { | |
| - OutputTokens apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaMessageDeltaUsage) UnmarshalJSON(data []byte) (err error) { | |
| + OutputTokens int64 `json:"output_tokens,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + OutputTokens resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaMessageDeltaUsage) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaMessageDeltaUsage) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaMessageDeltaUsageJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| +// The properties Content, Role are required. | |
| type BetaMessageParam struct { | |
| - Content param.Field[[]BetaContentBlockParamUnion] `json:"content,required"` | |
| - Role param.Field[BetaMessageParamRole] `json:"role,required"` | |
| + Content []BetaContentBlockParamUnion `json:"content,omitzero,required"` | |
| + // Any of "user", "assistant". | |
| + Role BetaMessageParamRole `json:"role,omitzero,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaMessageParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaMessageParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type BetaMessageParamRole string | |
| @@ -1197,421 +1423,309 @@ const ( | |
| BetaMessageParamRoleAssistant BetaMessageParamRole = "assistant" | |
| ) | |
| -func (r BetaMessageParamRole) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageParamRoleUser, BetaMessageParamRoleAssistant: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaMessageTokensCount struct { | |
| // The total number of tokens across the provided list of messages, system prompt, | |
| // and tools. | |
| - InputTokens int64 `json:"input_tokens,required"` | |
| - JSON betaMessageTokensCountJSON `json:"-"` | |
| -} | |
| - | |
| -// betaMessageTokensCountJSON contains the JSON metadata for the struct | |
| -// [BetaMessageTokensCount] | |
| -type betaMessageTokensCountJSON struct { | |
| - InputTokens apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaMessageTokensCount) UnmarshalJSON(data []byte) (err error) { | |
| + InputTokens int64 `json:"input_tokens,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + InputTokens resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaMessageTokensCount) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaMessageTokensCount) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaMessageTokensCountJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| type BetaMetadataParam struct { | |
| // An external identifier for the user who is associated with the request. | |
| // | |
| // This should be a uuid, hash value, or other opaque identifier. Anthropic may use | |
| // this id to help detect abuse. Do not include any identifying information such as | |
| // name, email address, or phone number. | |
| - UserID param.Field[string] `json:"user_id"` | |
| + UserID param.Opt[string] `json:"user_id,omitzero"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMetadataParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaMetadataParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaMetadataParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties Data, MediaType, Type are required. | |
| type BetaPlainTextSourceParam struct { | |
| - Data param.Field[string] `json:"data,required"` | |
| - MediaType param.Field[BetaPlainTextSourceMediaType] `json:"media_type,required"` | |
| - Type param.Field[BetaPlainTextSourceType] `json:"type,required"` | |
| + Data string `json:"data,required"` | |
| + // This field can be elided, and will marshal its zero value as "text/plain". | |
| + MediaType constant.TextPlain `json:"media_type,required"` | |
| + // This field can be elided, and will marshal its zero value as "text". | |
| + Type constant.Text `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaPlainTextSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaPlainTextSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaPlainTextSourceParam) implementsBetaBase64PDFBlockSourceUnionParam() {} | |
| - | |
| -type BetaPlainTextSourceMediaType string | |
| - | |
| -const ( | |
| - BetaPlainTextSourceMediaTypeTextPlain BetaPlainTextSourceMediaType = "text/plain" | |
| -) | |
| - | |
| -func (r BetaPlainTextSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaPlainTextSourceMediaTypeTextPlain: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaPlainTextSourceType string | |
| - | |
| -const ( | |
| - BetaPlainTextSourceTypeText BetaPlainTextSourceType = "text" | |
| -) | |
| - | |
| -func (r BetaPlainTextSourceType) IsKnown() bool { | |
| - switch r { | |
| - case BetaPlainTextSourceTypeText: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaPlainTextSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type BetaRawContentBlockDeltaEvent struct { | |
| - Delta BetaRawContentBlockDeltaEventDelta `json:"delta,required"` | |
| - Index int64 `json:"index,required"` | |
| - Type BetaRawContentBlockDeltaEventType `json:"type,required"` | |
| - JSON betaRawContentBlockDeltaEventJSON `json:"-"` | |
| -} | |
| - | |
| -// betaRawContentBlockDeltaEventJSON contains the JSON metadata for the struct | |
| -// [BetaRawContentBlockDeltaEvent] | |
| -type betaRawContentBlockDeltaEventJSON struct { | |
| - Delta apijson.Field | |
| - Index apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaRawContentBlockDeltaEvent) UnmarshalJSON(data []byte) (err error) { | |
| + Delta BetaRawContentBlockDeltaEventDeltaUnion `json:"delta,required"` | |
| + Index int64 `json:"index,required"` | |
| + Type constant.ContentBlockDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Delta resp.Field | |
| + Index resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaRawContentBlockDeltaEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaRawContentBlockDeltaEvent) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaRawContentBlockDeltaEventJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaRawContentBlockDeltaEvent) implementsBetaRawMessageStreamEvent() {} | |
| - | |
| -type BetaRawContentBlockDeltaEventDelta struct { | |
| - Type BetaRawContentBlockDeltaEventDeltaType `json:"type,required"` | |
| - // This field can have the runtime type of [BetaCitationsDeltaCitation]. | |
| - Citation interface{} `json:"citation"` | |
| - PartialJSON string `json:"partial_json"` | |
| - Signature string `json:"signature"` | |
| - Text string `json:"text"` | |
| - Thinking string `json:"thinking"` | |
| - JSON betaRawContentBlockDeltaEventDeltaJSON `json:"-"` | |
| - union BetaRawContentBlockDeltaEventDeltaUnion | |
| -} | |
| - | |
| -// betaRawContentBlockDeltaEventDeltaJSON contains the JSON metadata for the struct | |
| -// [BetaRawContentBlockDeltaEventDelta] | |
| -type betaRawContentBlockDeltaEventDeltaJSON struct { | |
| - Type apijson.Field | |
| - Citation apijson.Field | |
| - PartialJSON apijson.Field | |
| - Signature apijson.Field | |
| - Text apijson.Field | |
| - Thinking apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r betaRawContentBlockDeltaEventDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r *BetaRawContentBlockDeltaEventDelta) UnmarshalJSON(data []byte) (err error) { | |
| - *r = BetaRawContentBlockDeltaEventDelta{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| -} | |
| - | |
| -// AsUnion returns a [BetaRawContentBlockDeltaEventDeltaUnion] interface which you | |
| -// can cast to the specific types for more type safety. | |
| +// BetaRawContentBlockDeltaEventDeltaUnion contains all possible properties and | |
| +// values from [BetaTextDelta], [BetaInputJSONDelta], [BetaCitationsDelta], | |
| +// [BetaThinkingDelta], [BetaSignatureDelta]. | |
| // | |
| -// Possible runtime types of the union are [BetaTextDelta], [BetaInputJSONDelta], | |
| -// [BetaCitationsDelta], [BetaThinkingDelta], [BetaSignatureDelta]. | |
| -func (r BetaRawContentBlockDeltaEventDelta) AsUnion() BetaRawContentBlockDeltaEventDeltaUnion { | |
| - return r.union | |
| -} | |
| - | |
| -// Union satisfied by [BetaTextDelta], [BetaInputJSONDelta], [BetaCitationsDelta], | |
| -// [BetaThinkingDelta] or [BetaSignatureDelta]. | |
| -type BetaRawContentBlockDeltaEventDeltaUnion interface { | |
| - implementsBetaRawContentBlockDeltaEventDelta() | |
| +// Use the [BetaRawContentBlockDeltaEventDeltaUnion.AsAny] method to switch on the | |
| +// variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type BetaRawContentBlockDeltaEventDeltaUnion struct { | |
| + // This field is from variant [BetaTextDelta]. | |
| + Text string `json:"text"` | |
| + // Any of "text_delta", "input_json_delta", "citations_delta", "thinking_delta", | |
| + // "signature_delta". | |
| + Type string `json:"type"` | |
| + // This field is from variant [BetaInputJSONDelta]. | |
| + PartialJSON string `json:"partial_json"` | |
| + // This field is from variant [BetaCitationsDelta]. | |
| + Citation BetaCitationsDeltaCitationUnion `json:"citation"` | |
| + // This field is from variant [BetaThinkingDelta]. | |
| + Thinking string `json:"thinking"` | |
| + // This field is from variant [BetaSignatureDelta]. | |
| + Signature string `json:"signature"` | |
| + JSON struct { | |
| + Text resp.Field | |
| + Type resp.Field | |
| + PartialJSON resp.Field | |
| + Citation resp.Field | |
| + Thinking resp.Field | |
| + Signature resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := BetaRawContentBlockDeltaEventDeltaUnion.AsAny().(type) { | |
| +// case BetaTextDelta: | |
| +// case BetaInputJSONDelta: | |
| +// case BetaCitationsDelta: | |
| +// case BetaThinkingDelta: | |
| +// case BetaSignatureDelta: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u BetaRawContentBlockDeltaEventDeltaUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "text_delta": | |
| + return u.AsTextContentBlockDelta() | |
| + case "input_json_delta": | |
| + return u.AsInputJSONContentBlockDelta() | |
| + case "citations_delta": | |
| + return u.AsCitationsDelta() | |
| + case "thinking_delta": | |
| + return u.AsThinkingContentBlockDelta() | |
| + case "signature_delta": | |
| + return u.AsSignatureContentBlockDelta() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +func (u BetaRawContentBlockDeltaEventDeltaUnion) AsTextContentBlockDelta() (v BetaTextDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*BetaRawContentBlockDeltaEventDeltaUnion)(nil)).Elem(), | |
| - "type", | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaTextDelta{}), | |
| - DiscriminatorValue: "text_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaInputJSONDelta{}), | |
| - DiscriminatorValue: "input_json_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaCitationsDelta{}), | |
| - DiscriminatorValue: "citations_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaThinkingDelta{}), | |
| - DiscriminatorValue: "thinking_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaSignatureDelta{}), | |
| - DiscriminatorValue: "signature_delta", | |
| - }, | |
| - ) | |
| +func (u BetaRawContentBlockDeltaEventDeltaUnion) AsInputJSONContentBlockDelta() (v BetaInputJSONDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRawContentBlockDeltaEventDeltaType string | |
| - | |
| -const ( | |
| - BetaRawContentBlockDeltaEventDeltaTypeTextDelta BetaRawContentBlockDeltaEventDeltaType = "text_delta" | |
| - BetaRawContentBlockDeltaEventDeltaTypeInputJSONDelta BetaRawContentBlockDeltaEventDeltaType = "input_json_delta" | |
| - BetaRawContentBlockDeltaEventDeltaTypeCitationsDelta BetaRawContentBlockDeltaEventDeltaType = "citations_delta" | |
| - BetaRawContentBlockDeltaEventDeltaTypeThinkingDelta BetaRawContentBlockDeltaEventDeltaType = "thinking_delta" | |
| - BetaRawContentBlockDeltaEventDeltaTypeSignatureDelta BetaRawContentBlockDeltaEventDeltaType = "signature_delta" | |
| -) | |
| - | |
| -func (r BetaRawContentBlockDeltaEventDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawContentBlockDeltaEventDeltaTypeTextDelta, BetaRawContentBlockDeltaEventDeltaTypeInputJSONDelta, BetaRawContentBlockDeltaEventDeltaTypeCitationsDelta, BetaRawContentBlockDeltaEventDeltaTypeThinkingDelta, BetaRawContentBlockDeltaEventDeltaTypeSignatureDelta: | |
| - return true | |
| - } | |
| - return false | |
| +func (u BetaRawContentBlockDeltaEventDeltaUnion) AsCitationsDelta() (v BetaCitationsDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRawContentBlockDeltaEventType string | |
| - | |
| -const ( | |
| - BetaRawContentBlockDeltaEventTypeContentBlockDelta BetaRawContentBlockDeltaEventType = "content_block_delta" | |
| -) | |
| - | |
| -func (r BetaRawContentBlockDeltaEventType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawContentBlockDeltaEventTypeContentBlockDelta: | |
| - return true | |
| - } | |
| - return false | |
| +func (u BetaRawContentBlockDeltaEventDeltaUnion) AsThinkingContentBlockDelta() (v BetaThinkingDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRawContentBlockStartEvent struct { | |
| - ContentBlock BetaRawContentBlockStartEventContentBlock `json:"content_block,required"` | |
| - Index int64 `json:"index,required"` | |
| - Type BetaRawContentBlockStartEventType `json:"type,required"` | |
| - JSON betaRawContentBlockStartEventJSON `json:"-"` | |
| +func (u BetaRawContentBlockDeltaEventDeltaUnion) AsSignatureContentBlockDelta() (v BetaSignatureDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// betaRawContentBlockStartEventJSON contains the JSON metadata for the struct | |
| -// [BetaRawContentBlockStartEvent] | |
| -type betaRawContentBlockStartEventJSON struct { | |
| - ContentBlock apijson.Field | |
| - Index apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| +// Returns the unmodified JSON received from the API | |
| +func (u BetaRawContentBlockDeltaEventDeltaUnion) RawJSON() string { return u.JSON.raw } | |
| -func (r *BetaRawContentBlockStartEvent) UnmarshalJSON(data []byte) (err error) { | |
| +func (r *BetaRawContentBlockDeltaEventDeltaUnion) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaRawContentBlockStartEventJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaRawContentBlockStartEvent) implementsBetaRawMessageStreamEvent() {} | |
| - | |
| -type BetaRawContentBlockStartEventContentBlock struct { | |
| - Type BetaRawContentBlockStartEventContentBlockType `json:"type,required"` | |
| - ID string `json:"id"` | |
| - // This field can have the runtime type of [[]BetaTextCitation]. | |
| - Citations interface{} `json:"citations"` | |
| - Data string `json:"data"` | |
| - // This field can have the runtime type of [interface{}]. | |
| - Input interface{} `json:"input"` | |
| - Name string `json:"name"` | |
| - Signature string `json:"signature"` | |
| - Text string `json:"text"` | |
| - Thinking string `json:"thinking"` | |
| - JSON betaRawContentBlockStartEventContentBlockJSON `json:"-"` | |
| - union BetaRawContentBlockStartEventContentBlockUnion | |
| -} | |
| - | |
| -// betaRawContentBlockStartEventContentBlockJSON contains the JSON metadata for the | |
| -// struct [BetaRawContentBlockStartEventContentBlock] | |
| -type betaRawContentBlockStartEventContentBlockJSON struct { | |
| - Type apijson.Field | |
| - ID apijson.Field | |
| - Citations apijson.Field | |
| - Data apijson.Field | |
| - Input apijson.Field | |
| - Name apijson.Field | |
| - Signature apijson.Field | |
| - Text apijson.Field | |
| - Thinking apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r betaRawContentBlockStartEventContentBlockJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r *BetaRawContentBlockStartEventContentBlock) UnmarshalJSON(data []byte) (err error) { | |
| - *r = BetaRawContentBlockStartEventContentBlock{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| +type BetaRawContentBlockStartEvent struct { | |
| + ContentBlock BetaRawContentBlockStartEventContentBlockUnion `json:"content_block,required"` | |
| + Index int64 `json:"index,required"` | |
| + Type constant.ContentBlockStart `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ContentBlock resp.Field | |
| + Index resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaRawContentBlockStartEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaRawContentBlockStartEvent) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -// AsUnion returns a [BetaRawContentBlockStartEventContentBlockUnion] interface | |
| -// which you can cast to the specific types for more type safety. | |
| +// BetaRawContentBlockStartEventContentBlockUnion contains all possible properties | |
| +// and values from [BetaTextBlock], [BetaToolUseBlock], [BetaThinkingBlock], | |
| +// [BetaRedactedThinkingBlock]. | |
| +// | |
| +// Use the [BetaRawContentBlockStartEventContentBlockUnion.AsAny] method to switch | |
| +// on the variant. | |
| // | |
| -// Possible runtime types of the union are [BetaTextBlock], [BetaToolUseBlock], | |
| -// [BetaThinkingBlock], [BetaRedactedThinkingBlock]. | |
| -func (r BetaRawContentBlockStartEventContentBlock) AsUnion() BetaRawContentBlockStartEventContentBlockUnion { | |
| - return r.union | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type BetaRawContentBlockStartEventContentBlockUnion struct { | |
| + // This field is from variant [BetaTextBlock]. | |
| + Citations []BetaTextCitationUnion `json:"citations"` | |
| + // This field is from variant [BetaTextBlock]. | |
| + Text string `json:"text"` | |
| + // Any of "text", "tool_use", "thinking", "redacted_thinking". | |
| + Type string `json:"type"` | |
| + // This field is from variant [BetaToolUseBlock]. | |
| + ID string `json:"id"` | |
| + // This field is from variant [BetaToolUseBlock]. | |
| + Input interface{} `json:"input"` | |
| + // This field is from variant [BetaToolUseBlock]. | |
| + Name string `json:"name"` | |
| + // This field is from variant [BetaThinkingBlock]. | |
| + Signature string `json:"signature"` | |
| + // This field is from variant [BetaThinkingBlock]. | |
| + Thinking string `json:"thinking"` | |
| + // This field is from variant [BetaRedactedThinkingBlock]. | |
| + Data string `json:"data"` | |
| + JSON struct { | |
| + Citations resp.Field | |
| + Text resp.Field | |
| + Type resp.Field | |
| + ID resp.Field | |
| + Input resp.Field | |
| + Name resp.Field | |
| + Signature resp.Field | |
| + Thinking resp.Field | |
| + Data resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := BetaRawContentBlockStartEventContentBlockUnion.AsAny().(type) { | |
| +// case BetaTextBlock: | |
| +// case BetaToolUseBlock: | |
| +// case BetaThinkingBlock: | |
| +// case BetaRedactedThinkingBlock: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u BetaRawContentBlockStartEventContentBlockUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "text": | |
| + return u.AsResponseTextBlock() | |
| + case "tool_use": | |
| + return u.AsResponseToolUseBlock() | |
| + case "thinking": | |
| + return u.AsResponseThinkingBlock() | |
| + case "redacted_thinking": | |
| + return u.AsResponseRedactedThinkingBlock() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +func (u BetaRawContentBlockStartEventContentBlockUnion) AsResponseTextBlock() (v BetaTextBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// Union satisfied by [BetaTextBlock], [BetaToolUseBlock], [BetaThinkingBlock] or | |
| -// [BetaRedactedThinkingBlock]. | |
| -type BetaRawContentBlockStartEventContentBlockUnion interface { | |
| - implementsBetaRawContentBlockStartEventContentBlock() | |
| +func (u BetaRawContentBlockStartEventContentBlockUnion) AsResponseToolUseBlock() (v BetaToolUseBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*BetaRawContentBlockStartEventContentBlockUnion)(nil)).Elem(), | |
| - "type", | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaTextBlock{}), | |
| - DiscriminatorValue: "text", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaToolUseBlock{}), | |
| - DiscriminatorValue: "tool_use", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaThinkingBlock{}), | |
| - DiscriminatorValue: "thinking", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaRedactedThinkingBlock{}), | |
| - DiscriminatorValue: "redacted_thinking", | |
| - }, | |
| - ) | |
| +func (u BetaRawContentBlockStartEventContentBlockUnion) AsResponseThinkingBlock() (v BetaThinkingBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRawContentBlockStartEventContentBlockType string | |
| - | |
| -const ( | |
| - BetaRawContentBlockStartEventContentBlockTypeText BetaRawContentBlockStartEventContentBlockType = "text" | |
| - BetaRawContentBlockStartEventContentBlockTypeToolUse BetaRawContentBlockStartEventContentBlockType = "tool_use" | |
| - BetaRawContentBlockStartEventContentBlockTypeThinking BetaRawContentBlockStartEventContentBlockType = "thinking" | |
| - BetaRawContentBlockStartEventContentBlockTypeRedactedThinking BetaRawContentBlockStartEventContentBlockType = "redacted_thinking" | |
| -) | |
| - | |
| -func (r BetaRawContentBlockStartEventContentBlockType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawContentBlockStartEventContentBlockTypeText, BetaRawContentBlockStartEventContentBlockTypeToolUse, BetaRawContentBlockStartEventContentBlockTypeThinking, BetaRawContentBlockStartEventContentBlockTypeRedactedThinking: | |
| - return true | |
| - } | |
| - return false | |
| +func (u BetaRawContentBlockStartEventContentBlockUnion) AsResponseRedactedThinkingBlock() (v BetaRedactedThinkingBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRawContentBlockStartEventType string | |
| +// Returns the unmodified JSON received from the API | |
| +func (u BetaRawContentBlockStartEventContentBlockUnion) RawJSON() string { return u.JSON.raw } | |
| -const ( | |
| - BetaRawContentBlockStartEventTypeContentBlockStart BetaRawContentBlockStartEventType = "content_block_start" | |
| -) | |
| - | |
| -func (r BetaRawContentBlockStartEventType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawContentBlockStartEventTypeContentBlockStart: | |
| - return true | |
| - } | |
| - return false | |
| +func (r *BetaRawContentBlockStartEventContentBlockUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| type BetaRawContentBlockStopEvent struct { | |
| - Index int64 `json:"index,required"` | |
| - Type BetaRawContentBlockStopEventType `json:"type,required"` | |
| - JSON betaRawContentBlockStopEventJSON `json:"-"` | |
| -} | |
| - | |
| -// betaRawContentBlockStopEventJSON contains the JSON metadata for the struct | |
| -// [BetaRawContentBlockStopEvent] | |
| -type betaRawContentBlockStopEventJSON struct { | |
| - Index apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaRawContentBlockStopEvent) UnmarshalJSON(data []byte) (err error) { | |
| + Index int64 `json:"index,required"` | |
| + Type constant.ContentBlockStop `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Index resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaRawContentBlockStopEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaRawContentBlockStopEvent) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaRawContentBlockStopEventJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaRawContentBlockStopEvent) implementsBetaRawMessageStreamEvent() {} | |
| - | |
| -type BetaRawContentBlockStopEventType string | |
| - | |
| -const ( | |
| - BetaRawContentBlockStopEventTypeContentBlockStop BetaRawContentBlockStopEventType = "content_block_stop" | |
| -) | |
| - | |
| -func (r BetaRawContentBlockStopEventType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawContentBlockStopEventTypeContentBlockStop: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaRawMessageDeltaEvent struct { | |
| Delta BetaRawMessageDeltaEventDelta `json:"delta,required"` | |
| - Type BetaRawMessageDeltaEventType `json:"type,required"` | |
| + Type constant.MessageDelta `json:"type,required"` | |
| // Billing and rate-limit usage. | |
| // | |
| // Anthropic's API bills and rate-limits by token counts, as tokens represent the | |
| @@ -1627,743 +1741,672 @@ type BetaRawMessageDeltaEvent struct { | |
| // | |
| // Total input tokens in a request is the summation of `input_tokens`, | |
| // `cache_creation_input_tokens`, and `cache_read_input_tokens`. | |
| - Usage BetaMessageDeltaUsage `json:"usage,required"` | |
| - JSON betaRawMessageDeltaEventJSON `json:"-"` | |
| + Usage BetaMessageDeltaUsage `json:"usage,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Delta resp.Field | |
| + Type resp.Field | |
| + Usage resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaRawMessageDeltaEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaRawMessageDeltaEvent) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -// betaRawMessageDeltaEventJSON contains the JSON metadata for the struct | |
| -// [BetaRawMessageDeltaEvent] | |
| -type betaRawMessageDeltaEventJSON struct { | |
| - Delta apijson.Field | |
| - Type apijson.Field | |
| - Usage apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +type BetaRawMessageDeltaEventDelta struct { | |
| + // Any of "end_turn", "max_tokens", "stop_sequence", "tool_use". | |
| + StopReason string `json:"stop_reason,required"` | |
| + StopSequence string `json:"stop_sequence,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + StopReason resp.Field | |
| + StopSequence resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaRawMessageDeltaEventDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaRawMessageDeltaEventDelta) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r *BetaRawMessageDeltaEvent) UnmarshalJSON(data []byte) (err error) { | |
| +type BetaRawMessageStartEvent struct { | |
| + Message BetaMessage `json:"message,required"` | |
| + Type constant.MessageStart `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaRawMessageStartEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaRawMessageStartEvent) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaRawMessageDeltaEventJSON) RawJSON() string { | |
| - return r.raw | |
| +type BetaRawMessageStopEvent struct { | |
| + Type constant.MessageStop `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaRawMessageStopEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaRawMessageStopEvent) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r BetaRawMessageDeltaEvent) implementsBetaRawMessageStreamEvent() {} | |
| - | |
| -type BetaRawMessageDeltaEventDelta struct { | |
| - StopReason BetaRawMessageDeltaEventDeltaStopReason `json:"stop_reason,required,nullable"` | |
| - StopSequence string `json:"stop_sequence,required,nullable"` | |
| - JSON betaRawMessageDeltaEventDeltaJSON `json:"-"` | |
| +// BetaRawMessageStreamEventUnion contains all possible properties and values from | |
| +// [BetaRawMessageStartEvent], [BetaRawMessageDeltaEvent], | |
| +// [BetaRawMessageStopEvent], [BetaRawContentBlockStartEvent], | |
| +// [BetaRawContentBlockDeltaEvent], [BetaRawContentBlockStopEvent]. | |
| +// | |
| +// Use the [BetaRawMessageStreamEventUnion.AsAny] method to switch on the variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type BetaRawMessageStreamEventUnion struct { | |
| + // This field is from variant [BetaRawMessageStartEvent]. | |
| + Message BetaMessage `json:"message"` | |
| + // Any of "message_start", "message_delta", "message_stop", "content_block_start", | |
| + // "content_block_delta", "content_block_stop". | |
| + Type string `json:"type"` | |
| + // This field is a union of [BetaRawMessageDeltaEventDelta], | |
| + // [BetaRawContentBlockDeltaEventDeltaUnion] | |
| + Delta BetaRawMessageStreamEventUnionDelta `json:"delta"` | |
| + // This field is from variant [BetaRawMessageDeltaEvent]. | |
| + Usage BetaMessageDeltaUsage `json:"usage"` | |
| + // This field is from variant [BetaRawContentBlockStartEvent]. | |
| + ContentBlock BetaRawContentBlockStartEventContentBlockUnion `json:"content_block"` | |
| + Index int64 `json:"index"` | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + Delta resp.Field | |
| + Usage resp.Field | |
| + ContentBlock resp.Field | |
| + Index resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := BetaRawMessageStreamEventUnion.AsAny().(type) { | |
| +// case BetaRawMessageStartEvent: | |
| +// case BetaRawMessageDeltaEvent: | |
| +// case BetaRawMessageStopEvent: | |
| +// case BetaRawContentBlockStartEvent: | |
| +// case BetaRawContentBlockDeltaEvent: | |
| +// case BetaRawContentBlockStopEvent: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u BetaRawMessageStreamEventUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "message_start": | |
| + return u.AsMessageStartEvent() | |
| + case "message_delta": | |
| + return u.AsMessageDeltaEvent() | |
| + case "message_stop": | |
| + return u.AsMessageStopEvent() | |
| + case "content_block_start": | |
| + return u.AsContentBlockStartEvent() | |
| + case "content_block_delta": | |
| + return u.AsContentBlockDeltaEvent() | |
| + case "content_block_stop": | |
| + return u.AsContentBlockStopEvent() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +func (u BetaRawMessageStreamEventUnion) AsMessageStartEvent() (v BetaRawMessageStartEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// betaRawMessageDeltaEventDeltaJSON contains the JSON metadata for the struct | |
| -// [BetaRawMessageDeltaEventDelta] | |
| -type betaRawMessageDeltaEventDeltaJSON struct { | |
| - StopReason apijson.Field | |
| - StopSequence apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func (u BetaRawMessageStreamEventUnion) AsMessageDeltaEvent() (v BetaRawMessageDeltaEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r *BetaRawMessageDeltaEventDelta) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +func (u BetaRawMessageStreamEventUnion) AsMessageStopEvent() (v BetaRawMessageStopEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r betaRawMessageDeltaEventDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u BetaRawMessageStreamEventUnion) AsContentBlockStartEvent() (v BetaRawContentBlockStartEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRawMessageDeltaEventDeltaStopReason string | |
| - | |
| -const ( | |
| - BetaRawMessageDeltaEventDeltaStopReasonEndTurn BetaRawMessageDeltaEventDeltaStopReason = "end_turn" | |
| - BetaRawMessageDeltaEventDeltaStopReasonMaxTokens BetaRawMessageDeltaEventDeltaStopReason = "max_tokens" | |
| - BetaRawMessageDeltaEventDeltaStopReasonStopSequence BetaRawMessageDeltaEventDeltaStopReason = "stop_sequence" | |
| - BetaRawMessageDeltaEventDeltaStopReasonToolUse BetaRawMessageDeltaEventDeltaStopReason = "tool_use" | |
| -) | |
| - | |
| -func (r BetaRawMessageDeltaEventDeltaStopReason) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawMessageDeltaEventDeltaStopReasonEndTurn, BetaRawMessageDeltaEventDeltaStopReasonMaxTokens, BetaRawMessageDeltaEventDeltaStopReasonStopSequence, BetaRawMessageDeltaEventDeltaStopReasonToolUse: | |
| - return true | |
| - } | |
| - return false | |
| +func (u BetaRawMessageStreamEventUnion) AsContentBlockDeltaEvent() (v BetaRawContentBlockDeltaEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRawMessageDeltaEventType string | |
| - | |
| -const ( | |
| - BetaRawMessageDeltaEventTypeMessageDelta BetaRawMessageDeltaEventType = "message_delta" | |
| -) | |
| - | |
| -func (r BetaRawMessageDeltaEventType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawMessageDeltaEventTypeMessageDelta: | |
| - return true | |
| - } | |
| - return false | |
| +func (u BetaRawMessageStreamEventUnion) AsContentBlockStopEvent() (v BetaRawContentBlockStopEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRawMessageStartEvent struct { | |
| - Message BetaMessage `json:"message,required"` | |
| - Type BetaRawMessageStartEventType `json:"type,required"` | |
| - JSON betaRawMessageStartEventJSON `json:"-"` | |
| -} | |
| +// Returns the unmodified JSON received from the API | |
| +func (u BetaRawMessageStreamEventUnion) RawJSON() string { return u.JSON.raw } | |
| -// betaRawMessageStartEventJSON contains the JSON metadata for the struct | |
| -// [BetaRawMessageStartEvent] | |
| -type betaRawMessageStartEventJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func (r *BetaRawMessageStreamEventUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r *BetaRawMessageStartEvent) UnmarshalJSON(data []byte) (err error) { | |
| +// BetaRawMessageStreamEventUnionDelta is an implicit subunion of | |
| +// [BetaRawMessageStreamEventUnion]. BetaRawMessageStreamEventUnionDelta provides | |
| +// convenient access to the sub-properties of the union. | |
| +// | |
| +// For type safety it is recommended to directly use a variant of the | |
| +// [BetaRawMessageStreamEventUnion]. | |
| +type BetaRawMessageStreamEventUnionDelta struct { | |
| + // This field is from variant [BetaRawMessageDeltaEventDelta]. | |
| + StopReason string `json:"stop_reason"` | |
| + // This field is from variant [BetaRawMessageDeltaEventDelta]. | |
| + StopSequence string `json:"stop_sequence"` | |
| + // This field is from variant [BetaRawContentBlockDeltaEventDeltaUnion]. | |
| + Text string `json:"text"` | |
| + Type string `json:"type"` | |
| + // This field is from variant [BetaRawContentBlockDeltaEventDeltaUnion]. | |
| + PartialJSON string `json:"partial_json"` | |
| + // This field is from variant [BetaRawContentBlockDeltaEventDeltaUnion]. | |
| + Citation BetaCitationsDeltaCitationUnion `json:"citation"` | |
| + // This field is from variant [BetaRawContentBlockDeltaEventDeltaUnion]. | |
| + Thinking string `json:"thinking"` | |
| + // This field is from variant [BetaRawContentBlockDeltaEventDeltaUnion]. | |
| + Signature string `json:"signature"` | |
| + JSON struct { | |
| + StopReason resp.Field | |
| + StopSequence resp.Field | |
| + Text resp.Field | |
| + Type resp.Field | |
| + PartialJSON resp.Field | |
| + Citation resp.Field | |
| + Thinking resp.Field | |
| + Signature resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +func (r *BetaRawMessageStreamEventUnionDelta) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaRawMessageStartEventJSON) RawJSON() string { | |
| - return r.raw | |
| +type BetaRedactedThinkingBlock struct { | |
| + Data string `json:"data,required"` | |
| + Type constant.RedactedThinking `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Data resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaRedactedThinkingBlock) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaRedactedThinkingBlock) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r BetaRawMessageStartEvent) implementsBetaRawMessageStreamEvent() {} | |
| - | |
| -type BetaRawMessageStartEventType string | |
| - | |
| -const ( | |
| - BetaRawMessageStartEventTypeMessageStart BetaRawMessageStartEventType = "message_start" | |
| -) | |
| - | |
| -func (r BetaRawMessageStartEventType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawMessageStartEventTypeMessageStart: | |
| - return true | |
| - } | |
| - return false | |
| +func (r BetaRedactedThinkingBlock) ToParam() BetaRedactedThinkingBlockParam { | |
| + var p BetaRedactedThinkingBlockParam | |
| + p.Type = r.Type | |
| + p.Data = r.Data | |
| + return p | |
| } | |
| -type BetaRawMessageStopEvent struct { | |
| - Type BetaRawMessageStopEventType `json:"type,required"` | |
| - JSON betaRawMessageStopEventJSON `json:"-"` | |
| +// The properties Data, Type are required. | |
| +type BetaRedactedThinkingBlockParam struct { | |
| + Data string `json:"data,required"` | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "redacted_thinking". | |
| + Type constant.RedactedThinking `json:"type,required"` | |
| + paramObj | |
| } | |
| -// betaRawMessageStopEventJSON contains the JSON metadata for the struct | |
| -// [BetaRawMessageStopEvent] | |
| -type betaRawMessageStopEventJSON struct { | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaRedactedThinkingBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r BetaRedactedThinkingBlockParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaRedactedThinkingBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r *BetaRawMessageStopEvent) UnmarshalJSON(data []byte) (err error) { | |
| +type BetaSignatureDelta struct { | |
| + Signature string `json:"signature,required"` | |
| + Type constant.SignatureDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Signature resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaSignatureDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaSignatureDelta) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaRawMessageStopEventJSON) RawJSON() string { | |
| - return r.raw | |
| +type BetaTextBlock struct { | |
| + // Citations supporting the text block. | |
| + // | |
| + // The type of citation returned will depend on the type of document being cited. | |
| + // Citing a PDF results in `page_location`, plain text results in `char_location`, | |
| + // and content document results in `content_block_location`. | |
| + Citations []BetaTextCitationUnion `json:"citations,required"` | |
| + Text string `json:"text,required"` | |
| + Type constant.Text `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Citations resp.Field | |
| + Text resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaTextBlock) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaTextBlock) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r BetaRawMessageStopEvent) implementsBetaRawMessageStreamEvent() {} | |
| - | |
| -type BetaRawMessageStopEventType string | |
| - | |
| -const ( | |
| - BetaRawMessageStopEventTypeMessageStop BetaRawMessageStopEventType = "message_stop" | |
| -) | |
| +func (r BetaTextBlock) ToParam() BetaTextBlockParam { | |
| + var p BetaTextBlockParam | |
| + p.Type = r.Type | |
| + p.Text = r.Text | |
| + p.Citations = make([]BetaTextCitationParamUnion, len(r.Citations)) | |
| + for i, citation := range r.Citations { | |
| + switch citationVariant := citation.AsAny().(type) { | |
| + case BetaCitationCharLocation: | |
| + var citationParam BetaCitationCharLocationParam | |
| + citationParam.Type = citationVariant.Type | |
| + citationParam.DocumentTitle = toParam(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle) | |
| + citationParam.CitedText = citationVariant.CitedText | |
| + citationParam.DocumentIndex = citationVariant.DocumentIndex | |
| + citationParam.EndCharIndex = citationVariant.EndCharIndex | |
| + citationParam.StartCharIndex = citationVariant.StartCharIndex | |
| + p.Citations[i] = BetaTextCitationParamUnion{OfRequestCharLocationCitation: &citationParam} | |
| + case BetaCitationPageLocation: | |
| + var citationParam BetaCitationPageLocationParam | |
| + citationParam.Type = citationVariant.Type | |
| + citationParam.DocumentTitle = toParam(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle) | |
| + citationParam.DocumentIndex = citationVariant.DocumentIndex | |
| + citationParam.EndPageNumber = citationVariant.EndPageNumber | |
| + citationParam.StartPageNumber = citationVariant.StartPageNumber | |
| + p.Citations[i] = BetaTextCitationParamUnion{OfRequestPageLocationCitation: &citationParam} | |
| + case BetaCitationContentBlockLocation: | |
| + var citationParam BetaCitationContentBlockLocationParam | |
| + citationParam.Type = citationVariant.Type | |
| + citationParam.DocumentTitle = toParam(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle) | |
| + citationParam.CitedText = citationVariant.CitedText | |
| + citationParam.DocumentIndex = citationVariant.DocumentIndex | |
| + citationParam.EndBlockIndex = citationVariant.EndBlockIndex | |
| + citationParam.StartBlockIndex = citationVariant.StartBlockIndex | |
| + p.Citations[i] = BetaTextCitationParamUnion{OfRequestContentBlockLocationCitation: &citationParam} | |
| + } | |
| + } | |
| + return p | |
| +} | |
| + | |
| +// The properties Text, Type are required. | |
| +type BetaTextBlockParam struct { | |
| + Text string `json:"text,required"` | |
| + Citations []BetaTextCitationParamUnion `json:"citations,omitzero"` | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "text". | |
| + Type constant.Text `json:"type,required"` | |
| + paramObj | |
| +} | |
| -func (r BetaRawMessageStopEventType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawMessageStopEventTypeMessageStop: | |
| - return true | |
| - } | |
| - return false | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaTextBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r BetaTextBlockParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaTextBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -type BetaRawMessageStreamEvent struct { | |
| - Type BetaRawMessageStreamEventType `json:"type,required"` | |
| - // This field can have the runtime type of | |
| - // [BetaRawContentBlockStartEventContentBlock]. | |
| - ContentBlock interface{} `json:"content_block"` | |
| - // This field can have the runtime type of [BetaRawMessageDeltaEventDelta], | |
| - // [BetaRawContentBlockDeltaEventDelta]. | |
| - Delta interface{} `json:"delta"` | |
| - Index int64 `json:"index"` | |
| - Message BetaMessage `json:"message"` | |
| - // Billing and rate-limit usage. | |
| - // | |
| - // Anthropic's API bills and rate-limits by token counts, as tokens represent the | |
| - // underlying cost to our systems. | |
| - // | |
| - // Under the hood, the API transforms requests into a format suitable for the | |
| - // model. The model's output then goes through a parsing stage before becoming an | |
| - // API response. As a result, the token counts in `usage` will not match one-to-one | |
| - // with the exact visible content of an API request or response. | |
| - // | |
| - // For example, `output_tokens` will be non-zero, even for an empty string response | |
| - // from Claude. | |
| - // | |
| - // Total input tokens in a request is the summation of `input_tokens`, | |
| - // `cache_creation_input_tokens`, and `cache_read_input_tokens`. | |
| - Usage BetaMessageDeltaUsage `json:"usage"` | |
| - JSON betaRawMessageStreamEventJSON `json:"-"` | |
| - union BetaRawMessageStreamEventUnion | |
| -} | |
| - | |
| -// betaRawMessageStreamEventJSON contains the JSON metadata for the struct | |
| -// [BetaRawMessageStreamEvent] | |
| -type betaRawMessageStreamEventJSON struct { | |
| - Type apijson.Field | |
| - ContentBlock apijson.Field | |
| - Delta apijson.Field | |
| - Index apijson.Field | |
| - Message apijson.Field | |
| - Usage apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r betaRawMessageStreamEventJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r *BetaRawMessageStreamEvent) UnmarshalJSON(data []byte) (err error) { | |
| - *r = BetaRawMessageStreamEvent{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| -} | |
| - | |
| -// AsUnion returns a [BetaRawMessageStreamEventUnion] interface which you can cast | |
| -// to the specific types for more type safety. | |
| +// BetaTextCitationUnion contains all possible properties and values from | |
| +// [BetaCitationCharLocation], [BetaCitationPageLocation], | |
| +// [BetaCitationContentBlockLocation]. | |
| // | |
| -// Possible runtime types of the union are [BetaRawMessageStartEvent], | |
| -// [BetaRawMessageDeltaEvent], [BetaRawMessageStopEvent], | |
| -// [BetaRawContentBlockStartEvent], [BetaRawContentBlockDeltaEvent], | |
| -// [BetaRawContentBlockStopEvent]. | |
| -func (r BetaRawMessageStreamEvent) AsUnion() BetaRawMessageStreamEventUnion { | |
| - return r.union | |
| -} | |
| - | |
| -// Union satisfied by [BetaRawMessageStartEvent], [BetaRawMessageDeltaEvent], | |
| -// [BetaRawMessageStopEvent], [BetaRawContentBlockStartEvent], | |
| -// [BetaRawContentBlockDeltaEvent] or [BetaRawContentBlockStopEvent]. | |
| -type BetaRawMessageStreamEventUnion interface { | |
| - implementsBetaRawMessageStreamEvent() | |
| -} | |
| - | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*BetaRawMessageStreamEventUnion)(nil)).Elem(), | |
| - "type", | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaRawMessageStartEvent{}), | |
| - DiscriminatorValue: "message_start", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaRawMessageDeltaEvent{}), | |
| - DiscriminatorValue: "message_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaRawMessageStopEvent{}), | |
| - DiscriminatorValue: "message_stop", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaRawContentBlockStartEvent{}), | |
| - DiscriminatorValue: "content_block_start", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaRawContentBlockDeltaEvent{}), | |
| - DiscriminatorValue: "content_block_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaRawContentBlockStopEvent{}), | |
| - DiscriminatorValue: "content_block_stop", | |
| - }, | |
| - ) | |
| +// Use the [BetaTextCitationUnion.AsAny] method to switch on the variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type BetaTextCitationUnion struct { | |
| + CitedText string `json:"cited_text"` | |
| + DocumentIndex int64 `json:"document_index"` | |
| + DocumentTitle string `json:"document_title"` | |
| + // This field is from variant [BetaCitationCharLocation]. | |
| + EndCharIndex int64 `json:"end_char_index"` | |
| + // This field is from variant [BetaCitationCharLocation]. | |
| + StartCharIndex int64 `json:"start_char_index"` | |
| + // Any of "char_location", "page_location", "content_block_location". | |
| + Type string `json:"type"` | |
| + // This field is from variant [BetaCitationPageLocation]. | |
| + EndPageNumber int64 `json:"end_page_number"` | |
| + // This field is from variant [BetaCitationPageLocation]. | |
| + StartPageNumber int64 `json:"start_page_number"` | |
| + // This field is from variant [BetaCitationContentBlockLocation]. | |
| + EndBlockIndex int64 `json:"end_block_index"` | |
| + // This field is from variant [BetaCitationContentBlockLocation]. | |
| + StartBlockIndex int64 `json:"start_block_index"` | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndCharIndex resp.Field | |
| + StartCharIndex resp.Field | |
| + Type resp.Field | |
| + EndPageNumber resp.Field | |
| + StartPageNumber resp.Field | |
| + EndBlockIndex resp.Field | |
| + StartBlockIndex resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := BetaTextCitationUnion.AsAny().(type) { | |
| +// case BetaCitationCharLocation: | |
| +// case BetaCitationPageLocation: | |
| +// case BetaCitationContentBlockLocation: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u BetaTextCitationUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "char_location": | |
| + return u.AsResponseCharLocationCitation() | |
| + case "page_location": | |
| + return u.AsResponsePageLocationCitation() | |
| + case "content_block_location": | |
| + return u.AsResponseContentBlockLocationCitation() | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +func (u BetaTextCitationUnion) AsResponseCharLocationCitation() (v BetaCitationCharLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRawMessageStreamEventType string | |
| - | |
| -const ( | |
| - BetaRawMessageStreamEventTypeMessageStart BetaRawMessageStreamEventType = "message_start" | |
| - BetaRawMessageStreamEventTypeMessageDelta BetaRawMessageStreamEventType = "message_delta" | |
| - BetaRawMessageStreamEventTypeMessageStop BetaRawMessageStreamEventType = "message_stop" | |
| - BetaRawMessageStreamEventTypeContentBlockStart BetaRawMessageStreamEventType = "content_block_start" | |
| - BetaRawMessageStreamEventTypeContentBlockDelta BetaRawMessageStreamEventType = "content_block_delta" | |
| - BetaRawMessageStreamEventTypeContentBlockStop BetaRawMessageStreamEventType = "content_block_stop" | |
| -) | |
| - | |
| -func (r BetaRawMessageStreamEventType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRawMessageStreamEventTypeMessageStart, BetaRawMessageStreamEventTypeMessageDelta, BetaRawMessageStreamEventTypeMessageStop, BetaRawMessageStreamEventTypeContentBlockStart, BetaRawMessageStreamEventTypeContentBlockDelta, BetaRawMessageStreamEventTypeContentBlockStop: | |
| - return true | |
| - } | |
| - return false | |
| +func (u BetaTextCitationUnion) AsResponsePageLocationCitation() (v BetaCitationPageLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type BetaRedactedThinkingBlock struct { | |
| - Data string `json:"data,required"` | |
| - Type BetaRedactedThinkingBlockType `json:"type,required"` | |
| - JSON betaRedactedThinkingBlockJSON `json:"-"` | |
| +func (u BetaTextCitationUnion) AsResponseContentBlockLocationCitation() (v BetaCitationContentBlockLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// betaRedactedThinkingBlockJSON contains the JSON metadata for the struct | |
| -// [BetaRedactedThinkingBlock] | |
| -type betaRedactedThinkingBlockJSON struct { | |
| - Data apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| +// Returns the unmodified JSON received from the API | |
| +func (u BetaTextCitationUnion) RawJSON() string { return u.JSON.raw } | |
| -func (r *BetaRedactedThinkingBlock) UnmarshalJSON(data []byte) (err error) { | |
| +func (r *BetaTextCitationUnion) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaRedactedThinkingBlockJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaRedactedThinkingBlock) implementsBetaContentBlock() {} | |
| - | |
| -func (r BetaRedactedThinkingBlock) implementsBetaRawContentBlockStartEventContentBlock() {} | |
| - | |
| -type BetaRedactedThinkingBlockType string | |
| - | |
| -const ( | |
| - BetaRedactedThinkingBlockTypeRedactedThinking BetaRedactedThinkingBlockType = "redacted_thinking" | |
| -) | |
| - | |
| -func (r BetaRedactedThinkingBlockType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRedactedThinkingBlockTypeRedactedThinking: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaRedactedThinkingBlockParam struct { | |
| - Data param.Field[string] `json:"data,required"` | |
| - Type param.Field[BetaRedactedThinkingBlockParamType] `json:"type,required"` | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaTextCitationParamUnion struct { | |
| + OfRequestCharLocationCitation *BetaCitationCharLocationParam `json:",omitzero,inline"` | |
| + OfRequestPageLocationCitation *BetaCitationPageLocationParam `json:",omitzero,inline"` | |
| + OfRequestContentBlockLocationCitation *BetaCitationContentBlockLocationParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -func (r BetaRedactedThinkingBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaTextCitationParamUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u BetaTextCitationParamUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaTextCitationParamUnion](u.OfRequestCharLocationCitation, u.OfRequestPageLocationCitation, u.OfRequestContentBlockLocationCitation) | |
| } | |
| -func (r BetaRedactedThinkingBlockParam) implementsBetaContentBlockParamUnion() {} | |
| - | |
| -type BetaRedactedThinkingBlockParamType string | |
| - | |
| -const ( | |
| - BetaRedactedThinkingBlockParamTypeRedactedThinking BetaRedactedThinkingBlockParamType = "redacted_thinking" | |
| -) | |
| - | |
| -func (r BetaRedactedThinkingBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaRedactedThinkingBlockParamTypeRedactedThinking: | |
| - return true | |
| +func (u *BetaTextCitationParamUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfRequestCharLocationCitation) { | |
| + return u.OfRequestCharLocationCitation | |
| + } else if !param.IsOmitted(u.OfRequestPageLocationCitation) { | |
| + return u.OfRequestPageLocationCitation | |
| + } else if !param.IsOmitted(u.OfRequestContentBlockLocationCitation) { | |
| + return u.OfRequestContentBlockLocationCitation | |
| } | |
| - return false | |
| -} | |
| - | |
| -type BetaSignatureDelta struct { | |
| - Signature string `json:"signature,required"` | |
| - Type BetaSignatureDeltaType `json:"type,required"` | |
| - JSON betaSignatureDeltaJSON `json:"-"` | |
| + return nil | |
| } | |
| -// betaSignatureDeltaJSON contains the JSON metadata for the struct | |
| -// [BetaSignatureDelta] | |
| -type betaSignatureDeltaJSON struct { | |
| - Signature apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaSignatureDelta) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| -} | |
| - | |
| -func (r betaSignatureDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaSignatureDelta) implementsBetaRawContentBlockDeltaEventDelta() {} | |
| - | |
| -type BetaSignatureDeltaType string | |
| - | |
| -const ( | |
| - BetaSignatureDeltaTypeSignatureDelta BetaSignatureDeltaType = "signature_delta" | |
| -) | |
| - | |
| -func (r BetaSignatureDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaSignatureDeltaTypeSignatureDelta: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetEndCharIndex() *int64 { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return &vt.EndCharIndex | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaTextBlock struct { | |
| - // Citations supporting the text block. | |
| - // | |
| - // The type of citation returned will depend on the type of document being cited. | |
| - // Citing a PDF results in `page_location`, plain text results in `char_location`, | |
| - // and content document results in `content_block_location`. | |
| - Citations []BetaTextCitation `json:"citations,required,nullable"` | |
| - Text string `json:"text,required"` | |
| - Type BetaTextBlockType `json:"type,required"` | |
| - JSON betaTextBlockJSON `json:"-"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetStartCharIndex() *int64 { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return &vt.StartCharIndex | |
| + } | |
| + return nil | |
| } | |
| -// betaTextBlockJSON contains the JSON metadata for the struct [BetaTextBlock] | |
| -type betaTextBlockJSON struct { | |
| - Citations apijson.Field | |
| - Text apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetEndPageNumber() *int64 { | |
| + if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return &vt.EndPageNumber | |
| + } | |
| + return nil | |
| } | |
| -func (r *BetaTextBlock) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetStartPageNumber() *int64 { | |
| + if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return &vt.StartPageNumber | |
| + } | |
| + return nil | |
| } | |
| -func (r betaTextBlockJSON) RawJSON() string { | |
| - return r.raw | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetEndBlockIndex() *int64 { | |
| + if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return &vt.EndBlockIndex | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaTextBlock) implementsBetaContentBlock() {} | |
| - | |
| -func (r BetaTextBlock) implementsBetaRawContentBlockStartEventContentBlock() {} | |
| - | |
| -type BetaTextBlockType string | |
| - | |
| -const ( | |
| - BetaTextBlockTypeText BetaTextBlockType = "text" | |
| -) | |
| - | |
| -func (r BetaTextBlockType) IsKnown() bool { | |
| - switch r { | |
| - case BetaTextBlockTypeText: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetStartBlockIndex() *int64 { | |
| + if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return &vt.StartBlockIndex | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaTextBlockParam struct { | |
| - Text param.Field[string] `json:"text,required"` | |
| - Type param.Field[BetaTextBlockParamType] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| - Citations param.Field[[]BetaTextCitationParamUnion] `json:"citations"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetCitedText() *string { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return (*string)(&vt.CitedText) | |
| + } else if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return (*string)(&vt.CitedText) | |
| + } else if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return (*string)(&vt.CitedText) | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaTextBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetDocumentIndex() *int64 { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return (*int64)(&vt.DocumentIndex) | |
| + } else if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return (*int64)(&vt.DocumentIndex) | |
| + } else if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return (*int64)(&vt.DocumentIndex) | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaTextBlockParam) implementsBetaContentBlockParamUnion() {} | |
| - | |
| -func (r BetaTextBlockParam) implementsBetaContentBlockSourceContentUnionParam() {} | |
| - | |
| -func (r BetaTextBlockParam) implementsBetaToolResultBlockParamContentUnion() {} | |
| - | |
| -type BetaTextBlockParamType string | |
| - | |
| -const ( | |
| - BetaTextBlockParamTypeText BetaTextBlockParamType = "text" | |
| -) | |
| - | |
| -func (r BetaTextBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaTextBlockParamTypeText: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaTextCitation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - Type BetaTextCitationType `json:"type,required"` | |
| - EndBlockIndex int64 `json:"end_block_index"` | |
| - EndCharIndex int64 `json:"end_char_index"` | |
| - EndPageNumber int64 `json:"end_page_number"` | |
| - StartBlockIndex int64 `json:"start_block_index"` | |
| - StartCharIndex int64 `json:"start_char_index"` | |
| - StartPageNumber int64 `json:"start_page_number"` | |
| - JSON betaTextCitationJSON `json:"-"` | |
| - union BetaTextCitationUnion | |
| -} | |
| - | |
| -// betaTextCitationJSON contains the JSON metadata for the struct | |
| -// [BetaTextCitation] | |
| -type betaTextCitationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - Type apijson.Field | |
| - EndBlockIndex apijson.Field | |
| - EndCharIndex apijson.Field | |
| - EndPageNumber apijson.Field | |
| - StartBlockIndex apijson.Field | |
| - StartCharIndex apijson.Field | |
| - StartPageNumber apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r betaTextCitationJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r *BetaTextCitation) UnmarshalJSON(data []byte) (err error) { | |
| - *r = BetaTextCitation{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| -} | |
| - | |
| -// AsUnion returns a [BetaTextCitationUnion] interface which you can cast to the | |
| -// specific types for more type safety. | |
| -// | |
| -// Possible runtime types of the union are [BetaCitationCharLocation], | |
| -// [BetaCitationPageLocation], [BetaCitationContentBlockLocation]. | |
| -func (r BetaTextCitation) AsUnion() BetaTextCitationUnion { | |
| - return r.union | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetDocumentTitle() *string { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil && vt.DocumentTitle.IsPresent() { | |
| + return &vt.DocumentTitle.Value | |
| + } else if vt := u.OfRequestPageLocationCitation; vt != nil && vt.DocumentTitle.IsPresent() { | |
| + return &vt.DocumentTitle.Value | |
| + } else if vt := u.OfRequestContentBlockLocationCitation; vt != nil && vt.DocumentTitle.IsPresent() { | |
| + return &vt.DocumentTitle.Value | |
| + } | |
| + return nil | |
| } | |
| -// Union satisfied by [BetaCitationCharLocation], [BetaCitationPageLocation] or | |
| -// [BetaCitationContentBlockLocation]. | |
| -type BetaTextCitationUnion interface { | |
| - implementsBetaTextCitation() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaTextCitationParamUnion) GetType() *string { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*BetaTextCitationUnion)(nil)).Elem(), | |
| + apijson.RegisterUnion[BetaTextCitationParamUnion]( | |
| "type", | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaCitationCharLocation{}), | |
| + Type: reflect.TypeOf(BetaCitationCharLocationParam{}), | |
| DiscriminatorValue: "char_location", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaCitationPageLocation{}), | |
| + Type: reflect.TypeOf(BetaCitationPageLocationParam{}), | |
| DiscriminatorValue: "page_location", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaCitationContentBlockLocation{}), | |
| + Type: reflect.TypeOf(BetaCitationContentBlockLocationParam{}), | |
| DiscriminatorValue: "content_block_location", | |
| }, | |
| ) | |
| } | |
| -type BetaTextCitationType string | |
| - | |
| -const ( | |
| - BetaTextCitationTypeCharLocation BetaTextCitationType = "char_location" | |
| - BetaTextCitationTypePageLocation BetaTextCitationType = "page_location" | |
| - BetaTextCitationTypeContentBlockLocation BetaTextCitationType = "content_block_location" | |
| -) | |
| - | |
| -func (r BetaTextCitationType) IsKnown() bool { | |
| - switch r { | |
| - case BetaTextCitationTypeCharLocation, BetaTextCitationTypePageLocation, BetaTextCitationTypeContentBlockLocation: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaTextCitationParam struct { | |
| - CitedText param.Field[string] `json:"cited_text,required"` | |
| - DocumentIndex param.Field[int64] `json:"document_index,required"` | |
| - DocumentTitle param.Field[string] `json:"document_title,required"` | |
| - Type param.Field[BetaTextCitationParamType] `json:"type,required"` | |
| - EndBlockIndex param.Field[int64] `json:"end_block_index"` | |
| - EndCharIndex param.Field[int64] `json:"end_char_index"` | |
| - EndPageNumber param.Field[int64] `json:"end_page_number"` | |
| - StartBlockIndex param.Field[int64] `json:"start_block_index"` | |
| - StartCharIndex param.Field[int64] `json:"start_char_index"` | |
| - StartPageNumber param.Field[int64] `json:"start_page_number"` | |
| -} | |
| - | |
| -func (r BetaTextCitationParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaTextCitationParam) implementsBetaTextCitationParamUnion() {} | |
| - | |
| -// Satisfied by [BetaCitationCharLocationParam], [BetaCitationPageLocationParam], | |
| -// [BetaCitationContentBlockLocationParam], [BetaTextCitationParam]. | |
| -type BetaTextCitationParamUnion interface { | |
| - implementsBetaTextCitationParamUnion() | |
| -} | |
| - | |
| -type BetaTextCitationParamType string | |
| - | |
| -const ( | |
| - BetaTextCitationParamTypeCharLocation BetaTextCitationParamType = "char_location" | |
| - BetaTextCitationParamTypePageLocation BetaTextCitationParamType = "page_location" | |
| - BetaTextCitationParamTypeContentBlockLocation BetaTextCitationParamType = "content_block_location" | |
| -) | |
| - | |
| -func (r BetaTextCitationParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaTextCitationParamTypeCharLocation, BetaTextCitationParamTypePageLocation, BetaTextCitationParamTypeContentBlockLocation: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaTextDelta struct { | |
| - Text string `json:"text,required"` | |
| - Type BetaTextDeltaType `json:"type,required"` | |
| - JSON betaTextDeltaJSON `json:"-"` | |
| -} | |
| - | |
| -// betaTextDeltaJSON contains the JSON metadata for the struct [BetaTextDelta] | |
| -type betaTextDeltaJSON struct { | |
| - Text apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaTextDelta) UnmarshalJSON(data []byte) (err error) { | |
| + Text string `json:"text,required"` | |
| + Type constant.TextDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Text resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaTextDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaTextDelta) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaTextDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaTextDelta) implementsBetaRawContentBlockDeltaEventDelta() {} | |
| - | |
| -type BetaTextDeltaType string | |
| - | |
| -const ( | |
| - BetaTextDeltaTypeTextDelta BetaTextDeltaType = "text_delta" | |
| -) | |
| - | |
| -func (r BetaTextDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaTextDeltaTypeTextDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaThinkingBlock struct { | |
| - Signature string `json:"signature,required"` | |
| - Thinking string `json:"thinking,required"` | |
| - Type BetaThinkingBlockType `json:"type,required"` | |
| - JSON betaThinkingBlockJSON `json:"-"` | |
| -} | |
| - | |
| -// betaThinkingBlockJSON contains the JSON metadata for the struct | |
| -// [BetaThinkingBlock] | |
| -type betaThinkingBlockJSON struct { | |
| - Signature apijson.Field | |
| - Thinking apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaThinkingBlock) UnmarshalJSON(data []byte) (err error) { | |
| + Signature string `json:"signature,required"` | |
| + Thinking string `json:"thinking,required"` | |
| + Type constant.Thinking `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Signature resp.Field | |
| + Thinking resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaThinkingBlock) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaThinkingBlock) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaThinkingBlockJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaThinkingBlock) implementsBetaContentBlock() {} | |
| - | |
| -func (r BetaThinkingBlock) implementsBetaRawContentBlockStartEventContentBlock() {} | |
| - | |
| -type BetaThinkingBlockType string | |
| - | |
| -const ( | |
| - BetaThinkingBlockTypeThinking BetaThinkingBlockType = "thinking" | |
| -) | |
| - | |
| -func (r BetaThinkingBlockType) IsKnown() bool { | |
| - switch r { | |
| - case BetaThinkingBlockTypeThinking: | |
| - return true | |
| - } | |
| - return false | |
| +func (r BetaThinkingBlock) ToParam() BetaThinkingBlockParam { | |
| + var p BetaThinkingBlockParam | |
| + p.Type = r.Type | |
| + p.Signature = r.Signature | |
| + p.Thinking = r.Thinking | |
| + return p | |
| } | |
| +// The properties Signature, Thinking, Type are required. | |
| type BetaThinkingBlockParam struct { | |
| - Signature param.Field[string] `json:"signature,required"` | |
| - Thinking param.Field[string] `json:"thinking,required"` | |
| - Type param.Field[BetaThinkingBlockParamType] `json:"type,required"` | |
| + Signature string `json:"signature,required"` | |
| + Thinking string `json:"thinking,required"` | |
| + // This field can be elided, and will marshal its zero value as "thinking". | |
| + Type constant.Thinking `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaThinkingBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaThinkingBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaThinkingBlockParam) implementsBetaContentBlockParamUnion() {} | |
| - | |
| -type BetaThinkingBlockParamType string | |
| - | |
| -const ( | |
| - BetaThinkingBlockParamTypeThinking BetaThinkingBlockParamType = "thinking" | |
| -) | |
| - | |
| -func (r BetaThinkingBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaThinkingBlockParamTypeThinking: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaThinkingBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The property Type is required. | |
| type BetaThinkingConfigDisabledParam struct { | |
| - Type param.Field[BetaThinkingConfigDisabledType] `json:"type,required"` | |
| + // This field can be elided, and will marshal its zero value as "disabled". | |
| + Type constant.Disabled `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaThinkingConfigDisabledParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaThinkingConfigDisabledParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaThinkingConfigDisabledParam) implementsBetaThinkingConfigParamUnion() {} | |
| - | |
| -type BetaThinkingConfigDisabledType string | |
| - | |
| -const ( | |
| - BetaThinkingConfigDisabledTypeDisabled BetaThinkingConfigDisabledType = "disabled" | |
| -) | |
| - | |
| -func (r BetaThinkingConfigDisabledType) IsKnown() bool { | |
| - switch r { | |
| - case BetaThinkingConfigDisabledTypeDisabled: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaThinkingConfigDisabledParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties BudgetTokens, Type are required. | |
| type BetaThinkingConfigEnabledParam struct { | |
| // Determines how many tokens Claude can use for its internal reasoning process. | |
| // Larger budgets can enable more thorough analysis for complex problems, improving | |
| @@ -2374,184 +2417,156 @@ type BetaThinkingConfigEnabledParam struct { | |
| // See | |
| // [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| // for details. | |
| - BudgetTokens param.Field[int64] `json:"budget_tokens,required"` | |
| - Type param.Field[BetaThinkingConfigEnabledType] `json:"type,required"` | |
| + BudgetTokens int64 `json:"budget_tokens,required"` | |
| + // This field can be elided, and will marshal its zero value as "enabled". | |
| + Type constant.Enabled `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaThinkingConfigEnabledParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaThinkingConfigEnabledParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaThinkingConfigEnabledParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r BetaThinkingConfigEnabledParam) implementsBetaThinkingConfigParamUnion() {} | |
| - | |
| -type BetaThinkingConfigEnabledType string | |
| - | |
| -const ( | |
| - BetaThinkingConfigEnabledTypeEnabled BetaThinkingConfigEnabledType = "enabled" | |
| -) | |
| - | |
| -func (r BetaThinkingConfigEnabledType) IsKnown() bool { | |
| - switch r { | |
| - case BetaThinkingConfigEnabledTypeEnabled: | |
| - return true | |
| - } | |
| - return false | |
| +func BetaThinkingConfigParamOfThinkingConfigEnabled(budgetTokens int64) BetaThinkingConfigParamUnion { | |
| + var variant BetaThinkingConfigEnabledParam | |
| + variant.BudgetTokens = budgetTokens | |
| + return BetaThinkingConfigParamUnion{OfThinkingConfigEnabled: &variant} | |
| } | |
| -// Configuration for enabling Claude's extended thinking. | |
| +// Only one field can be non-zero. | |
| // | |
| -// 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.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| -// for details. | |
| -type BetaThinkingConfigParam struct { | |
| - Type param.Field[BetaThinkingConfigParamType] `json:"type,required"` | |
| - // Determines how many tokens Claude can use for its internal reasoning process. | |
| - // Larger budgets can enable more thorough analysis for complex problems, improving | |
| - // response quality. | |
| - // | |
| - // Must be ≥1024 and less than `max_tokens`. | |
| - // | |
| - // See | |
| - // [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| - // for details. | |
| - BudgetTokens param.Field[int64] `json:"budget_tokens"` | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaThinkingConfigParamUnion struct { | |
| + OfThinkingConfigEnabled *BetaThinkingConfigEnabledParam `json:",omitzero,inline"` | |
| + OfThinkingConfigDisabled *BetaThinkingConfigDisabledParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -func (r BetaThinkingConfigParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaThinkingConfigParamUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u BetaThinkingConfigParamUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaThinkingConfigParamUnion](u.OfThinkingConfigEnabled, u.OfThinkingConfigDisabled) | |
| } | |
| -func (r BetaThinkingConfigParam) implementsBetaThinkingConfigParamUnion() {} | |
| - | |
| -// 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.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| -// for details. | |
| -// | |
| -// Satisfied by [BetaThinkingConfigEnabledParam], | |
| -// [BetaThinkingConfigDisabledParam], [BetaThinkingConfigParam]. | |
| -type BetaThinkingConfigParamUnion interface { | |
| - implementsBetaThinkingConfigParamUnion() | |
| +func (u *BetaThinkingConfigParamUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfThinkingConfigEnabled) { | |
| + return u.OfThinkingConfigEnabled | |
| + } else if !param.IsOmitted(u.OfThinkingConfigDisabled) { | |
| + return u.OfThinkingConfigDisabled | |
| + } | |
| + return nil | |
| } | |
| -type BetaThinkingConfigParamType string | |
| - | |
| -const ( | |
| - BetaThinkingConfigParamTypeEnabled BetaThinkingConfigParamType = "enabled" | |
| - BetaThinkingConfigParamTypeDisabled BetaThinkingConfigParamType = "disabled" | |
| -) | |
| - | |
| -func (r BetaThinkingConfigParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaThinkingConfigParamTypeEnabled, BetaThinkingConfigParamTypeDisabled: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaThinkingConfigParamUnion) GetBudgetTokens() *int64 { | |
| + if vt := u.OfThinkingConfigEnabled; vt != nil { | |
| + return &vt.BudgetTokens | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaThinkingDelta struct { | |
| - Thinking string `json:"thinking,required"` | |
| - Type BetaThinkingDeltaType `json:"type,required"` | |
| - JSON betaThinkingDeltaJSON `json:"-"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaThinkingConfigParamUnion) GetType() *string { | |
| + if vt := u.OfThinkingConfigEnabled; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfThinkingConfigDisabled; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| -// betaThinkingDeltaJSON contains the JSON metadata for the struct | |
| -// [BetaThinkingDelta] | |
| -type betaThinkingDeltaJSON struct { | |
| - Thinking apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func init() { | |
| + apijson.RegisterUnion[BetaThinkingConfigParamUnion]( | |
| + "type", | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaThinkingConfigEnabledParam{}), | |
| + DiscriminatorValue: "enabled", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaThinkingConfigDisabledParam{}), | |
| + DiscriminatorValue: "disabled", | |
| + }, | |
| + ) | |
| } | |
| -func (r *BetaThinkingDelta) UnmarshalJSON(data []byte) (err error) { | |
| +type BetaThinkingDelta struct { | |
| + Thinking string `json:"thinking,required"` | |
| + Type constant.ThinkingDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Thinking resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaThinkingDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaThinkingDelta) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaThinkingDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaThinkingDelta) implementsBetaRawContentBlockDeltaEventDelta() {} | |
| - | |
| -type BetaThinkingDeltaType string | |
| - | |
| -const ( | |
| - BetaThinkingDeltaTypeThinkingDelta BetaThinkingDeltaType = "thinking_delta" | |
| -) | |
| - | |
| -func (r BetaThinkingDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaThinkingDeltaTypeThinkingDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| +// The properties InputSchema, Name are required. | |
| type BetaToolParam struct { | |
| // [JSON schema](https://json-schema.org/draft/2020-12) for this tool's input. | |
| // | |
| // This defines the shape of the `input` that your tool accepts and that the model | |
| // will produce. | |
| - InputSchema param.Field[BetaToolInputSchemaParam] `json:"input_schema,required"` | |
| + InputSchema BetaToolInputSchemaParam `json:"input_schema,omitzero,required"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[string] `json:"name,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| + Name string `json:"name,required"` | |
| // Description of what this tool does. | |
| // | |
| // Tool descriptions should be as detailed as possible. The more information that | |
| // the model has about what the tool is and how to use it, the better it will | |
| // perform. You can use natural language descriptions to reinforce important | |
| // aspects of the tool input JSON schema. | |
| - Description param.Field[string] `json:"description"` | |
| - Type param.Field[BetaToolType] `json:"type"` | |
| + Description param.Opt[string] `json:"description,omitzero"` | |
| + // Any of "custom". | |
| + Type BetaToolType `json:"type,omitzero"` | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaToolParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r BetaToolParam) implementsBetaToolUnionUnionParam() {} | |
| - | |
| -func (r BetaToolParam) implementsBetaMessageCountTokensParamsToolUnion() {} | |
| - | |
| // [JSON schema](https://json-schema.org/draft/2020-12) for this tool's input. | |
| // | |
| // This defines the shape of the `input` that your tool accepts and that the model | |
| // will produce. | |
| +// | |
| +// The property Type is required. | |
| type BetaToolInputSchemaParam struct { | |
| - Type param.Field[BetaToolInputSchemaType] `json:"type,required"` | |
| - Properties param.Field[interface{}] `json:"properties"` | |
| - ExtraFields map[string]interface{} `json:"-,extras"` | |
| + Properties interface{} `json:"properties,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "object". | |
| + Type constant.Object `json:"type,required"` | |
| + ExtraFields map[string]interface{} `json:"-,extras"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolInputSchemaParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolInputSchemaParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -type BetaToolInputSchemaType string | |
| - | |
| -const ( | |
| - BetaToolInputSchemaTypeObject BetaToolInputSchemaType = "object" | |
| -) | |
| - | |
| -func (r BetaToolInputSchemaType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolInputSchemaTypeObject: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaToolInputSchemaParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type BetaToolType string | |
| @@ -2560,749 +2575,727 @@ const ( | |
| BetaToolTypeCustom BetaToolType = "custom" | |
| ) | |
| -func (r BetaToolType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolTypeCustom: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| +// The properties Name, Type are required. | |
| type BetaToolBash20241022Param struct { | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[BetaToolBash20241022Name] `json:"name,required"` | |
| - Type param.Field[BetaToolBash20241022Type] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| + // | |
| + // This field can be elided, and will marshal its zero value as "bash". | |
| + Name constant.Bash `json:"name,required"` | |
| + // This field can be elided, and will marshal its zero value as "bash_20241022". | |
| + Type constant.Bash20241022 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolBash20241022Param) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolBash20241022Param) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaToolBash20241022Param) implementsBetaToolUnionUnionParam() {} | |
| - | |
| -func (r BetaToolBash20241022Param) implementsBetaMessageCountTokensParamsToolUnion() {} | |
| - | |
| -// Name of the tool. | |
| -// | |
| -// This is how the tool will be called by the model and in tool_use blocks. | |
| -type BetaToolBash20241022Name string | |
| - | |
| -const ( | |
| - BetaToolBash20241022NameBash BetaToolBash20241022Name = "bash" | |
| -) | |
| - | |
| -func (r BetaToolBash20241022Name) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolBash20241022NameBash: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaToolBash20241022Type string | |
| - | |
| -const ( | |
| - BetaToolBash20241022TypeBash20241022 BetaToolBash20241022Type = "bash_20241022" | |
| -) | |
| - | |
| -func (r BetaToolBash20241022Type) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolBash20241022TypeBash20241022: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaToolBash20241022Param | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties Name, Type are required. | |
| type BetaToolBash20250124Param struct { | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[BetaToolBash20250124Name] `json:"name,required"` | |
| - Type param.Field[BetaToolBash20250124Type] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| + // | |
| + // This field can be elided, and will marshal its zero value as "bash". | |
| + Name constant.Bash `json:"name,required"` | |
| + // This field can be elided, and will marshal its zero value as "bash_20250124". | |
| + Type constant.Bash20250124 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolBash20250124Param) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolBash20250124Param) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaToolBash20250124Param | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r BetaToolBash20250124Param) implementsBetaToolUnionUnionParam() {} | |
| - | |
| -func (r BetaToolBash20250124Param) implementsBetaMessageCountTokensParamsToolUnion() {} | |
| +func BetaToolChoiceParamOfToolChoiceTool(name string) BetaToolChoiceUnionParam { | |
| + var variant BetaToolChoiceToolParam | |
| + variant.Name = name | |
| + return BetaToolChoiceUnionParam{OfToolChoiceTool: &variant} | |
| +} | |
| -// Name of the tool. | |
| +// Only one field can be non-zero. | |
| // | |
| -// This is how the tool will be called by the model and in tool_use blocks. | |
| -type BetaToolBash20250124Name string | |
| - | |
| -const ( | |
| - BetaToolBash20250124NameBash BetaToolBash20250124Name = "bash" | |
| -) | |
| - | |
| -func (r BetaToolBash20250124Name) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolBash20250124NameBash: | |
| - return true | |
| - } | |
| - return false | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaToolChoiceUnionParam struct { | |
| + OfToolChoiceAuto *BetaToolChoiceAutoParam `json:",omitzero,inline"` | |
| + OfToolChoiceAny *BetaToolChoiceAnyParam `json:",omitzero,inline"` | |
| + OfToolChoiceTool *BetaToolChoiceToolParam `json:",omitzero,inline"` | |
| + OfToolChoiceNone *BetaToolChoiceNoneParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -type BetaToolBash20250124Type string | |
| - | |
| -const ( | |
| - BetaToolBash20250124TypeBash20250124 BetaToolBash20250124Type = "bash_20250124" | |
| -) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaToolChoiceUnionParam) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u BetaToolChoiceUnionParam) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaToolChoiceUnionParam](u.OfToolChoiceAuto, u.OfToolChoiceAny, u.OfToolChoiceTool, u.OfToolChoiceNone) | |
| +} | |
| -func (r BetaToolBash20250124Type) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolBash20250124TypeBash20250124: | |
| - return true | |
| +func (u *BetaToolChoiceUnionParam) asAny() any { | |
| + if !param.IsOmitted(u.OfToolChoiceAuto) { | |
| + return u.OfToolChoiceAuto | |
| + } else if !param.IsOmitted(u.OfToolChoiceAny) { | |
| + return u.OfToolChoiceAny | |
| + } else if !param.IsOmitted(u.OfToolChoiceTool) { | |
| + return u.OfToolChoiceTool | |
| + } else if !param.IsOmitted(u.OfToolChoiceNone) { | |
| + return u.OfToolChoiceNone | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -// 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. | |
| -type BetaToolChoiceParam struct { | |
| - Type param.Field[BetaToolChoiceType] `json:"type,required"` | |
| - // Whether to disable parallel tool use. | |
| - // | |
| - // Defaults to `false`. If set to `true`, the model will output at most one tool | |
| - // use. | |
| - DisableParallelToolUse param.Field[bool] `json:"disable_parallel_tool_use"` | |
| - // The name of the tool to use. | |
| - Name param.Field[string] `json:"name"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolChoiceUnionParam) GetName() *string { | |
| + if vt := u.OfToolChoiceTool; vt != nil { | |
| + return &vt.Name | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaToolChoiceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolChoiceUnionParam) GetType() *string { | |
| + if vt := u.OfToolChoiceAuto; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfToolChoiceAny; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfToolChoiceTool; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfToolChoiceNone; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaToolChoiceParam) implementsBetaToolChoiceUnionParam() {} | |
| - | |
| -// 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. | |
| -// | |
| -// Satisfied by [BetaToolChoiceAutoParam], [BetaToolChoiceAnyParam], | |
| -// [BetaToolChoiceToolParam], [BetaToolChoiceNoneParam], [BetaToolChoiceParam]. | |
| -type BetaToolChoiceUnionParam interface { | |
| - implementsBetaToolChoiceUnionParam() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolChoiceUnionParam) GetDisableParallelToolUse() *bool { | |
| + if vt := u.OfToolChoiceAuto; vt != nil && vt.DisableParallelToolUse.IsPresent() { | |
| + return &vt.DisableParallelToolUse.Value | |
| + } else if vt := u.OfToolChoiceAny; vt != nil && vt.DisableParallelToolUse.IsPresent() { | |
| + return &vt.DisableParallelToolUse.Value | |
| + } else if vt := u.OfToolChoiceTool; vt != nil && vt.DisableParallelToolUse.IsPresent() { | |
| + return &vt.DisableParallelToolUse.Value | |
| + } | |
| + return nil | |
| } | |
| -type BetaToolChoiceType string | |
| - | |
| -const ( | |
| - BetaToolChoiceTypeAuto BetaToolChoiceType = "auto" | |
| - BetaToolChoiceTypeAny BetaToolChoiceType = "any" | |
| - BetaToolChoiceTypeTool BetaToolChoiceType = "tool" | |
| - BetaToolChoiceTypeNone BetaToolChoiceType = "none" | |
| -) | |
| - | |
| -func (r BetaToolChoiceType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolChoiceTypeAuto, BetaToolChoiceTypeAny, BetaToolChoiceTypeTool, BetaToolChoiceTypeNone: | |
| - return true | |
| - } | |
| - return false | |
| +func init() { | |
| + apijson.RegisterUnion[BetaToolChoiceUnionParam]( | |
| + "type", | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaToolChoiceAutoParam{}), | |
| + DiscriminatorValue: "auto", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaToolChoiceAnyParam{}), | |
| + DiscriminatorValue: "any", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaToolChoiceToolParam{}), | |
| + DiscriminatorValue: "tool", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaToolChoiceNoneParam{}), | |
| + DiscriminatorValue: "none", | |
| + }, | |
| + ) | |
| } | |
| // The model will use any available tools. | |
| +// | |
| +// The property Type is required. | |
| type BetaToolChoiceAnyParam struct { | |
| - Type param.Field[BetaToolChoiceAnyType] `json:"type,required"` | |
| // Whether to disable parallel tool use. | |
| // | |
| // Defaults to `false`. If set to `true`, the model will output exactly one tool | |
| // use. | |
| - DisableParallelToolUse param.Field[bool] `json:"disable_parallel_tool_use"` | |
| + DisableParallelToolUse param.Opt[bool] `json:"disable_parallel_tool_use,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "any". | |
| + Type constant.Any `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolChoiceAnyParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolChoiceAnyParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaToolChoiceAnyParam) implementsBetaToolChoiceUnionParam() {} | |
| - | |
| -type BetaToolChoiceAnyType string | |
| - | |
| -const ( | |
| - BetaToolChoiceAnyTypeAny BetaToolChoiceAnyType = "any" | |
| -) | |
| - | |
| -func (r BetaToolChoiceAnyType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolChoiceAnyTypeAny: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaToolChoiceAnyParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| // The model will automatically decide whether to use tools. | |
| +// | |
| +// The property Type is required. | |
| type BetaToolChoiceAutoParam struct { | |
| - Type param.Field[BetaToolChoiceAutoType] `json:"type,required"` | |
| // Whether to disable parallel tool use. | |
| // | |
| // Defaults to `false`. If set to `true`, the model will output at most one tool | |
| // use. | |
| - DisableParallelToolUse param.Field[bool] `json:"disable_parallel_tool_use"` | |
| + DisableParallelToolUse param.Opt[bool] `json:"disable_parallel_tool_use,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "auto". | |
| + Type constant.Auto `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolChoiceAutoParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolChoiceAutoParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaToolChoiceAutoParam) implementsBetaToolChoiceUnionParam() {} | |
| - | |
| -type BetaToolChoiceAutoType string | |
| - | |
| -const ( | |
| - BetaToolChoiceAutoTypeAuto BetaToolChoiceAutoType = "auto" | |
| -) | |
| - | |
| -func (r BetaToolChoiceAutoType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolChoiceAutoTypeAuto: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaToolChoiceAutoParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| // The model will not be allowed to use tools. | |
| -type BetaToolChoiceNoneParam struct { | |
| - Type param.Field[BetaToolChoiceNoneType] `json:"type,required"` | |
| -} | |
| - | |
| -func (r BetaToolChoiceNoneParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaToolChoiceNoneParam) implementsBetaToolChoiceUnionParam() {} | |
| - | |
| -type BetaToolChoiceNoneType string | |
| - | |
| -const ( | |
| - BetaToolChoiceNoneTypeNone BetaToolChoiceNoneType = "none" | |
| -) | |
| +// | |
| +// The property Type is required. | |
| +type BetaToolChoiceNoneParam struct { | |
| + // This field can be elided, and will marshal its zero value as "none". | |
| + Type constant.None `json:"type,required"` | |
| + paramObj | |
| +} | |
| -func (r BetaToolChoiceNoneType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolChoiceNoneTypeNone: | |
| - return true | |
| - } | |
| - return false | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolChoiceNoneParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r BetaToolChoiceNoneParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaToolChoiceNoneParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| // The model will use the specified tool with `tool_choice.name`. | |
| +// | |
| +// The properties Name, Type are required. | |
| type BetaToolChoiceToolParam struct { | |
| // The name of the tool to use. | |
| - Name param.Field[string] `json:"name,required"` | |
| - Type param.Field[BetaToolChoiceToolType] `json:"type,required"` | |
| + Name string `json:"name,required"` | |
| // Whether to disable parallel tool use. | |
| // | |
| // Defaults to `false`. If set to `true`, the model will output exactly one tool | |
| // use. | |
| - DisableParallelToolUse param.Field[bool] `json:"disable_parallel_tool_use"` | |
| + DisableParallelToolUse param.Opt[bool] `json:"disable_parallel_tool_use,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "tool". | |
| + Type constant.Tool `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolChoiceToolParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolChoiceToolParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaToolChoiceToolParam) implementsBetaToolChoiceUnionParam() {} | |
| - | |
| -type BetaToolChoiceToolType string | |
| - | |
| -const ( | |
| - BetaToolChoiceToolTypeTool BetaToolChoiceToolType = "tool" | |
| -) | |
| - | |
| -func (r BetaToolChoiceToolType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolChoiceToolTypeTool: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaToolChoiceToolParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties DisplayHeightPx, DisplayWidthPx, Name, Type are required. | |
| type BetaToolComputerUse20241022Param struct { | |
| // The height of the display in pixels. | |
| - DisplayHeightPx param.Field[int64] `json:"display_height_px,required"` | |
| + DisplayHeightPx int64 `json:"display_height_px,required"` | |
| // The width of the display in pixels. | |
| - DisplayWidthPx param.Field[int64] `json:"display_width_px,required"` | |
| + DisplayWidthPx int64 `json:"display_width_px,required"` | |
| + // The X11 display number (e.g. 0, 1) for the display. | |
| + DisplayNumber param.Opt[int64] `json:"display_number,omitzero"` | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[BetaToolComputerUse20241022Name] `json:"name,required"` | |
| - Type param.Field[BetaToolComputerUse20241022Type] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| - // The X11 display number (e.g. 0, 1) for the display. | |
| - DisplayNumber param.Field[int64] `json:"display_number"` | |
| + // | |
| + // This field can be elided, and will marshal its zero value as "computer". | |
| + Name constant.Computer `json:"name,required"` | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "computer_20241022". | |
| + Type constant.Computer20241022 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolComputerUse20241022Param) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolComputerUse20241022Param) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaToolComputerUse20241022Param) implementsBetaToolUnionUnionParam() {} | |
| - | |
| -func (r BetaToolComputerUse20241022Param) implementsBetaMessageCountTokensParamsToolUnion() {} | |
| - | |
| -// Name of the tool. | |
| -// | |
| -// This is how the tool will be called by the model and in tool_use blocks. | |
| -type BetaToolComputerUse20241022Name string | |
| - | |
| -const ( | |
| - BetaToolComputerUse20241022NameComputer BetaToolComputerUse20241022Name = "computer" | |
| -) | |
| - | |
| -func (r BetaToolComputerUse20241022Name) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolComputerUse20241022NameComputer: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaToolComputerUse20241022Type string | |
| - | |
| -const ( | |
| - BetaToolComputerUse20241022TypeComputer20241022 BetaToolComputerUse20241022Type = "computer_20241022" | |
| -) | |
| - | |
| -func (r BetaToolComputerUse20241022Type) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolComputerUse20241022TypeComputer20241022: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaToolComputerUse20241022Param | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties DisplayHeightPx, DisplayWidthPx, Name, Type are required. | |
| type BetaToolComputerUse20250124Param struct { | |
| // The height of the display in pixels. | |
| - DisplayHeightPx param.Field[int64] `json:"display_height_px,required"` | |
| + DisplayHeightPx int64 `json:"display_height_px,required"` | |
| // The width of the display in pixels. | |
| - DisplayWidthPx param.Field[int64] `json:"display_width_px,required"` | |
| + DisplayWidthPx int64 `json:"display_width_px,required"` | |
| + // The X11 display number (e.g. 0, 1) for the display. | |
| + DisplayNumber param.Opt[int64] `json:"display_number,omitzero"` | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[BetaToolComputerUse20250124Name] `json:"name,required"` | |
| - Type param.Field[BetaToolComputerUse20250124Type] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| - // The X11 display number (e.g. 0, 1) for the display. | |
| - DisplayNumber param.Field[int64] `json:"display_number"` | |
| + // | |
| + // This field can be elided, and will marshal its zero value as "computer". | |
| + Name constant.Computer `json:"name,required"` | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "computer_20250124". | |
| + Type constant.Computer20250124 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolComputerUse20250124Param) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolComputerUse20250124Param) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaToolComputerUse20250124Param | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r BetaToolComputerUse20250124Param) implementsBetaToolUnionUnionParam() {} | |
| - | |
| -func (r BetaToolComputerUse20250124Param) implementsBetaMessageCountTokensParamsToolUnion() {} | |
| +// The properties ToolUseID, Type are required. | |
| +type BetaToolResultBlockParam struct { | |
| + ToolUseID string `json:"tool_use_id,required"` | |
| + IsError param.Opt[bool] `json:"is_error,omitzero"` | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + Content []BetaToolResultBlockParamContentUnion `json:"content,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "tool_result". | |
| + Type constant.ToolResult `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolResultBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r BetaToolResultBlockParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaToolResultBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| +} | |
| -// Name of the tool. | |
| +// Only one field can be non-zero. | |
| // | |
| -// This is how the tool will be called by the model and in tool_use blocks. | |
| -type BetaToolComputerUse20250124Name string | |
| - | |
| -const ( | |
| - BetaToolComputerUse20250124NameComputer BetaToolComputerUse20250124Name = "computer" | |
| -) | |
| - | |
| -func (r BetaToolComputerUse20250124Name) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolComputerUse20250124NameComputer: | |
| - return true | |
| - } | |
| - return false | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaToolResultBlockParamContentUnion struct { | |
| + OfRequestTextBlock *BetaTextBlockParam `json:",omitzero,inline"` | |
| + OfRequestImageBlock *BetaImageBlockParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -type BetaToolComputerUse20250124Type string | |
| - | |
| -const ( | |
| - BetaToolComputerUse20250124TypeComputer20250124 BetaToolComputerUse20250124Type = "computer_20250124" | |
| -) | |
| - | |
| -func (r BetaToolComputerUse20250124Type) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolComputerUse20250124TypeComputer20250124: | |
| - return true | |
| - } | |
| - return false | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaToolResultBlockParamContentUnion) IsPresent() bool { | |
| + return !param.IsOmitted(u) && !u.IsNull() | |
| } | |
| - | |
| -type BetaToolResultBlockParam struct { | |
| - ToolUseID param.Field[string] `json:"tool_use_id,required"` | |
| - Type param.Field[BetaToolResultBlockParamType] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| - Content param.Field[[]BetaToolResultBlockParamContentUnion] `json:"content"` | |
| - IsError param.Field[bool] `json:"is_error"` | |
| +func (u BetaToolResultBlockParamContentUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaToolResultBlockParamContentUnion](u.OfRequestTextBlock, u.OfRequestImageBlock) | |
| } | |
| -func (r BetaToolResultBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +func (u *BetaToolResultBlockParamContentUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfRequestTextBlock) { | |
| + return u.OfRequestTextBlock | |
| + } else if !param.IsOmitted(u.OfRequestImageBlock) { | |
| + return u.OfRequestImageBlock | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaToolResultBlockParam) implementsBetaContentBlockParamUnion() {} | |
| - | |
| -type BetaToolResultBlockParamType string | |
| - | |
| -const ( | |
| - BetaToolResultBlockParamTypeToolResult BetaToolResultBlockParamType = "tool_result" | |
| -) | |
| - | |
| -func (r BetaToolResultBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolResultBlockParamTypeToolResult: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolResultBlockParamContentUnion) GetText() *string { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return &vt.Text | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaToolResultBlockParamContent struct { | |
| - Type param.Field[BetaToolResultBlockParamContentType] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| - Citations param.Field[interface{}] `json:"citations"` | |
| - Source param.Field[interface{}] `json:"source"` | |
| - Text param.Field[string] `json:"text"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolResultBlockParamContentUnion) GetCitations() []BetaTextCitationParamUnion { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return vt.Citations | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaToolResultBlockParamContent) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolResultBlockParamContentUnion) GetSource() *BetaImageBlockParamSourceUnion { | |
| + if vt := u.OfRequestImageBlock; vt != nil { | |
| + return &vt.Source | |
| + } | |
| + return nil | |
| } | |
| -func (r BetaToolResultBlockParamContent) implementsBetaToolResultBlockParamContentUnion() {} | |
| - | |
| -// Satisfied by [BetaTextBlockParam], [BetaImageBlockParam], | |
| -// [BetaToolResultBlockParamContent]. | |
| -type BetaToolResultBlockParamContentUnion interface { | |
| - implementsBetaToolResultBlockParamContentUnion() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolResultBlockParamContentUnion) GetType() *string { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestImageBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| -type BetaToolResultBlockParamContentType string | |
| - | |
| -const ( | |
| - BetaToolResultBlockParamContentTypeText BetaToolResultBlockParamContentType = "text" | |
| - BetaToolResultBlockParamContentTypeImage BetaToolResultBlockParamContentType = "image" | |
| -) | |
| - | |
| -func (r BetaToolResultBlockParamContentType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolResultBlockParamContentTypeText, BetaToolResultBlockParamContentTypeImage: | |
| - return true | |
| +// Returns a pointer to the underlying variant's CacheControl property, if present. | |
| +func (u BetaToolResultBlockParamContentUnion) GetCacheControl() *BetaCacheControlEphemeralParam { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestImageBlock; vt != nil { | |
| + return &vt.CacheControl | |
| } | |
| - return false | |
| + return nil | |
| +} | |
| + | |
| +func init() { | |
| + apijson.RegisterUnion[BetaToolResultBlockParamContentUnion]( | |
| + "type", | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaTextBlockParam{}), | |
| + DiscriminatorValue: "text", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(BetaImageBlockParam{}), | |
| + DiscriminatorValue: "image", | |
| + }, | |
| + ) | |
| } | |
| +// The properties Name, Type are required. | |
| type BetaToolTextEditor20241022Param struct { | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[BetaToolTextEditor20241022Name] `json:"name,required"` | |
| - Type param.Field[BetaToolTextEditor20241022Type] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| + // | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "str_replace_editor". | |
| + Name constant.StrReplaceEditor `json:"name,required"` | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "text_editor_20241022". | |
| + Type constant.TextEditor20241022 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolTextEditor20241022Param) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolTextEditor20241022Param) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaToolTextEditor20241022Param) implementsBetaToolUnionUnionParam() {} | |
| - | |
| -func (r BetaToolTextEditor20241022Param) implementsBetaMessageCountTokensParamsToolUnion() {} | |
| - | |
| -// Name of the tool. | |
| -// | |
| -// This is how the tool will be called by the model and in tool_use blocks. | |
| -type BetaToolTextEditor20241022Name string | |
| - | |
| -const ( | |
| - BetaToolTextEditor20241022NameStrReplaceEditor BetaToolTextEditor20241022Name = "str_replace_editor" | |
| -) | |
| - | |
| -func (r BetaToolTextEditor20241022Name) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolTextEditor20241022NameStrReplaceEditor: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaToolTextEditor20241022Type string | |
| - | |
| -const ( | |
| - BetaToolTextEditor20241022TypeTextEditor20241022 BetaToolTextEditor20241022Type = "text_editor_20241022" | |
| -) | |
| - | |
| -func (r BetaToolTextEditor20241022Type) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolTextEditor20241022TypeTextEditor20241022: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaToolTextEditor20241022Param | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties Name, Type are required. | |
| type BetaToolTextEditor20250124Param struct { | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[BetaToolTextEditor20250124Name] `json:"name,required"` | |
| - Type param.Field[BetaToolTextEditor20250124Type] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| + // | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "str_replace_editor". | |
| + Name constant.StrReplaceEditor `json:"name,required"` | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "text_editor_20250124". | |
| + Type constant.TextEditor20250124 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolTextEditor20250124Param) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolTextEditor20250124Param) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaToolTextEditor20250124Param) implementsBetaToolUnionUnionParam() {} | |
| - | |
| -func (r BetaToolTextEditor20250124Param) implementsBetaMessageCountTokensParamsToolUnion() {} | |
| - | |
| -// Name of the tool. | |
| -// | |
| -// This is how the tool will be called by the model and in tool_use blocks. | |
| -type BetaToolTextEditor20250124Name string | |
| - | |
| -const ( | |
| - BetaToolTextEditor20250124NameStrReplaceEditor BetaToolTextEditor20250124Name = "str_replace_editor" | |
| -) | |
| - | |
| -func (r BetaToolTextEditor20250124Name) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolTextEditor20250124NameStrReplaceEditor: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type BetaToolTextEditor20250124Type string | |
| - | |
| -const ( | |
| - BetaToolTextEditor20250124TypeTextEditor20250124 BetaToolTextEditor20250124Type = "text_editor_20250124" | |
| -) | |
| - | |
| -func (r BetaToolTextEditor20250124Type) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolTextEditor20250124TypeTextEditor20250124: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaToolTextEditor20250124Param | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -type BetaToolUnionParam struct { | |
| - // Name of the tool. | |
| - // | |
| - // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[string] `json:"name,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| - // Description of what this tool does. | |
| - // | |
| - // Tool descriptions should be as detailed as possible. The more information that | |
| - // the model has about what the tool is and how to use it, the better it will | |
| - // perform. You can use natural language descriptions to reinforce important | |
| - // aspects of the tool input JSON schema. | |
| - Description param.Field[string] `json:"description"` | |
| - // The height of the display in pixels. | |
| - DisplayHeightPx param.Field[int64] `json:"display_height_px"` | |
| - // The X11 display number (e.g. 0, 1) for the display. | |
| - DisplayNumber param.Field[int64] `json:"display_number"` | |
| - // The width of the display in pixels. | |
| - DisplayWidthPx param.Field[int64] `json:"display_width_px"` | |
| - InputSchema param.Field[interface{}] `json:"input_schema"` | |
| - Type param.Field[BetaToolUnionType] `json:"type"` | |
| +func BetaToolUnionParamOfTool(inputSchema BetaToolInputSchemaParam, name string) BetaToolUnionParam { | |
| + var variant BetaToolParam | |
| + variant.InputSchema = inputSchema | |
| + variant.Name = name | |
| + return BetaToolUnionParam{OfTool: &variant} | |
| } | |
| -func (r BetaToolUnionParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +func BetaToolUnionParamOfComputerUseTool20241022(displayHeightPx int64, displayWidthPx int64) BetaToolUnionParam { | |
| + var variant BetaToolComputerUse20241022Param | |
| + variant.DisplayHeightPx = displayHeightPx | |
| + variant.DisplayWidthPx = displayWidthPx | |
| + return BetaToolUnionParam{OfComputerUseTool20241022: &variant} | |
| } | |
| -func (r BetaToolUnionParam) implementsBetaToolUnionUnionParam() {} | |
| - | |
| -// Satisfied by [BetaToolParam], [BetaToolComputerUse20241022Param], | |
| -// [BetaToolBash20241022Param], [BetaToolTextEditor20241022Param], | |
| -// [BetaToolComputerUse20250124Param], [BetaToolBash20250124Param], | |
| -// [BetaToolTextEditor20250124Param], [BetaToolUnionParam]. | |
| -type BetaToolUnionUnionParam interface { | |
| - implementsBetaToolUnionUnionParam() | |
| +func BetaToolUnionParamOfComputerUseTool20250124(displayHeightPx int64, displayWidthPx int64) BetaToolUnionParam { | |
| + var variant BetaToolComputerUse20250124Param | |
| + variant.DisplayHeightPx = displayHeightPx | |
| + variant.DisplayWidthPx = displayWidthPx | |
| + return BetaToolUnionParam{OfComputerUseTool20250124: &variant} | |
| } | |
| -type BetaToolUnionType string | |
| - | |
| -const ( | |
| - BetaToolUnionTypeCustom BetaToolUnionType = "custom" | |
| - BetaToolUnionTypeComputer20241022 BetaToolUnionType = "computer_20241022" | |
| - BetaToolUnionTypeBash20241022 BetaToolUnionType = "bash_20241022" | |
| - BetaToolUnionTypeTextEditor20241022 BetaToolUnionType = "text_editor_20241022" | |
| - BetaToolUnionTypeComputer20250124 BetaToolUnionType = "computer_20250124" | |
| - BetaToolUnionTypeBash20250124 BetaToolUnionType = "bash_20250124" | |
| - BetaToolUnionTypeTextEditor20250124 BetaToolUnionType = "text_editor_20250124" | |
| -) | |
| - | |
| -func (r BetaToolUnionType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolUnionTypeCustom, BetaToolUnionTypeComputer20241022, BetaToolUnionTypeBash20241022, BetaToolUnionTypeTextEditor20241022, BetaToolUnionTypeComputer20250124, BetaToolUnionTypeBash20250124, BetaToolUnionTypeTextEditor20250124: | |
| - return true | |
| - } | |
| - return false | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaToolUnionParam struct { | |
| + OfTool *BetaToolParam `json:",omitzero,inline"` | |
| + OfComputerUseTool20241022 *BetaToolComputerUse20241022Param `json:",omitzero,inline"` | |
| + OfBashTool20241022 *BetaToolBash20241022Param `json:",omitzero,inline"` | |
| + OfTextEditor20241022 *BetaToolTextEditor20241022Param `json:",omitzero,inline"` | |
| + OfComputerUseTool20250124 *BetaToolComputerUse20250124Param `json:",omitzero,inline"` | |
| + OfBashTool20250124 *BetaToolBash20250124Param `json:",omitzero,inline"` | |
| + OfTextEditor20250124 *BetaToolTextEditor20250124Param `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaToolUnionParam) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u BetaToolUnionParam) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaToolUnionParam](u.OfTool, | |
| + u.OfComputerUseTool20241022, | |
| + u.OfBashTool20241022, | |
| + u.OfTextEditor20241022, | |
| + u.OfComputerUseTool20250124, | |
| + u.OfBashTool20250124, | |
| + u.OfTextEditor20250124) | |
| +} | |
| + | |
| +func (u *BetaToolUnionParam) asAny() any { | |
| + if !param.IsOmitted(u.OfTool) { | |
| + return u.OfTool | |
| + } else if !param.IsOmitted(u.OfComputerUseTool20241022) { | |
| + return u.OfComputerUseTool20241022 | |
| + } else if !param.IsOmitted(u.OfBashTool20241022) { | |
| + return u.OfBashTool20241022 | |
| + } else if !param.IsOmitted(u.OfTextEditor20241022) { | |
| + return u.OfTextEditor20241022 | |
| + } else if !param.IsOmitted(u.OfComputerUseTool20250124) { | |
| + return u.OfComputerUseTool20250124 | |
| + } else if !param.IsOmitted(u.OfBashTool20250124) { | |
| + return u.OfBashTool20250124 | |
| + } else if !param.IsOmitted(u.OfTextEditor20250124) { | |
| + return u.OfTextEditor20250124 | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolUnionParam) GetInputSchema() *BetaToolInputSchemaParam { | |
| + if vt := u.OfTool; vt != nil { | |
| + return &vt.InputSchema | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolUnionParam) GetDescription() *string { | |
| + if vt := u.OfTool; vt != nil && vt.Description.IsPresent() { | |
| + return &vt.Description.Value | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolUnionParam) GetName() *string { | |
| + if vt := u.OfTool; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfBashTool20241022; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfTextEditor20241022; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolUnionParam) GetType() *string { | |
| + if vt := u.OfTool; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfBashTool20241022; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfTextEditor20241022; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolUnionParam) GetDisplayHeightPx() *int64 { | |
| + if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return (*int64)(&vt.DisplayHeightPx) | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return (*int64)(&vt.DisplayHeightPx) | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolUnionParam) GetDisplayWidthPx() *int64 { | |
| + if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return (*int64)(&vt.DisplayWidthPx) | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return (*int64)(&vt.DisplayWidthPx) | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaToolUnionParam) GetDisplayNumber() *int64 { | |
| + if vt := u.OfComputerUseTool20241022; vt != nil && vt.DisplayNumber.IsPresent() { | |
| + return &vt.DisplayNumber.Value | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil && vt.DisplayNumber.IsPresent() { | |
| + return &vt.DisplayNumber.Value | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's CacheControl property, if present. | |
| +func (u BetaToolUnionParam) GetCacheControl() *BetaCacheControlEphemeralParam { | |
| + if vt := u.OfTool; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfBashTool20241022; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfTextEditor20241022; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return &vt.CacheControl | |
| + } | |
| + return nil | |
| } | |
| type BetaToolUseBlock struct { | |
| - ID string `json:"id,required"` | |
| - Input interface{} `json:"input,required"` | |
| - Name string `json:"name,required"` | |
| - Type BetaToolUseBlockType `json:"type,required"` | |
| - JSON betaToolUseBlockJSON `json:"-"` | |
| -} | |
| - | |
| -// betaToolUseBlockJSON contains the JSON metadata for the struct | |
| -// [BetaToolUseBlock] | |
| -type betaToolUseBlockJSON struct { | |
| - ID apijson.Field | |
| - Input apijson.Field | |
| - Name apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaToolUseBlock) UnmarshalJSON(data []byte) (err error) { | |
| + ID string `json:"id,required"` | |
| + Input interface{} `json:"input,required"` | |
| + Name string `json:"name,required"` | |
| + Type constant.ToolUse `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + Input resp.Field | |
| + Name resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaToolUseBlock) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaToolUseBlock) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaToolUseBlockJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaToolUseBlock) implementsBetaContentBlock() {} | |
| - | |
| -func (r BetaToolUseBlock) implementsBetaRawContentBlockStartEventContentBlock() {} | |
| - | |
| -type BetaToolUseBlockType string | |
| - | |
| -const ( | |
| - BetaToolUseBlockTypeToolUse BetaToolUseBlockType = "tool_use" | |
| -) | |
| - | |
| -func (r BetaToolUseBlockType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolUseBlockTypeToolUse: | |
| - return true | |
| - } | |
| - return false | |
| +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 | |
| } | |
| +// The properties ID, Input, Name, Type are required. | |
| type BetaToolUseBlockParam struct { | |
| - ID param.Field[string] `json:"id,required"` | |
| - Input param.Field[interface{}] `json:"input,required"` | |
| - Name param.Field[string] `json:"name,required"` | |
| - Type param.Field[BetaToolUseBlockParamType] `json:"type,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| -} | |
| - | |
| + ID string `json:"id,required"` | |
| + Input interface{} `json:"input,omitzero,required"` | |
| + Name string `json:"name,required"` | |
| + CacheControl BetaCacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "tool_use". | |
| + Type constant.ToolUse `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaToolUseBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaToolUseBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaToolUseBlockParam) implementsBetaContentBlockParamUnion() {} | |
| - | |
| -type BetaToolUseBlockParamType string | |
| - | |
| -const ( | |
| - BetaToolUseBlockParamTypeToolUse BetaToolUseBlockParamType = "tool_use" | |
| -) | |
| - | |
| -func (r BetaToolUseBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case BetaToolUseBlockParamTypeToolUse: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaToolUseBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties Type, URL are required. | |
| type BetaURLImageSourceParam struct { | |
| - Type param.Field[BetaURLImageSourceType] `json:"type,required"` | |
| - URL param.Field[string] `json:"url,required"` | |
| + URL string `json:"url,required"` | |
| + // This field can be elided, and will marshal its zero value as "url". | |
| + Type constant.URL `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaURLImageSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaURLImageSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaURLImageSourceParam) implementsBetaImageBlockParamSourceUnion() {} | |
| - | |
| -type BetaURLImageSourceType string | |
| - | |
| -const ( | |
| - BetaURLImageSourceTypeURL BetaURLImageSourceType = "url" | |
| -) | |
| - | |
| -func (r BetaURLImageSourceType) IsKnown() bool { | |
| - switch r { | |
| - case BetaURLImageSourceTypeURL: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaURLImageSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties Type, URL are required. | |
| type BetaURLPDFSourceParam struct { | |
| - Type param.Field[BetaURLPDFSourceType] `json:"type,required"` | |
| - URL param.Field[string] `json:"url,required"` | |
| + URL string `json:"url,required"` | |
| + // This field can be elided, and will marshal its zero value as "url". | |
| + Type constant.URL `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaURLPDFSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaURLPDFSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r BetaURLPDFSourceParam) implementsBetaBase64PDFBlockSourceUnionParam() {} | |
| - | |
| -type BetaURLPDFSourceType string | |
| - | |
| -const ( | |
| - BetaURLPDFSourceTypeURL BetaURLPDFSourceType = "url" | |
| -) | |
| - | |
| -func (r BetaURLPDFSourceType) IsKnown() bool { | |
| - switch r { | |
| - case BetaURLPDFSourceTypeURL: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow BetaURLPDFSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type BetaUsage struct { | |
| // The number of input tokens used to create the cache entry. | |
| - CacheCreationInputTokens int64 `json:"cache_creation_input_tokens,required,nullable"` | |
| + CacheCreationInputTokens int64 `json:"cache_creation_input_tokens,required"` | |
| // The number of input tokens read from the cache. | |
| - CacheReadInputTokens int64 `json:"cache_read_input_tokens,required,nullable"` | |
| + CacheReadInputTokens int64 `json:"cache_read_input_tokens,required"` | |
| // The number of input tokens which were used. | |
| InputTokens int64 `json:"input_tokens,required"` | |
| // The number of output tokens which were used. | |
| - OutputTokens int64 `json:"output_tokens,required"` | |
| - JSON betaUsageJSON `json:"-"` | |
| -} | |
| - | |
| -// betaUsageJSON contains the JSON metadata for the struct [BetaUsage] | |
| -type betaUsageJSON struct { | |
| - CacheCreationInputTokens apijson.Field | |
| - CacheReadInputTokens apijson.Field | |
| - InputTokens apijson.Field | |
| - OutputTokens apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaUsage) UnmarshalJSON(data []byte) (err error) { | |
| + OutputTokens int64 `json:"output_tokens,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CacheCreationInputTokens resp.Field | |
| + CacheReadInputTokens resp.Field | |
| + InputTokens resp.Field | |
| + OutputTokens resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r BetaUsage) RawJSON() string { return r.JSON.raw } | |
| +func (r *BetaUsage) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r betaUsageJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| type BetaMessageNewParams struct { | |
| // The maximum number of tokens to generate before stopping. | |
| // | |
| @@ -3311,7 +3304,7 @@ type BetaMessageNewParams struct { | |
| // | |
| // Different models have different maximum values for this parameter. See | |
| // [models](https://docs.anthropic.com/en/docs/models-overview) for details. | |
| - MaxTokens param.Field[int64] `json:"max_tokens,required"` | |
| + MaxTokens int64 `json:"max_tokens,required"` | |
| // Input messages. | |
| // | |
| // Our models are trained to operate on alternating `user` and `assistant` | |
| @@ -3404,13 +3397,40 @@ type BetaMessageNewParams struct { | |
| // [system prompt](https://docs.anthropic.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. | |
| - Messages param.Field[[]BetaMessageParam] `json:"messages,required"` | |
| + 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 param.Field[Model] `json:"model,required"` | |
| + Model Model `json:"model,omitzero,required"` | |
| + // 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"` | |
| // An object describing metadata about the request. | |
| - Metadata param.Field[BetaMetadataParam] `json:"metadata"` | |
| + Metadata BetaMetadataParam `json:"metadata,omitzero"` | |
| // Custom text sequences that will cause the model to stop generating. | |
| // | |
| // Our models will normally stop when they have naturally completed their turn, | |
| @@ -3420,22 +3440,13 @@ type BetaMessageNewParams struct { | |
| // 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 param.Field[[]string] `json:"stop_sequences"` | |
| + 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.anthropic.com/en/docs/system-prompts). | |
| - System param.Field[[]BetaTextBlockParam] `json:"system"` | |
| - // 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.Field[float64] `json:"temperature"` | |
| + System []BetaTextBlockParam `json:"system,omitzero"` | |
| // Configuration for enabling Claude's extended thinking. | |
| // | |
| // When enabled, responses include `thinking` content blocks showing Claude's | |
| @@ -3445,10 +3456,10 @@ type BetaMessageNewParams struct { | |
| // See | |
| // [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| // for details. | |
| - Thinking param.Field[BetaThinkingConfigParamUnion] `json:"thinking"` | |
| + 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 param.Field[BetaToolChoiceUnionParam] `json:"tool_choice"` | |
| + 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` | |
| @@ -3524,31 +3535,19 @@ type BetaMessageNewParams struct { | |
| // JSON structure of output. | |
| // | |
| // See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details. | |
| - Tools param.Field[[]BetaToolUnionUnionParam] `json:"tools"` | |
| - // 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.Field[int64] `json:"top_k"` | |
| - // 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.Field[float64] `json:"top_p"` | |
| + Tools []BetaToolUnionParam `json:"tools,omitzero"` | |
| // Optional header to specify the beta version(s) you want to use. | |
| - Betas param.Field[[]AnthropicBeta] `header:"anthropic-beta"` | |
| + Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| func (r BetaMessageNewParams) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaMessageNewParams | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type BetaMessageCountTokensParams struct { | |
| @@ -3644,17 +3643,17 @@ type BetaMessageCountTokensParams struct { | |
| // [system prompt](https://docs.anthropic.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. | |
| - Messages param.Field[[]BetaMessageParam] `json:"messages,required"` | |
| + 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 param.Field[Model] `json:"model,required"` | |
| + Model Model `json:"model,omitzero,required"` | |
| // 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.anthropic.com/en/docs/system-prompts). | |
| - System param.Field[BetaMessageCountTokensParamsSystemUnion] `json:"system"` | |
| + System BetaMessageCountTokensParamsSystemUnion `json:"system,omitzero"` | |
| // Configuration for enabling Claude's extended thinking. | |
| // | |
| // When enabled, responses include `thinking` content blocks showing Claude's | |
| @@ -3664,10 +3663,10 @@ type BetaMessageCountTokensParams struct { | |
| // See | |
| // [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| // for details. | |
| - Thinking param.Field[BetaThinkingConfigParamUnion] `json:"thinking"` | |
| + 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 param.Field[BetaToolChoiceUnionParam] `json:"tool_choice"` | |
| + 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` | |
| @@ -3743,84 +3742,198 @@ type BetaMessageCountTokensParams struct { | |
| // JSON structure of output. | |
| // | |
| // See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details. | |
| - Tools param.Field[[]BetaMessageCountTokensParamsToolUnion] `json:"tools"` | |
| + Tools []BetaMessageCountTokensParamsToolUnion `json:"tools,omitzero"` | |
| // Optional header to specify the beta version(s) you want to use. | |
| - Betas param.Field[[]AnthropicBeta] `header:"anthropic-beta"` | |
| + Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageCountTokensParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| func (r BetaMessageCountTokensParams) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaMessageCountTokensParams | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -// 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.anthropic.com/en/docs/system-prompts). | |
| +// Only one field can be non-zero. | |
| // | |
| -// Satisfied by [shared.UnionString], [BetaMessageCountTokensParamsSystemArray]. | |
| -type BetaMessageCountTokensParamsSystemUnion interface { | |
| - ImplementsBetaMessageCountTokensParamsSystemUnion() | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaMessageCountTokensParamsSystemUnion struct { | |
| + OfString param.Opt[string] `json:",omitzero,inline"` | |
| + OfBetaMessageCountTokenssSystemArray []BetaTextBlockParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -type BetaMessageCountTokensParamsSystemArray []BetaTextBlockParam | |
| - | |
| -func (r BetaMessageCountTokensParamsSystemArray) ImplementsBetaMessageCountTokensParamsSystemUnion() { | |
| -} | |
| - | |
| -type BetaMessageCountTokensParamsTool struct { | |
| - // Name of the tool. | |
| - // | |
| - // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[string] `json:"name,required"` | |
| - CacheControl param.Field[BetaCacheControlEphemeralParam] `json:"cache_control"` | |
| - // Description of what this tool does. | |
| - // | |
| - // Tool descriptions should be as detailed as possible. The more information that | |
| - // the model has about what the tool is and how to use it, the better it will | |
| - // perform. You can use natural language descriptions to reinforce important | |
| - // aspects of the tool input JSON schema. | |
| - Description param.Field[string] `json:"description"` | |
| - // The height of the display in pixels. | |
| - DisplayHeightPx param.Field[int64] `json:"display_height_px"` | |
| - // The X11 display number (e.g. 0, 1) for the display. | |
| - DisplayNumber param.Field[int64] `json:"display_number"` | |
| - // The width of the display in pixels. | |
| - DisplayWidthPx param.Field[int64] `json:"display_width_px"` | |
| - InputSchema param.Field[interface{}] `json:"input_schema"` | |
| - Type param.Field[BetaMessageCountTokensParamsToolsType] `json:"type"` | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaMessageCountTokensParamsSystemUnion) IsPresent() bool { | |
| + return !param.IsOmitted(u) && !u.IsNull() | |
| } | |
| - | |
| -func (r BetaMessageCountTokensParamsTool) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +func (u BetaMessageCountTokensParamsSystemUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaMessageCountTokensParamsSystemUnion](u.OfString, u.OfBetaMessageCountTokenssSystemArray) | |
| } | |
| -func (r BetaMessageCountTokensParamsTool) implementsBetaMessageCountTokensParamsToolUnion() {} | |
| - | |
| -// Satisfied by [BetaToolParam], [BetaToolComputerUse20241022Param], | |
| -// [BetaToolBash20241022Param], [BetaToolTextEditor20241022Param], | |
| -// [BetaToolComputerUse20250124Param], [BetaToolBash20250124Param], | |
| -// [BetaToolTextEditor20250124Param], [BetaMessageCountTokensParamsTool]. | |
| -type BetaMessageCountTokensParamsToolUnion interface { | |
| - implementsBetaMessageCountTokensParamsToolUnion() | |
| +func (u *BetaMessageCountTokensParamsSystemUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfString) { | |
| + return &u.OfString.Value | |
| + } else if !param.IsOmitted(u.OfBetaMessageCountTokenssSystemArray) { | |
| + return &u.OfBetaMessageCountTokenssSystemArray | |
| + } | |
| + return nil | |
| } | |
| -type BetaMessageCountTokensParamsToolsType string | |
| - | |
| -const ( | |
| - BetaMessageCountTokensParamsToolsTypeCustom BetaMessageCountTokensParamsToolsType = "custom" | |
| - BetaMessageCountTokensParamsToolsTypeComputer20241022 BetaMessageCountTokensParamsToolsType = "computer_20241022" | |
| - BetaMessageCountTokensParamsToolsTypeBash20241022 BetaMessageCountTokensParamsToolsType = "bash_20241022" | |
| - BetaMessageCountTokensParamsToolsTypeTextEditor20241022 BetaMessageCountTokensParamsToolsType = "text_editor_20241022" | |
| - BetaMessageCountTokensParamsToolsTypeComputer20250124 BetaMessageCountTokensParamsToolsType = "computer_20250124" | |
| - BetaMessageCountTokensParamsToolsTypeBash20250124 BetaMessageCountTokensParamsToolsType = "bash_20250124" | |
| - BetaMessageCountTokensParamsToolsTypeTextEditor20250124 BetaMessageCountTokensParamsToolsType = "text_editor_20250124" | |
| -) | |
| - | |
| -func (r BetaMessageCountTokensParamsToolsType) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageCountTokensParamsToolsTypeCustom, BetaMessageCountTokensParamsToolsTypeComputer20241022, BetaMessageCountTokensParamsToolsTypeBash20241022, BetaMessageCountTokensParamsToolsTypeTextEditor20241022, BetaMessageCountTokensParamsToolsTypeComputer20250124, BetaMessageCountTokensParamsToolsTypeBash20250124, BetaMessageCountTokensParamsToolsTypeTextEditor20250124: | |
| - return true | |
| - } | |
| - return false | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type BetaMessageCountTokensParamsToolUnion struct { | |
| + OfTool *BetaToolParam `json:",omitzero,inline"` | |
| + OfComputerUseTool20241022 *BetaToolComputerUse20241022Param `json:",omitzero,inline"` | |
| + OfBashTool20241022 *BetaToolBash20241022Param `json:",omitzero,inline"` | |
| + OfTextEditor20241022 *BetaToolTextEditor20241022Param `json:",omitzero,inline"` | |
| + OfComputerUseTool20250124 *BetaToolComputerUse20250124Param `json:",omitzero,inline"` | |
| + OfBashTool20250124 *BetaToolBash20250124Param `json:",omitzero,inline"` | |
| + OfTextEditor20250124 *BetaToolTextEditor20250124Param `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u BetaMessageCountTokensParamsToolUnion) IsPresent() bool { | |
| + return !param.IsOmitted(u) && !u.IsNull() | |
| +} | |
| +func (u BetaMessageCountTokensParamsToolUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[BetaMessageCountTokensParamsToolUnion](u.OfTool, | |
| + u.OfComputerUseTool20241022, | |
| + u.OfBashTool20241022, | |
| + u.OfTextEditor20241022, | |
| + u.OfComputerUseTool20250124, | |
| + u.OfBashTool20250124, | |
| + u.OfTextEditor20250124) | |
| +} | |
| + | |
| +func (u *BetaMessageCountTokensParamsToolUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfTool) { | |
| + return u.OfTool | |
| + } else if !param.IsOmitted(u.OfComputerUseTool20241022) { | |
| + return u.OfComputerUseTool20241022 | |
| + } else if !param.IsOmitted(u.OfBashTool20241022) { | |
| + return u.OfBashTool20241022 | |
| + } else if !param.IsOmitted(u.OfTextEditor20241022) { | |
| + return u.OfTextEditor20241022 | |
| + } else if !param.IsOmitted(u.OfComputerUseTool20250124) { | |
| + return u.OfComputerUseTool20250124 | |
| + } else if !param.IsOmitted(u.OfBashTool20250124) { | |
| + return u.OfBashTool20250124 | |
| + } else if !param.IsOmitted(u.OfTextEditor20250124) { | |
| + return u.OfTextEditor20250124 | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaMessageCountTokensParamsToolUnion) GetInputSchema() *BetaToolInputSchemaParam { | |
| + if vt := u.OfTool; vt != nil { | |
| + return &vt.InputSchema | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaMessageCountTokensParamsToolUnion) GetDescription() *string { | |
| + if vt := u.OfTool; vt != nil && vt.Description.IsPresent() { | |
| + return &vt.Description.Value | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaMessageCountTokensParamsToolUnion) GetName() *string { | |
| + if vt := u.OfTool; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfBashTool20241022; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfTextEditor20241022; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaMessageCountTokensParamsToolUnion) GetType() *string { | |
| + if vt := u.OfTool; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfBashTool20241022; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfTextEditor20241022; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaMessageCountTokensParamsToolUnion) GetDisplayHeightPx() *int64 { | |
| + if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return (*int64)(&vt.DisplayHeightPx) | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return (*int64)(&vt.DisplayHeightPx) | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaMessageCountTokensParamsToolUnion) GetDisplayWidthPx() *int64 { | |
| + if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return (*int64)(&vt.DisplayWidthPx) | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return (*int64)(&vt.DisplayWidthPx) | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u BetaMessageCountTokensParamsToolUnion) GetDisplayNumber() *int64 { | |
| + if vt := u.OfComputerUseTool20241022; vt != nil && vt.DisplayNumber.IsPresent() { | |
| + return &vt.DisplayNumber.Value | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil && vt.DisplayNumber.IsPresent() { | |
| + return &vt.DisplayNumber.Value | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// Returns a pointer to the underlying variant's CacheControl property, if present. | |
| +func (u BetaMessageCountTokensParamsToolUnion) GetCacheControl() *BetaCacheControlEphemeralParam { | |
| + if vt := u.OfTool; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfComputerUseTool20241022; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfBashTool20241022; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfTextEditor20241022; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfComputerUseTool20250124; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return &vt.CacheControl | |
| + } | |
| + return nil | |
| } | |
| diff --git a/betamessage_test.go b/betamessage_test.go | |
| index e479321..d46a047 100644 | |
| --- a/betamessage_test.go | |
| +++ b/betamessage_test.go | |
| @@ -26,50 +26,57 @@ func TestBetaMessageNewWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.BetaMessageParam{{ | |
| - Content: anthropic.F([]anthropic.BetaContentBlockParamUnion{anthropic.BetaTextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.BetaTextBlockParamTypeText), CacheControl: anthropic.F(anthropic.BetaCacheControlEphemeralParam{Type: anthropic.F(anthropic.BetaCacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.BetaTextCitationParamUnion{anthropic.BetaCitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.BetaCitationCharLocationParamTypeCharLocation)}})}}), | |
| - Role: anthropic.F(anthropic.BetaMessageParamRoleUser), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - Metadata: anthropic.F(anthropic.BetaMetadataParam{ | |
| - UserID: anthropic.F("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| - }), | |
| - StopSequences: anthropic.F([]string{"string"}), | |
| - System: anthropic.F([]anthropic.BetaTextBlockParam{{Text: anthropic.F("x"), Type: anthropic.F(anthropic.BetaTextBlockParamTypeText), CacheControl: anthropic.F(anthropic.BetaCacheControlEphemeralParam{Type: anthropic.F(anthropic.BetaCacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.BetaTextCitationParamUnion{anthropic.BetaCitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.BetaCitationCharLocationParamTypeCharLocation)}})}}), | |
| - Temperature: anthropic.F(1.000000), | |
| - Thinking: anthropic.F[anthropic.BetaThinkingConfigParamUnion](anthropic.BetaThinkingConfigEnabledParam{ | |
| - BudgetTokens: anthropic.F(int64(1024)), | |
| - Type: anthropic.F(anthropic.BetaThinkingConfigEnabledTypeEnabled), | |
| - }), | |
| - ToolChoice: anthropic.F[anthropic.BetaToolChoiceUnionParam](anthropic.BetaToolChoiceAutoParam{ | |
| - Type: anthropic.F(anthropic.BetaToolChoiceAutoTypeAuto), | |
| - DisableParallelToolUse: anthropic.F(true), | |
| - }), | |
| - Tools: anthropic.F([]anthropic.BetaToolUnionUnionParam{anthropic.BetaToolParam{ | |
| - InputSchema: anthropic.F(anthropic.BetaToolInputSchemaParam{ | |
| - Type: anthropic.F(anthropic.BetaToolInputSchemaTypeObject), | |
| - Properties: anthropic.F[any](map[string]interface{}{ | |
| - "location": map[string]interface{}{ | |
| - "description": "The city and state, e.g. San Francisco, CA", | |
| - "type": "string", | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.BetaMessageParam{{ | |
| + Content: []anthropic.BetaContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.BetaTextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.BetaCacheControlEphemeralParam{}, Citations: []anthropic.BetaTextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.BetaCitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + Role: anthropic.BetaMessageParamRoleUser, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + Metadata: anthropic.BetaMetadataParam{ | |
| + UserID: anthropic.String("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| + }, | |
| + StopSequences: []string{"string"}, | |
| + System: []anthropic.BetaTextBlockParam{{Text: "x", CacheControl: anthropic.BetaCacheControlEphemeralParam{}, Citations: []anthropic.BetaTextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.BetaCitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}}, | |
| + Temperature: anthropic.Float(1), | |
| + Thinking: anthropic.BetaThinkingConfigParamUnion{ | |
| + OfThinkingConfigEnabled: &anthropic.BetaThinkingConfigEnabledParam{ | |
| + BudgetTokens: 1024, | |
| + }, | |
| + }, | |
| + ToolChoice: anthropic.BetaToolChoiceUnionParam{ | |
| + OfToolChoiceAuto: &anthropic.BetaToolChoiceAutoParam{ | |
| + DisableParallelToolUse: anthropic.Bool(true), | |
| + }, | |
| + }, | |
| + Tools: []anthropic.BetaToolUnionParam{{ | |
| + OfTool: &anthropic.BetaToolParam{ | |
| + InputSchema: anthropic.BetaToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| + "location": map[string]interface{}{ | |
| + "description": "The city and state, e.g. San Francisco, CA", | |
| + "type": "string", | |
| + }, | |
| + "unit": map[string]interface{}{ | |
| + "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| + "type": "string", | |
| + }, | |
| }, | |
| - "unit": map[string]interface{}{ | |
| - "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| - "type": "string", | |
| - }, | |
| - }), | |
| - }), | |
| - Name: anthropic.F("name"), | |
| - CacheControl: anthropic.F(anthropic.BetaCacheControlEphemeralParam{ | |
| - Type: anthropic.F(anthropic.BetaCacheControlEphemeralTypeEphemeral), | |
| - }), | |
| - Description: anthropic.F("Get the current weather in a given location"), | |
| - Type: anthropic.F(anthropic.BetaToolTypeCustom), | |
| - }}), | |
| - TopK: anthropic.F(int64(5)), | |
| - TopP: anthropic.F(0.700000), | |
| - Betas: anthropic.F([]anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}), | |
| + }, | |
| + Name: "name", | |
| + CacheControl: anthropic.BetaCacheControlEphemeralParam{}, | |
| + Description: anthropic.String("Get the current weather in a given location"), | |
| + Type: anthropic.BetaToolTypeCustom, | |
| + }, | |
| + }}, | |
| + TopK: anthropic.Int(5), | |
| + TopP: anthropic.Float(0.7), | |
| + Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}, | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| @@ -93,56 +100,61 @@ func TestBetaMessageCountTokensWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Beta.Messages.CountTokens(context.TODO(), anthropic.BetaMessageCountTokensParams{ | |
| - Messages: anthropic.F([]anthropic.BetaMessageParam{{ | |
| - Content: anthropic.F([]anthropic.BetaContentBlockParamUnion{anthropic.BetaTextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.BetaTextBlockParamTypeText), CacheControl: anthropic.F(anthropic.BetaCacheControlEphemeralParam{Type: anthropic.F(anthropic.BetaCacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.BetaTextCitationParamUnion{anthropic.BetaCitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.BetaCitationCharLocationParamTypeCharLocation)}})}}), | |
| - Role: anthropic.F(anthropic.BetaMessageParamRoleUser), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - System: anthropic.F[anthropic.BetaMessageCountTokensParamsSystemUnion](anthropic.BetaMessageCountTokensParamsSystemArray([]anthropic.BetaTextBlockParam{{ | |
| - Text: anthropic.F("Today's date is 2024-06-01."), | |
| - Type: anthropic.F(anthropic.BetaTextBlockParamTypeText), | |
| - CacheControl: anthropic.F(anthropic.BetaCacheControlEphemeralParam{ | |
| - Type: anthropic.F(anthropic.BetaCacheControlEphemeralTypeEphemeral), | |
| - }), | |
| - Citations: anthropic.F([]anthropic.BetaTextCitationParamUnion{anthropic.BetaCitationCharLocationParam{ | |
| - CitedText: anthropic.F("cited_text"), | |
| - DocumentIndex: anthropic.F(int64(0)), | |
| - DocumentTitle: anthropic.F("x"), | |
| - EndCharIndex: anthropic.F(int64(0)), | |
| - StartCharIndex: anthropic.F(int64(0)), | |
| - Type: anthropic.F(anthropic.BetaCitationCharLocationParamTypeCharLocation), | |
| - }}), | |
| - }})), | |
| - Thinking: anthropic.F[anthropic.BetaThinkingConfigParamUnion](anthropic.BetaThinkingConfigEnabledParam{ | |
| - BudgetTokens: anthropic.F(int64(1024)), | |
| - Type: anthropic.F(anthropic.BetaThinkingConfigEnabledTypeEnabled), | |
| - }), | |
| - ToolChoice: anthropic.F[anthropic.BetaToolChoiceUnionParam](anthropic.BetaToolChoiceAutoParam{ | |
| - Type: anthropic.F(anthropic.BetaToolChoiceAutoTypeAuto), | |
| - DisableParallelToolUse: anthropic.F(true), | |
| - }), | |
| - Tools: anthropic.F([]anthropic.BetaMessageCountTokensParamsToolUnion{anthropic.BetaToolParam{ | |
| - InputSchema: anthropic.F(anthropic.BetaToolInputSchemaParam{ | |
| - Type: anthropic.F(anthropic.BetaToolInputSchemaTypeObject), | |
| - Properties: anthropic.F[any](map[string]interface{}{ | |
| - "location": map[string]interface{}{ | |
| - "description": "The city and state, e.g. San Francisco, CA", | |
| - "type": "string", | |
| + Messages: []anthropic.BetaMessageParam{{ | |
| + Content: []anthropic.BetaContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.BetaTextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.BetaCacheControlEphemeralParam{}, Citations: []anthropic.BetaTextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.BetaCitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + Role: anthropic.BetaMessageParamRoleUser, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + System: anthropic.BetaMessageCountTokensParamsSystemUnion{ | |
| + OfBetaMessageCountTokenssSystemArray: []anthropic.BetaTextBlockParam{{ | |
| + Text: "Today's date is 2024-06-01.", | |
| + CacheControl: anthropic.BetaCacheControlEphemeralParam{}, | |
| + Citations: []anthropic.BetaTextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.BetaCitationCharLocationParam{ | |
| + CitedText: "cited_text", | |
| + DocumentIndex: 0, | |
| + DocumentTitle: anthropic.String("x"), | |
| + EndCharIndex: 0, | |
| + StartCharIndex: 0, | |
| }, | |
| - "unit": map[string]interface{}{ | |
| - "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| - "type": "string", | |
| + }}, | |
| + }}, | |
| + }, | |
| + Thinking: anthropic.BetaThinkingConfigParamUnion{ | |
| + OfThinkingConfigEnabled: &anthropic.BetaThinkingConfigEnabledParam{ | |
| + BudgetTokens: 1024, | |
| + }, | |
| + }, | |
| + ToolChoice: anthropic.BetaToolChoiceUnionParam{ | |
| + OfToolChoiceAuto: &anthropic.BetaToolChoiceAutoParam{ | |
| + DisableParallelToolUse: anthropic.Bool(true), | |
| + }, | |
| + }, | |
| + Tools: []anthropic.BetaMessageCountTokensParamsToolUnion{{ | |
| + OfTool: &anthropic.BetaToolParam{ | |
| + InputSchema: anthropic.BetaToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| + "location": map[string]interface{}{ | |
| + "description": "The city and state, e.g. San Francisco, CA", | |
| + "type": "string", | |
| + }, | |
| + "unit": map[string]interface{}{ | |
| + "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| + "type": "string", | |
| + }, | |
| }, | |
| - }), | |
| - }), | |
| - Name: anthropic.F("name"), | |
| - CacheControl: anthropic.F(anthropic.BetaCacheControlEphemeralParam{ | |
| - Type: anthropic.F(anthropic.BetaCacheControlEphemeralTypeEphemeral), | |
| - }), | |
| - Description: anthropic.F("Get the current weather in a given location"), | |
| - Type: anthropic.F(anthropic.BetaToolTypeCustom), | |
| - }}), | |
| - Betas: anthropic.F([]anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}), | |
| + }, | |
| + Name: "name", | |
| + CacheControl: anthropic.BetaCacheControlEphemeralParam{}, | |
| + Description: anthropic.String("Get the current weather in a given location"), | |
| + Type: anthropic.BetaToolTypeCustom, | |
| + }, | |
| + }}, | |
| + Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}, | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| diff --git a/betamessagebatch.go b/betamessagebatch.go | |
| index 74e765e..52cea48 100644 | |
| --- a/betamessagebatch.go | |
| +++ b/betamessagebatch.go | |
| @@ -4,21 +4,22 @@ package anthropic | |
| import ( | |
| "context" | |
| + "encoding/json" | |
| "errors" | |
| "fmt" | |
| "net/http" | |
| "net/url" | |
| - "reflect" | |
| "time" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apijson" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apiquery" | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| "github.com/anthropics/anthropic-sdk-go/internal/requestconfig" | |
| "github.com/anthropics/anthropic-sdk-go/option" | |
| "github.com/anthropics/anthropic-sdk-go/packages/jsonl" | |
| "github.com/anthropics/anthropic-sdk-go/packages/pagination" | |
| - "github.com/tidwall/gjson" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| + "github.com/anthropics/anthropic-sdk-go/shared/constant" | |
| ) | |
| // BetaMessageBatchService contains methods and other services that help with | |
| @@ -34,8 +35,8 @@ type BetaMessageBatchService struct { | |
| // 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{} | |
| +func NewBetaMessageBatchService(opts ...option.RequestOption) (r BetaMessageBatchService) { | |
| + r = BetaMessageBatchService{} | |
| r.Options = opts | |
| return | |
| } | |
| @@ -49,7 +50,7 @@ func NewBetaMessageBatchService(opts ...option.RequestOption) (r *BetaMessageBat | |
| // Learn more about the Message Batches API in our | |
| // [user guide](/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.Value { | |
| + for _, v := range params.Betas { | |
| opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%s", v))) | |
| } | |
| opts = append(r.Options[:], opts...) | |
| @@ -66,7 +67,7 @@ func (r *BetaMessageBatchService) New(ctx context.Context, params BetaMessageBat | |
| // Learn more about the Message Batches API in our | |
| // [user guide](/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.Value { | |
| + for _, v := range query.Betas { | |
| opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%s", v))) | |
| } | |
| opts = append(r.Options[:], opts...) | |
| @@ -87,7 +88,7 @@ func (r *BetaMessageBatchService) Get(ctx context.Context, messageBatchID string | |
| // [user guide](/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.Value { | |
| + for _, v := range params.Betas { | |
| opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%s", v))) | |
| } | |
| opts = append(r.Options[:], opts...) | |
| @@ -122,7 +123,7 @@ func (r *BetaMessageBatchService) ListAutoPaging(ctx context.Context, params Bet | |
| // Learn more about the Message Batches API in our | |
| // [user guide](/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.Value { | |
| + for _, v := range body.Betas { | |
| opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%s", v))) | |
| } | |
| opts = append(r.Options[:], opts...) | |
| @@ -149,7 +150,7 @@ func (r *BetaMessageBatchService) Delete(ctx context.Context, messageBatchID str | |
| // Learn more about the Message Batches API in our | |
| // [user guide](/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.Value { | |
| + for _, v := range body.Betas { | |
| opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%s", v))) | |
| } | |
| opts = append(r.Options[:], opts...) | |
| @@ -176,7 +177,7 @@ func (r *BetaMessageBatchService) ResultsStreaming(ctx context.Context, messageB | |
| raw *http.Response | |
| err error | |
| ) | |
| - for _, v := range query.Betas.Value { | |
| + for _, v := range query.Betas { | |
| opts = append(opts, option.WithHeaderAdd("anthropic-beta", fmt.Sprintf("%s", v))) | |
| } | |
| opts = append(r.Options[:], opts...) | |
| @@ -196,44 +197,23 @@ type BetaDeletedMessageBatch struct { | |
| // Deleted object type. | |
| // | |
| // For Message Batches, this is always `"message_batch_deleted"`. | |
| - Type BetaDeletedMessageBatchType `json:"type,required"` | |
| - JSON betaDeletedMessageBatchJSON `json:"-"` | |
| -} | |
| - | |
| -// betaDeletedMessageBatchJSON contains the JSON metadata for the struct | |
| -// [BetaDeletedMessageBatch] | |
| -type betaDeletedMessageBatchJSON struct { | |
| - ID apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaDeletedMessageBatch) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.MessageBatchDeleted `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaDeletedMessageBatchJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -// Deleted object type. | |
| -// | |
| -// For Message Batches, this is always `"message_batch_deleted"`. | |
| -type BetaDeletedMessageBatchType string | |
| - | |
| -const ( | |
| - BetaDeletedMessageBatchTypeMessageBatchDeleted BetaDeletedMessageBatchType = "message_batch_deleted" | |
| -) | |
| - | |
| -func (r BetaDeletedMessageBatchType) IsKnown() bool { | |
| - switch r { | |
| - case BetaDeletedMessageBatchTypeMessageBatchDeleted: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaMessageBatch struct { | |
| // Unique object identifier. | |
| // | |
| @@ -241,10 +221,10 @@ type BetaMessageBatch struct { | |
| 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,nullable" format:"date-time"` | |
| + 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,nullable" format:"date-time"` | |
| + 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"` | |
| @@ -253,11 +233,13 @@ type BetaMessageBatch struct { | |
| // | |
| // Processing ends when every request in a Message Batch has either succeeded, | |
| // errored, canceled, or expired. | |
| - EndedAt time.Time `json:"ended_at,required,nullable" format:"date-time"` | |
| + 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. | |
| // | |
| @@ -270,39 +252,35 @@ type BetaMessageBatch struct { | |
| // | |
| // 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,nullable"` | |
| + ResultsURL string `json:"results_url,required"` | |
| // Object type. | |
| // | |
| // For Message Batches, this is always `"message_batch"`. | |
| - Type BetaMessageBatchType `json:"type,required"` | |
| - JSON betaMessageBatchJSON `json:"-"` | |
| -} | |
| - | |
| -// betaMessageBatchJSON contains the JSON metadata for the struct | |
| -// [BetaMessageBatch] | |
| -type betaMessageBatchJSON struct { | |
| - ID apijson.Field | |
| - ArchivedAt apijson.Field | |
| - CancelInitiatedAt apijson.Field | |
| - CreatedAt apijson.Field | |
| - EndedAt apijson.Field | |
| - ExpiresAt apijson.Field | |
| - ProcessingStatus apijson.Field | |
| - RequestCounts apijson.Field | |
| - ResultsURL apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaMessageBatch) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.MessageBatch `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + ArchivedAt resp.Field | |
| + CancelInitiatedAt resp.Field | |
| + CreatedAt resp.Field | |
| + EndedAt resp.Field | |
| + ExpiresAt resp.Field | |
| + ProcessingStatus resp.Field | |
| + RequestCounts resp.Field | |
| + ResultsURL resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaMessageBatchJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| // Processing status of the Message Batch. | |
| type BetaMessageBatchProcessingStatus string | |
| @@ -312,144 +290,59 @@ const ( | |
| BetaMessageBatchProcessingStatusEnded BetaMessageBatchProcessingStatus = "ended" | |
| ) | |
| -func (r BetaMessageBatchProcessingStatus) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageBatchProcessingStatusInProgress, BetaMessageBatchProcessingStatusCanceling, BetaMessageBatchProcessingStatusEnded: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -// Object type. | |
| -// | |
| -// For Message Batches, this is always `"message_batch"`. | |
| -type BetaMessageBatchType string | |
| - | |
| -const ( | |
| - BetaMessageBatchTypeMessageBatch BetaMessageBatchType = "message_batch" | |
| -) | |
| - | |
| -func (r BetaMessageBatchType) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageBatchTypeMessageBatch: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaMessageBatchCanceledResult struct { | |
| - Type BetaMessageBatchCanceledResultType `json:"type,required"` | |
| - JSON betaMessageBatchCanceledResultJSON `json:"-"` | |
| -} | |
| - | |
| -// betaMessageBatchCanceledResultJSON contains the JSON metadata for the struct | |
| -// [BetaMessageBatchCanceledResult] | |
| -type betaMessageBatchCanceledResultJSON struct { | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaMessageBatchCanceledResult) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.Canceled `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaMessageBatchCanceledResultJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaMessageBatchCanceledResult) implementsBetaMessageBatchResult() {} | |
| - | |
| -type BetaMessageBatchCanceledResultType string | |
| - | |
| -const ( | |
| - BetaMessageBatchCanceledResultTypeCanceled BetaMessageBatchCanceledResultType = "canceled" | |
| -) | |
| - | |
| -func (r BetaMessageBatchCanceledResultType) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageBatchCanceledResultTypeCanceled: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaMessageBatchErroredResult struct { | |
| - Error BetaErrorResponse `json:"error,required"` | |
| - Type BetaMessageBatchErroredResultType `json:"type,required"` | |
| - JSON betaMessageBatchErroredResultJSON `json:"-"` | |
| -} | |
| - | |
| -// betaMessageBatchErroredResultJSON contains the JSON metadata for the struct | |
| -// [BetaMessageBatchErroredResult] | |
| -type betaMessageBatchErroredResultJSON struct { | |
| - Error apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaMessageBatchErroredResult) UnmarshalJSON(data []byte) (err error) { | |
| + Error BetaErrorResponse `json:"error,required"` | |
| + Type constant.Errored `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Error resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaMessageBatchErroredResultJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaMessageBatchErroredResult) implementsBetaMessageBatchResult() {} | |
| - | |
| -type BetaMessageBatchErroredResultType string | |
| - | |
| -const ( | |
| - BetaMessageBatchErroredResultTypeErrored BetaMessageBatchErroredResultType = "errored" | |
| -) | |
| - | |
| -func (r BetaMessageBatchErroredResultType) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageBatchErroredResultTypeErrored: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type BetaMessageBatchExpiredResult struct { | |
| - Type BetaMessageBatchExpiredResultType `json:"type,required"` | |
| - JSON betaMessageBatchExpiredResultJSON `json:"-"` | |
| -} | |
| - | |
| -// betaMessageBatchExpiredResultJSON contains the JSON metadata for the struct | |
| -// [BetaMessageBatchExpiredResult] | |
| -type betaMessageBatchExpiredResultJSON struct { | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaMessageBatchExpiredResult) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.Expired `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaMessageBatchExpiredResultJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r BetaMessageBatchExpiredResult) implementsBetaMessageBatchResult() {} | |
| - | |
| -type BetaMessageBatchExpiredResultType string | |
| - | |
| -const ( | |
| - BetaMessageBatchExpiredResultTypeExpired BetaMessageBatchExpiredResultType = "expired" | |
| -) | |
| - | |
| -func (r BetaMessageBatchExpiredResultType) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageBatchExpiredResultTypeExpired: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| // This is a single line in the response `.jsonl` file and does not represent the | |
| // response as a whole. | |
| type BetaMessageBatchIndividualResponse struct { | |
| @@ -463,27 +356,23 @@ type BetaMessageBatchIndividualResponse struct { | |
| // 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 BetaMessageBatchResult `json:"result,required"` | |
| - JSON betaMessageBatchIndividualResponseJSON `json:"-"` | |
| -} | |
| - | |
| -// betaMessageBatchIndividualResponseJSON contains the JSON metadata for the struct | |
| -// [BetaMessageBatchIndividualResponse] | |
| -type betaMessageBatchIndividualResponseJSON struct { | |
| - CustomID apijson.Field | |
| - Result apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaMessageBatchIndividualResponse) UnmarshalJSON(data []byte) (err error) { | |
| + Result BetaMessageBatchResultUnion `json:"result,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CustomID resp.Field | |
| + Result resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaMessageBatchIndividualResponseJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| type BetaMessageBatchRequestCounts struct { | |
| // Number of requests in the Message Batch that have been canceled. | |
| // | |
| @@ -502,206 +391,166 @@ type BetaMessageBatchRequestCounts struct { | |
| // 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 betaMessageBatchRequestCountsJSON `json:"-"` | |
| -} | |
| - | |
| -// betaMessageBatchRequestCountsJSON contains the JSON metadata for the struct | |
| -// [BetaMessageBatchRequestCounts] | |
| -type betaMessageBatchRequestCountsJSON struct { | |
| - Canceled apijson.Field | |
| - Errored apijson.Field | |
| - Expired apijson.Field | |
| - Processing apijson.Field | |
| - Succeeded apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaMessageBatchRequestCounts) UnmarshalJSON(data []byte) (err error) { | |
| + Succeeded int64 `json:"succeeded,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Canceled resp.Field | |
| + Errored resp.Field | |
| + Expired resp.Field | |
| + Processing resp.Field | |
| + Succeeded resp.Field | |
| + ExtraFields map[string]resp.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) | |
| } | |
| -func (r betaMessageBatchRequestCountsJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -// Processing result for this request. | |
| +// BetaMessageBatchResultUnion contains all possible properties and values from | |
| +// [BetaMessageBatchSucceededResult], [BetaMessageBatchErroredResult], | |
| +// [BetaMessageBatchCanceledResult], [BetaMessageBatchExpiredResult]. | |
| // | |
| -// 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. | |
| -type BetaMessageBatchResult struct { | |
| - Type BetaMessageBatchResultType `json:"type,required"` | |
| - Error BetaErrorResponse `json:"error"` | |
| - Message BetaMessage `json:"message"` | |
| - JSON betaMessageBatchResultJSON `json:"-"` | |
| - union BetaMessageBatchResultUnion | |
| -} | |
| - | |
| -// betaMessageBatchResultJSON contains the JSON metadata for the struct | |
| -// [BetaMessageBatchResult] | |
| -type betaMessageBatchResultJSON struct { | |
| - Type apijson.Field | |
| - Error apijson.Field | |
| - Message apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r betaMessageBatchResultJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r *BetaMessageBatchResult) UnmarshalJSON(data []byte) (err error) { | |
| - *r = BetaMessageBatchResult{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| -} | |
| - | |
| -// AsUnion returns a [BetaMessageBatchResultUnion] interface which you can cast to | |
| -// the specific types for more type safety. | |
| +// Use the [BetaMessageBatchResultUnion.AsAny] method to switch on the variant. | |
| // | |
| -// Possible runtime types of the union are [BetaMessageBatchSucceededResult], | |
| -// [BetaMessageBatchErroredResult], [BetaMessageBatchCanceledResult], | |
| -// [BetaMessageBatchExpiredResult]. | |
| -func (r BetaMessageBatchResult) AsUnion() BetaMessageBatchResultUnion { | |
| - return r.union | |
| -} | |
| - | |
| -// Processing result for this request. | |
| +// 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 resp.Field | |
| + Type resp.Field | |
| + Error resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| // | |
| -// 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. | |
| -// | |
| -// Union satisfied by [BetaMessageBatchSucceededResult], | |
| -// [BetaMessageBatchErroredResult], [BetaMessageBatchCanceledResult] or | |
| -// [BetaMessageBatchExpiredResult]. | |
| -type BetaMessageBatchResultUnion interface { | |
| - implementsBetaMessageBatchResult() | |
| -} | |
| - | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*BetaMessageBatchResultUnion)(nil)).Elem(), | |
| - "type", | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaMessageBatchSucceededResult{}), | |
| - DiscriminatorValue: "succeeded", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaMessageBatchErroredResult{}), | |
| - DiscriminatorValue: "errored", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaMessageBatchCanceledResult{}), | |
| - DiscriminatorValue: "canceled", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(BetaMessageBatchExpiredResult{}), | |
| - DiscriminatorValue: "expired", | |
| - }, | |
| - ) | |
| -} | |
| - | |
| -type BetaMessageBatchResultType string | |
| - | |
| -const ( | |
| - BetaMessageBatchResultTypeSucceeded BetaMessageBatchResultType = "succeeded" | |
| - BetaMessageBatchResultTypeErrored BetaMessageBatchResultType = "errored" | |
| - BetaMessageBatchResultTypeCanceled BetaMessageBatchResultType = "canceled" | |
| - BetaMessageBatchResultTypeExpired BetaMessageBatchResultType = "expired" | |
| -) | |
| - | |
| -func (r BetaMessageBatchResultType) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageBatchResultTypeSucceeded, BetaMessageBatchResultTypeErrored, BetaMessageBatchResultTypeCanceled, BetaMessageBatchResultTypeExpired: | |
| - return true | |
| +// switch variant := BetaMessageBatchResultUnion.AsAny().(type) { | |
| +// case BetaMessageBatchSucceededResult: | |
| +// case BetaMessageBatchErroredResult: | |
| +// case BetaMessageBatchCanceledResult: | |
| +// case BetaMessageBatchExpiredResult: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u BetaMessageBatchResultUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "succeeded": | |
| + return u.AsSucceededResult() | |
| + case "errored": | |
| + return u.AsErroredResult() | |
| + case "canceled": | |
| + return u.AsCanceledResult() | |
| + case "expired": | |
| + return u.AsExpiredResult() | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type BetaMessageBatchSucceededResult struct { | |
| - Message BetaMessage `json:"message,required"` | |
| - Type BetaMessageBatchSucceededResultType `json:"type,required"` | |
| - JSON betaMessageBatchSucceededResultJSON `json:"-"` | |
| +func (u BetaMessageBatchResultUnion) AsSucceededResult() (v BetaMessageBatchSucceededResult) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// betaMessageBatchSucceededResultJSON contains the JSON metadata for the struct | |
| -// [BetaMessageBatchSucceededResult] | |
| -type betaMessageBatchSucceededResultJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func (u BetaMessageBatchResultUnion) AsErroredResult() (v BetaMessageBatchErroredResult) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r *BetaMessageBatchSucceededResult) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +func (u BetaMessageBatchResultUnion) AsCanceledResult() (v BetaMessageBatchCanceledResult) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r betaMessageBatchSucceededResultJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u BetaMessageBatchResultUnion) AsExpiredResult() (v BetaMessageBatchExpiredResult) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r BetaMessageBatchSucceededResult) implementsBetaMessageBatchResult() {} | |
| +// Returns the unmodified JSON received from the API | |
| +func (u BetaMessageBatchResultUnion) RawJSON() string { return u.JSON.raw } | |
| -type BetaMessageBatchSucceededResultType string | |
| - | |
| -const ( | |
| - BetaMessageBatchSucceededResultTypeSucceeded BetaMessageBatchSucceededResultType = "succeeded" | |
| -) | |
| +func (r *BetaMessageBatchResultUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r BetaMessageBatchSucceededResultType) IsKnown() bool { | |
| - switch r { | |
| - case BetaMessageBatchSucceededResultTypeSucceeded: | |
| - return true | |
| - } | |
| - return false | |
| +type BetaMessageBatchSucceededResult struct { | |
| + Message BetaMessage `json:"message,required"` | |
| + Type constant.Succeeded `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.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 param.Field[[]BetaMessageBatchNewParamsRequest] `json:"requests,required"` | |
| + Requests []BetaMessageBatchNewParamsRequest `json:"requests,omitzero,required"` | |
| // Optional header to specify the beta version(s) you want to use. | |
| - Betas param.Field[[]AnthropicBeta] `header:"anthropic-beta"` | |
| + Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageBatchNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| func (r BetaMessageBatchNewParams) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaMessageBatchNewParams | |
| + return param.MarshalObject(r, (*shadow)(&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 param.Field[string] `json:"custom_id,required"` | |
| + CustomID string `json:"custom_id,required"` | |
| // Messages API creation parameters for the individual request. | |
| // | |
| // See the [Messages API reference](/en/api/messages) for full documentation on | |
| // available parameters. | |
| - Params param.Field[BetaMessageBatchNewParamsRequestsParams] `json:"params,required"` | |
| + Params BetaMessageBatchNewParamsRequestParams `json:"params,omitzero,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageBatchNewParamsRequest) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r BetaMessageBatchNewParamsRequest) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow BetaMessageBatchNewParamsRequest | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| // Messages API creation parameters for the individual request. | |
| // | |
| // See the [Messages API reference](/en/api/messages) for full documentation on | |
| // available parameters. | |
| -type BetaMessageBatchNewParamsRequestsParams struct { | |
| +// | |
| +// 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 | |
| @@ -709,7 +558,7 @@ type BetaMessageBatchNewParamsRequestsParams struct { | |
| // | |
| // Different models have different maximum values for this parameter. See | |
| // [models](https://docs.anthropic.com/en/docs/models-overview) for details. | |
| - MaxTokens param.Field[int64] `json:"max_tokens,required"` | |
| + MaxTokens int64 `json:"max_tokens,required"` | |
| // Input messages. | |
| // | |
| // Our models are trained to operate on alternating `user` and `assistant` | |
| @@ -802,13 +651,45 @@ type BetaMessageBatchNewParamsRequestsParams struct { | |
| // [system prompt](https://docs.anthropic.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. | |
| - Messages param.Field[[]BetaMessageParam] `json:"messages,required"` | |
| + 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 param.Field[Model] `json:"model,required"` | |
| + Model Model `json:"model,omitzero,required"` | |
| + // Whether to incrementally stream the response using server-sent events. | |
| + // | |
| + // See [streaming](https://docs.anthropic.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"` | |
| // An object describing metadata about the request. | |
| - Metadata param.Field[BetaMetadataParam] `json:"metadata"` | |
| + Metadata BetaMetadataParam `json:"metadata,omitzero"` | |
| // Custom text sequences that will cause the model to stop generating. | |
| // | |
| // Our models will normally stop when they have naturally completed their turn, | |
| @@ -818,27 +699,13 @@ type BetaMessageBatchNewParamsRequestsParams struct { | |
| // 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 param.Field[[]string] `json:"stop_sequences"` | |
| - // Whether to incrementally stream the response using server-sent events. | |
| - // | |
| - // See [streaming](https://docs.anthropic.com/en/api/messages-streaming) for | |
| - // details. | |
| - Stream param.Field[bool] `json:"stream"` | |
| + 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.anthropic.com/en/docs/system-prompts). | |
| - System param.Field[[]BetaTextBlockParam] `json:"system"` | |
| - // 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.Field[float64] `json:"temperature"` | |
| + System []BetaTextBlockParam `json:"system,omitzero"` | |
| // Configuration for enabling Claude's extended thinking. | |
| // | |
| // When enabled, responses include `thinking` content blocks showing Claude's | |
| @@ -848,10 +715,10 @@ type BetaMessageBatchNewParamsRequestsParams struct { | |
| // See | |
| // [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| // for details. | |
| - Thinking param.Field[BetaThinkingConfigParamUnion] `json:"thinking"` | |
| + 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 param.Field[BetaToolChoiceUnionParam] `json:"tool_choice"` | |
| + 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` | |
| @@ -927,51 +794,50 @@ type BetaMessageBatchNewParamsRequestsParams struct { | |
| // JSON structure of output. | |
| // | |
| // See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details. | |
| - Tools param.Field[[]BetaToolUnionUnionParam] `json:"tools"` | |
| - // 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.Field[int64] `json:"top_k"` | |
| - // 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.Field[float64] `json:"top_p"` | |
| + Tools []BetaToolUnionParam `json:"tools,omitzero"` | |
| + paramObj | |
| } | |
| -func (r BetaMessageBatchNewParamsRequestsParams) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageBatchNewParamsRequestParams) IsPresent() bool { | |
| + return !param.IsOmitted(f) && !f.IsNull() | |
| +} | |
| +func (r BetaMessageBatchNewParamsRequestParams) MarshalJSON() (data []byte, err error) { | |
| + type shadow BetaMessageBatchNewParamsRequestParams | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type BetaMessageBatchGetParams struct { | |
| // Optional header to specify the beta version(s) you want to use. | |
| - Betas param.Field[[]AnthropicBeta] `header:"anthropic-beta"` | |
| + Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageBatchGetParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| 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.Field[string] `query:"after_id"` | |
| + 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.Field[string] `query:"before_id"` | |
| + 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.Field[int64] `query:"limit"` | |
| + Limit param.Opt[int64] `query:"limit,omitzero" json:"-"` | |
| // Optional header to specify the beta version(s) you want to use. | |
| - Betas param.Field[[]AnthropicBeta] `header:"anthropic-beta"` | |
| + Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageBatchListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| // URLQuery serializes [BetaMessageBatchListParams]'s query parameters as | |
| // `url.Values`. | |
| func (r BetaMessageBatchListParams) URLQuery() (v url.Values) { | |
| @@ -983,15 +849,30 @@ func (r BetaMessageBatchListParams) URLQuery() (v url.Values) { | |
| type BetaMessageBatchDeleteParams struct { | |
| // Optional header to specify the beta version(s) you want to use. | |
| - Betas param.Field[[]AnthropicBeta] `header:"anthropic-beta"` | |
| + Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageBatchDeleteParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| type BetaMessageBatchCancelParams struct { | |
| // Optional header to specify the beta version(s) you want to use. | |
| - Betas param.Field[[]AnthropicBeta] `header:"anthropic-beta"` | |
| + Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageBatchCancelParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| type BetaMessageBatchResultsParams struct { | |
| // Optional header to specify the beta version(s) you want to use. | |
| - Betas param.Field[[]AnthropicBeta] `header:"anthropic-beta"` | |
| + Betas []AnthropicBeta `header:"anthropic-beta,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaMessageBatchResultsParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| diff --git a/betamessagebatch_test.go b/betamessagebatch_test.go | |
| index 6a82651..c11eb26 100644 | |
| --- a/betamessagebatch_test.go | |
| +++ b/betamessagebatch_test.go | |
| @@ -26,56 +26,63 @@ func TestBetaMessageBatchNewWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Beta.Messages.Batches.New(context.TODO(), anthropic.BetaMessageBatchNewParams{ | |
| - Requests: anthropic.F([]anthropic.BetaMessageBatchNewParamsRequest{{ | |
| - CustomID: anthropic.F("my-custom-id-1"), | |
| - Params: anthropic.F(anthropic.BetaMessageBatchNewParamsRequestsParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.BetaMessageParam{{ | |
| - Content: anthropic.F([]anthropic.BetaContentBlockParamUnion{anthropic.BetaTextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.BetaTextBlockParamTypeText), CacheControl: anthropic.F(anthropic.BetaCacheControlEphemeralParam{Type: anthropic.F(anthropic.BetaCacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.BetaTextCitationParamUnion{anthropic.BetaCitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.BetaCitationCharLocationParamTypeCharLocation)}})}}), | |
| - Role: anthropic.F(anthropic.BetaMessageParamRoleUser), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - Metadata: anthropic.F(anthropic.BetaMetadataParam{ | |
| - UserID: anthropic.F("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| - }), | |
| - StopSequences: anthropic.F([]string{"string"}), | |
| - Stream: anthropic.F(true), | |
| - System: anthropic.F([]anthropic.BetaTextBlockParam{{Text: anthropic.F("x"), Type: anthropic.F(anthropic.BetaTextBlockParamTypeText), CacheControl: anthropic.F(anthropic.BetaCacheControlEphemeralParam{Type: anthropic.F(anthropic.BetaCacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.BetaTextCitationParamUnion{anthropic.BetaCitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.BetaCitationCharLocationParamTypeCharLocation)}})}}), | |
| - Temperature: anthropic.F(1.000000), | |
| - Thinking: anthropic.F[anthropic.BetaThinkingConfigParamUnion](anthropic.BetaThinkingConfigEnabledParam{ | |
| - BudgetTokens: anthropic.F(int64(1024)), | |
| - Type: anthropic.F(anthropic.BetaThinkingConfigEnabledTypeEnabled), | |
| - }), | |
| - ToolChoice: anthropic.F[anthropic.BetaToolChoiceUnionParam](anthropic.BetaToolChoiceAutoParam{ | |
| - Type: anthropic.F(anthropic.BetaToolChoiceAutoTypeAuto), | |
| - DisableParallelToolUse: anthropic.F(true), | |
| - }), | |
| - Tools: anthropic.F([]anthropic.BetaToolUnionUnionParam{anthropic.BetaToolParam{ | |
| - InputSchema: anthropic.F(anthropic.BetaToolInputSchemaParam{ | |
| - Type: anthropic.F(anthropic.BetaToolInputSchemaTypeObject), | |
| - Properties: anthropic.F[any](map[string]interface{}{ | |
| - "location": map[string]interface{}{ | |
| - "description": "The city and state, e.g. San Francisco, CA", | |
| - "type": "string", | |
| + Requests: []anthropic.BetaMessageBatchNewParamsRequest{{ | |
| + CustomID: "my-custom-id-1", | |
| + Params: anthropic.BetaMessageBatchNewParamsRequestParams{ | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.BetaMessageParam{{ | |
| + Content: []anthropic.BetaContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.BetaTextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.BetaCacheControlEphemeralParam{}, Citations: []anthropic.BetaTextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.BetaCitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + Role: anthropic.BetaMessageParamRoleUser, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + Metadata: anthropic.BetaMetadataParam{ | |
| + UserID: anthropic.String("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| + }, | |
| + StopSequences: []string{"string"}, | |
| + Stream: anthropic.Bool(true), | |
| + System: []anthropic.BetaTextBlockParam{{Text: "x", CacheControl: anthropic.BetaCacheControlEphemeralParam{}, Citations: []anthropic.BetaTextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.BetaCitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}}, | |
| + Temperature: anthropic.Float(1), | |
| + Thinking: anthropic.BetaThinkingConfigParamUnion{ | |
| + OfThinkingConfigEnabled: &anthropic.BetaThinkingConfigEnabledParam{ | |
| + BudgetTokens: 1024, | |
| + }, | |
| + }, | |
| + ToolChoice: anthropic.BetaToolChoiceUnionParam{ | |
| + OfToolChoiceAuto: &anthropic.BetaToolChoiceAutoParam{ | |
| + DisableParallelToolUse: anthropic.Bool(true), | |
| + }, | |
| + }, | |
| + Tools: []anthropic.BetaToolUnionParam{{ | |
| + OfTool: &anthropic.BetaToolParam{ | |
| + InputSchema: anthropic.BetaToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| + "location": map[string]interface{}{ | |
| + "description": "The city and state, e.g. San Francisco, CA", | |
| + "type": "string", | |
| + }, | |
| + "unit": map[string]interface{}{ | |
| + "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| + "type": "string", | |
| + }, | |
| }, | |
| - "unit": map[string]interface{}{ | |
| - "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| - "type": "string", | |
| - }, | |
| - }), | |
| - }), | |
| - Name: anthropic.F("name"), | |
| - CacheControl: anthropic.F(anthropic.BetaCacheControlEphemeralParam{ | |
| - Type: anthropic.F(anthropic.BetaCacheControlEphemeralTypeEphemeral), | |
| - }), | |
| - Description: anthropic.F("Get the current weather in a given location"), | |
| - Type: anthropic.F(anthropic.BetaToolTypeCustom), | |
| - }}), | |
| - TopK: anthropic.F(int64(5)), | |
| - TopP: anthropic.F(0.700000), | |
| - }), | |
| - }}), | |
| - Betas: anthropic.F([]anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}), | |
| + }, | |
| + Name: "name", | |
| + CacheControl: anthropic.BetaCacheControlEphemeralParam{}, | |
| + Description: anthropic.String("Get the current weather in a given location"), | |
| + Type: anthropic.BetaToolTypeCustom, | |
| + }, | |
| + }}, | |
| + TopK: anthropic.Int(5), | |
| + TopP: anthropic.Float(0.7), | |
| + }, | |
| + }}, | |
| + Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}, | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| @@ -102,7 +109,7 @@ func TestBetaMessageBatchGetWithOptionalParams(t *testing.T) { | |
| context.TODO(), | |
| "message_batch_id", | |
| anthropic.BetaMessageBatchGetParams{ | |
| - Betas: anthropic.F([]anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}), | |
| + Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}, | |
| }, | |
| ) | |
| if err != nil { | |
| @@ -127,10 +134,10 @@ func TestBetaMessageBatchListWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Beta.Messages.Batches.List(context.TODO(), anthropic.BetaMessageBatchListParams{ | |
| - AfterID: anthropic.F("after_id"), | |
| - BeforeID: anthropic.F("before_id"), | |
| - Limit: anthropic.F(int64(1)), | |
| - Betas: anthropic.F([]anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}), | |
| + AfterID: anthropic.String("after_id"), | |
| + BeforeID: anthropic.String("before_id"), | |
| + Limit: anthropic.Int(1), | |
| + Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}, | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| @@ -157,7 +164,7 @@ func TestBetaMessageBatchDeleteWithOptionalParams(t *testing.T) { | |
| context.TODO(), | |
| "message_batch_id", | |
| anthropic.BetaMessageBatchDeleteParams{ | |
| - Betas: anthropic.F([]anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}), | |
| + Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}, | |
| }, | |
| ) | |
| if err != nil { | |
| @@ -185,7 +192,7 @@ func TestBetaMessageBatchCancelWithOptionalParams(t *testing.T) { | |
| context.TODO(), | |
| "message_batch_id", | |
| anthropic.BetaMessageBatchCancelParams{ | |
| - Betas: anthropic.F([]anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}), | |
| + Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaMessageBatches2024_09_24}, | |
| }, | |
| ) | |
| if err != nil { | |
| diff --git a/betamodel.go b/betamodel.go | |
| index 76d3e64..b9fec3e 100644 | |
| --- a/betamodel.go | |
| +++ b/betamodel.go | |
| @@ -12,10 +12,12 @@ import ( | |
| "github.com/anthropics/anthropic-sdk-go/internal/apijson" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apiquery" | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| "github.com/anthropics/anthropic-sdk-go/internal/requestconfig" | |
| "github.com/anthropics/anthropic-sdk-go/option" | |
| "github.com/anthropics/anthropic-sdk-go/packages/pagination" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| + "github.com/anthropics/anthropic-sdk-go/shared/constant" | |
| ) | |
| // BetaModelService contains methods and other services that help with interacting | |
| @@ -31,8 +33,8 @@ type BetaModelService struct { | |
| // 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{} | |
| +func NewBetaModelService(opts ...option.RequestOption) (r BetaModelService) { | |
| + r = BetaModelService{} | |
| r.Options = opts | |
| return | |
| } | |
| @@ -92,58 +94,43 @@ type BetaModelInfo struct { | |
| // Object type. | |
| // | |
| // For Models, this is always `"model"`. | |
| - Type BetaModelInfoType `json:"type,required"` | |
| - JSON betaModelInfoJSON `json:"-"` | |
| + Type constant.Model `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + CreatedAt resp.Field | |
| + DisplayName resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| } | |
| -// betaModelInfoJSON contains the JSON metadata for the struct [BetaModelInfo] | |
| -type betaModelInfoJSON struct { | |
| - ID apijson.Field | |
| - CreatedAt apijson.Field | |
| - DisplayName apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *BetaModelInfo) UnmarshalJSON(data []byte) (err error) { | |
| +// 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) | |
| } | |
| -func (r betaModelInfoJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -// Object type. | |
| -// | |
| -// For Models, this is always `"model"`. | |
| -type BetaModelInfoType string | |
| - | |
| -const ( | |
| - BetaModelInfoTypeModel BetaModelInfoType = "model" | |
| -) | |
| - | |
| -func (r BetaModelInfoType) IsKnown() bool { | |
| - switch r { | |
| - case BetaModelInfoTypeModel: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| 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.Field[string] `query:"after_id"` | |
| + 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.Field[string] `query:"before_id"` | |
| + 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.Field[int64] `query:"limit"` | |
| + Limit param.Opt[int64] `query:"limit,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f BetaModelListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| // URLQuery serializes [BetaModelListParams]'s query parameters as `url.Values`. | |
| func (r BetaModelListParams) URLQuery() (v url.Values) { | |
| return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ | |
| diff --git a/betamodel_test.go b/betamodel_test.go | |
| index 77bf1a8..1cb6042 100644 | |
| --- a/betamodel_test.go | |
| +++ b/betamodel_test.go | |
| @@ -48,9 +48,9 @@ func TestBetaModelListWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Beta.Models.List(context.TODO(), anthropic.BetaModelListParams{ | |
| - AfterID: anthropic.F("after_id"), | |
| - BeforeID: anthropic.F("before_id"), | |
| - Limit: anthropic.F(int64(1)), | |
| + AfterID: anthropic.String("after_id"), | |
| + BeforeID: anthropic.String("before_id"), | |
| + Limit: anthropic.Int(1), | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| diff --git a/client.go b/client.go | |
| index 8ece40c..d5549a9 100644 | |
| --- a/client.go | |
| +++ b/client.go | |
| @@ -16,17 +16,15 @@ import ( | |
| // directly, and instead use the [NewClient] method instead. | |
| type Client struct { | |
| Options []option.RequestOption | |
| - Completions *CompletionService | |
| - Messages *MessageService | |
| - Models *ModelService | |
| - Beta *BetaService | |
| + Completions CompletionService | |
| + Messages MessageService | |
| + Models ModelService | |
| + Beta BetaService | |
| } | |
| -// NewClient generates a new client with the default option read from the | |
| -// environment (ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN). The option passed in as | |
| -// arguments are applied after these default arguments, and all option will be | |
| -// passed down to the services and requests that this client makes. | |
| -func NewClient(opts ...option.RequestOption) (r *Client) { | |
| +// DefaultClientOptions read from the environment (ANTHROPIC_API_KEY, | |
| +// ANTHROPIC_AUTH_TOKEN). This should be used to initialize new clients. | |
| +func DefaultClientOptions() []option.RequestOption { | |
| defaults := []option.RequestOption{option.WithEnvironmentProduction()} | |
| if o, ok := os.LookupEnv("ANTHROPIC_API_KEY"); ok { | |
| defaults = append(defaults, option.WithAPIKey(o)) | |
| @@ -34,9 +32,17 @@ func NewClient(opts ...option.RequestOption) (r *Client) { | |
| if o, ok := os.LookupEnv("ANTHROPIC_AUTH_TOKEN"); ok { | |
| defaults = append(defaults, option.WithAuthToken(o)) | |
| } | |
| - opts = append(defaults, opts...) | |
| + return defaults | |
| +} | |
| + | |
| +// NewClient generates a new client with the default option read from the | |
| +// environment (ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN). The option passed in as | |
| +// arguments are applied after these default arguments, and all option will be | |
| +// passed down to the services and requests that this client makes. | |
| +func NewClient(opts ...option.RequestOption) (r Client) { | |
| + opts = append(DefaultClientOptions(), opts...) | |
| - r = &Client{Options: opts} | |
| + r = Client{Options: opts} | |
| r.Completions = NewCompletionService(opts...) | |
| r.Messages = NewMessageService(opts...) | |
| diff --git a/client_test.go b/client_test.go | |
| index 7cd6621..50774e4 100644 | |
| --- a/client_test.go | |
| +++ b/client_test.go | |
| @@ -27,6 +27,7 @@ func (t *closureTransport) RoundTrip(req *http.Request) (*http.Response, error) | |
| func TestUserAgentHeader(t *testing.T) { | |
| var userAgent string | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -39,12 +40,16 @@ func TestUserAgentHeader(t *testing.T) { | |
| }), | |
| ) | |
| client.Messages.New(context.Background(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if userAgent != fmt.Sprintf("Anthropic/Go %s", internal.PackageVersion) { | |
| t.Errorf("Expected User-Agent to be correct, but got: %#v", userAgent) | |
| @@ -54,6 +59,7 @@ func TestUserAgentHeader(t *testing.T) { | |
| func TestRetryAfter(t *testing.T) { | |
| retryCountHeaders := make([]string, 0) | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -69,12 +75,16 @@ func TestRetryAfter(t *testing.T) { | |
| }), | |
| ) | |
| _, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if err == nil { | |
| t.Error("Expected there to be a cancel error") | |
| @@ -94,6 +104,7 @@ func TestRetryAfter(t *testing.T) { | |
| func TestDeleteRetryCountHeader(t *testing.T) { | |
| retryCountHeaders := make([]string, 0) | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -110,12 +121,16 @@ func TestDeleteRetryCountHeader(t *testing.T) { | |
| option.WithHeaderDel("X-Stainless-Retry-Count"), | |
| ) | |
| _, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if err == nil { | |
| t.Error("Expected there to be a cancel error") | |
| @@ -130,6 +145,7 @@ func TestDeleteRetryCountHeader(t *testing.T) { | |
| func TestOverwriteRetryCountHeader(t *testing.T) { | |
| retryCountHeaders := make([]string, 0) | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -146,12 +162,16 @@ func TestOverwriteRetryCountHeader(t *testing.T) { | |
| option.WithHeader("X-Stainless-Retry-Count", "42"), | |
| ) | |
| _, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if err == nil { | |
| t.Error("Expected there to be a cancel error") | |
| @@ -166,6 +186,7 @@ func TestOverwriteRetryCountHeader(t *testing.T) { | |
| func TestRetryAfterMs(t *testing.T) { | |
| attempts := 0 | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -181,12 +202,16 @@ func TestRetryAfterMs(t *testing.T) { | |
| }), | |
| ) | |
| _, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if err == nil { | |
| t.Error("Expected there to be a cancel error") | |
| @@ -198,6 +223,7 @@ func TestRetryAfterMs(t *testing.T) { | |
| func TestContextCancel(t *testing.T) { | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -210,12 +236,16 @@ func TestContextCancel(t *testing.T) { | |
| cancelCtx, cancel := context.WithCancel(context.Background()) | |
| cancel() | |
| _, err := client.Messages.New(cancelCtx, anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if err == nil { | |
| t.Error("Expected there to be a cancel error") | |
| @@ -224,6 +254,7 @@ func TestContextCancel(t *testing.T) { | |
| func TestContextCancelDelay(t *testing.T) { | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -236,12 +267,16 @@ func TestContextCancelDelay(t *testing.T) { | |
| cancelCtx, cancel := context.WithTimeout(context.Background(), 2*time.Millisecond) | |
| defer cancel() | |
| _, err := client.Messages.New(cancelCtx, anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if err == nil { | |
| t.Error("expected there to be a cancel error") | |
| @@ -258,6 +293,7 @@ func TestContextDeadline(t *testing.T) { | |
| go func() { | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -268,12 +304,16 @@ func TestContextDeadline(t *testing.T) { | |
| }), | |
| ) | |
| _, err := client.Messages.New(deadlineCtx, anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Role: anthropic.MessageParamRoleUser, | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| if err == nil { | |
| t.Error("expected there to be a deadline error") | |
| @@ -301,6 +341,7 @@ func TestContextDeadlineStreaming(t *testing.T) { | |
| go func() { | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -319,12 +360,16 @@ func TestContextDeadlineStreaming(t *testing.T) { | |
| }), | |
| ) | |
| stream := client.Messages.NewStreaming(deadlineCtx, anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + Role: anthropic.MessageParamRoleUser, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }) | |
| for stream.Next() { | |
| _ = stream.Current() | |
| @@ -352,6 +397,7 @@ func TestContextDeadlineStreamingWithRequestTimeout(t *testing.T) { | |
| go func() { | |
| client := anthropic.NewClient( | |
| + option.WithAPIKey("my-anthropic-api-key"), | |
| option.WithHTTPClient(&http.Client{ | |
| Transport: &closureTransport{ | |
| fn: func(req *http.Request) (*http.Response, error) { | |
| @@ -372,12 +418,16 @@ func TestContextDeadlineStreamingWithRequestTimeout(t *testing.T) { | |
| stream := client.Messages.NewStreaming( | |
| context.Background(), | |
| anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + Role: anthropic.MessageParamRoleUser, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| }, | |
| option.WithRequestTimeout((100 * time.Millisecond)), | |
| ) | |
| diff --git a/completion.go b/completion.go | |
| index 4489146..e768ab2 100644 | |
| --- a/completion.go | |
| +++ b/completion.go | |
| @@ -7,10 +7,12 @@ import ( | |
| "net/http" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apijson" | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| "github.com/anthropics/anthropic-sdk-go/internal/requestconfig" | |
| "github.com/anthropics/anthropic-sdk-go/option" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| "github.com/anthropics/anthropic-sdk-go/packages/ssestream" | |
| + "github.com/anthropics/anthropic-sdk-go/shared/constant" | |
| ) | |
| // CompletionService contains methods and other services that help with interacting | |
| @@ -26,8 +28,8 @@ type CompletionService struct { | |
| // NewCompletionService 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 NewCompletionService(opts ...option.RequestOption) (r *CompletionService) { | |
| - r = &CompletionService{} | |
| +func NewCompletionService(opts ...option.RequestOption) (r CompletionService) { | |
| + r = CompletionService{} | |
| r.Options = opts | |
| return | |
| } | |
| @@ -89,60 +91,40 @@ type Completion struct { | |
| // - `"stop_sequence"`: we reached a stop sequence — either provided by you via the | |
| // `stop_sequences` parameter, or a stop sequence built into the model | |
| // - `"max_tokens"`: we exceeded `max_tokens_to_sample` or the model's maximum | |
| - StopReason string `json:"stop_reason,required,nullable"` | |
| + StopReason string `json:"stop_reason,required"` | |
| // Object type. | |
| // | |
| // For Text Completions, this is always `"completion"`. | |
| - Type CompletionType `json:"type,required"` | |
| - JSON completionJSON `json:"-"` | |
| + Type constant.Completion `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + Completion resp.Field | |
| + Model resp.Field | |
| + StopReason resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| } | |
| -// completionJSON contains the JSON metadata for the struct [Completion] | |
| -type completionJSON struct { | |
| - ID apijson.Field | |
| - Completion apijson.Field | |
| - Model apijson.Field | |
| - StopReason apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *Completion) UnmarshalJSON(data []byte) (err error) { | |
| +// Returns the unmodified JSON received from the API | |
| +func (r Completion) RawJSON() string { return r.JSON.raw } | |
| +func (r *Completion) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r completionJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -// Object type. | |
| -// | |
| -// For Text Completions, this is always `"completion"`. | |
| -type CompletionType string | |
| - | |
| -const ( | |
| - CompletionTypeCompletion CompletionType = "completion" | |
| -) | |
| - | |
| -func (r CompletionType) IsKnown() bool { | |
| - switch r { | |
| - case CompletionTypeCompletion: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type CompletionNewParams 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. | |
| - MaxTokensToSample param.Field[int64] `json:"max_tokens_to_sample,required"` | |
| + MaxTokensToSample int64 `json:"max_tokens_to_sample,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 param.Field[Model] `json:"model,required"` | |
| + Model Model `json:"model,omitzero,required"` | |
| // The prompt that you want Claude to complete. | |
| // | |
| // For proper response generation you will need to format your prompt using | |
| @@ -156,15 +138,7 @@ type CompletionNewParams struct { | |
| // our guide to | |
| // [prompt design](https://docs.anthropic.com/en/docs/intro-to-prompting) for more | |
| // details. | |
| - Prompt param.Field[string] `json:"prompt,required"` | |
| - // An object describing metadata about the request. | |
| - Metadata param.Field[MetadataParam] `json:"metadata"` | |
| - // Sequences that will cause the model to stop generating. | |
| - // | |
| - // Our models stop on `"\n\nHuman:"`, and may include additional built-in stop | |
| - // sequences in the future. By providing the stop_sequences parameter, you may | |
| - // include additional strings that will cause the model to stop generating. | |
| - StopSequences param.Field[[]string] `json:"stop_sequences"` | |
| + Prompt string `json:"prompt,required"` | |
| // Amount of randomness injected into the response. | |
| // | |
| // Defaults to `1.0`. Ranges from `0.0` to `1.0`. Use `temperature` closer to `0.0` | |
| @@ -173,7 +147,7 @@ type CompletionNewParams struct { | |
| // | |
| // Note that even with `temperature` of `0.0`, the results will not be fully | |
| // deterministic. | |
| - Temperature param.Field[float64] `json:"temperature"` | |
| + 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. | |
| @@ -181,7 +155,7 @@ type CompletionNewParams struct { | |
| // | |
| // Recommended for advanced use cases only. You usually only need to use | |
| // `temperature`. | |
| - TopK param.Field[int64] `json:"top_k"` | |
| + TopK param.Opt[int64] `json:"top_k,omitzero"` | |
| // Use nucleus sampling. | |
| // | |
| // In nucleus sampling, we compute the cumulative distribution over all the options | |
| @@ -191,9 +165,23 @@ type CompletionNewParams struct { | |
| // | |
| // Recommended for advanced use cases only. You usually only need to use | |
| // `temperature`. | |
| - TopP param.Field[float64] `json:"top_p"` | |
| + TopP param.Opt[float64] `json:"top_p,omitzero"` | |
| + // An object describing metadata about the request. | |
| + Metadata MetadataParam `json:"metadata,omitzero"` | |
| + // Sequences that will cause the model to stop generating. | |
| + // | |
| + // Our models stop on `"\n\nHuman:"`, and may include additional built-in stop | |
| + // sequences in the future. By providing the stop_sequences parameter, you may | |
| + // include additional strings that will cause the model to stop generating. | |
| + StopSequences []string `json:"stop_sequences,omitzero"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f CompletionNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| func (r CompletionNewParams) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow CompletionNewParams | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| diff --git a/completion_test.go b/completion_test.go | |
| index 708008b..edc613b 100644 | |
| --- a/completion_test.go | |
| +++ b/completion_test.go | |
| @@ -26,16 +26,16 @@ func TestCompletionNewWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Completions.New(context.TODO(), anthropic.CompletionNewParams{ | |
| - MaxTokensToSample: anthropic.F(int64(256)), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - Prompt: anthropic.F("\n\nHuman: Hello, world!\n\nAssistant:"), | |
| - Metadata: anthropic.F(anthropic.MetadataParam{ | |
| - UserID: anthropic.F("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| - }), | |
| - StopSequences: anthropic.F([]string{"string"}), | |
| - Temperature: anthropic.F(1.000000), | |
| - TopK: anthropic.F(int64(5)), | |
| - TopP: anthropic.F(0.700000), | |
| + MaxTokensToSample: 256, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + Prompt: "\n\nHuman: Hello, world!\n\nAssistant:", | |
| + Metadata: anthropic.MetadataParam{ | |
| + UserID: anthropic.String("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| + }, | |
| + StopSequences: []string{"string"}, | |
| + Temperature: anthropic.Float(1), | |
| + TopK: anthropic.Int(5), | |
| + TopP: anthropic.Float(0.7), | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| diff --git a/examples/bedrock-streaming/main.go b/examples/bedrock-streaming/main.go | |
| index 3cbde70..6579376 100644 | |
| --- a/examples/bedrock-streaming/main.go | |
| +++ b/examples/bedrock-streaming/main.go | |
| @@ -2,7 +2,6 @@ package main | |
| import ( | |
| "context" | |
| - | |
| "github.com/anthropics/anthropic-sdk-go" | |
| "github.com/anthropics/anthropic-sdk-go/bedrock" | |
| ) | |
| @@ -17,12 +16,12 @@ func main() { | |
| println("[user]: " + content) | |
| stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{ | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| - }), | |
| - Model: anthropic.F("anthropic.claude-3-sonnet-20240229-v1:0"), | |
| - StopSequences: anthropic.F([]string{"```\n"}), | |
| + }, | |
| + Model: "us.anthropic.claude-3-5-haiku-20241022-v1:0", | |
| + StopSequences: []string{"```\n"}, | |
| }) | |
| print("[assistant]: ") | |
| @@ -30,14 +29,13 @@ func main() { | |
| for stream.Next() { | |
| event := stream.Current() | |
| - switch delta := event.Delta.(type) { | |
| - case anthropic.ContentBlockDeltaEventDelta: | |
| - if delta.Text != "" { | |
| - print(delta.Text) | |
| - } | |
| - case anthropic.MessageDeltaEventDelta: | |
| - if delta.StopSequence != "" { | |
| - print(delta.StopSequence) | |
| + switch eventVariant := event.AsAny().(type) { | |
| + case anthropic.MessageDeltaEvent: | |
| + print(eventVariant.Delta.StopSequence) | |
| + case anthropic.ContentBlockDeltaEvent: | |
| + switch deltaVariant := eventVariant.Delta.AsAny().(type) { | |
| + case anthropic.TextDelta: | |
| + print(deltaVariant.Text) | |
| } | |
| } | |
| } | |
| diff --git a/examples/bedrock/main.go b/examples/bedrock/main.go | |
| index f5a955c..f854be8 100644 | |
| --- a/examples/bedrock/main.go | |
| +++ b/examples/bedrock/main.go | |
| @@ -17,12 +17,12 @@ func main() { | |
| println("[user]: " + content) | |
| message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{ | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| - }), | |
| - Model: anthropic.F("anthropic.claude-3-sonnet-20240229-v1:0"), | |
| - StopSequences: anthropic.F([]string{"```\n"}), | |
| + }, | |
| + Model: "us.anthropic.claude-3-5-haiku-20241022-v1:0", | |
| + StopSequences: []string{"```\n"}, | |
| }) | |
| if err != nil { | |
| panic(err) | |
| diff --git a/examples/message-streaming/main.go b/examples/message-streaming/main.go | |
| index 4ec65c8..9a69d1a 100644 | |
| --- a/examples/message-streaming/main.go | |
| +++ b/examples/message-streaming/main.go | |
| @@ -2,6 +2,7 @@ package main | |
| import ( | |
| "context" | |
| + "fmt" | |
| "github.com/anthropics/anthropic-sdk-go" | |
| ) | |
| @@ -14,12 +15,12 @@ func main() { | |
| println("[user]: " + content) | |
| stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{ | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| - }), | |
| - Model: anthropic.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - StopSequences: anthropic.F([]string{"```\n"}), | |
| + }, | |
| + Model: anthropic.ModelClaude_3_5_Sonnet_20240620, | |
| + StopSequences: []string{"```\n"}, | |
| }) | |
| print("[assistant]: ") | |
| @@ -27,14 +28,13 @@ func main() { | |
| for stream.Next() { | |
| event := stream.Current() | |
| - switch delta := event.Delta.(type) { | |
| - case anthropic.ContentBlockDeltaEventDelta: | |
| - if delta.Text != "" { | |
| - print(delta.Text) | |
| - } | |
| - case anthropic.MessageDeltaEventDelta: | |
| - if delta.StopSequence != "" { | |
| - print(delta.StopSequence) | |
| + switch eventVariant := event.AsAny().(type) { | |
| + case anthropic.MessageDeltaEvent: | |
| + print(eventVariant.Delta.StopSequence) | |
| + case anthropic.ContentBlockDeltaEvent: | |
| + switch deltaVariant := eventVariant.Delta.AsAny().(type) { | |
| + case anthropic.TextDelta: | |
| + print(deltaVariant.Text) | |
| } | |
| } | |
| } | |
| diff --git a/examples/message/main.go b/examples/message/main.go | |
| index 3c2a590..8d3b4c9 100644 | |
| --- a/examples/message/main.go | |
| +++ b/examples/message/main.go | |
| @@ -14,15 +14,12 @@ func main() { | |
| println("[user]: " + content) | |
| message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.Int(1024), | |
| - System: anthropic.F([]anthropic.TextBlockParam{ | |
| - anthropic.NewTextBlock("Be very serious"), | |
| - }), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{ | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| - }), | |
| - Model: anthropic.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - StopSequences: anthropic.F([]string{"```\n"}), | |
| + }, | |
| + Model: anthropic.ModelClaude_3_5_Sonnet_20240620, | |
| + StopSequences: []string{"```\n"}, | |
| }) | |
| if err != nil { | |
| panic(err) | |
| diff --git a/examples/multimodal/main.go b/examples/multimodal/main.go | |
| index a58cc5a..00f9a6c 100644 | |
| --- a/examples/multimodal/main.go | |
| +++ b/examples/multimodal/main.go | |
| @@ -28,15 +28,15 @@ func main() { | |
| fileEncoded := base64.StdEncoding.EncodeToString(fileBytes) | |
| message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{ | |
| anthropic.NewUserMessage( | |
| anthropic.NewTextBlock(content), | |
| anthropic.NewImageBlockBase64("image/png", fileEncoded), | |
| ), | |
| - }), | |
| - Model: anthropic.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - StopSequences: anthropic.F([]string{"```\n"}), | |
| + }, | |
| + Model: anthropic.ModelClaude_3_5_Sonnet_20240620, | |
| + StopSequences: []string{"```\n"}, | |
| }) | |
| if err != nil { | |
| panic(err) | |
| diff --git a/examples/multimodal/nine_dogs.png b/examples/multimodal/nine_dogs.png | |
| new file mode 100644 | |
| index 0000000..1e211ce | |
| Binary files /dev/null and b/examples/multimodal/nine_dogs.png differ | |
| diff --git a/examples/tools-streaming-jsonschema/main.go b/examples/tools-streaming-jsonschema/main.go | |
| index 33c7cad..6e5d080 100644 | |
| --- a/examples/tools-streaming-jsonschema/main.go | |
| +++ b/examples/tools-streaming-jsonschema/main.go | |
| @@ -20,29 +20,33 @@ func main() { | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| } | |
| - tools := []anthropic.ToolParam{ | |
| + toolParams := []anthropic.ToolParam{ | |
| { | |
| - Name: anthropic.F("get_coordinates"), | |
| - Description: anthropic.F("Accepts a place as an address, then returns the latitude and longitude coordinates."), | |
| - InputSchema: anthropic.F(GetCoordinatesInputSchema), | |
| + Name: "get_coordinates", | |
| + Description: anthropic.String("Accepts a place as an address, then returns the latitude and longitude coordinates."), | |
| + InputSchema: GetCoordinatesInputSchema, | |
| }, | |
| { | |
| - Name: anthropic.F("get_temperature_unit"), | |
| - InputSchema: anthropic.F(GetTemperatureUnitInputSchema), | |
| + Name: "get_temperature_unit", | |
| + InputSchema: GetTemperatureUnitInputSchema, | |
| }, | |
| { | |
| - Name: anthropic.F("get_weather"), | |
| - Description: anthropic.F("Get the weather at a specific location"), | |
| - InputSchema: anthropic.F(GetWeatherInputSchema), | |
| + Name: "get_weather", | |
| + Description: anthropic.String("Get the weather at a specific location"), | |
| + InputSchema: GetWeatherInputSchema, | |
| }, | |
| } | |
| + tools := make([]anthropic.ToolUnionParam, len(toolParams)) | |
| + for i, toolParam := range toolParams { | |
| + tools[i] = anthropic.ToolUnionParam{OfTool: &toolParam} | |
| + } | |
| for { | |
| stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{ | |
| - Model: anthropic.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F(messages), | |
| - Tools: anthropic.F(tools), | |
| + Model: anthropic.ModelClaude3_7Sonnet20250219, | |
| + MaxTokens: 1024, | |
| + Messages: messages, | |
| + Tools: tools, | |
| }) | |
| print(color("[assistant]: ")) | |
| @@ -55,7 +59,7 @@ func main() { | |
| panic(err) | |
| } | |
| - switch event := event.AsUnion().(type) { | |
| + switch event := event.AsAny().(type) { | |
| case anthropic.ContentBlockStartEvent: | |
| if event.ContentBlock.Name != "" { | |
| print(event.ContentBlock.Name + ": ") | |
| @@ -79,28 +83,29 @@ func main() { | |
| toolResults := []anthropic.ContentBlockParamUnion{} | |
| for _, block := range message.Content { | |
| - if block.Type == anthropic.ContentBlockTypeToolUse { | |
| + switch variant := block.AsAny().(type) { | |
| + case anthropic.ToolUseBlock: | |
| print(color("[user (" + block.Name + ")]: ")) | |
| var response interface{} | |
| switch block.Name { | |
| case "get_coordinates": | |
| input := GetCoordinatesInput{} | |
| - err := json.Unmarshal(block.Input, &input) | |
| + err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input) | |
| if err != nil { | |
| panic(err) | |
| } | |
| response = GetCoordinates(input.Location) | |
| case "get_temperature_unit": | |
| input := GetTemperatureUnitInput{} | |
| - err := json.Unmarshal(block.Input, &input) | |
| + err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input) | |
| if err != nil { | |
| panic(err) | |
| } | |
| response = GetTemperatureUnit(input.Country) | |
| case "get_weather": | |
| input := GetWeatherInput{} | |
| - err := json.Unmarshal(block.Input, &input) | |
| + err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input) | |
| if err != nil { | |
| panic(err) | |
| } | |
| @@ -122,10 +127,7 @@ func main() { | |
| break | |
| } | |
| - messages = append(messages, anthropic.MessageParam{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F(toolResults), | |
| - }) | |
| + messages = append(messages, anthropic.NewUserMessage(toolResults...)) | |
| } | |
| } | |
| @@ -183,13 +185,18 @@ func GetWeather(lat, long float64, unit string) GetWeatherResponse { | |
| } | |
| } | |
| -func GenerateSchema[T any]() interface{} { | |
| +func GenerateSchema[T any]() anthropic.ToolInputSchemaParam { | |
| reflector := jsonschema.Reflector{ | |
| AllowAdditionalProperties: false, | |
| DoNotReference: true, | |
| } | |
| var v T | |
| - return reflector.Reflect(v) | |
| + | |
| + schema := reflector.Reflect(v) | |
| + | |
| + return anthropic.ToolInputSchemaParam{ | |
| + Properties: schema.Properties, | |
| + } | |
| } | |
| func color(s string) string { | |
| diff --git a/examples/tools-streaming/main.go b/examples/tools-streaming/main.go | |
| index b9b49d1..0e6f71d 100644 | |
| --- a/examples/tools-streaming/main.go | |
| +++ b/examples/tools-streaming/main.go | |
| @@ -19,38 +19,35 @@ func main() { | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| } | |
| - tools := []anthropic.ToolParam{ | |
| + toolParams := []anthropic.ToolParam{ | |
| { | |
| - Name: anthropic.F("get_coordinates"), | |
| - Description: anthropic.F("Accepts a place as an address, then returns the latitude and longitude coordinates."), | |
| - InputSchema: anthropic.F[interface{}](map[string]interface{}{ | |
| - "type": "object", | |
| - "properties": map[string]interface{}{ | |
| + Name: "get_coordinates", | |
| + Description: anthropic.String("Accepts a place as an address, then returns the latitude and longitude coordinates."), | |
| + InputSchema: anthropic.ToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| "location": map[string]interface{}{ | |
| "type": "string", | |
| "description": "The location to look up.", | |
| }, | |
| }, | |
| - }), | |
| + }, | |
| }, | |
| { | |
| - Name: anthropic.F("get_temperature_unit"), | |
| - InputSchema: anthropic.F[interface{}](map[string]interface{}{ | |
| - "type": "object", | |
| - "properties": map[string]interface{}{ | |
| + Name: "get_temperature_unit", | |
| + InputSchema: anthropic.ToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| "country": map[string]interface{}{ | |
| "type": "string", | |
| "description": "The country", | |
| }, | |
| }, | |
| - }), | |
| + }, | |
| }, | |
| { | |
| - Name: anthropic.F("get_weather"), | |
| - Description: anthropic.F("Get the weather at a specific location"), | |
| - InputSchema: anthropic.F[interface{}](map[string]interface{}{ | |
| - "type": "object", | |
| - "properties": map[string]interface{}{ | |
| + Name: "get_weather", | |
| + Description: anthropic.String("Get the weather at a specific location"), | |
| + InputSchema: anthropic.ToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| "lat": map[string]interface{}{ | |
| "type": "number", | |
| "description": "The lattitude of the location to check weather.", | |
| @@ -65,16 +62,20 @@ func main() { | |
| "description": "Unit for the output", | |
| }, | |
| }, | |
| - }), | |
| + }, | |
| }, | |
| } | |
| + tools := make([]anthropic.ToolUnionParam, len(toolParams)) | |
| + for i, toolParam := range toolParams { | |
| + tools[i] = anthropic.ToolUnionParam{OfTool: &toolParam} | |
| + } | |
| for { | |
| stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{ | |
| - Model: anthropic.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F(messages), | |
| - Tools: anthropic.F(tools), | |
| + Model: anthropic.ModelClaude3_7Sonnet20250219, | |
| + MaxTokens: 1024, | |
| + Messages: messages, | |
| + Tools: tools, | |
| }) | |
| print(color("[assistant]: ")) | |
| @@ -87,7 +88,7 @@ func main() { | |
| panic(err) | |
| } | |
| - switch event := event.AsUnion().(type) { | |
| + switch event := event.AsAny().(type) { | |
| case anthropic.ContentBlockStartEvent: | |
| if event.ContentBlock.Name != "" { | |
| print(event.ContentBlock.Name + ": ") | |
| @@ -111,7 +112,8 @@ func main() { | |
| toolResults := []anthropic.ContentBlockParamUnion{} | |
| for _, block := range message.Content { | |
| - if block.Type == anthropic.ContentBlockTypeToolUse { | |
| + switch variant := block.AsAny().(type) { | |
| + case anthropic.ToolUseBlock: | |
| print(color("[user (" + block.Name + ")]: ")) | |
| var response interface{} | |
| @@ -120,7 +122,7 @@ func main() { | |
| var input struct { | |
| Location string `json:"location"` | |
| } | |
| - err := json.Unmarshal(block.Input, &input) | |
| + err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input) | |
| if err != nil { | |
| panic(err) | |
| } | |
| @@ -129,7 +131,7 @@ func main() { | |
| var input struct { | |
| Country string `json:"country"` | |
| } | |
| - err := json.Unmarshal(block.Input, &input) | |
| + err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input) | |
| if err != nil { | |
| panic(err) | |
| } | |
| @@ -140,7 +142,7 @@ func main() { | |
| Long float64 `json:"long"` | |
| Unit string `json:"unit"` | |
| } | |
| - err := json.Unmarshal(block.Input, &input) | |
| + err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input) | |
| if err != nil { | |
| panic(err) | |
| } | |
| @@ -162,10 +164,7 @@ func main() { | |
| break | |
| } | |
| - messages = append(messages, anthropic.MessageParam{ | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - Content: anthropic.F(toolResults), | |
| - }) | |
| + messages = append(messages, anthropic.NewUserMessage(toolResults...)) | |
| } | |
| } | |
| diff --git a/examples/tools/main.go b/examples/tools/main.go | |
| index 864e622..a6274eb 100644 | |
| --- a/examples/tools/main.go | |
| +++ b/examples/tools/main.go | |
| @@ -19,38 +19,35 @@ func main() { | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| } | |
| - tools := []anthropic.ToolParam{ | |
| + toolParams := []anthropic.ToolParam{ | |
| { | |
| - Name: anthropic.F("get_coordinates"), | |
| - Description: anthropic.F("Accepts a place as an address, then returns the latitude and longitude coordinates."), | |
| - InputSchema: anthropic.F[interface{}](map[string]interface{}{ | |
| - "type": "object", | |
| - "properties": map[string]interface{}{ | |
| + Name: "get_coordinates", | |
| + Description: anthropic.String("Accepts a place as an address, then returns the latitude and longitude coordinates."), | |
| + InputSchema: anthropic.ToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| "location": map[string]interface{}{ | |
| "type": "string", | |
| "description": "The location to look up.", | |
| }, | |
| }, | |
| - }), | |
| + }, | |
| }, | |
| { | |
| - Name: anthropic.F("get_temperature_unit"), | |
| - InputSchema: anthropic.F[interface{}](map[string]interface{}{ | |
| - "type": "object", | |
| - "properties": map[string]interface{}{ | |
| + Name: "get_temperature_unit", | |
| + InputSchema: anthropic.ToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| "country": map[string]interface{}{ | |
| "type": "string", | |
| "description": "The country", | |
| }, | |
| }, | |
| - }), | |
| + }, | |
| }, | |
| { | |
| - Name: anthropic.F("get_weather"), | |
| - Description: anthropic.F("Get the weather at a specific location"), | |
| - InputSchema: anthropic.F[interface{}](map[string]interface{}{ | |
| - "type": "object", | |
| - "properties": map[string]interface{}{ | |
| + Name: "get_weather", | |
| + Description: anthropic.String("Get the weather at a specific location"), | |
| + InputSchema: anthropic.ToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| "lat": map[string]interface{}{ | |
| "type": "number", | |
| "description": "The lattitude of the location to check weather.", | |
| @@ -65,16 +62,20 @@ func main() { | |
| "description": "Unit for the output", | |
| }, | |
| }, | |
| - }), | |
| + }, | |
| }, | |
| } | |
| + 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.F(anthropic.ModelClaude3_5SonnetLatest), | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F(messages), | |
| - Tools: anthropic.F(tools), | |
| + Model: anthropic.ModelClaude_3_5_Sonnet_20240620, | |
| + MaxTokens: 1024, | |
| + Messages: messages, | |
| + Tools: tools, | |
| }) | |
| if err != nil { | |
| @@ -84,12 +85,13 @@ func main() { | |
| print(color("[assistant]: ")) | |
| for _, block := range message.Content { | |
| - switch block := block.AsUnion().(type) { | |
| + switch block := block.AsAny().(type) { | |
| case anthropic.TextBlock: | |
| println(block.Text) | |
| println() | |
| case anthropic.ToolUseBlock: | |
| - println(block.Name + ": " + string(block.Input)) | |
| + inputJSON, _ := json.Marshal(block.Input) | |
| + println(block.Name + ": " + string(inputJSON)) | |
| println() | |
| } | |
| } | |
| @@ -99,7 +101,8 @@ func main() { | |
| toolResults := []anthropic.ContentBlockParamUnion{} | |
| for _, block := range message.Content { | |
| - if block.Type == anthropic.ContentBlockTypeToolUse { | |
| + switch variant := block.AsAny().(type) { | |
| + case anthropic.ToolUseBlock: | |
| print(color("[user (" + block.Name + ")]: ")) | |
| var response interface{} | |
| @@ -108,16 +111,18 @@ func main() { | |
| var input struct { | |
| Location string `json:"location"` | |
| } | |
| - err := json.Unmarshal(block.Input, &input) | |
| + | |
| + err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input) | |
| if err != nil { | |
| panic(err) | |
| } | |
| + | |
| response = GetCoordinates(input.Location) | |
| case "get_temperature_unit": | |
| var input struct { | |
| Country string `json:"country"` | |
| } | |
| - err := json.Unmarshal(block.Input, &input) | |
| + err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input) | |
| if err != nil { | |
| panic(err) | |
| } | |
| @@ -128,7 +133,7 @@ func main() { | |
| Long float64 `json:"long"` | |
| Unit string `json:"unit"` | |
| } | |
| - err := json.Unmarshal(block.Input, &input) | |
| + err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input) | |
| if err != nil { | |
| panic(err) | |
| } | |
| diff --git a/examples/vertex-streaming/main.go b/examples/vertex-streaming/main.go | |
| index 0256e66..33cd37f 100644 | |
| --- a/examples/vertex-streaming/main.go | |
| +++ b/examples/vertex-streaming/main.go | |
| @@ -2,14 +2,13 @@ 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", "stainless-399616"), | |
| + vertex.WithGoogleAuth(context.Background(), "us-central1", "id-xxx"), | |
| ) | |
| content := "Write me a function to call the Anthropic message API in Node.js using the Anthropic Typescript SDK." | |
| @@ -17,12 +16,12 @@ func main() { | |
| println("[user]: " + content) | |
| stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{ | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| - }), | |
| - Model: anthropic.F("claude-3-sonnet@20240229"), | |
| - StopSequences: anthropic.F([]string{"```\n"}), | |
| + }, | |
| + Model: "claude-3-5-sonnet-v2@20241022", | |
| + StopSequences: []string{"```\n"}, | |
| }) | |
| print("[assistant]: ") | |
| @@ -30,16 +29,17 @@ func main() { | |
| for stream.Next() { | |
| event := stream.Current() | |
| - switch delta := event.Delta.(type) { | |
| - case anthropic.ContentBlockDeltaEventDelta: | |
| - if delta.Text != "" { | |
| - print(delta.Text) | |
| + switch variant := event.AsAny().(type) { | |
| + case anthropic.ContentBlockDeltaEvent: | |
| + if variant.Delta.Text != "" { | |
| + print(variant.Delta.Text) | |
| } | |
| - case anthropic.MessageDeltaEventDelta: | |
| - if delta.StopSequence != "" { | |
| - print(delta.StopSequence) | |
| + case anthropic.MessageDeltaEvent: | |
| + if variant.Delta.StopSequence != "" { | |
| + print(variant.Delta.StopSequence) | |
| } | |
| } | |
| + | |
| } | |
| println() | |
| diff --git a/examples/vertex/main.go b/examples/vertex/main.go | |
| index 092ecbd..6dc6d2e 100644 | |
| --- a/examples/vertex/main.go | |
| +++ b/examples/vertex/main.go | |
| @@ -2,27 +2,26 @@ package main | |
| import ( | |
| "context" | |
| + "github.com/anthropics/anthropic-sdk-go/vertex" | |
| "github.com/anthropics/anthropic-sdk-go" | |
| - "github.com/anthropics/anthropic-sdk-go/vertex" | |
| ) | |
| func main() { | |
| client := anthropic.NewClient( | |
| - vertex.WithGoogleAuth(context.Background(), "us-central1", "stainless-399616"), | |
| + vertex.WithGoogleAuth(context.Background(), "us-central1", "id-xxx"), | |
| ) | |
| - | |
| content := "Write me a function to call the Anthropic message API in Node.js using the Anthropic Typescript SDK." | |
| println("[user]: " + content) | |
| message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.Int(1024), | |
| - Messages: anthropic.F([]anthropic.MessageParam{ | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{ | |
| anthropic.NewUserMessage(anthropic.NewTextBlock(content)), | |
| - }), | |
| - Model: anthropic.F("claude-3-sonnet@20240229"), | |
| - StopSequences: anthropic.F([]string{"```\n"}), | |
| + }, | |
| + Model: "claude-3-5-sonnet-v2@20241022", | |
| + StopSequences: []string{"```\n"}, | |
| }) | |
| if err != nil { | |
| panic(err) | |
| diff --git a/field.go b/field.go | |
| index ab83192..8c2fd50 100644 | |
| --- a/field.go | |
| +++ b/field.go | |
| @@ -1,43 +1,28 @@ | |
| package anthropic | |
| import ( | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| "io" | |
| + "time" | |
| ) | |
| -// F is a param field helper used to initialize a [param.Field] generic struct. | |
| -// This helps specify null, zero values, and overrides, as well as normal values. | |
| -// You can read more about this in our [README]. | |
| -// | |
| -// [README]: https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#readme-request-fields | |
| -func F[T any](value T) param.Field[T] { return param.Field[T]{Value: value, Present: true} } | |
| +func String(s string) param.Opt[string] { return param.NewOpt(s) } | |
| +func Int(i int64) param.Opt[int64] { return param.NewOpt(i) } | |
| +func Bool(b bool) param.Opt[bool] { return param.NewOpt(b) } | |
| +func Float(f float64) param.Opt[float64] { return param.NewOpt(f) } | |
| +func Time(t time.Time) param.Opt[time.Time] { return param.NewOpt(t) } | |
| -// Null is a param field helper which explicitly sends null to the API. | |
| -func Null[T any]() param.Field[T] { return param.Field[T]{Null: true, Present: true} } | |
| +func Opt[T comparable](v T) param.Opt[T] { return param.NewOpt(v) } | |
| +func Ptr[T any](v T) *T { return &v } | |
| -// Raw is a param field helper for specifying values for fields when the | |
| -// type you are looking to send is different from the type that is specified in | |
| -// the SDK. For example, if the type of the field is an integer, but you want | |
| -// to send a float, you could do that by setting the corresponding field with | |
| -// Raw[int](0.5). | |
| -func Raw[T any](value any) param.Field[T] { return param.Field[T]{Raw: value, Present: true} } | |
| +func IntPtr(v int64) *int64 { return &v } | |
| +func BoolPtr(v bool) *bool { return &v } | |
| +func FloatPtr(v float64) *float64 { return &v } | |
| +func StringPtr(v string) *string { return &v } | |
| +func TimePtr(v time.Time) *time.Time { return &v } | |
| -// Int is a param field helper which helps specify integers. This is | |
| -// particularly helpful when specifying integer constants for fields. | |
| -func Int(value int64) param.Field[int64] { return F(value) } | |
| - | |
| -// String is a param field helper which helps specify strings. | |
| -func String(value string) param.Field[string] { return F(value) } | |
| - | |
| -// Float is a param field helper which helps specify floats. | |
| -func Float(value float64) param.Field[float64] { return F(value) } | |
| - | |
| -// Bool is a param field helper which helps specify bools. | |
| -func Bool(value bool) param.Field[bool] { return F(value) } | |
| - | |
| -// FileParam is a param field helper which helps files with a mime content-type. | |
| -func FileParam(reader io.Reader, filename string, contentType string) param.Field[io.Reader] { | |
| - return F[io.Reader](&file{reader, filename, contentType}) | |
| +func File(rdr io.Reader, filename string, contentType string) file { | |
| + return file{rdr, filename, contentType} | |
| } | |
| type file struct { | |
| @@ -46,5 +31,15 @@ type file struct { | |
| contentType string | |
| } | |
| -func (f *file) ContentType() string { return f.contentType } | |
| -func (f *file) Filename() string { return f.name } | |
| +func (f file) Filename() string { | |
| + if f.name != "" { | |
| + return f.name | |
| + } else if named, ok := f.Reader.(interface{ Name() string }); ok { | |
| + return named.Name() | |
| + } | |
| + return "" | |
| +} | |
| + | |
| +func (f file) ContentType() string { | |
| + return f.contentType | |
| +} | |
| diff --git a/go.mod b/go.mod | |
| index 59d9048..8f37d06 100644 | |
| --- a/go.mod | |
| +++ b/go.mod | |
| @@ -2,13 +2,20 @@ module github.com/anthropics/anthropic-sdk-go | |
| go 1.21 | |
| +require ( | |
| + github.com/aws/aws-sdk-go-v2 v1.30.3 | |
| + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 | |
| + github.com/aws/aws-sdk-go-v2/config v1.27.27 | |
| + github.com/tidwall/gjson v1.14.4 | |
| + github.com/tidwall/sjson v1.2.5 | |
| + golang.org/x/oauth2 v0.21.0 | |
| + google.golang.org/api v0.189.0 | |
| +) | |
| + | |
| require ( | |
| cloud.google.com/go/auth v0.7.2 // indirect | |
| cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect | |
| cloud.google.com/go/compute/metadata v0.5.0 // indirect | |
| - github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect | |
| - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect | |
| - github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect | |
| github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect | |
| github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect | |
| github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect | |
| @@ -26,12 +33,9 @@ require ( | |
| github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | |
| github.com/golang/protobuf v1.5.4 // indirect | |
| github.com/google/s2a-go v0.1.7 // indirect | |
| - github.com/google/uuid v1.6.0 // indirect | |
| github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect | |
| - github.com/tidwall/gjson v1.14.4 // indirect | |
| github.com/tidwall/match v1.1.1 // indirect | |
| github.com/tidwall/pretty v1.2.1 // indirect | |
| - github.com/tidwall/sjson v1.2.5 // indirect | |
| go.opencensus.io v0.24.0 // indirect | |
| go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect | |
| go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect | |
| @@ -40,12 +44,10 @@ require ( | |
| go.opentelemetry.io/otel/trace v1.24.0 // indirect | |
| golang.org/x/crypto v0.25.0 // indirect | |
| golang.org/x/net v0.27.0 // indirect | |
| - golang.org/x/oauth2 v0.21.0 // indirect | |
| golang.org/x/sync v0.7.0 // indirect | |
| golang.org/x/sys v0.22.0 // indirect | |
| golang.org/x/text v0.16.0 // indirect | |
| golang.org/x/time v0.5.0 // indirect | |
| - google.golang.org/api v0.189.0 // indirect | |
| google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade // indirect | |
| google.golang.org/grpc v1.64.1 // indirect | |
| google.golang.org/protobuf v1.34.2 // indirect | |
| diff --git a/go.sum b/go.sum | |
| index 5d70b97..912e1aa 100644 | |
| --- a/go.sum | |
| +++ b/go.sum | |
| @@ -1,11 +1,8 @@ | |
| cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | |
| -cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= | |
| cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE= | |
| cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs= | |
| cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI= | |
| cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I= | |
| -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= | |
| -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= | |
| cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= | |
| cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= | |
| github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | |
| @@ -41,6 +38,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA | |
| github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | |
| github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= | |
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
| +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
| github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | |
| github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | |
| @@ -75,14 +73,14 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw | |
| github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |
| github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |
| github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |
| +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= | |
| +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | |
| github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= | |
| github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= | |
| github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | |
| -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | |
| -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | |
| -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | |
| github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= | |
| github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= | |
| +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |
| github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | |
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |
| @@ -91,6 +89,8 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE | |
| github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |
| github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | |
| github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | |
| +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | |
| +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | |
| github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= | |
| github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= | |
| github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= | |
| @@ -162,7 +162,6 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 | |
| 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-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= | |
| -google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg= | |
| google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade h1:oCRSWfwGXQsqlVdErcyTt4A93Y8fo0/9D4b1gnI++qo= | |
| google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= | |
| google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | |
| @@ -185,6 +184,7 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h | |
| google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= | |
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |
| +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | |
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |
| honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | |
| honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | |
| diff --git a/internal/apierror/apierror.go b/internal/apierror/apierror.go | |
| index c17aaf3..1c08c6e 100644 | |
| --- a/internal/apierror/apierror.go | |
| +++ b/internal/apierror/apierror.go | |
| @@ -8,35 +8,33 @@ import ( | |
| "net/http/httputil" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apijson" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| ) | |
| // Error represents an error that originates from the API, i.e. when a request is | |
| // made and the API returns a response with a HTTP status code. Other errors are | |
| // not wrapped by this SDK. | |
| type Error struct { | |
| - JSON errorJSON `json:"-"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| StatusCode int | |
| Request *http.Request | |
| Response *http.Response | |
| } | |
| -// errorJSON contains the JSON metadata for the struct [Error] | |
| -type errorJSON struct { | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *Error) UnmarshalJSON(data []byte) (err error) { | |
| +// Returns the unmodified JSON received from the API | |
| +func (r Error) RawJSON() string { return r.JSON.raw } | |
| +func (r *Error) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r errorJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| func (r *Error) Error() string { | |
| // Attempt to re-populate the response body | |
| - return fmt.Sprintf("%s \"%s\": %d %s %s", r.Request.Method, r.Request.URL, r.Response.StatusCode, http.StatusText(r.Response.StatusCode), r.JSON.RawJSON()) | |
| + return fmt.Sprintf("%s %q: %d %s %s", r.Request.Method, r.Request.URL, r.Response.StatusCode, http.StatusText(r.Response.StatusCode), r.JSON.raw) | |
| } | |
| func (r *Error) DumpRequest(body bool) []byte { | |
| diff --git a/internal/apiform/encoder.go b/internal/apiform/encoder.go | |
| index 707670c..164d260 100644 | |
| --- a/internal/apiform/encoder.go | |
| +++ b/internal/apiform/encoder.go | |
| @@ -13,7 +13,8 @@ import ( | |
| "sync" | |
| "time" | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| + internalparam "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| ) | |
| var encoders sync.Map // map[encoderEntry]encoderFunc | |
| @@ -180,10 +181,14 @@ func (e *encoder) newArrayTypeEncoder(t reflect.Type) encoderFunc { | |
| } | |
| func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { | |
| - if t.Implements(reflect.TypeOf((*param.FieldLike)(nil)).Elem()) { | |
| + if t.Implements(reflect.TypeOf((*internalparam.FieldLike)(nil)).Elem()) { | |
| return e.newFieldTypeEncoder(t) | |
| } | |
| + if idx, ok := param.OptionalPrimitiveTypes[t]; ok { | |
| + return e.newRichFieldTypeEncoder(t, idx) | |
| + } | |
| + | |
| encoderFields := []encoderField{} | |
| extraEncoder := (*encoderField)(nil) | |
| @@ -217,7 +222,7 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { | |
| extraEncoder = &encoderField{ptag, e.typeEncoder(field.Type.Elem()), idx} | |
| continue | |
| } | |
| - if ptag.name == "-" { | |
| + if ptag.name == "-" || ptag.name == "" { | |
| continue | |
| } | |
| @@ -231,7 +236,20 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { | |
| e.dateFormat = "2006-01-02" | |
| } | |
| } | |
| - encoderFields = append(encoderFields, encoderField{ptag, e.typeEncoder(field.Type), idx}) | |
| + | |
| + var encoderFn encoderFunc | |
| + if ptag.omitzero { | |
| + typeEncoderFn := e.typeEncoder(field.Type) | |
| + encoderFn = func(key string, value reflect.Value, writer *multipart.Writer) error { | |
| + if value.IsZero() { | |
| + return nil | |
| + } | |
| + return typeEncoderFn(key, value, writer) | |
| + } | |
| + } else { | |
| + encoderFn = e.typeEncoder(field.Type) | |
| + } | |
| + encoderFields = append(encoderFields, encoderField{ptag, encoderFn, idx}) | |
| e.dateFormat = oldFormat | |
| } | |
| } | |
| diff --git a/internal/apiform/richparam.go b/internal/apiform/richparam.go | |
| new file mode 100644 | |
| index 0000000..929e51e | |
| --- /dev/null | |
| +++ b/internal/apiform/richparam.go | |
| @@ -0,0 +1,20 @@ | |
| +package apiform | |
| + | |
| +import ( | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "mime/multipart" | |
| + "reflect" | |
| +) | |
| + | |
| +func (e *encoder) newRichFieldTypeEncoder(t reflect.Type, underlyingValueIdx []int) encoderFunc { | |
| + underlying := t.FieldByIndex(underlyingValueIdx) | |
| + primitiveEncoder := e.newPrimitiveTypeEncoder(underlying.Type) | |
| + return func(key string, value reflect.Value, writer *multipart.Writer) error { | |
| + if opt, ok := value.Interface().(param.Optional); ok && opt.IsPresent() { | |
| + return primitiveEncoder(key, value.FieldByIndex(underlyingValueIdx), writer) | |
| + } else if ok && opt.IsNull() { | |
| + return writer.WriteField(key, "null") | |
| + } | |
| + return nil | |
| + } | |
| +} | |
| diff --git a/internal/apiform/tag.go b/internal/apiform/tag.go | |
| index b22e054..736fc1e 100644 | |
| --- a/internal/apiform/tag.go | |
| +++ b/internal/apiform/tag.go | |
| @@ -14,6 +14,7 @@ type parsedStructTag struct { | |
| required bool | |
| extras bool | |
| metadata bool | |
| + omitzero bool | |
| } | |
| func parseFormStructTag(field reflect.StructField) (tag parsedStructTag, ok bool) { | |
| @@ -37,6 +38,8 @@ func parseFormStructTag(field reflect.StructField) (tag parsedStructTag, ok bool | |
| tag.extras = true | |
| case "metadata": | |
| tag.metadata = true | |
| + case "omitzero": | |
| + tag.omitzero = true | |
| } | |
| } | |
| return | |
| diff --git a/internal/apijson/decoder.go b/internal/apijson/decoder.go | |
| index 68b7ed6..b3bd832 100644 | |
| --- a/internal/apijson/decoder.go | |
| +++ b/internal/apijson/decoder.go | |
| @@ -173,6 +173,9 @@ func (d *decoderBuilder) newTypeDecoder(t reflect.Type) decoderFunc { | |
| return nil | |
| } | |
| case reflect.Struct: | |
| + if isEmbeddedUnion(t) { | |
| + return d.newEmbeddedUnionDecoder(t) | |
| + } | |
| return d.newStructTypeDecoder(t) | |
| case reflect.Array: | |
| fallthrough | |
| @@ -343,7 +346,7 @@ func (d *decoderBuilder) newStructTypeDecoder(t reflect.Type) decoderFunc { | |
| decoderFields := map[string]decoderField{} | |
| anonymousDecoders := []decoderField{} | |
| extraDecoder := (*decoderField)(nil) | |
| - inlineDecoder := (*decoderField)(nil) | |
| + var inlineDecoders []decoderField | |
| for i := 0; i < t.NumField(); i++ { | |
| idx := []int{i} | |
| @@ -373,7 +376,8 @@ func (d *decoderBuilder) newStructTypeDecoder(t reflect.Type) decoderFunc { | |
| continue | |
| } | |
| if ptag.inline { | |
| - inlineDecoder = &decoderField{ptag, d.typeDecoder(field.Type), idx, field.Name} | |
| + df := decoderField{ptag, d.typeDecoder(field.Type), idx, field.Name} | |
| + inlineDecoders = append(inlineDecoders, df) | |
| continue | |
| } | |
| if ptag.metadata { | |
| @@ -406,12 +410,13 @@ func (d *decoderBuilder) newStructTypeDecoder(t reflect.Type) decoderFunc { | |
| decoder.fn(node, value.FieldByIndex(decoder.idx), state) | |
| } | |
| - if inlineDecoder != nil { | |
| + for _, inlineDecoder := range inlineDecoders { | |
| var meta Field | |
| dest := value.FieldByIndex(inlineDecoder.idx) | |
| isValid := false | |
| if dest.IsValid() && node.Type != gjson.Null { | |
| - err = inlineDecoder.fn(node, dest, state) | |
| + inlineState := decoderState{exactness: state.exactness, strict: true} | |
| + err = inlineDecoder.fn(node, dest, &inlineState) | |
| if err == nil { | |
| isValid = true | |
| } | |
| @@ -423,20 +428,18 @@ func (d *decoderBuilder) newStructTypeDecoder(t reflect.Type) decoderFunc { | |
| status: null, | |
| } | |
| } else if !isValid { | |
| - meta = Field{ | |
| - raw: node.Raw, | |
| - status: invalid, | |
| + // If an inline decoder fails, unset the field and move on. | |
| + if dest.IsValid() { | |
| + dest.SetZero() | |
| } | |
| + continue | |
| } else if isValid { | |
| meta = Field{ | |
| raw: node.Raw, | |
| status: valid, | |
| } | |
| } | |
| - if metadata := getSubField(value, inlineDecoder.idx, inlineDecoder.goname); metadata.IsValid() { | |
| - metadata.Set(reflect.ValueOf(meta)) | |
| - } | |
| - return err | |
| + setMetadataSubField(value, inlineDecoder.idx, inlineDecoder.goname, meta) | |
| } | |
| typedExtraType := reflect.Type(nil) | |
| @@ -489,9 +492,7 @@ func (d *decoderBuilder) newStructTypeDecoder(t reflect.Type) decoderFunc { | |
| } | |
| if explicit { | |
| - if metadata := getSubField(value, df.idx, df.goname); metadata.IsValid() { | |
| - metadata.Set(reflect.ValueOf(meta)) | |
| - } | |
| + setMetadataSubField(value, df.idx, df.goname, meta) | |
| } | |
| if !explicit { | |
| untypedExtraFields[fieldName] = meta | |
| @@ -510,8 +511,8 @@ func (d *decoderBuilder) newStructTypeDecoder(t reflect.Type) decoderFunc { | |
| state.exactness = extras | |
| } | |
| - if metadata := getSubField(value, []int{-1}, "ExtraFields"); metadata.IsValid() && len(untypedExtraFields) > 0 { | |
| - metadata.Set(reflect.ValueOf(untypedExtraFields)) | |
| + if len(untypedExtraFields) > 0 { | |
| + setMetadataExtraFields(value, []int{-1}, "ExtraFields", untypedExtraFields) | |
| } | |
| return nil | |
| } | |
| @@ -662,9 +663,17 @@ func canParseAsNumber(str string) bool { | |
| return err == nil | |
| } | |
| +var stringType = reflect.TypeOf(string("")) | |
| + | |
| func guardUnknown(state *decoderState, v reflect.Value) bool { | |
| if have, ok := v.Interface().(interface{ IsKnown() bool }); guardStrict(state, ok && !have.IsKnown()) { | |
| return true | |
| } | |
| + | |
| + constantString, ok := v.Interface().(interface{ Default() string }) | |
| + named := v.Type() != stringType | |
| + if guardStrict(state, ok && named && v.Equal(reflect.ValueOf(constantString.Default()))) { | |
| + return true | |
| + } | |
| return false | |
| } | |
| diff --git a/internal/apijson/encoder.go b/internal/apijson/encoder.go | |
| index 0ad0a12..0fb294f 100644 | |
| --- a/internal/apijson/encoder.go | |
| +++ b/internal/apijson/encoder.go | |
| @@ -381,7 +381,7 @@ func (e *encoder) encodeMapEntries(json []byte, v reflect.Value) ([]byte, error) | |
| return json, nil | |
| } | |
| -func (e *encoder) newMapEncoder(t reflect.Type) encoderFunc { | |
| +func (e *encoder) newMapEncoder(_ reflect.Type) encoderFunc { | |
| return func(value reflect.Value) ([]byte, error) { | |
| json := []byte("{}") | |
| var err error | |
| diff --git a/internal/apijson/enum.go b/internal/apijson/enum.go | |
| new file mode 100644 | |
| index 0000000..ec98f8c | |
| --- /dev/null | |
| +++ b/internal/apijson/enum.go | |
| @@ -0,0 +1,87 @@ | |
| +package apijson | |
| + | |
| +import ( | |
| + "fmt" | |
| + "reflect" | |
| + "sync" | |
| +) | |
| + | |
| +/********************/ | |
| +/* Validating Enums */ | |
| +/********************/ | |
| + | |
| +type validationEntry struct { | |
| + field reflect.StructField | |
| + nullable bool | |
| + legalValues []reflect.Value | |
| +} | |
| + | |
| +type validatorFunc func(reflect.Value) exactness | |
| + | |
| +var validators sync.Map | |
| +var validationRegistry = map[reflect.Type][]validationEntry{} | |
| + | |
| +func RegisterFieldValidator[T any, V string | bool | int](fieldName string, nullable bool, values ...V) { | |
| + var t T | |
| + parentType := reflect.TypeOf(t) | |
| + | |
| + if _, ok := validationRegistry[parentType]; !ok { | |
| + validationRegistry[parentType] = []validationEntry{} | |
| + } | |
| + | |
| + // The following checks run at initialization time, | |
| + // it is impossible for them to panic if any tests pass. | |
| + if parentType.Kind() != reflect.Struct { | |
| + panic(fmt.Sprintf("apijson: cannot initialize validator for non-struct %s", parentType.String())) | |
| + } | |
| + field, found := parentType.FieldByName(fieldName) | |
| + if !found { | |
| + panic(fmt.Sprintf("apijson: cannot initialize validator for unknown field %q in %s", fieldName, parentType.String())) | |
| + } | |
| + | |
| + newEntry := validationEntry{field, nullable, make([]reflect.Value, len(values))} | |
| + for i, value := range values { | |
| + newEntry.legalValues[i] = reflect.ValueOf(value) | |
| + } | |
| + | |
| + // Store the information necessary to create a validator, so that we can use it | |
| + // lazily create the validator function when did. | |
| + validationRegistry[parentType] = append(validationRegistry[parentType], newEntry) | |
| +} | |
| + | |
| +// Enums are the only types which are validated | |
| +func typeValidator(t reflect.Type) validatorFunc { | |
| + entry, ok := validationRegistry[t] | |
| + if !ok { | |
| + return nil | |
| + } | |
| + | |
| + if fi, ok := validators.Load(t); ok { | |
| + return fi.(validatorFunc) | |
| + } | |
| + | |
| + fi, _ := validators.LoadOrStore(t, validatorFunc(func(v reflect.Value) exactness { | |
| + return validateEnum(v, entry) | |
| + })) | |
| + return fi.(validatorFunc) | |
| +} | |
| + | |
| +func validateEnum(v reflect.Value, entry []validationEntry) exactness { | |
| + if v.Kind() != reflect.Struct { | |
| + return loose | |
| + } | |
| + | |
| + for _, check := range entry { | |
| + field := v.FieldByIndex(check.field.Index) | |
| + if !field.IsValid() { | |
| + return loose | |
| + } | |
| + for _, opt := range check.legalValues { | |
| + if field.Equal(opt) { | |
| + return exact | |
| + } | |
| + } | |
| + } | |
| + | |
| + return loose | |
| +} | |
| diff --git a/internal/apijson/field.go b/internal/apijson/field.go | |
| index 3ef207c..854d6dd 100644 | |
| --- a/internal/apijson/field.go | |
| +++ b/internal/apijson/field.go | |
| @@ -1,7 +1,5 @@ | |
| package apijson | |
| -import "reflect" | |
| - | |
| type status uint8 | |
| const ( | |
| @@ -23,19 +21,3 @@ func (j Field) IsNull() bool { return j.status <= null } | |
| func (j Field) IsMissing() bool { return j.status == missing } | |
| func (j Field) IsInvalid() bool { return j.status == invalid } | |
| func (j Field) Raw() string { return j.raw } | |
| - | |
| -func getSubField(root reflect.Value, index []int, name string) reflect.Value { | |
| - strct := root.FieldByIndex(index[:len(index)-1]) | |
| - if !strct.IsValid() { | |
| - panic("couldn't find encapsulating struct for field " + name) | |
| - } | |
| - meta := strct.FieldByName("JSON") | |
| - if !meta.IsValid() { | |
| - return reflect.Value{} | |
| - } | |
| - field := meta.FieldByName(name) | |
| - if !field.IsValid() { | |
| - return reflect.Value{} | |
| - } | |
| - return field | |
| -} | |
| diff --git a/internal/apijson/json_test.go b/internal/apijson/json_test.go | |
| index e656344..0c4de11 100644 | |
| --- a/internal/apijson/json_test.go | |
| +++ b/internal/apijson/json_test.go | |
| @@ -86,8 +86,8 @@ type JSONFieldStruct struct { | |
| B int64 `json:"b"` | |
| C string `json:"c"` | |
| D string `json:"d"` | |
| - ExtraFields map[string]int64 `json:"-,extras"` | |
| - JSON JSONFieldStructJSON `json:"-,metadata"` | |
| + ExtraFields map[string]int64 `json:",extras"` | |
| + JSON JSONFieldStructJSON `json:",metadata"` | |
| } | |
| type JSONFieldStructJSON struct { | |
| @@ -112,13 +112,13 @@ type Union interface { | |
| } | |
| type Inline struct { | |
| - InlineField Primitives `json:"-,inline"` | |
| - JSON InlineJSON `json:"-,metadata"` | |
| + InlineField Primitives `json:",inline"` | |
| + JSON InlineJSON `json:",metadata"` | |
| } | |
| type InlineArray struct { | |
| - InlineField []string `json:"-,inline"` | |
| - JSON InlineJSON `json:"-,metadata"` | |
| + InlineField []string `json:",inline"` | |
| + JSON InlineJSON `json:",metadata"` | |
| } | |
| type InlineJSON struct { | |
| @@ -150,7 +150,7 @@ type UnionTime time.Time | |
| func (UnionTime) union() {} | |
| func init() { | |
| - RegisterUnion(reflect.TypeOf((*Union)(nil)).Elem(), "type", | |
| + RegisterUnion[Union]("type", | |
| UnionVariant{ | |
| TypeFilter: gjson.String, | |
| Type: reflect.TypeOf(UnionTime{}), | |
| @@ -237,7 +237,7 @@ func (r *UnmarshalStruct) UnmarshalJSON(json []byte) error { | |
| func (ComplexUnionTypeB) complexUnion() {} | |
| func init() { | |
| - RegisterUnion(reflect.TypeOf((*ComplexUnion)(nil)).Elem(), "", | |
| + RegisterUnion[ComplexUnion]("", | |
| UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| Type: reflect.TypeOf(ComplexUnionA{}), | |
| @@ -300,8 +300,7 @@ func (r *MarshallingUnionB) UnmarshalJSON(data []byte) (err error) { | |
| } | |
| func init() { | |
| - RegisterUnion( | |
| - reflect.TypeOf((*MarshallingUnion)(nil)).Elem(), | |
| + RegisterUnion[MarshallingUnion]( | |
| "", | |
| UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| diff --git a/internal/apijson/port.go b/internal/apijson/port.go | |
| index 502ab77..b40013c 100644 | |
| --- a/internal/apijson/port.go | |
| +++ b/internal/apijson/port.go | |
| @@ -53,7 +53,7 @@ func Port(from any, to any) error { | |
| for i := 0; i < t.NumField(); i++ { | |
| field := t.Field(i) | |
| ptag, ok := parseJSONStructTag(field) | |
| - if !ok || ptag.name == "-" { | |
| + if !ok || ptag.name == "-" || ptag.name == "" { | |
| continue | |
| } | |
| values[ptag.name] = v.Field(i) | |
| diff --git a/internal/apijson/registry.go b/internal/apijson/registry.go | |
| index 119cc5f..e82c1d5 100644 | |
| --- a/internal/apijson/registry.go | |
| +++ b/internal/apijson/registry.go | |
| @@ -20,7 +20,8 @@ type unionEntry struct { | |
| variants []UnionVariant | |
| } | |
| -func RegisterUnion(typ reflect.Type, discriminator string, variants ...UnionVariant) { | |
| +func RegisterUnion[T any](discriminator string, variants ...UnionVariant) { | |
| + typ := reflect.TypeOf((*T)(nil)).Elem() | |
| unionRegistry[typ] = unionEntry{ | |
| discriminatorKey: discriminator, | |
| variants: variants, | |
| diff --git a/internal/apijson/subfield.go b/internal/apijson/subfield.go | |
| new file mode 100644 | |
| index 0000000..9785f60 | |
| --- /dev/null | |
| +++ b/internal/apijson/subfield.go | |
| @@ -0,0 +1,67 @@ | |
| +package apijson | |
| + | |
| +import ( | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| + "reflect" | |
| +) | |
| + | |
| +func getSubField(root reflect.Value, index []int, name string) reflect.Value { | |
| + strct := root.FieldByIndex(index[:len(index)-1]) | |
| + if !strct.IsValid() { | |
| + panic("couldn't find encapsulating struct for field " + name) | |
| + } | |
| + meta := strct.FieldByName("JSON") | |
| + if !meta.IsValid() { | |
| + return reflect.Value{} | |
| + } | |
| + field := meta.FieldByName(name) | |
| + if !field.IsValid() { | |
| + return reflect.Value{} | |
| + } | |
| + return field | |
| +} | |
| + | |
| +func setMetadataSubField(root reflect.Value, index []int, name string, meta Field) { | |
| + target := getSubField(root, index, name) | |
| + if !target.IsValid() { | |
| + return | |
| + } | |
| + | |
| + if target.Type() == reflect.TypeOf(meta) { | |
| + target.Set(reflect.ValueOf(meta)) | |
| + } else if respMeta := meta.toRespField(); target.Type() == reflect.TypeOf(respMeta) { | |
| + target.Set(reflect.ValueOf(respMeta)) | |
| + } | |
| +} | |
| + | |
| +func setMetadataExtraFields(root reflect.Value, index []int, name string, metaExtras map[string]Field) { | |
| + target := getSubField(root, index, name) | |
| + if !target.IsValid() { | |
| + return | |
| + } | |
| + | |
| + if target.Type() == reflect.TypeOf(metaExtras) { | |
| + target.Set(reflect.ValueOf(metaExtras)) | |
| + return | |
| + } | |
| + | |
| + newMap := make(map[string]resp.Field, len(metaExtras)) | |
| + if target.Type() == reflect.TypeOf(newMap) { | |
| + for k, v := range metaExtras { | |
| + newMap[k] = v.toRespField() | |
| + } | |
| + target.Set(reflect.ValueOf(newMap)) | |
| + } | |
| +} | |
| + | |
| +func (f Field) toRespField() resp.Field { | |
| + if f.IsNull() { | |
| + return resp.NewNullField() | |
| + } else if f.IsMissing() { | |
| + return resp.Field{} | |
| + } else if f.IsInvalid() { | |
| + return resp.NewInvalidField(f.raw) | |
| + } else { | |
| + return resp.NewValidField(f.raw) | |
| + } | |
| +} | |
| diff --git a/internal/apijson/union.go b/internal/apijson/union.go | |
| new file mode 100644 | |
| index 0000000..d1223cc | |
| --- /dev/null | |
| +++ b/internal/apijson/union.go | |
| @@ -0,0 +1,101 @@ | |
| +package apijson | |
| + | |
| +import ( | |
| + "errors" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "reflect" | |
| + | |
| + "github.com/tidwall/gjson" | |
| +) | |
| + | |
| +func isEmbeddedUnion(t reflect.Type) bool { | |
| + var apiunion param.APIUnion | |
| + for i := 0; i < t.NumField(); i++ { | |
| + if t.Field(i).Type == reflect.TypeOf(apiunion) && t.Field(i).Anonymous { | |
| + return true | |
| + } | |
| + } | |
| + return false | |
| +} | |
| + | |
| +func RegisterDiscriminatedUnion[T any](key string, mappings map[string]reflect.Type) { | |
| + var t T | |
| + entry := unionEntry{ | |
| + discriminatorKey: key, | |
| + variants: []UnionVariant{}, | |
| + } | |
| + for k, typ := range mappings { | |
| + entry.variants = append(entry.variants, UnionVariant{ | |
| + DiscriminatorValue: k, | |
| + Type: typ, | |
| + }) | |
| + } | |
| + unionRegistry[reflect.TypeOf(t)] = entry | |
| +} | |
| + | |
| +func (d *decoderBuilder) newEmbeddedUnionDecoder(t reflect.Type) decoderFunc { | |
| + decoders := []decoderFunc{} | |
| + | |
| + for i := 0; i < t.NumField(); i++ { | |
| + variant := t.Field(i) | |
| + decoder := d.typeDecoder(variant.Type) | |
| + decoders = append(decoders, decoder) | |
| + } | |
| + | |
| + unionEntry := unionEntry{ | |
| + variants: []UnionVariant{}, | |
| + } | |
| + | |
| + return func(n gjson.Result, v reflect.Value, state *decoderState) error { | |
| + // If there is a discriminator match, circumvent the exactness logic entirely | |
| + for idx, variant := range unionEntry.variants { | |
| + decoder := decoders[idx] | |
| + if variant.TypeFilter != n.Type { | |
| + continue | |
| + } | |
| + | |
| + if len(unionEntry.discriminatorKey) != 0 { | |
| + discriminatorValue := n.Get(unionEntry.discriminatorKey).Value() | |
| + if discriminatorValue == variant.DiscriminatorValue { | |
| + inner := reflect.New(variant.Type).Elem() | |
| + err := decoder(n, inner, state) | |
| + v.Set(inner) | |
| + return err | |
| + } | |
| + } | |
| + } | |
| + | |
| + // Set bestExactness to worse than loose | |
| + bestExactness := loose - 1 | |
| + for idx, variant := range unionEntry.variants { | |
| + decoder := decoders[idx] | |
| + if variant.TypeFilter != n.Type { | |
| + continue | |
| + } | |
| + sub := decoderState{strict: state.strict, exactness: exact} | |
| + inner := reflect.New(variant.Type).Elem() | |
| + err := decoder(n, inner, &sub) | |
| + if err != nil { | |
| + continue | |
| + } | |
| + if sub.exactness == exact { | |
| + v.Set(inner) | |
| + return nil | |
| + } | |
| + if sub.exactness > bestExactness { | |
| + v.Set(inner) | |
| + bestExactness = sub.exactness | |
| + } | |
| + } | |
| + | |
| + if bestExactness < loose { | |
| + return errors.New("apijson: was not able to coerce type as union") | |
| + } | |
| + | |
| + if guardStrict(state, bestExactness != exact) { | |
| + return errors.New("apijson: was not able to coerce type as union strictly") | |
| + } | |
| + | |
| + return nil | |
| + } | |
| +} | |
| diff --git a/internal/apiquery/encoder.go b/internal/apiquery/encoder.go | |
| index 9db8518..4277a1e 100644 | |
| --- a/internal/apiquery/encoder.go | |
| +++ b/internal/apiquery/encoder.go | |
| @@ -9,7 +9,8 @@ import ( | |
| "sync" | |
| "time" | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| + internalparam "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| ) | |
| var encoders sync.Map // map[reflect.Type]encoderFunc | |
| @@ -85,7 +86,8 @@ func (e *encoder) newTypeEncoder(t reflect.Type) encoderFunc { | |
| if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { | |
| return e.newTimeTypeEncoder(t) | |
| } | |
| - if !e.root && t.Implements(reflect.TypeOf((*json.Marshaler)(nil)).Elem()) { | |
| + | |
| + if !e.root && t.Implements(reflect.TypeOf((*json.Marshaler)(nil)).Elem()) && param.OptionalPrimitiveTypes[t] == nil { | |
| return marshalerEncoder | |
| } | |
| e.root = false | |
| @@ -115,10 +117,14 @@ func (e *encoder) newTypeEncoder(t reflect.Type) encoderFunc { | |
| } | |
| func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { | |
| - if t.Implements(reflect.TypeOf((*param.FieldLike)(nil)).Elem()) { | |
| + if t.Implements(reflect.TypeOf((*internalparam.FieldLike)(nil)).Elem()) { | |
| return e.newFieldTypeEncoder(t) | |
| } | |
| + if idx, ok := param.OptionalPrimitiveTypes[t]; ok { | |
| + return e.newRichFieldTypeEncoder(t, idx) | |
| + } | |
| + | |
| encoderFields := []encoderField{} | |
| // This helper allows us to recursively collect field encoders into a flat | |
| @@ -145,7 +151,7 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { | |
| continue | |
| } | |
| - if ptag.name == "-" && !ptag.inline { | |
| + if (ptag.name == "-" || ptag.name == "") && !ptag.inline { | |
| continue | |
| } | |
| @@ -159,7 +165,19 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { | |
| e.dateFormat = "2006-01-02" | |
| } | |
| } | |
| - encoderFields = append(encoderFields, encoderField{ptag, e.typeEncoder(field.Type), idx}) | |
| + var encoderFn encoderFunc | |
| + if ptag.omitzero { | |
| + typeEncoderFn := e.typeEncoder(field.Type) | |
| + encoderFn = func(key string, value reflect.Value) []Pair { | |
| + if value.IsZero() { | |
| + return nil | |
| + } | |
| + return typeEncoderFn(key, value) | |
| + } | |
| + } else { | |
| + encoderFn = e.typeEncoder(field.Type) | |
| + } | |
| + encoderFields = append(encoderFields, encoderField{ptag, encoderFn, idx}) | |
| e.dateFormat = oldFormat | |
| } | |
| } | |
| diff --git a/internal/apiquery/query_test.go b/internal/apiquery/query_test.go | |
| index 1e740d6..98cb6c5 100644 | |
| --- a/internal/apiquery/query_test.go | |
| +++ b/internal/apiquery/query_test.go | |
| @@ -1,6 +1,7 @@ | |
| package apiquery | |
| import ( | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| "net/url" | |
| "testing" | |
| "time" | |
| @@ -101,6 +102,15 @@ type DeeplyNested3 struct { | |
| D *string `query:"d"` | |
| } | |
| +type RichPrimitives struct { | |
| + A param.Opt[string] `query:"a"` | |
| +} | |
| + | |
| +type QueryOmitTest struct { | |
| + A param.Opt[string] `query:"a,omitzero"` | |
| + B string `query:"b,omitzero"` | |
| +} | |
| + | |
| var tests = map[string]struct { | |
| enc string | |
| val interface{} | |
| @@ -320,6 +330,29 @@ var tests = map[string]struct { | |
| }, | |
| QuerySettings{NestedFormat: NestedQueryFormatDots}, | |
| }, | |
| + | |
| + "rich_primitives": { | |
| + `a=hello`, | |
| + RichPrimitives{ | |
| + A: param.Opt[string]{Value: "hello"}, | |
| + }, | |
| + QuerySettings{}, | |
| + }, | |
| + | |
| + "rich_primitives_omit": { | |
| + ``, | |
| + QueryOmitTest{ | |
| + A: param.Opt[string]{}, | |
| + }, | |
| + QuerySettings{}, | |
| + }, | |
| + "query_omit": { | |
| + `a=hello`, | |
| + QueryOmitTest{ | |
| + A: param.Opt[string]{Value: "hello"}, | |
| + }, | |
| + QuerySettings{}, | |
| + }, | |
| } | |
| func TestEncode(t *testing.T) { | |
| diff --git a/internal/apiquery/richparam.go b/internal/apiquery/richparam.go | |
| new file mode 100644 | |
| index 0000000..1f385b4 | |
| --- /dev/null | |
| +++ b/internal/apiquery/richparam.go | |
| @@ -0,0 +1,19 @@ | |
| +package apiquery | |
| + | |
| +import ( | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "reflect" | |
| +) | |
| + | |
| +func (e *encoder) newRichFieldTypeEncoder(t reflect.Type, underlyingValueIdx []int) encoderFunc { | |
| + underlying := t.FieldByIndex(underlyingValueIdx) | |
| + primitiveEncoder := e.newPrimitiveTypeEncoder(underlying.Type) | |
| + return func(key string, value reflect.Value) []Pair { | |
| + if fielder, ok := value.Interface().(param.Optional); ok && fielder.IsPresent() { | |
| + return primitiveEncoder(key, value.FieldByIndex(underlyingValueIdx)) | |
| + } else if ok && fielder.IsNull() { | |
| + return []Pair{{key, "null"}} | |
| + } | |
| + return nil | |
| + } | |
| +} | |
| diff --git a/internal/apiquery/tag.go b/internal/apiquery/tag.go | |
| index 7ccd739..772c40e 100644 | |
| --- a/internal/apiquery/tag.go | |
| +++ b/internal/apiquery/tag.go | |
| @@ -11,6 +11,7 @@ const formatStructTag = "format" | |
| type parsedStructTag struct { | |
| name string | |
| omitempty bool | |
| + omitzero bool | |
| inline bool | |
| } | |
| @@ -26,6 +27,8 @@ func parseQueryStructTag(field reflect.StructField) (tag parsedStructTag, ok boo | |
| tag.name = parts[0] | |
| for _, part := range parts[1:] { | |
| switch part { | |
| + case "omitzero": | |
| + tag.omitzero = true | |
| case "omitempty": | |
| tag.omitempty = true | |
| case "inline": | |
| diff --git a/internal/encoding/json/decode.go b/internal/encoding/json/decode.go | |
| new file mode 100644 | |
| index 0000000..f1c7ef5 | |
| --- /dev/null | |
| +++ b/internal/encoding/json/decode.go | |
| @@ -0,0 +1,1324 @@ | |
| +// Vendored from Go 1.24.0-pre-release | |
| +// To find alterations, check package shims, and comments beginning in SHIM(). | |
| +// | |
| +// Copyright 2010 The Go Authors. All rights reserved. | |
| +// Use of this source code is governed by a BSD-style | |
| +// license that can be found in the LICENSE file. | |
| + | |
| +// Represents JSON data structure using native Go types: booleans, floats, | |
| +// strings, arrays, and maps. | |
| + | |
| +package json | |
| + | |
| +import ( | |
| + "encoding" | |
| + "encoding/base64" | |
| + "fmt" | |
| + "github.com/anthropics/anthropic-sdk-go/internal/encoding/json/shims" | |
| + "reflect" | |
| + "strconv" | |
| + "strings" | |
| + "unicode" | |
| + "unicode/utf16" | |
| + "unicode/utf8" | |
| + _ "unsafe" // for linkname | |
| +) | |
| + | |
| +// Unmarshal parses the JSON-encoded data and stores the result | |
| +// in the value pointed to by v. If v is nil or not a pointer, | |
| +// Unmarshal returns an [InvalidUnmarshalError]. | |
| +// | |
| +// Unmarshal uses the inverse of the encodings that | |
| +// [Marshal] uses, allocating maps, slices, and pointers as necessary, | |
| +// with the following additional rules: | |
| +// | |
| +// To unmarshal JSON into a pointer, Unmarshal first handles the case of | |
| +// the JSON being the JSON literal null. In that case, Unmarshal sets | |
| +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into | |
| +// the value pointed at by the pointer. If the pointer is nil, Unmarshal | |
| +// allocates a new value for it to point to. | |
| +// | |
| +// To unmarshal JSON into a value implementing [Unmarshaler], | |
| +// Unmarshal calls that value's [Unmarshaler.UnmarshalJSON] method, including | |
| +// when the input is a JSON null. | |
| +// Otherwise, if the value implements [encoding.TextUnmarshaler] | |
| +// and the input is a JSON quoted string, Unmarshal calls | |
| +// [encoding.TextUnmarshaler.UnmarshalText] with the unquoted form of the string. | |
| +// | |
| +// To unmarshal JSON into a struct, Unmarshal matches incoming object | |
| +// keys to the keys used by [Marshal] (either the struct field name or its tag), | |
| +// preferring an exact match but also accepting a case-insensitive match. By | |
| +// default, object keys which don't have a corresponding struct field are | |
| +// ignored (see [Decoder.DisallowUnknownFields] for an alternative). | |
| +// | |
| +// To unmarshal JSON into an interface value, | |
| +// Unmarshal stores one of these in the interface value: | |
| +// | |
| +// - bool, for JSON booleans | |
| +// - float64, for JSON numbers | |
| +// - string, for JSON strings | |
| +// - []any, for JSON arrays | |
| +// - map[string]any, for JSON objects | |
| +// - nil for JSON null | |
| +// | |
| +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length | |
| +// to zero and then appends each element to the slice. | |
| +// As a special case, to unmarshal an empty JSON array into a slice, | |
| +// Unmarshal replaces the slice with a new empty slice. | |
| +// | |
| +// To unmarshal a JSON array into a Go array, Unmarshal decodes | |
| +// JSON array elements into corresponding Go array elements. | |
| +// If the Go array is smaller than the JSON array, | |
| +// the additional JSON array elements are discarded. | |
| +// If the JSON array is smaller than the Go array, | |
| +// the additional Go array elements are set to zero values. | |
| +// | |
| +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to | |
| +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal | |
| +// reuses the existing map, keeping existing entries. Unmarshal then stores | |
| +// key-value pairs from the JSON object into the map. The map's key type must | |
| +// either be any string type, an integer, or implement [encoding.TextUnmarshaler]. | |
| +// | |
| +// If the JSON-encoded data contain a syntax error, Unmarshal returns a [SyntaxError]. | |
| +// | |
| +// If a JSON value is not appropriate for a given target type, | |
| +// or if a JSON number overflows the target type, Unmarshal | |
| +// skips that field and completes the unmarshaling as best it can. | |
| +// If no more serious errors are encountered, Unmarshal returns | |
| +// an [UnmarshalTypeError] describing the earliest such error. In any | |
| +// case, it's not guaranteed that all the remaining fields following | |
| +// the problematic one will be unmarshaled into the target object. | |
| +// | |
| +// The JSON null value unmarshals into an interface, map, pointer, or slice | |
| +// by setting that Go value to nil. Because null is often used in JSON to mean | |
| +// “not present,” unmarshaling a JSON null into any other Go type has no effect | |
| +// on the value and produces no error. | |
| +// | |
| +// When unmarshaling quoted strings, invalid UTF-8 or | |
| +// invalid UTF-16 surrogate pairs are not treated as an error. | |
| +// Instead, they are replaced by the Unicode replacement | |
| +// character U+FFFD. | |
| +func Unmarshal(data []byte, v any) error { | |
| + // Check for well-formedness. | |
| + // Avoids filling out half a data structure | |
| + // before discovering a JSON syntax error. | |
| + var d decodeState | |
| + err := checkValid(data, &d.scan) | |
| + if err != nil { | |
| + return err | |
| + } | |
| + | |
| + d.init(data) | |
| + return d.unmarshal(v) | |
| +} | |
| + | |
| +// Unmarshaler is the interface implemented by types | |
| +// that can unmarshal a JSON description of themselves. | |
| +// The input can be assumed to be a valid encoding of | |
| +// a JSON value. UnmarshalJSON must copy the JSON data | |
| +// if it wishes to retain the data after returning. | |
| +// | |
| +// By convention, to approximate the behavior of [Unmarshal] itself, | |
| +// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. | |
| +type Unmarshaler interface { | |
| + UnmarshalJSON([]byte) error | |
| +} | |
| + | |
| +// An UnmarshalTypeError describes a JSON value that was | |
| +// not appropriate for a value of a specific Go type. | |
| +type UnmarshalTypeError struct { | |
| + Value string // description of JSON value - "bool", "array", "number -5" | |
| + Type reflect.Type // type of Go value it could not be assigned to | |
| + Offset int64 // error occurred after reading Offset bytes | |
| + Struct string // name of the struct type containing the field | |
| + Field string // the full path from root node to the field, include embedded struct | |
| +} | |
| + | |
| +func (e *UnmarshalTypeError) Error() string { | |
| + if e.Struct != "" || e.Field != "" { | |
| + return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() | |
| + } | |
| + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() | |
| +} | |
| + | |
| +// An UnmarshalFieldError describes a JSON object key that | |
| +// led to an unexported (and therefore unwritable) struct field. | |
| +// | |
| +// Deprecated: No longer used; kept for compatibility. | |
| +type UnmarshalFieldError struct { | |
| + Key string | |
| + Type reflect.Type | |
| + Field reflect.StructField | |
| +} | |
| + | |
| +func (e *UnmarshalFieldError) Error() string { | |
| + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() | |
| +} | |
| + | |
| +// An InvalidUnmarshalError describes an invalid argument passed to [Unmarshal]. | |
| +// (The argument to [Unmarshal] must be a non-nil pointer.) | |
| +type InvalidUnmarshalError struct { | |
| + Type reflect.Type | |
| +} | |
| + | |
| +func (e *InvalidUnmarshalError) Error() string { | |
| + if e.Type == nil { | |
| + return "json: Unmarshal(nil)" | |
| + } | |
| + | |
| + if e.Type.Kind() != reflect.Pointer { | |
| + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" | |
| + } | |
| + return "json: Unmarshal(nil " + e.Type.String() + ")" | |
| +} | |
| + | |
| +func (d *decodeState) unmarshal(v any) error { | |
| + rv := reflect.ValueOf(v) | |
| + if rv.Kind() != reflect.Pointer || rv.IsNil() { | |
| + return &InvalidUnmarshalError{reflect.TypeOf(v)} | |
| + } | |
| + | |
| + d.scan.reset() | |
| + d.scanWhile(scanSkipSpace) | |
| + // We decode rv not rv.Elem because the Unmarshaler interface | |
| + // test must be applied at the top level of the value. | |
| + err := d.value(rv) | |
| + if err != nil { | |
| + return d.addErrorContext(err) | |
| + } | |
| + return d.savedError | |
| +} | |
| + | |
| +// A Number represents a JSON number literal. | |
| +type Number string | |
| + | |
| +// String returns the literal text of the number. | |
| +func (n Number) String() string { return string(n) } | |
| + | |
| +// Float64 returns the number as a float64. | |
| +func (n Number) Float64() (float64, error) { | |
| + return strconv.ParseFloat(string(n), 64) | |
| +} | |
| + | |
| +// Int64 returns the number as an int64. | |
| +func (n Number) Int64() (int64, error) { | |
| + return strconv.ParseInt(string(n), 10, 64) | |
| +} | |
| + | |
| +// An errorContext provides context for type errors during decoding. | |
| +type errorContext struct { | |
| + Struct reflect.Type | |
| + FieldStack []string | |
| +} | |
| + | |
| +// decodeState represents the state while decoding a JSON value. | |
| +type decodeState struct { | |
| + data []byte | |
| + off int // next read offset in data | |
| + opcode int // last read result | |
| + scan scanner | |
| + errorContext *errorContext | |
| + savedError error | |
| + useNumber bool | |
| + disallowUnknownFields bool | |
| +} | |
| + | |
| +// readIndex returns the position of the last byte read. | |
| +func (d *decodeState) readIndex() int { | |
| + return d.off - 1 | |
| +} | |
| + | |
| +// phasePanicMsg is used as a panic message when we end up with something that | |
| +// shouldn't happen. It can indicate a bug in the JSON decoder, or that | |
| +// something is editing the data slice while the decoder executes. | |
| +const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" | |
| + | |
| +func (d *decodeState) init(data []byte) *decodeState { | |
| + d.data = data | |
| + d.off = 0 | |
| + d.savedError = nil | |
| + if d.errorContext != nil { | |
| + d.errorContext.Struct = nil | |
| + // Reuse the allocated space for the FieldStack slice. | |
| + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] | |
| + } | |
| + return d | |
| +} | |
| + | |
| +// saveError saves the first err it is called with, | |
| +// for reporting at the end of the unmarshal. | |
| +func (d *decodeState) saveError(err error) { | |
| + if d.savedError == nil { | |
| + d.savedError = d.addErrorContext(err) | |
| + } | |
| +} | |
| + | |
| +// addErrorContext returns a new error enhanced with information from d.errorContext | |
| +func (d *decodeState) addErrorContext(err error) error { | |
| + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { | |
| + switch err := err.(type) { | |
| + case *UnmarshalTypeError: | |
| + err.Struct = d.errorContext.Struct.Name() | |
| + fieldStack := d.errorContext.FieldStack | |
| + if err.Field != "" { | |
| + fieldStack = append(fieldStack, err.Field) | |
| + } | |
| + err.Field = strings.Join(fieldStack, ".") | |
| + } | |
| + } | |
| + return err | |
| +} | |
| + | |
| +// skip scans to the end of what was started. | |
| +func (d *decodeState) skip() { | |
| + s, data, i := &d.scan, d.data, d.off | |
| + depth := len(s.parseState) | |
| + for { | |
| + op := s.step(s, data[i]) | |
| + i++ | |
| + if len(s.parseState) < depth { | |
| + d.off = i | |
| + d.opcode = op | |
| + return | |
| + } | |
| + } | |
| +} | |
| + | |
| +// scanNext processes the byte at d.data[d.off]. | |
| +func (d *decodeState) scanNext() { | |
| + if d.off < len(d.data) { | |
| + d.opcode = d.scan.step(&d.scan, d.data[d.off]) | |
| + d.off++ | |
| + } else { | |
| + d.opcode = d.scan.eof() | |
| + d.off = len(d.data) + 1 // mark processed EOF with len+1 | |
| + } | |
| +} | |
| + | |
| +// scanWhile processes bytes in d.data[d.off:] until it | |
| +// receives a scan code not equal to op. | |
| +func (d *decodeState) scanWhile(op int) { | |
| + s, data, i := &d.scan, d.data, d.off | |
| + for i < len(data) { | |
| + newOp := s.step(s, data[i]) | |
| + i++ | |
| + if newOp != op { | |
| + d.opcode = newOp | |
| + d.off = i | |
| + return | |
| + } | |
| + } | |
| + | |
| + d.off = len(data) + 1 // mark processed EOF with len+1 | |
| + d.opcode = d.scan.eof() | |
| +} | |
| + | |
| +// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the | |
| +// common case where we're decoding a literal. The decoder scans the input | |
| +// twice, once for syntax errors and to check the length of the value, and the | |
| +// second to perform the decoding. | |
| +// | |
| +// Only in the second step do we use decodeState to tokenize literals, so we | |
| +// know there aren't any syntax errors. We can take advantage of that knowledge, | |
| +// and scan a literal's bytes much more quickly. | |
| +func (d *decodeState) rescanLiteral() { | |
| + data, i := d.data, d.off | |
| +Switch: | |
| + switch data[i-1] { | |
| + case '"': // string | |
| + for ; i < len(data); i++ { | |
| + switch data[i] { | |
| + case '\\': | |
| + i++ // escaped char | |
| + case '"': | |
| + i++ // tokenize the closing quote too | |
| + break Switch | |
| + } | |
| + } | |
| + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number | |
| + for ; i < len(data); i++ { | |
| + switch data[i] { | |
| + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', | |
| + '.', 'e', 'E', '+', '-': | |
| + default: | |
| + break Switch | |
| + } | |
| + } | |
| + case 't': // true | |
| + i += len("rue") | |
| + case 'f': // false | |
| + i += len("alse") | |
| + case 'n': // null | |
| + i += len("ull") | |
| + } | |
| + if i < len(data) { | |
| + d.opcode = stateEndValue(&d.scan, data[i]) | |
| + } else { | |
| + d.opcode = scanEnd | |
| + } | |
| + d.off = i + 1 | |
| +} | |
| + | |
| +// value consumes a JSON value from d.data[d.off-1:], decoding into v, and | |
| +// reads the following byte ahead. If v is invalid, the value is discarded. | |
| +// The first byte of the value has been read already. | |
| +func (d *decodeState) value(v reflect.Value) error { | |
| + switch d.opcode { | |
| + default: | |
| + panic(phasePanicMsg) | |
| + | |
| + case scanBeginArray: | |
| + if v.IsValid() { | |
| + if err := d.array(v); err != nil { | |
| + return err | |
| + } | |
| + } else { | |
| + d.skip() | |
| + } | |
| + d.scanNext() | |
| + | |
| + case scanBeginObject: | |
| + if v.IsValid() { | |
| + if err := d.object(v); err != nil { | |
| + return err | |
| + } | |
| + } else { | |
| + d.skip() | |
| + } | |
| + d.scanNext() | |
| + | |
| + case scanBeginLiteral: | |
| + // All bytes inside literal return scanContinue op code. | |
| + start := d.readIndex() | |
| + d.rescanLiteral() | |
| + | |
| + if v.IsValid() { | |
| + if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { | |
| + return err | |
| + } | |
| + } | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +type unquotedValue struct{} | |
| + | |
| +// valueQuoted is like value but decodes a | |
| +// quoted string literal or literal null into an interface value. | |
| +// If it finds anything other than a quoted string literal or null, | |
| +// valueQuoted returns unquotedValue{}. | |
| +func (d *decodeState) valueQuoted() any { | |
| + switch d.opcode { | |
| + default: | |
| + panic(phasePanicMsg) | |
| + | |
| + case scanBeginArray, scanBeginObject: | |
| + d.skip() | |
| + d.scanNext() | |
| + | |
| + case scanBeginLiteral: | |
| + v := d.literalInterface() | |
| + switch v.(type) { | |
| + case nil, string: | |
| + return v | |
| + } | |
| + } | |
| + return unquotedValue{} | |
| +} | |
| + | |
| +// indirect walks down v allocating pointers as needed, | |
| +// until it gets to a non-pointer. | |
| +// If it encounters an Unmarshaler, indirect stops and returns that. | |
| +// If decodingNull is true, indirect stops at the first settable pointer so it | |
| +// can be set to nil. | |
| +func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { | |
| + // Issue #24153 indicates that it is generally not a guaranteed property | |
| + // that you may round-trip a reflect.Value by calling Value.Addr().Elem() | |
| + // and expect the value to still be settable for values derived from | |
| + // unexported embedded struct fields. | |
| + // | |
| + // The logic below effectively does this when it first addresses the value | |
| + // (to satisfy possible pointer methods) and continues to dereference | |
| + // subsequent pointers as necessary. | |
| + // | |
| + // After the first round-trip, we set v back to the original value to | |
| + // preserve the original RW flags contained in reflect.Value. | |
| + v0 := v | |
| + haveAddr := false | |
| + | |
| + // If v is a named type and is addressable, | |
| + // start with its address, so that if the type has pointer methods, | |
| + // we find them. | |
| + if v.Kind() != reflect.Pointer && v.Type().Name() != "" && v.CanAddr() { | |
| + haveAddr = true | |
| + v = v.Addr() | |
| + } | |
| + for { | |
| + // Load value from interface, but only if the result will be | |
| + // usefully addressable. | |
| + if v.Kind() == reflect.Interface && !v.IsNil() { | |
| + e := v.Elem() | |
| + if e.Kind() == reflect.Pointer && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Pointer) { | |
| + haveAddr = false | |
| + v = e | |
| + continue | |
| + } | |
| + } | |
| + | |
| + if v.Kind() != reflect.Pointer { | |
| + break | |
| + } | |
| + | |
| + if decodingNull && v.CanSet() { | |
| + break | |
| + } | |
| + | |
| + // Prevent infinite loop if v is an interface pointing to its own address: | |
| + // var v any | |
| + // v = &v | |
| + if v.Elem().Kind() == reflect.Interface && v.Elem().Elem().Equal(v) { | |
| + v = v.Elem() | |
| + break | |
| + } | |
| + if v.IsNil() { | |
| + v.Set(reflect.New(v.Type().Elem())) | |
| + } | |
| + if v.Type().NumMethod() > 0 && v.CanInterface() { | |
| + if u, ok := v.Interface().(Unmarshaler); ok { | |
| + return u, nil, reflect.Value{} | |
| + } | |
| + if !decodingNull { | |
| + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { | |
| + return nil, u, reflect.Value{} | |
| + } | |
| + } | |
| + } | |
| + | |
| + if haveAddr { | |
| + v = v0 // restore original value after round-trip Value.Addr().Elem() | |
| + haveAddr = false | |
| + } else { | |
| + v = v.Elem() | |
| + } | |
| + } | |
| + return nil, nil, v | |
| +} | |
| + | |
| +// array consumes an array from d.data[d.off-1:], decoding into v. | |
| +// The first byte of the array ('[') has been read already. | |
| +func (d *decodeState) array(v reflect.Value) error { | |
| + // Check for unmarshaler. | |
| + u, ut, pv := indirect(v, false) | |
| + if u != nil { | |
| + start := d.readIndex() | |
| + d.skip() | |
| + return u.UnmarshalJSON(d.data[start:d.off]) | |
| + } | |
| + if ut != nil { | |
| + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) | |
| + d.skip() | |
| + return nil | |
| + } | |
| + v = pv | |
| + | |
| + // Check type of target. | |
| + switch v.Kind() { | |
| + case reflect.Interface: | |
| + if v.NumMethod() == 0 { | |
| + // Decoding into nil interface? Switch to non-reflect code. | |
| + ai := d.arrayInterface() | |
| + v.Set(reflect.ValueOf(ai)) | |
| + return nil | |
| + } | |
| + // Otherwise it's invalid. | |
| + fallthrough | |
| + default: | |
| + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) | |
| + d.skip() | |
| + return nil | |
| + case reflect.Array, reflect.Slice: | |
| + break | |
| + } | |
| + | |
| + i := 0 | |
| + for { | |
| + // Look ahead for ] - can only happen on first iteration. | |
| + d.scanWhile(scanSkipSpace) | |
| + if d.opcode == scanEndArray { | |
| + break | |
| + } | |
| + | |
| + // Expand slice length, growing the slice if necessary. | |
| + if v.Kind() == reflect.Slice { | |
| + if i >= v.Cap() { | |
| + v.Grow(1) | |
| + } | |
| + if i >= v.Len() { | |
| + v.SetLen(i + 1) | |
| + } | |
| + } | |
| + | |
| + if i < v.Len() { | |
| + // Decode into element. | |
| + if err := d.value(v.Index(i)); err != nil { | |
| + return err | |
| + } | |
| + } else { | |
| + // Ran out of fixed array: skip. | |
| + if err := d.value(reflect.Value{}); err != nil { | |
| + return err | |
| + } | |
| + } | |
| + i++ | |
| + | |
| + // Next token must be , or ]. | |
| + if d.opcode == scanSkipSpace { | |
| + d.scanWhile(scanSkipSpace) | |
| + } | |
| + if d.opcode == scanEndArray { | |
| + break | |
| + } | |
| + if d.opcode != scanArrayValue { | |
| + panic(phasePanicMsg) | |
| + } | |
| + } | |
| + | |
| + if i < v.Len() { | |
| + if v.Kind() == reflect.Array { | |
| + for ; i < v.Len(); i++ { | |
| + v.Index(i).SetZero() // zero remainder of array | |
| + } | |
| + } else { | |
| + v.SetLen(i) // truncate the slice | |
| + } | |
| + } | |
| + if i == 0 && v.Kind() == reflect.Slice { | |
| + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +var nullLiteral = []byte("null") | |
| + | |
| +// SHIM(reflect): reflect.TypeFor[T]() reflect.T | |
| +var textUnmarshalerType = shims.TypeFor[encoding.TextUnmarshaler]() | |
| + | |
| +// object consumes an object from d.data[d.off-1:], decoding into v. | |
| +// The first byte ('{') of the object has been read already. | |
| +func (d *decodeState) object(v reflect.Value) error { | |
| + // Check for unmarshaler. | |
| + u, ut, pv := indirect(v, false) | |
| + if u != nil { | |
| + start := d.readIndex() | |
| + d.skip() | |
| + return u.UnmarshalJSON(d.data[start:d.off]) | |
| + } | |
| + if ut != nil { | |
| + d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) | |
| + d.skip() | |
| + return nil | |
| + } | |
| + v = pv | |
| + t := v.Type() | |
| + | |
| + // Decoding into nil interface? Switch to non-reflect code. | |
| + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { | |
| + oi := d.objectInterface() | |
| + v.Set(reflect.ValueOf(oi)) | |
| + return nil | |
| + } | |
| + | |
| + var fields structFields | |
| + | |
| + // Check type of target: | |
| + // struct or | |
| + // map[T1]T2 where T1 is string, an integer type, | |
| + // or an encoding.TextUnmarshaler | |
| + switch v.Kind() { | |
| + case reflect.Map: | |
| + // Map key must either have string kind, have an integer kind, | |
| + // or be an encoding.TextUnmarshaler. | |
| + switch t.Key().Kind() { | |
| + case reflect.String, | |
| + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | |
| + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | |
| + default: | |
| + if !reflect.PointerTo(t.Key()).Implements(textUnmarshalerType) { | |
| + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) | |
| + d.skip() | |
| + return nil | |
| + } | |
| + } | |
| + if v.IsNil() { | |
| + v.Set(reflect.MakeMap(t)) | |
| + } | |
| + case reflect.Struct: | |
| + fields = cachedTypeFields(t) | |
| + // ok | |
| + default: | |
| + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) | |
| + d.skip() | |
| + return nil | |
| + } | |
| + | |
| + var mapElem reflect.Value | |
| + var origErrorContext errorContext | |
| + if d.errorContext != nil { | |
| + origErrorContext = *d.errorContext | |
| + } | |
| + | |
| + for { | |
| + // Read opening " of string key or closing }. | |
| + d.scanWhile(scanSkipSpace) | |
| + if d.opcode == scanEndObject { | |
| + // closing } - can only happen on first iteration. | |
| + break | |
| + } | |
| + if d.opcode != scanBeginLiteral { | |
| + panic(phasePanicMsg) | |
| + } | |
| + | |
| + // Read key. | |
| + start := d.readIndex() | |
| + d.rescanLiteral() | |
| + item := d.data[start:d.readIndex()] | |
| + key, ok := unquoteBytes(item) | |
| + if !ok { | |
| + panic(phasePanicMsg) | |
| + } | |
| + | |
| + // Figure out field corresponding to key. | |
| + var subv reflect.Value | |
| + destring := false // whether the value is wrapped in a string to be decoded first | |
| + | |
| + if v.Kind() == reflect.Map { | |
| + elemType := t.Elem() | |
| + if !mapElem.IsValid() { | |
| + mapElem = reflect.New(elemType).Elem() | |
| + } else { | |
| + mapElem.SetZero() | |
| + } | |
| + subv = mapElem | |
| + } else { | |
| + f := fields.byExactName[string(key)] | |
| + if f == nil { | |
| + f = fields.byFoldedName[string(foldName(key))] | |
| + } | |
| + if f != nil { | |
| + subv = v | |
| + destring = f.quoted | |
| + if d.errorContext == nil { | |
| + d.errorContext = new(errorContext) | |
| + } | |
| + for i, ind := range f.index { | |
| + if subv.Kind() == reflect.Pointer { | |
| + if subv.IsNil() { | |
| + // If a struct embeds a pointer to an unexported type, | |
| + // it is not possible to set a newly allocated value | |
| + // since the field is unexported. | |
| + // | |
| + // See https://golang.org/issue/21357 | |
| + if !subv.CanSet() { | |
| + d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) | |
| + // Invalidate subv to ensure d.value(subv) skips over | |
| + // the JSON value without assigning it to subv. | |
| + subv = reflect.Value{} | |
| + destring = false | |
| + break | |
| + } | |
| + subv.Set(reflect.New(subv.Type().Elem())) | |
| + } | |
| + subv = subv.Elem() | |
| + } | |
| + if i < len(f.index)-1 { | |
| + d.errorContext.FieldStack = append( | |
| + d.errorContext.FieldStack, | |
| + subv.Type().Field(ind).Name, | |
| + ) | |
| + } | |
| + subv = subv.Field(ind) | |
| + } | |
| + d.errorContext.Struct = t | |
| + d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) | |
| + } else if d.disallowUnknownFields { | |
| + d.saveError(fmt.Errorf("json: unknown field %q", key)) | |
| + } | |
| + } | |
| + | |
| + // Read : before value. | |
| + if d.opcode == scanSkipSpace { | |
| + d.scanWhile(scanSkipSpace) | |
| + } | |
| + if d.opcode != scanObjectKey { | |
| + panic(phasePanicMsg) | |
| + } | |
| + d.scanWhile(scanSkipSpace) | |
| + | |
| + if destring { | |
| + switch qv := d.valueQuoted().(type) { | |
| + case nil: | |
| + if err := d.literalStore(nullLiteral, subv, false); err != nil { | |
| + return err | |
| + } | |
| + case string: | |
| + if err := d.literalStore([]byte(qv), subv, true); err != nil { | |
| + return err | |
| + } | |
| + default: | |
| + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) | |
| + } | |
| + } else { | |
| + if err := d.value(subv); err != nil { | |
| + return err | |
| + } | |
| + } | |
| + | |
| + // Write value back to map; | |
| + // if using struct, subv points into struct already. | |
| + if v.Kind() == reflect.Map { | |
| + kt := t.Key() | |
| + var kv reflect.Value | |
| + if reflect.PointerTo(kt).Implements(textUnmarshalerType) { | |
| + kv = reflect.New(kt) | |
| + if err := d.literalStore(item, kv, true); err != nil { | |
| + return err | |
| + } | |
| + kv = kv.Elem() | |
| + } else { | |
| + switch kt.Kind() { | |
| + case reflect.String: | |
| + kv = reflect.New(kt).Elem() | |
| + kv.SetString(string(key)) | |
| + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
| + s := string(key) | |
| + n, err := strconv.ParseInt(s, 10, 64) | |
| + // SHIM(reflect): reflect.Type.OverflowInt(int64) bool | |
| + okt := shims.OverflowableType{Type: kt} | |
| + if err != nil || okt.OverflowInt(n) { | |
| + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) | |
| + break | |
| + } | |
| + kv = reflect.New(kt).Elem() | |
| + kv.SetInt(n) | |
| + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | |
| + s := string(key) | |
| + n, err := strconv.ParseUint(s, 10, 64) | |
| + // SHIM(reflect): reflect.Type.OverflowUint(uint64) bool | |
| + okt := shims.OverflowableType{Type: kt} | |
| + if err != nil || okt.OverflowUint(n) { | |
| + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) | |
| + break | |
| + } | |
| + kv = reflect.New(kt).Elem() | |
| + kv.SetUint(n) | |
| + default: | |
| + panic("json: Unexpected key type") // should never occur | |
| + } | |
| + } | |
| + if kv.IsValid() { | |
| + v.SetMapIndex(kv, subv) | |
| + } | |
| + } | |
| + | |
| + // Next token must be , or }. | |
| + if d.opcode == scanSkipSpace { | |
| + d.scanWhile(scanSkipSpace) | |
| + } | |
| + if d.errorContext != nil { | |
| + // Reset errorContext to its original state. | |
| + // Keep the same underlying array for FieldStack, to reuse the | |
| + // space and avoid unnecessary allocs. | |
| + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] | |
| + d.errorContext.Struct = origErrorContext.Struct | |
| + } | |
| + if d.opcode == scanEndObject { | |
| + break | |
| + } | |
| + if d.opcode != scanObjectValue { | |
| + panic(phasePanicMsg) | |
| + } | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// convertNumber converts the number literal s to a float64 or a Number | |
| +// depending on the setting of d.useNumber. | |
| +func (d *decodeState) convertNumber(s string) (any, error) { | |
| + if d.useNumber { | |
| + return Number(s), nil | |
| + } | |
| + f, err := strconv.ParseFloat(s, 64) | |
| + if err != nil { | |
| + // SHIM(reflect): reflect.TypeFor[T]() reflect.Type | |
| + return nil, &UnmarshalTypeError{Value: "number " + s, Type: shims.TypeFor[float64](), Offset: int64(d.off)} | |
| + } | |
| + return f, nil | |
| +} | |
| + | |
| +// SHIM(reflect): TypeFor[T]() reflect.Type | |
| +var numberType = shims.TypeFor[Number]() | |
| + | |
| +// literalStore decodes a literal stored in item into v. | |
| +// | |
| +// fromQuoted indicates whether this literal came from unwrapping a | |
| +// string from the ",string" struct tag option. this is used only to | |
| +// produce more helpful error messages. | |
| +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { | |
| + // Check for unmarshaler. | |
| + if len(item) == 0 { | |
| + // Empty string given. | |
| + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) | |
| + return nil | |
| + } | |
| + isNull := item[0] == 'n' // null | |
| + u, ut, pv := indirect(v, isNull) | |
| + if u != nil { | |
| + return u.UnmarshalJSON(item) | |
| + } | |
| + if ut != nil { | |
| + if item[0] != '"' { | |
| + if fromQuoted { | |
| + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) | |
| + return nil | |
| + } | |
| + val := "number" | |
| + switch item[0] { | |
| + case 'n': | |
| + val = "null" | |
| + case 't', 'f': | |
| + val = "bool" | |
| + } | |
| + d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + return nil | |
| + } | |
| + s, ok := unquoteBytes(item) | |
| + if !ok { | |
| + if fromQuoted { | |
| + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) | |
| + } | |
| + panic(phasePanicMsg) | |
| + } | |
| + return ut.UnmarshalText(s) | |
| + } | |
| + | |
| + v = pv | |
| + | |
| + switch c := item[0]; c { | |
| + case 'n': // null | |
| + // The main parser checks that only true and false can reach here, | |
| + // but if this was a quoted string input, it could be anything. | |
| + if fromQuoted && string(item) != "null" { | |
| + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) | |
| + break | |
| + } | |
| + switch v.Kind() { | |
| + case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice: | |
| + v.SetZero() | |
| + // otherwise, ignore null for primitives/string | |
| + } | |
| + case 't', 'f': // true, false | |
| + value := item[0] == 't' | |
| + // The main parser checks that only true and false can reach here, | |
| + // but if this was a quoted string input, it could be anything. | |
| + if fromQuoted && string(item) != "true" && string(item) != "false" { | |
| + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) | |
| + break | |
| + } | |
| + switch v.Kind() { | |
| + default: | |
| + if fromQuoted { | |
| + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) | |
| + } else { | |
| + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + } | |
| + case reflect.Bool: | |
| + v.SetBool(value) | |
| + case reflect.Interface: | |
| + if v.NumMethod() == 0 { | |
| + v.Set(reflect.ValueOf(value)) | |
| + } else { | |
| + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + } | |
| + } | |
| + | |
| + case '"': // string | |
| + s, ok := unquoteBytes(item) | |
| + if !ok { | |
| + if fromQuoted { | |
| + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) | |
| + } | |
| + panic(phasePanicMsg) | |
| + } | |
| + switch v.Kind() { | |
| + default: | |
| + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + case reflect.Slice: | |
| + if v.Type().Elem().Kind() != reflect.Uint8 { | |
| + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + break | |
| + } | |
| + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) | |
| + n, err := base64.StdEncoding.Decode(b, s) | |
| + if err != nil { | |
| + d.saveError(err) | |
| + break | |
| + } | |
| + v.SetBytes(b[:n]) | |
| + case reflect.String: | |
| + t := string(s) | |
| + if v.Type() == numberType && !isValidNumber(t) { | |
| + return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) | |
| + } | |
| + v.SetString(t) | |
| + case reflect.Interface: | |
| + if v.NumMethod() == 0 { | |
| + v.Set(reflect.ValueOf(string(s))) | |
| + } else { | |
| + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + } | |
| + } | |
| + | |
| + default: // number | |
| + if c != '-' && (c < '0' || c > '9') { | |
| + if fromQuoted { | |
| + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) | |
| + } | |
| + panic(phasePanicMsg) | |
| + } | |
| + switch v.Kind() { | |
| + default: | |
| + if v.Kind() == reflect.String && v.Type() == numberType { | |
| + // s must be a valid number, because it's | |
| + // already been tokenized. | |
| + v.SetString(string(item)) | |
| + break | |
| + } | |
| + if fromQuoted { | |
| + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) | |
| + } | |
| + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + case reflect.Interface: | |
| + n, err := d.convertNumber(string(item)) | |
| + if err != nil { | |
| + d.saveError(err) | |
| + break | |
| + } | |
| + if v.NumMethod() != 0 { | |
| + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + break | |
| + } | |
| + v.Set(reflect.ValueOf(n)) | |
| + | |
| + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
| + n, err := strconv.ParseInt(string(item), 10, 64) | |
| + if err != nil || v.OverflowInt(n) { | |
| + d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + break | |
| + } | |
| + v.SetInt(n) | |
| + | |
| + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | |
| + n, err := strconv.ParseUint(string(item), 10, 64) | |
| + if err != nil || v.OverflowUint(n) { | |
| + d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + break | |
| + } | |
| + v.SetUint(n) | |
| + | |
| + case reflect.Float32, reflect.Float64: | |
| + n, err := strconv.ParseFloat(string(item), v.Type().Bits()) | |
| + if err != nil || v.OverflowFloat(n) { | |
| + d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) | |
| + break | |
| + } | |
| + v.SetFloat(n) | |
| + } | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// The xxxInterface routines build up a value to be stored | |
| +// in an empty interface. They are not strictly necessary, | |
| +// but they avoid the weight of reflection in this common case. | |
| + | |
| +// valueInterface is like value but returns any. | |
| +func (d *decodeState) valueInterface() (val any) { | |
| + switch d.opcode { | |
| + default: | |
| + panic(phasePanicMsg) | |
| + case scanBeginArray: | |
| + val = d.arrayInterface() | |
| + d.scanNext() | |
| + case scanBeginObject: | |
| + val = d.objectInterface() | |
| + d.scanNext() | |
| + case scanBeginLiteral: | |
| + val = d.literalInterface() | |
| + } | |
| + return | |
| +} | |
| + | |
| +// arrayInterface is like array but returns []any. | |
| +func (d *decodeState) arrayInterface() []any { | |
| + var v = make([]any, 0) | |
| + for { | |
| + // Look ahead for ] - can only happen on first iteration. | |
| + d.scanWhile(scanSkipSpace) | |
| + if d.opcode == scanEndArray { | |
| + break | |
| + } | |
| + | |
| + v = append(v, d.valueInterface()) | |
| + | |
| + // Next token must be , or ]. | |
| + if d.opcode == scanSkipSpace { | |
| + d.scanWhile(scanSkipSpace) | |
| + } | |
| + if d.opcode == scanEndArray { | |
| + break | |
| + } | |
| + if d.opcode != scanArrayValue { | |
| + panic(phasePanicMsg) | |
| + } | |
| + } | |
| + return v | |
| +} | |
| + | |
| +// objectInterface is like object but returns map[string]any. | |
| +func (d *decodeState) objectInterface() map[string]any { | |
| + m := make(map[string]any) | |
| + for { | |
| + // Read opening " of string key or closing }. | |
| + d.scanWhile(scanSkipSpace) | |
| + if d.opcode == scanEndObject { | |
| + // closing } - can only happen on first iteration. | |
| + break | |
| + } | |
| + if d.opcode != scanBeginLiteral { | |
| + panic(phasePanicMsg) | |
| + } | |
| + | |
| + // Read string key. | |
| + start := d.readIndex() | |
| + d.rescanLiteral() | |
| + item := d.data[start:d.readIndex()] | |
| + key, ok := unquote(item) | |
| + if !ok { | |
| + panic(phasePanicMsg) | |
| + } | |
| + | |
| + // Read : before value. | |
| + if d.opcode == scanSkipSpace { | |
| + d.scanWhile(scanSkipSpace) | |
| + } | |
| + if d.opcode != scanObjectKey { | |
| + panic(phasePanicMsg) | |
| + } | |
| + d.scanWhile(scanSkipSpace) | |
| + | |
| + // Read value. | |
| + m[key] = d.valueInterface() | |
| + | |
| + // Next token must be , or }. | |
| + if d.opcode == scanSkipSpace { | |
| + d.scanWhile(scanSkipSpace) | |
| + } | |
| + if d.opcode == scanEndObject { | |
| + break | |
| + } | |
| + if d.opcode != scanObjectValue { | |
| + panic(phasePanicMsg) | |
| + } | |
| + } | |
| + return m | |
| +} | |
| + | |
| +// literalInterface consumes and returns a literal from d.data[d.off-1:] and | |
| +// it reads the following byte ahead. The first byte of the literal has been | |
| +// read already (that's how the caller knows it's a literal). | |
| +func (d *decodeState) literalInterface() any { | |
| + // All bytes inside literal return scanContinue op code. | |
| + start := d.readIndex() | |
| + d.rescanLiteral() | |
| + | |
| + item := d.data[start:d.readIndex()] | |
| + | |
| + switch c := item[0]; c { | |
| + case 'n': // null | |
| + return nil | |
| + | |
| + case 't', 'f': // true, false | |
| + return c == 't' | |
| + | |
| + case '"': // string | |
| + s, ok := unquote(item) | |
| + if !ok { | |
| + panic(phasePanicMsg) | |
| + } | |
| + return s | |
| + | |
| + default: // number | |
| + if c != '-' && (c < '0' || c > '9') { | |
| + panic(phasePanicMsg) | |
| + } | |
| + n, err := d.convertNumber(string(item)) | |
| + if err != nil { | |
| + d.saveError(err) | |
| + } | |
| + return n | |
| + } | |
| +} | |
| + | |
| +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, | |
| +// or it returns -1. | |
| +func getu4(s []byte) rune { | |
| + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { | |
| + return -1 | |
| + } | |
| + var r rune | |
| + for _, c := range s[2:6] { | |
| + switch { | |
| + case '0' <= c && c <= '9': | |
| + c = c - '0' | |
| + case 'a' <= c && c <= 'f': | |
| + c = c - 'a' + 10 | |
| + case 'A' <= c && c <= 'F': | |
| + c = c - 'A' + 10 | |
| + default: | |
| + return -1 | |
| + } | |
| + r = r*16 + rune(c) | |
| + } | |
| + return r | |
| +} | |
| + | |
| +// unquote converts a quoted JSON string literal s into an actual string t. | |
| +// The rules are different than for Go, so cannot use strconv.Unquote. | |
| +func unquote(s []byte) (t string, ok bool) { | |
| + s, ok = unquoteBytes(s) | |
| + t = string(s) | |
| + return | |
| +} | |
| + | |
| +// unquoteBytes should be an internal detail, | |
| +// but widely used packages access it using linkname. | |
| +// Notable members of the hall of shame include: | |
| +// - github.com/bytedance/sonic | |
| +// | |
| +// Do not remove or change the type signature. | |
| +// See go.dev/issue/67401. | |
| +// | |
| +//go:linkname unquoteBytes | |
| +func unquoteBytes(s []byte) (t []byte, ok bool) { | |
| + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { | |
| + return | |
| + } | |
| + s = s[1 : len(s)-1] | |
| + | |
| + // Check for unusual characters. If there are none, | |
| + // then no unquoting is needed, so return a slice of the | |
| + // original bytes. | |
| + r := 0 | |
| + for r < len(s) { | |
| + c := s[r] | |
| + if c == '\\' || c == '"' || c < ' ' { | |
| + break | |
| + } | |
| + if c < utf8.RuneSelf { | |
| + r++ | |
| + continue | |
| + } | |
| + rr, size := utf8.DecodeRune(s[r:]) | |
| + if rr == utf8.RuneError && size == 1 { | |
| + break | |
| + } | |
| + r += size | |
| + } | |
| + if r == len(s) { | |
| + return s, true | |
| + } | |
| + | |
| + b := make([]byte, len(s)+2*utf8.UTFMax) | |
| + w := copy(b, s[0:r]) | |
| + for r < len(s) { | |
| + // Out of room? Can only happen if s is full of | |
| + // malformed UTF-8 and we're replacing each | |
| + // byte with RuneError. | |
| + if w >= len(b)-2*utf8.UTFMax { | |
| + nb := make([]byte, (len(b)+utf8.UTFMax)*2) | |
| + copy(nb, b[0:w]) | |
| + b = nb | |
| + } | |
| + switch c := s[r]; { | |
| + case c == '\\': | |
| + r++ | |
| + if r >= len(s) { | |
| + return | |
| + } | |
| + switch s[r] { | |
| + default: | |
| + return | |
| + case '"', '\\', '/', '\'': | |
| + b[w] = s[r] | |
| + r++ | |
| + w++ | |
| + case 'b': | |
| + b[w] = '\b' | |
| + r++ | |
| + w++ | |
| + case 'f': | |
| + b[w] = '\f' | |
| + r++ | |
| + w++ | |
| + case 'n': | |
| + b[w] = '\n' | |
| + r++ | |
| + w++ | |
| + case 'r': | |
| + b[w] = '\r' | |
| + r++ | |
| + w++ | |
| + case 't': | |
| + b[w] = '\t' | |
| + r++ | |
| + w++ | |
| + case 'u': | |
| + r-- | |
| + rr := getu4(s[r:]) | |
| + if rr < 0 { | |
| + return | |
| + } | |
| + r += 6 | |
| + if utf16.IsSurrogate(rr) { | |
| + rr1 := getu4(s[r:]) | |
| + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { | |
| + // A valid pair; consume. | |
| + r += 6 | |
| + w += utf8.EncodeRune(b[w:], dec) | |
| + break | |
| + } | |
| + // Invalid surrogate; fall back to replacement rune. | |
| + rr = unicode.ReplacementChar | |
| + } | |
| + w += utf8.EncodeRune(b[w:], rr) | |
| + } | |
| + | |
| + // Quote, control characters are invalid. | |
| + case c == '"', c < ' ': | |
| + return | |
| + | |
| + // ASCII | |
| + case c < utf8.RuneSelf: | |
| + b[w] = c | |
| + r++ | |
| + w++ | |
| + | |
| + // Coerce to well-formed UTF-8. | |
| + default: | |
| + rr, size := utf8.DecodeRune(s[r:]) | |
| + r += size | |
| + w += utf8.EncodeRune(b[w:], rr) | |
| + } | |
| + } | |
| + return b[0:w], true | |
| +} | |
| diff --git a/internal/encoding/json/encode.go b/internal/encoding/json/encode.go | |
| new file mode 100644 | |
| index 0000000..98b819d | |
| --- /dev/null | |
| +++ b/internal/encoding/json/encode.go | |
| @@ -0,0 +1,1398 @@ | |
| +// Vendored from Go 1.24.0-pre-release | |
| +// To find alterations, check package shims, and comments beginning in SHIM(). | |
| +// | |
| +// Copyright 2010 The Go Authors. All rights reserved. | |
| +// Use of this source code is governed by a BSD-style | |
| +// license that can be found in the LICENSE file. | |
| + | |
| +// Package json implements encoding and decoding of JSON as defined in | |
| +// RFC 7159. The mapping between JSON and Go values is described | |
| +// in the documentation for the Marshal and Unmarshal functions. | |
| +// | |
| +// See "JSON and Go" for an introduction to this package: | |
| +// https://golang.org/doc/articles/json_and_go.html | |
| +package json | |
| + | |
| +import ( | |
| + "bytes" | |
| + "cmp" | |
| + "encoding" | |
| + "encoding/base64" | |
| + "fmt" | |
| + "github.com/anthropics/anthropic-sdk-go/internal/encoding/json/sentinel" | |
| + "github.com/anthropics/anthropic-sdk-go/internal/encoding/json/shims" | |
| + "math" | |
| + "reflect" | |
| + "slices" | |
| + "strconv" | |
| + "strings" | |
| + "sync" | |
| + "unicode" | |
| + "unicode/utf8" | |
| + _ "unsafe" // for linkname | |
| +) | |
| + | |
| +// Marshal returns the JSON encoding of v. | |
| +// | |
| +// Marshal traverses the value v recursively. | |
| +// If an encountered value implements [Marshaler] | |
| +// and is not a nil pointer, Marshal calls [Marshaler.MarshalJSON] | |
| +// to produce JSON. If no [Marshaler.MarshalJSON] method is present but the | |
| +// value implements [encoding.TextMarshaler] instead, Marshal calls | |
| +// [encoding.TextMarshaler.MarshalText] and encodes the result as a JSON string. | |
| +// The nil pointer exception is not strictly necessary | |
| +// but mimics a similar, necessary exception in the behavior of | |
| +// [Unmarshaler.UnmarshalJSON]. | |
| +// | |
| +// Otherwise, Marshal uses the following type-dependent default encodings: | |
| +// | |
| +// Boolean values encode as JSON booleans. | |
| +// | |
| +// Floating point, integer, and [Number] values encode as JSON numbers. | |
| +// NaN and +/-Inf values will return an [UnsupportedValueError]. | |
| +// | |
| +// String values encode as JSON strings coerced to valid UTF-8, | |
| +// replacing invalid bytes with the Unicode replacement rune. | |
| +// So that the JSON will be safe to embed inside HTML <script> tags, | |
| +// the string is encoded using [HTMLEscape], | |
| +// which replaces "<", ">", "&", U+2028, and U+2029 are escaped | |
| +// to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029". | |
| +// This replacement can be disabled when using an [Encoder], | |
| +// by calling [Encoder.SetEscapeHTML](false). | |
| +// | |
| +// Array and slice values encode as JSON arrays, except that | |
| +// []byte encodes as a base64-encoded string, and a nil slice | |
| +// encodes as the null JSON value. | |
| +// | |
| +// Struct values encode as JSON objects. | |
| +// Each exported struct field becomes a member of the object, using the | |
| +// field name as the object key, unless the field is omitted for one of the | |
| +// reasons given below. | |
| +// | |
| +// The encoding of each struct field can be customized by the format string | |
| +// stored under the "json" key in the struct field's tag. | |
| +// The format string gives the name of the field, possibly followed by a | |
| +// comma-separated list of options. The name may be empty in order to | |
| +// specify options without overriding the default field name. | |
| +// | |
| +// The "omitempty" option specifies that the field should be omitted | |
| +// from the encoding if the field has an empty value, defined as | |
| +// false, 0, a nil pointer, a nil interface value, and any array, | |
| +// slice, map, or string of length zero. | |
| +// | |
| +// As a special case, if the field tag is "-", the field is always omitted. | |
| +// Note that a field with name "-" can still be generated using the tag "-,". | |
| +// | |
| +// Examples of struct field tags and their meanings: | |
| +// | |
| +// // Field appears in JSON as key "myName". | |
| +// Field int `json:"myName"` | |
| +// | |
| +// // Field appears in JSON as key "myName" and | |
| +// // the field is omitted from the object if its value is empty, | |
| +// // as defined above. | |
| +// Field int `json:"myName,omitempty"` | |
| +// | |
| +// // Field appears in JSON as key "Field" (the default), but | |
| +// // the field is skipped if empty. | |
| +// // Note the leading comma. | |
| +// Field int `json:",omitempty"` | |
| +// | |
| +// // Field is ignored by this package. | |
| +// Field int `json:"-"` | |
| +// | |
| +// // Field appears in JSON as key "-". | |
| +// Field int `json:"-,"` | |
| +// | |
| +// The "omitzero" option specifies that the field should be omitted | |
| +// from the encoding if the field has a zero value, according to rules: | |
| +// | |
| +// 1) If the field type has an "IsZero() bool" method, that will be used to | |
| +// determine whether the value is zero. | |
| +// | |
| +// 2) Otherwise, the value is zero if it is the zero value for its type. | |
| +// | |
| +// If both "omitempty" and "omitzero" are specified, the field will be omitted | |
| +// if the value is either empty or zero (or both). | |
| +// | |
| +// The "string" option signals that a field is stored as JSON inside a | |
| +// JSON-encoded string. It applies only to fields of string, floating point, | |
| +// integer, or boolean types. This extra level of encoding is sometimes used | |
| +// when communicating with JavaScript programs: | |
| +// | |
| +// Int64String int64 `json:",string"` | |
| +// | |
| +// The key name will be used if it's a non-empty string consisting of | |
| +// only Unicode letters, digits, and ASCII punctuation except quotation | |
| +// marks, backslash, and comma. | |
| +// | |
| +// Embedded struct fields are usually marshaled as if their inner exported fields | |
| +// were fields in the outer struct, subject to the usual Go visibility rules amended | |
| +// as described in the next paragraph. | |
| +// An anonymous struct field with a name given in its JSON tag is treated as | |
| +// having that name, rather than being anonymous. | |
| +// An anonymous struct field of interface type is treated the same as having | |
| +// that type as its name, rather than being anonymous. | |
| +// | |
| +// The Go visibility rules for struct fields are amended for JSON when | |
| +// deciding which field to marshal or unmarshal. If there are | |
| +// multiple fields at the same level, and that level is the least | |
| +// nested (and would therefore be the nesting level selected by the | |
| +// usual Go rules), the following extra rules apply: | |
| +// | |
| +// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, | |
| +// even if there are multiple untagged fields that would otherwise conflict. | |
| +// | |
| +// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. | |
| +// | |
| +// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. | |
| +// | |
| +// Handling of anonymous struct fields is new in Go 1.1. | |
| +// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of | |
| +// an anonymous struct field in both current and earlier versions, give the field | |
| +// a JSON tag of "-". | |
| +// | |
| +// Map values encode as JSON objects. The map's key type must either be a | |
| +// string, an integer type, or implement [encoding.TextMarshaler]. The map keys | |
| +// are sorted and used as JSON object keys by applying the following rules, | |
| +// subject to the UTF-8 coercion described for string values above: | |
| +// - keys of any string type are used directly | |
| +// - keys that implement [encoding.TextMarshaler] are marshaled | |
| +// - integer keys are converted to strings | |
| +// | |
| +// Pointer values encode as the value pointed to. | |
| +// A nil pointer encodes as the null JSON value. | |
| +// | |
| +// Interface values encode as the value contained in the interface. | |
| +// A nil interface value encodes as the null JSON value. | |
| +// | |
| +// Channel, complex, and function values cannot be encoded in JSON. | |
| +// Attempting to encode such a value causes Marshal to return | |
| +// an [UnsupportedTypeError]. | |
| +// | |
| +// JSON cannot represent cyclic data structures and Marshal does not | |
| +// handle them. Passing cyclic structures to Marshal will result in | |
| +// an error. | |
| +func Marshal(v any) ([]byte, error) { | |
| + e := newEncodeState() | |
| + defer encodeStatePool.Put(e) | |
| + | |
| + err := e.marshal(v, encOpts{escapeHTML: true}) | |
| + if err != nil { | |
| + return nil, err | |
| + } | |
| + buf := append([]byte(nil), e.Bytes()...) | |
| + | |
| + return buf, nil | |
| +} | |
| + | |
| +// MarshalIndent is like [Marshal] but applies [Indent] to format the output. | |
| +// Each JSON element in the output will begin on a new line beginning with prefix | |
| +// followed by one or more copies of indent according to the indentation nesting. | |
| +func MarshalIndent(v any, prefix, indent string) ([]byte, error) { | |
| + b, err := Marshal(v) | |
| + if err != nil { | |
| + return nil, err | |
| + } | |
| + b2 := make([]byte, 0, indentGrowthFactor*len(b)) | |
| + b2, err = appendIndent(b2, b, prefix, indent) | |
| + if err != nil { | |
| + return nil, err | |
| + } | |
| + return b2, nil | |
| +} | |
| + | |
| +// Marshaler is the interface implemented by types that | |
| +// can marshal themselves into valid JSON. | |
| +type Marshaler interface { | |
| + MarshalJSON() ([]byte, error) | |
| +} | |
| + | |
| +// An UnsupportedTypeError is returned by [Marshal] when attempting | |
| +// to encode an unsupported value type. | |
| +type UnsupportedTypeError struct { | |
| + Type reflect.Type | |
| +} | |
| + | |
| +func (e *UnsupportedTypeError) Error() string { | |
| + return "json: unsupported type: " + e.Type.String() | |
| +} | |
| + | |
| +// An UnsupportedValueError is returned by [Marshal] when attempting | |
| +// to encode an unsupported value. | |
| +type UnsupportedValueError struct { | |
| + Value reflect.Value | |
| + Str string | |
| +} | |
| + | |
| +func (e *UnsupportedValueError) Error() string { | |
| + return "json: unsupported value: " + e.Str | |
| +} | |
| + | |
| +// Before Go 1.2, an InvalidUTF8Error was returned by [Marshal] when | |
| +// attempting to encode a string value with invalid UTF-8 sequences. | |
| +// As of Go 1.2, [Marshal] instead coerces the string to valid UTF-8 by | |
| +// replacing invalid bytes with the Unicode replacement rune U+FFFD. | |
| +// | |
| +// Deprecated: No longer used; kept for compatibility. | |
| +type InvalidUTF8Error struct { | |
| + S string // the whole string value that caused the error | |
| +} | |
| + | |
| +func (e *InvalidUTF8Error) Error() string { | |
| + return "json: invalid UTF-8 in string: " + strconv.Quote(e.S) | |
| +} | |
| + | |
| +// A MarshalerError represents an error from calling a | |
| +// [Marshaler.MarshalJSON] or [encoding.TextMarshaler.MarshalText] method. | |
| +type MarshalerError struct { | |
| + Type reflect.Type | |
| + Err error | |
| + sourceFunc string | |
| +} | |
| + | |
| +func (e *MarshalerError) Error() string { | |
| + srcFunc := e.sourceFunc | |
| + if srcFunc == "" { | |
| + srcFunc = "MarshalJSON" | |
| + } | |
| + return "json: error calling " + srcFunc + | |
| + " for type " + e.Type.String() + | |
| + ": " + e.Err.Error() | |
| +} | |
| + | |
| +// Unwrap returns the underlying error. | |
| +func (e *MarshalerError) Unwrap() error { return e.Err } | |
| + | |
| +const hex = "0123456789abcdef" | |
| + | |
| +// An encodeState encodes JSON into a bytes.Buffer. | |
| +type encodeState struct { | |
| + bytes.Buffer // accumulated output | |
| + | |
| + // Keep track of what pointers we've seen in the current recursive call | |
| + // path, to avoid cycles that could lead to a stack overflow. Only do | |
| + // the relatively expensive map operations if ptrLevel is larger than | |
| + // startDetectingCyclesAfter, so that we skip the work if we're within a | |
| + // reasonable amount of nested pointers deep. | |
| + ptrLevel uint | |
| + ptrSeen map[any]struct{} | |
| +} | |
| + | |
| +const startDetectingCyclesAfter = 1000 | |
| + | |
| +var encodeStatePool sync.Pool | |
| + | |
| +func newEncodeState() *encodeState { | |
| + if v := encodeStatePool.Get(); v != nil { | |
| + e := v.(*encodeState) | |
| + e.Reset() | |
| + if len(e.ptrSeen) > 0 { | |
| + panic("ptrEncoder.encode should have emptied ptrSeen via defers") | |
| + } | |
| + e.ptrLevel = 0 | |
| + return e | |
| + } | |
| + return &encodeState{ptrSeen: make(map[any]struct{})} | |
| +} | |
| + | |
| +// jsonError is an error wrapper type for internal use only. | |
| +// Panics with errors are wrapped in jsonError so that the top-level recover | |
| +// can distinguish intentional panics from this package. | |
| +type jsonError struct{ error } | |
| + | |
| +func (e *encodeState) marshal(v any, opts encOpts) (err error) { | |
| + defer func() { | |
| + if r := recover(); r != nil { | |
| + if je, ok := r.(jsonError); ok { | |
| + err = je.error | |
| + } else { | |
| + panic(r) | |
| + } | |
| + } | |
| + }() | |
| + e.reflectValue(reflect.ValueOf(v), opts) | |
| + return nil | |
| +} | |
| + | |
| +// error aborts the encoding by panicking with err wrapped in jsonError. | |
| +func (e *encodeState) error(err error) { | |
| + panic(jsonError{err}) | |
| +} | |
| + | |
| +func isEmptyValue(v reflect.Value) bool { | |
| + switch v.Kind() { | |
| + case reflect.String: | |
| + return v.Len() == 0 | |
| + case reflect.Array, reflect.Map, reflect.Slice: | |
| + return v.Len() == 0 | |
| + case reflect.Bool, | |
| + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | |
| + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, | |
| + reflect.Float32, reflect.Float64, | |
| + reflect.Interface, reflect.Pointer: | |
| + return v.IsZero() | |
| + } | |
| + return false | |
| +} | |
| + | |
| +func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) { | |
| + valueEncoder(v)(e, v, opts) | |
| +} | |
| + | |
| +type encOpts struct { | |
| + // quoted causes primitive fields to be encoded inside JSON strings. | |
| + quoted bool | |
| + // escapeHTML causes '<', '>', and '&' to be escaped in JSON strings. | |
| + escapeHTML bool | |
| + // EDIT(begin): save the timefmt | |
| + timefmt string | |
| + // EDIT(end) | |
| +} | |
| + | |
| +type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts) | |
| + | |
| +var encoderCache sync.Map // map[reflect.Type]encoderFunc | |
| + | |
| +func valueEncoder(v reflect.Value) encoderFunc { | |
| + if !v.IsValid() { | |
| + return invalidValueEncoder | |
| + } | |
| + return typeEncoder(v.Type()) | |
| +} | |
| + | |
| +func typeEncoder(t reflect.Type) encoderFunc { | |
| + if fi, ok := encoderCache.Load(t); ok { | |
| + return fi.(encoderFunc) | |
| + } | |
| + | |
| + // To deal with recursive types, populate the map with an | |
| + // indirect func before we build it. This type waits on the | |
| + // real func (f) to be ready and then calls it. This indirect | |
| + // func is only used for recursive types. | |
| + var ( | |
| + wg sync.WaitGroup | |
| + f encoderFunc | |
| + ) | |
| + wg.Add(1) | |
| + fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(e *encodeState, v reflect.Value, opts encOpts) { | |
| + wg.Wait() | |
| + f(e, v, opts) | |
| + })) | |
| + if loaded { | |
| + return fi.(encoderFunc) | |
| + } | |
| + | |
| + // Compute the real encoder and replace the indirect func with it. | |
| + f = newTypeEncoder(t, true) | |
| + wg.Done() | |
| + encoderCache.Store(t, f) | |
| + return f | |
| +} | |
| + | |
| +var ( | |
| + // SHIM(begin): TypeFor[T]() reflect.Type | |
| + marshalerType = shims.TypeFor[Marshaler]() | |
| + textMarshalerType = shims.TypeFor[encoding.TextMarshaler]() | |
| + // SHIM(end) | |
| +) | |
| + | |
| +// newTypeEncoder constructs an encoderFunc for a type. | |
| +// The returned encoder only checks CanAddr when allowAddr is true. | |
| +func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc { | |
| + // EDIT(begin): add custom time encoder | |
| + if t == timeType { | |
| + return newTimeEncoder() | |
| + } | |
| + // EDIT(end) | |
| + | |
| + // If we have a non-pointer value whose type implements | |
| + // Marshaler with a value receiver, then we're better off taking | |
| + // the address of the value - otherwise we end up with an | |
| + // allocation as we cast the value to an interface. | |
| + if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(marshalerType) { | |
| + return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false)) | |
| + } | |
| + | |
| + if t.Implements(marshalerType) { | |
| + return marshalerEncoder | |
| + } | |
| + if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(textMarshalerType) { | |
| + return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false)) | |
| + } | |
| + if t.Implements(textMarshalerType) { | |
| + return textMarshalerEncoder | |
| + } | |
| + | |
| + switch t.Kind() { | |
| + case reflect.Bool: | |
| + return boolEncoder | |
| + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
| + return intEncoder | |
| + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | |
| + return uintEncoder | |
| + case reflect.Float32: | |
| + return float32Encoder | |
| + case reflect.Float64: | |
| + return float64Encoder | |
| + case reflect.String: | |
| + return stringEncoder | |
| + case reflect.Interface: | |
| + return interfaceEncoder | |
| + case reflect.Struct: | |
| + return newStructEncoder(t) | |
| + case reflect.Map: | |
| + return newMapEncoder(t) | |
| + case reflect.Slice: | |
| + return newSliceEncoder(t) | |
| + case reflect.Array: | |
| + return newArrayEncoder(t) | |
| + case reflect.Pointer: | |
| + return newPtrEncoder(t) | |
| + default: | |
| + return unsupportedTypeEncoder | |
| + } | |
| +} | |
| + | |
| +func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) { | |
| + e.WriteString("null") | |
| +} | |
| + | |
| +func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { | |
| + if v.Kind() == reflect.Pointer && v.IsNil() { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + m, ok := v.Interface().(Marshaler) | |
| + if !ok { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + | |
| + // EDIT(begin): use custom time encoder | |
| + if timeMarshalEncoder(e, v, opts) { | |
| + return | |
| + } | |
| + // EDIT(end) | |
| + | |
| + b, err := m.MarshalJSON() | |
| + if err == nil { | |
| + e.Grow(len(b)) | |
| + out := e.AvailableBuffer() | |
| + out, err = appendCompact(out, b, opts.escapeHTML) | |
| + e.Buffer.Write(out) | |
| + } | |
| + if err != nil { | |
| + e.error(&MarshalerError{v.Type(), err, "MarshalJSON"}) | |
| + } | |
| +} | |
| + | |
| +func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { | |
| + va := v.Addr() | |
| + if va.IsNil() { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + | |
| + // EDIT(begin): use custom time encoder | |
| + if timeMarshalEncoder(e, v, opts) { | |
| + return | |
| + } | |
| + // EDIT(end) | |
| + | |
| + m := va.Interface().(Marshaler) | |
| + b, err := m.MarshalJSON() | |
| + if err == nil { | |
| + e.Grow(len(b)) | |
| + out := e.AvailableBuffer() | |
| + out, err = appendCompact(out, b, opts.escapeHTML) | |
| + e.Buffer.Write(out) | |
| + } | |
| + if err != nil { | |
| + e.error(&MarshalerError{v.Type(), err, "MarshalJSON"}) | |
| + } | |
| +} | |
| + | |
| +func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { | |
| + if v.Kind() == reflect.Pointer && v.IsNil() { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + m, ok := v.Interface().(encoding.TextMarshaler) | |
| + if !ok { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + b, err := m.MarshalText() | |
| + if err != nil { | |
| + e.error(&MarshalerError{v.Type(), err, "MarshalText"}) | |
| + } | |
| + e.Write(appendString(e.AvailableBuffer(), b, opts.escapeHTML)) | |
| +} | |
| + | |
| +func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { | |
| + va := v.Addr() | |
| + if va.IsNil() { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + m := va.Interface().(encoding.TextMarshaler) | |
| + b, err := m.MarshalText() | |
| + if err != nil { | |
| + e.error(&MarshalerError{v.Type(), err, "MarshalText"}) | |
| + } | |
| + e.Write(appendString(e.AvailableBuffer(), b, opts.escapeHTML)) | |
| +} | |
| + | |
| +func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) { | |
| + b := e.AvailableBuffer() | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + b = strconv.AppendBool(b, v.Bool()) | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + e.Write(b) | |
| +} | |
| + | |
| +func intEncoder(e *encodeState, v reflect.Value, opts encOpts) { | |
| + b := e.AvailableBuffer() | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + b = strconv.AppendInt(b, v.Int(), 10) | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + e.Write(b) | |
| +} | |
| + | |
| +func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) { | |
| + b := e.AvailableBuffer() | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + b = strconv.AppendUint(b, v.Uint(), 10) | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + e.Write(b) | |
| +} | |
| + | |
| +type floatEncoder int // number of bits | |
| + | |
| +func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { | |
| + f := v.Float() | |
| + if math.IsInf(f, 0) || math.IsNaN(f) { | |
| + e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))}) | |
| + } | |
| + | |
| + // Convert as if by ES6 number to string conversion. | |
| + // This matches most other JSON generators. | |
| + // See golang.org/issue/6384 and golang.org/issue/14135. | |
| + // Like fmt %g, but the exponent cutoffs are different | |
| + // and exponents themselves are not padded to two digits. | |
| + b := e.AvailableBuffer() | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + abs := math.Abs(f) | |
| + fmt := byte('f') | |
| + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. | |
| + if abs != 0 { | |
| + if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { | |
| + fmt = 'e' | |
| + } | |
| + } | |
| + b = strconv.AppendFloat(b, f, fmt, -1, int(bits)) | |
| + if fmt == 'e' { | |
| + // clean up e-09 to e-9 | |
| + n := len(b) | |
| + if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' { | |
| + b[n-2] = b[n-1] | |
| + b = b[:n-1] | |
| + } | |
| + } | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + e.Write(b) | |
| +} | |
| + | |
| +var ( | |
| + float32Encoder = (floatEncoder(32)).encode | |
| + float64Encoder = (floatEncoder(64)).encode | |
| +) | |
| + | |
| +func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { | |
| + if v.Type() == numberType { | |
| + numStr := v.String() | |
| + // In Go1.5 the empty string encodes to "0", while this is not a valid number literal | |
| + // we keep compatibility so check validity after this. | |
| + if numStr == "" { | |
| + numStr = "0" // Number's zero-val | |
| + } | |
| + if !isValidNumber(numStr) { | |
| + e.error(fmt.Errorf("json: invalid number literal %q", numStr)) | |
| + } | |
| + b := e.AvailableBuffer() | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + b = append(b, numStr...) | |
| + b = mayAppendQuote(b, opts.quoted) | |
| + e.Write(b) | |
| + return | |
| + } | |
| + if opts.quoted { | |
| + b := appendString(nil, v.String(), opts.escapeHTML) | |
| + e.Write(appendString(e.AvailableBuffer(), b, false)) // no need to escape again since it is already escaped | |
| + } else { | |
| + e.Write(appendString(e.AvailableBuffer(), v.String(), opts.escapeHTML)) | |
| + } | |
| +} | |
| + | |
| +// isValidNumber reports whether s is a valid JSON number literal. | |
| +// | |
| +// isValidNumber should be an internal detail, | |
| +// but widely used packages access it using linkname. | |
| +// Notable members of the hall of shame include: | |
| +// - github.com/bytedance/sonic | |
| +// | |
| +// Do not remove or change the type signature. | |
| +// See go.dev/issue/67401. | |
| +// | |
| +//go:linkname isValidNumber | |
| +func isValidNumber(s string) bool { | |
| + // This function implements the JSON numbers grammar. | |
| + // See https://tools.ietf.org/html/rfc7159#section-6 | |
| + // and https://www.json.org/img/number.png | |
| + | |
| + if s == "" { | |
| + return false | |
| + } | |
| + | |
| + // Optional - | |
| + if s[0] == '-' { | |
| + s = s[1:] | |
| + if s == "" { | |
| + return false | |
| + } | |
| + } | |
| + | |
| + // Digits | |
| + switch { | |
| + default: | |
| + return false | |
| + | |
| + case s[0] == '0': | |
| + s = s[1:] | |
| + | |
| + case '1' <= s[0] && s[0] <= '9': | |
| + s = s[1:] | |
| + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { | |
| + s = s[1:] | |
| + } | |
| + } | |
| + | |
| + // . followed by 1 or more digits. | |
| + if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { | |
| + s = s[2:] | |
| + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { | |
| + s = s[1:] | |
| + } | |
| + } | |
| + | |
| + // e or E followed by an optional - or + and | |
| + // 1 or more digits. | |
| + if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { | |
| + s = s[1:] | |
| + if s[0] == '+' || s[0] == '-' { | |
| + s = s[1:] | |
| + if s == "" { | |
| + return false | |
| + } | |
| + } | |
| + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { | |
| + s = s[1:] | |
| + } | |
| + } | |
| + | |
| + // Make sure we are at the end. | |
| + return s == "" | |
| +} | |
| + | |
| +func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) { | |
| + if v.IsNil() { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + e.reflectValue(v.Elem(), opts) | |
| +} | |
| + | |
| +func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) { | |
| + e.error(&UnsupportedTypeError{v.Type()}) | |
| +} | |
| + | |
| +type structEncoder struct { | |
| + fields structFields | |
| +} | |
| + | |
| +type structFields struct { | |
| + list []field | |
| + byExactName map[string]*field | |
| + byFoldedName map[string]*field | |
| +} | |
| + | |
| +func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { | |
| + next := byte('{') | |
| +FieldLoop: | |
| + for i := range se.fields.list { | |
| + f := &se.fields.list[i] | |
| + | |
| + // Find the nested struct field by following f.index. | |
| + fv := v | |
| + for _, i := range f.index { | |
| + if fv.Kind() == reflect.Pointer { | |
| + if fv.IsNil() { | |
| + continue FieldLoop | |
| + } | |
| + fv = fv.Elem() | |
| + } | |
| + fv = fv.Field(i) | |
| + } | |
| + | |
| + if (f.omitEmpty && isEmptyValue(fv)) || | |
| + (f.omitZero && (f.isZero == nil && fv.IsZero() || (f.isZero != nil && f.isZero(fv)))) { | |
| + continue | |
| + } | |
| + e.WriteByte(next) | |
| + next = ',' | |
| + if opts.escapeHTML { | |
| + e.WriteString(f.nameEscHTML) | |
| + } else { | |
| + e.WriteString(f.nameNonEsc) | |
| + } | |
| + opts.quoted = f.quoted | |
| + f.encoder(e, fv, opts) | |
| + } | |
| + if next == '{' { | |
| + e.WriteString("{}") | |
| + } else { | |
| + e.WriteByte('}') | |
| + } | |
| +} | |
| + | |
| +func newStructEncoder(t reflect.Type) encoderFunc { | |
| + se := structEncoder{fields: cachedTypeFields(t)} | |
| + return se.encode | |
| +} | |
| + | |
| +type mapEncoder struct { | |
| + elemEnc encoderFunc | |
| +} | |
| + | |
| +func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { | |
| + if v.IsNil() { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { | |
| + // We're a large number of nested ptrEncoder.encode calls deep; | |
| + // start checking if we've run into a pointer cycle. | |
| + ptr := v.UnsafePointer() | |
| + if _, ok := e.ptrSeen[ptr]; ok { | |
| + e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) | |
| + } | |
| + e.ptrSeen[ptr] = struct{}{} | |
| + defer delete(e.ptrSeen, ptr) | |
| + } | |
| + e.WriteByte('{') | |
| + | |
| + // Extract and sort the keys. | |
| + var ( | |
| + sv = make([]reflectWithString, v.Len()) | |
| + mi = v.MapRange() | |
| + err error | |
| + ) | |
| + for i := 0; mi.Next(); i++ { | |
| + if sv[i].ks, err = resolveKeyName(mi.Key()); err != nil { | |
| + e.error(fmt.Errorf("json: encoding error for type %q: %q", v.Type().String(), err.Error())) | |
| + } | |
| + sv[i].v = mi.Value() | |
| + } | |
| + slices.SortFunc(sv, func(i, j reflectWithString) int { | |
| + return strings.Compare(i.ks, j.ks) | |
| + }) | |
| + | |
| + for i, kv := range sv { | |
| + if i > 0 { | |
| + e.WriteByte(',') | |
| + } | |
| + e.Write(appendString(e.AvailableBuffer(), kv.ks, opts.escapeHTML)) | |
| + e.WriteByte(':') | |
| + me.elemEnc(e, kv.v, opts) | |
| + } | |
| + e.WriteByte('}') | |
| + e.ptrLevel-- | |
| +} | |
| + | |
| +func newMapEncoder(t reflect.Type) encoderFunc { | |
| + switch t.Key().Kind() { | |
| + case reflect.String, | |
| + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | |
| + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | |
| + default: | |
| + if !t.Key().Implements(textMarshalerType) { | |
| + return unsupportedTypeEncoder | |
| + } | |
| + } | |
| + me := mapEncoder{typeEncoder(t.Elem())} | |
| + return me.encode | |
| +} | |
| + | |
| +func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) { | |
| + if v.IsNil() { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + | |
| + s := v.Bytes() | |
| + b := e.AvailableBuffer() | |
| + b = append(b, '"') | |
| + // SHIM(base64): base64.StdEncoding.AppendEncode([]byte, []byte) []byte | |
| + b = (shims.AppendableStdEncoding{Encoding: base64.StdEncoding}).AppendEncode(b, s) | |
| + b = append(b, '"') | |
| + e.Write(b) | |
| +} | |
| + | |
| +// sliceEncoder just wraps an arrayEncoder, checking to make sure the value isn't nil. | |
| +type sliceEncoder struct { | |
| + arrayEnc encoderFunc | |
| +} | |
| + | |
| +func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { | |
| + if v.IsNil() { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { | |
| + // We're a large number of nested ptrEncoder.encode calls deep; | |
| + // start checking if we've run into a pointer cycle. | |
| + // Here we use a struct to memorize the pointer to the first element of the slice | |
| + // and its length. | |
| + ptr := struct { | |
| + ptr any // always an unsafe.Pointer, but avoids a dependency on package unsafe | |
| + len int | |
| + }{v.UnsafePointer(), v.Len()} | |
| + if _, ok := e.ptrSeen[ptr]; ok { | |
| + e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) | |
| + } | |
| + e.ptrSeen[ptr] = struct{}{} | |
| + defer delete(e.ptrSeen, ptr) | |
| + } | |
| + se.arrayEnc(e, v, opts) | |
| + e.ptrLevel-- | |
| +} | |
| + | |
| +func newSliceEncoder(t reflect.Type) encoderFunc { | |
| + // Byte slices get special treatment; arrays don't. | |
| + if t.Elem().Kind() == reflect.Uint8 { | |
| + p := reflect.PointerTo(t.Elem()) | |
| + if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) { | |
| + return encodeByteSlice | |
| + } | |
| + } | |
| + enc := sliceEncoder{newArrayEncoder(t)} | |
| + return enc.encode | |
| +} | |
| + | |
| +type arrayEncoder struct { | |
| + elemEnc encoderFunc | |
| +} | |
| + | |
| +func (ae arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { | |
| + e.WriteByte('[') | |
| + n := v.Len() | |
| + for i := 0; i < n; i++ { | |
| + if i > 0 { | |
| + e.WriteByte(',') | |
| + } | |
| + ae.elemEnc(e, v.Index(i), opts) | |
| + } | |
| + e.WriteByte(']') | |
| +} | |
| + | |
| +func newArrayEncoder(t reflect.Type) encoderFunc { | |
| + enc := arrayEncoder{typeEncoder(t.Elem())} | |
| + return enc.encode | |
| +} | |
| + | |
| +type ptrEncoder struct { | |
| + elemEnc encoderFunc | |
| +} | |
| + | |
| +func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { | |
| + // EDIT(begin) | |
| + // | |
| + // if v.IsNil() { | |
| + // e.WriteString("null") | |
| + // return | |
| + // } | |
| + | |
| + if v.IsNil() || sentinel.IsValueNullPtr(v) || sentinel.IsValueNullSlice(v) { | |
| + e.WriteString("null") | |
| + return | |
| + } | |
| + | |
| + // EDIT(end) | |
| + if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { | |
| + // We're a large number of nested ptrEncoder.encode calls deep; | |
| + // start checking if we've run into a pointer cycle. | |
| + ptr := v.Interface() | |
| + if _, ok := e.ptrSeen[ptr]; ok { | |
| + e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) | |
| + } | |
| + e.ptrSeen[ptr] = struct{}{} | |
| + defer delete(e.ptrSeen, ptr) | |
| + } | |
| + pe.elemEnc(e, v.Elem(), opts) | |
| + e.ptrLevel-- | |
| +} | |
| + | |
| +func newPtrEncoder(t reflect.Type) encoderFunc { | |
| + enc := ptrEncoder{typeEncoder(t.Elem())} | |
| + return enc.encode | |
| +} | |
| + | |
| +type condAddrEncoder struct { | |
| + canAddrEnc, elseEnc encoderFunc | |
| +} | |
| + | |
| +func (ce condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { | |
| + if v.CanAddr() { | |
| + ce.canAddrEnc(e, v, opts) | |
| + } else { | |
| + ce.elseEnc(e, v, opts) | |
| + } | |
| +} | |
| + | |
| +// newCondAddrEncoder returns an encoder that checks whether its value | |
| +// CanAddr and delegates to canAddrEnc if so, else to elseEnc. | |
| +func newCondAddrEncoder(canAddrEnc, elseEnc encoderFunc) encoderFunc { | |
| + enc := condAddrEncoder{canAddrEnc: canAddrEnc, elseEnc: elseEnc} | |
| + return enc.encode | |
| +} | |
| + | |
| +func isValidTag(s string) bool { | |
| + if s == "" { | |
| + return false | |
| + } | |
| + for _, c := range s { | |
| + switch { | |
| + case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c): | |
| + // Backslash and quote chars are reserved, but | |
| + // otherwise any punctuation chars are allowed | |
| + // in a tag name. | |
| + case !unicode.IsLetter(c) && !unicode.IsDigit(c): | |
| + return false | |
| + } | |
| + } | |
| + return true | |
| +} | |
| + | |
| +func typeByIndex(t reflect.Type, index []int) reflect.Type { | |
| + for _, i := range index { | |
| + if t.Kind() == reflect.Pointer { | |
| + t = t.Elem() | |
| + } | |
| + t = t.Field(i).Type | |
| + } | |
| + return t | |
| +} | |
| + | |
| +type reflectWithString struct { | |
| + v reflect.Value | |
| + ks string | |
| +} | |
| + | |
| +func resolveKeyName(k reflect.Value) (string, error) { | |
| + if k.Kind() == reflect.String { | |
| + return k.String(), nil | |
| + } | |
| + if tm, ok := k.Interface().(encoding.TextMarshaler); ok { | |
| + if k.Kind() == reflect.Pointer && k.IsNil() { | |
| + return "", nil | |
| + } | |
| + buf, err := tm.MarshalText() | |
| + return string(buf), err | |
| + } | |
| + switch k.Kind() { | |
| + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
| + return strconv.FormatInt(k.Int(), 10), nil | |
| + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | |
| + return strconv.FormatUint(k.Uint(), 10), nil | |
| + } | |
| + panic("unexpected map key type") | |
| +} | |
| + | |
| +func appendString[Bytes []byte | string](dst []byte, src Bytes, escapeHTML bool) []byte { | |
| + dst = append(dst, '"') | |
| + start := 0 | |
| + for i := 0; i < len(src); { | |
| + if b := src[i]; b < utf8.RuneSelf { | |
| + if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) { | |
| + i++ | |
| + continue | |
| + } | |
| + dst = append(dst, src[start:i]...) | |
| + switch b { | |
| + case '\\', '"': | |
| + dst = append(dst, '\\', b) | |
| + case '\b': | |
| + dst = append(dst, '\\', 'b') | |
| + case '\f': | |
| + dst = append(dst, '\\', 'f') | |
| + case '\n': | |
| + dst = append(dst, '\\', 'n') | |
| + case '\r': | |
| + dst = append(dst, '\\', 'r') | |
| + case '\t': | |
| + dst = append(dst, '\\', 't') | |
| + default: | |
| + // This encodes bytes < 0x20 except for \b, \f, \n, \r and \t. | |
| + // If escapeHTML is set, it also escapes <, >, and & | |
| + // because they can lead to security holes when | |
| + // user-controlled strings are rendered into JSON | |
| + // and served to some browsers. | |
| + dst = append(dst, '\\', 'u', '0', '0', hex[b>>4], hex[b&0xF]) | |
| + } | |
| + i++ | |
| + start = i | |
| + continue | |
| + } | |
| + // TODO(https://go.dev/issue/56948): Use generic utf8 functionality. | |
| + // For now, cast only a small portion of byte slices to a string | |
| + // so that it can be stack allocated. This slows down []byte slightly | |
| + // due to the extra copy, but keeps string performance roughly the same. | |
| + n := len(src) - i | |
| + if n > utf8.UTFMax { | |
| + n = utf8.UTFMax | |
| + } | |
| + c, size := utf8.DecodeRuneInString(string(src[i : i+n])) | |
| + if c == utf8.RuneError && size == 1 { | |
| + dst = append(dst, src[start:i]...) | |
| + dst = append(dst, `\ufffd`...) | |
| + i += size | |
| + start = i | |
| + continue | |
| + } | |
| + // U+2028 is LINE SEPARATOR. | |
| + // U+2029 is PARAGRAPH SEPARATOR. | |
| + // They are both technically valid characters in JSON strings, | |
| + // but don't work in JSONP, which has to be evaluated as JavaScript, | |
| + // and can lead to security holes there. It is valid JSON to | |
| + // escape them, so we do so unconditionally. | |
| + // See https://en.wikipedia.org/wiki/JSON#Safety. | |
| + if c == '\u2028' || c == '\u2029' { | |
| + dst = append(dst, src[start:i]...) | |
| + dst = append(dst, '\\', 'u', '2', '0', '2', hex[c&0xF]) | |
| + i += size | |
| + start = i | |
| + continue | |
| + } | |
| + i += size | |
| + } | |
| + dst = append(dst, src[start:]...) | |
| + dst = append(dst, '"') | |
| + return dst | |
| +} | |
| + | |
| +// A field represents a single field found in a struct. | |
| +type field struct { | |
| + name string | |
| + nameBytes []byte // []byte(name) | |
| + | |
| + nameNonEsc string // `"` + name + `":` | |
| + nameEscHTML string // `"` + HTMLEscape(name) + `":` | |
| + | |
| + tag bool | |
| + index []int | |
| + typ reflect.Type | |
| + omitEmpty bool | |
| + omitZero bool | |
| + isZero func(reflect.Value) bool | |
| + quoted bool | |
| + | |
| + encoder encoderFunc | |
| + | |
| + // EDIT(begin): save the timefmt if present | |
| + timefmt string | |
| + // EDIT(end) | |
| +} | |
| + | |
| +type isZeroer interface { | |
| + IsZero() bool | |
| +} | |
| + | |
| +// SHIM(reflect): TypeFor[T]() reflect.Type | |
| +var isZeroerType = shims.TypeFor[isZeroer]() | |
| + | |
| +// typeFields returns a list of fields that JSON should recognize for the given type. | |
| +// The algorithm is breadth-first search over the set of structs to include - the top struct | |
| +// and then any reachable anonymous structs. | |
| +// | |
| +// typeFields should be an internal detail, | |
| +// but widely used packages access it using linkname. | |
| +// Notable members of the hall of shame include: | |
| +// - github.com/bytedance/sonic | |
| +// | |
| +// Do not remove or change the type signature. | |
| +// See go.dev/issue/67401. | |
| +// | |
| +//go:linkname typeFields | |
| +func typeFields(t reflect.Type) structFields { | |
| + // Anonymous fields to explore at the current level and the next. | |
| + current := []field{} | |
| + next := []field{{typ: t}} | |
| + | |
| + // Count of queued names for current level and the next. | |
| + var count, nextCount map[reflect.Type]int | |
| + | |
| + // Types already visited at an earlier level. | |
| + visited := map[reflect.Type]bool{} | |
| + | |
| + // Fields found. | |
| + var fields []field | |
| + | |
| + // Buffer to run appendHTMLEscape on field names. | |
| + var nameEscBuf []byte | |
| + | |
| + for len(next) > 0 { | |
| + current, next = next, current[:0] | |
| + count, nextCount = nextCount, map[reflect.Type]int{} | |
| + | |
| + for _, f := range current { | |
| + if visited[f.typ] { | |
| + continue | |
| + } | |
| + visited[f.typ] = true | |
| + | |
| + // Scan f.typ for fields to include. | |
| + for i := 0; i < f.typ.NumField(); i++ { | |
| + sf := f.typ.Field(i) | |
| + if sf.Anonymous { | |
| + t := sf.Type | |
| + if t.Kind() == reflect.Pointer { | |
| + t = t.Elem() | |
| + } | |
| + if !sf.IsExported() && t.Kind() != reflect.Struct { | |
| + // Ignore embedded fields of unexported non-struct types. | |
| + continue | |
| + } | |
| + // Do not ignore embedded fields of unexported struct types | |
| + // since they may have exported fields. | |
| + } else if !sf.IsExported() { | |
| + // Ignore unexported non-embedded fields. | |
| + continue | |
| + } | |
| + tag := sf.Tag.Get("json") | |
| + if tag == "-" { | |
| + continue | |
| + } | |
| + name, opts := parseTag(tag) | |
| + if !isValidTag(name) { | |
| + name = "" | |
| + } | |
| + index := make([]int, len(f.index)+1) | |
| + copy(index, f.index) | |
| + index[len(f.index)] = i | |
| + | |
| + ft := sf.Type | |
| + if ft.Name() == "" && ft.Kind() == reflect.Pointer { | |
| + // Follow pointer. | |
| + ft = ft.Elem() | |
| + } | |
| + | |
| + // Only strings, floats, integers, and booleans can be quoted. | |
| + quoted := false | |
| + if opts.Contains("string") { | |
| + switch ft.Kind() { | |
| + case reflect.Bool, | |
| + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | |
| + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, | |
| + reflect.Float32, reflect.Float64, | |
| + reflect.String: | |
| + quoted = true | |
| + } | |
| + } | |
| + | |
| + // Record found field and index sequence. | |
| + if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { | |
| + tagged := name != "" | |
| + if name == "" { | |
| + name = sf.Name | |
| + } | |
| + field := field{ | |
| + name: name, | |
| + tag: tagged, | |
| + index: index, | |
| + typ: ft, | |
| + omitEmpty: opts.Contains("omitempty"), | |
| + omitZero: opts.Contains("omitzero"), | |
| + quoted: quoted, | |
| + // EDIT(begin): save the timefmt | |
| + timefmt: sf.Tag.Get("format"), | |
| + // EDIT(end) | |
| + } | |
| + field.nameBytes = []byte(field.name) | |
| + | |
| + // Build nameEscHTML and nameNonEsc ahead of time. | |
| + nameEscBuf = appendHTMLEscape(nameEscBuf[:0], field.nameBytes) | |
| + field.nameEscHTML = `"` + string(nameEscBuf) + `":` | |
| + field.nameNonEsc = `"` + field.name + `":` | |
| + | |
| + if field.omitZero { | |
| + t := sf.Type | |
| + // Provide a function that uses a type's IsZero method. | |
| + switch { | |
| + case t.Kind() == reflect.Interface && t.Implements(isZeroerType): | |
| + field.isZero = func(v reflect.Value) bool { | |
| + // Avoid panics calling IsZero on a nil interface or | |
| + // non-nil interface with nil pointer. | |
| + return v.IsNil() || | |
| + (v.Elem().Kind() == reflect.Pointer && v.Elem().IsNil()) || | |
| + v.Interface().(isZeroer).IsZero() | |
| + } | |
| + case t.Kind() == reflect.Pointer && t.Implements(isZeroerType): | |
| + field.isZero = func(v reflect.Value) bool { | |
| + // Avoid panics calling IsZero on nil pointer. | |
| + return v.IsNil() || v.Interface().(isZeroer).IsZero() | |
| + } | |
| + case t.Implements(isZeroerType): | |
| + field.isZero = func(v reflect.Value) bool { | |
| + return v.Interface().(isZeroer).IsZero() | |
| + } | |
| + case reflect.PointerTo(t).Implements(isZeroerType): | |
| + field.isZero = func(v reflect.Value) bool { | |
| + if !v.CanAddr() { | |
| + // Temporarily box v so we can take the address. | |
| + v2 := reflect.New(v.Type()).Elem() | |
| + v2.Set(v) | |
| + v = v2 | |
| + } | |
| + return v.Addr().Interface().(isZeroer).IsZero() | |
| + } | |
| + } | |
| + } | |
| + | |
| + fields = append(fields, field) | |
| + if count[f.typ] > 1 { | |
| + // If there were multiple instances, add a second, | |
| + // so that the annihilation code will see a duplicate. | |
| + // It only cares about the distinction between 1 and 2, | |
| + // so don't bother generating any more copies. | |
| + fields = append(fields, fields[len(fields)-1]) | |
| + } | |
| + continue | |
| + } | |
| + | |
| + // Record new anonymous struct to explore in next round. | |
| + nextCount[ft]++ | |
| + if nextCount[ft] == 1 { | |
| + next = append(next, field{name: ft.Name(), index: index, typ: ft}) | |
| + } | |
| + } | |
| + } | |
| + } | |
| + | |
| + slices.SortFunc(fields, func(a, b field) int { | |
| + // sort field by name, breaking ties with depth, then | |
| + // breaking ties with "name came from json tag", then | |
| + // breaking ties with index sequence. | |
| + if c := strings.Compare(a.name, b.name); c != 0 { | |
| + return c | |
| + } | |
| + if c := cmp.Compare(len(a.index), len(b.index)); c != 0 { | |
| + return c | |
| + } | |
| + if a.tag != b.tag { | |
| + if a.tag { | |
| + return -1 | |
| + } | |
| + return +1 | |
| + } | |
| + return slices.Compare(a.index, b.index) | |
| + }) | |
| + | |
| + // Delete all fields that are hidden by the Go rules for embedded fields, | |
| + // except that fields with JSON tags are promoted. | |
| + | |
| + // The fields are sorted in primary order of name, secondary order | |
| + // of field index length. Loop over names; for each name, delete | |
| + // hidden fields by choosing the one dominant field that survives. | |
| + out := fields[:0] | |
| + for advance, i := 0, 0; i < len(fields); i += advance { | |
| + // One iteration per name. | |
| + // Find the sequence of fields with the name of this first field. | |
| + fi := fields[i] | |
| + name := fi.name | |
| + for advance = 1; i+advance < len(fields); advance++ { | |
| + fj := fields[i+advance] | |
| + if fj.name != name { | |
| + break | |
| + } | |
| + } | |
| + if advance == 1 { // Only one field with this name | |
| + out = append(out, fi) | |
| + continue | |
| + } | |
| + dominant, ok := dominantField(fields[i : i+advance]) | |
| + if ok { | |
| + out = append(out, dominant) | |
| + } | |
| + } | |
| + | |
| + fields = out | |
| + slices.SortFunc(fields, func(i, j field) int { | |
| + return slices.Compare(i.index, j.index) | |
| + }) | |
| + | |
| + for i := range fields { | |
| + f := &fields[i] | |
| + f.encoder = typeEncoder(typeByIndex(t, f.index)) | |
| + | |
| + // EDIT(begin): add custom timefmt if necessary | |
| + if f.timefmt != "" { | |
| + f.encoder = continueWithTimeFmt(f.timefmt, f.encoder) | |
| + } | |
| + // EDIT(end) | |
| + } | |
| + exactNameIndex := make(map[string]*field, len(fields)) | |
| + foldedNameIndex := make(map[string]*field, len(fields)) | |
| + for i, field := range fields { | |
| + exactNameIndex[field.name] = &fields[i] | |
| + // For historical reasons, first folded match takes precedence. | |
| + if _, ok := foldedNameIndex[string(foldName(field.nameBytes))]; !ok { | |
| + foldedNameIndex[string(foldName(field.nameBytes))] = &fields[i] | |
| + } | |
| + } | |
| + return structFields{fields, exactNameIndex, foldedNameIndex} | |
| +} | |
| + | |
| +// dominantField looks through the fields, all of which are known to | |
| +// have the same name, to find the single field that dominates the | |
| +// others using Go's embedding rules, modified by the presence of | |
| +// JSON tags. If there are multiple top-level fields, the boolean | |
| +// will be false: This condition is an error in Go and we skip all | |
| +// the fields. | |
| +func dominantField(fields []field) (field, bool) { | |
| + // The fields are sorted in increasing index-length order, then by presence of tag. | |
| + // That means that the first field is the dominant one. We need only check | |
| + // for error cases: two fields at top level, either both tagged or neither tagged. | |
| + if len(fields) > 1 && len(fields[0].index) == len(fields[1].index) && fields[0].tag == fields[1].tag { | |
| + return field{}, false | |
| + } | |
| + return fields[0], true | |
| +} | |
| + | |
| +var fieldCache sync.Map // map[reflect.Type]structFields | |
| + | |
| +// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. | |
| +func cachedTypeFields(t reflect.Type) structFields { | |
| + if f, ok := fieldCache.Load(t); ok { | |
| + return f.(structFields) | |
| + } | |
| + f, _ := fieldCache.LoadOrStore(t, typeFields(t)) | |
| + return f.(structFields) | |
| +} | |
| + | |
| +func mayAppendQuote(b []byte, quoted bool) []byte { | |
| + if quoted { | |
| + b = append(b, '"') | |
| + } | |
| + return b | |
| +} | |
| diff --git a/internal/encoding/json/fold.go b/internal/encoding/json/fold.go | |
| new file mode 100644 | |
| index 0000000..c4c671b | |
| --- /dev/null | |
| +++ b/internal/encoding/json/fold.go | |
| @@ -0,0 +1,48 @@ | |
| +// Copyright 2013 The Go Authors. All rights reserved. | |
| +// Use of this source code is governed by a BSD-style | |
| +// license that can be found in the LICENSE file. | |
| + | |
| +package json | |
| + | |
| +import ( | |
| + "unicode" | |
| + "unicode/utf8" | |
| +) | |
| + | |
| +// foldName returns a folded string such that foldName(x) == foldName(y) | |
| +// is identical to bytes.EqualFold(x, y). | |
| +func foldName(in []byte) []byte { | |
| + // This is inlinable to take advantage of "function outlining". | |
| + var arr [32]byte // large enough for most JSON names | |
| + return appendFoldedName(arr[:0], in) | |
| +} | |
| + | |
| +func appendFoldedName(out, in []byte) []byte { | |
| + for i := 0; i < len(in); { | |
| + // Handle single-byte ASCII. | |
| + if c := in[i]; c < utf8.RuneSelf { | |
| + if 'a' <= c && c <= 'z' { | |
| + c -= 'a' - 'A' | |
| + } | |
| + out = append(out, c) | |
| + i++ | |
| + continue | |
| + } | |
| + // Handle multi-byte Unicode. | |
| + r, n := utf8.DecodeRune(in[i:]) | |
| + out = utf8.AppendRune(out, foldRune(r)) | |
| + i += n | |
| + } | |
| + return out | |
| +} | |
| + | |
| +// foldRune is returns the smallest rune for all runes in the same fold set. | |
| +func foldRune(r rune) rune { | |
| + for { | |
| + r2 := unicode.SimpleFold(r) | |
| + if r2 <= r { | |
| + return r2 | |
| + } | |
| + r = r2 | |
| + } | |
| +} | |
| diff --git a/internal/encoding/json/indent.go b/internal/encoding/json/indent.go | |
| new file mode 100644 | |
| index 0000000..01bfdf6 | |
| --- /dev/null | |
| +++ b/internal/encoding/json/indent.go | |
| @@ -0,0 +1,182 @@ | |
| +// Copyright 2010 The Go Authors. All rights reserved. | |
| +// Use of this source code is governed by a BSD-style | |
| +// license that can be found in the LICENSE file. | |
| + | |
| +package json | |
| + | |
| +import "bytes" | |
| + | |
| +// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 | |
| +// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 | |
| +// so that the JSON will be safe to embed inside HTML <script> tags. | |
| +// For historical reasons, web browsers don't honor standard HTML | |
| +// escaping within <script> tags, so an alternative JSON encoding must be used. | |
| +func HTMLEscape(dst *bytes.Buffer, src []byte) { | |
| + dst.Grow(len(src)) | |
| + dst.Write(appendHTMLEscape(dst.AvailableBuffer(), src)) | |
| +} | |
| + | |
| +func appendHTMLEscape(dst, src []byte) []byte { | |
| + // The characters can only appear in string literals, | |
| + // so just scan the string one byte at a time. | |
| + start := 0 | |
| + for i, c := range src { | |
| + if c == '<' || c == '>' || c == '&' { | |
| + dst = append(dst, src[start:i]...) | |
| + dst = append(dst, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xF]) | |
| + start = i + 1 | |
| + } | |
| + // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9). | |
| + if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { | |
| + dst = append(dst, src[start:i]...) | |
| + dst = append(dst, '\\', 'u', '2', '0', '2', hex[src[i+2]&0xF]) | |
| + start = i + len("\u2029") | |
| + } | |
| + } | |
| + return append(dst, src[start:]...) | |
| +} | |
| + | |
| +// Compact appends to dst the JSON-encoded src with | |
| +// insignificant space characters elided. | |
| +func Compact(dst *bytes.Buffer, src []byte) error { | |
| + dst.Grow(len(src)) | |
| + b := dst.AvailableBuffer() | |
| + b, err := appendCompact(b, src, false) | |
| + dst.Write(b) | |
| + return err | |
| +} | |
| + | |
| +func appendCompact(dst, src []byte, escape bool) ([]byte, error) { | |
| + origLen := len(dst) | |
| + scan := newScanner() | |
| + defer freeScanner(scan) | |
| + start := 0 | |
| + for i, c := range src { | |
| + if escape && (c == '<' || c == '>' || c == '&') { | |
| + if start < i { | |
| + dst = append(dst, src[start:i]...) | |
| + } | |
| + dst = append(dst, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xF]) | |
| + start = i + 1 | |
| + } | |
| + // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9). | |
| + if escape && c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { | |
| + if start < i { | |
| + dst = append(dst, src[start:i]...) | |
| + } | |
| + dst = append(dst, '\\', 'u', '2', '0', '2', hex[src[i+2]&0xF]) | |
| + start = i + 3 | |
| + } | |
| + v := scan.step(scan, c) | |
| + if v >= scanSkipSpace { | |
| + if v == scanError { | |
| + break | |
| + } | |
| + if start < i { | |
| + dst = append(dst, src[start:i]...) | |
| + } | |
| + start = i + 1 | |
| + } | |
| + } | |
| + if scan.eof() == scanError { | |
| + return dst[:origLen], scan.err | |
| + } | |
| + if start < len(src) { | |
| + dst = append(dst, src[start:]...) | |
| + } | |
| + return dst, nil | |
| +} | |
| + | |
| +func appendNewline(dst []byte, prefix, indent string, depth int) []byte { | |
| + dst = append(dst, '\n') | |
| + dst = append(dst, prefix...) | |
| + for i := 0; i < depth; i++ { | |
| + dst = append(dst, indent...) | |
| + } | |
| + return dst | |
| +} | |
| + | |
| +// indentGrowthFactor specifies the growth factor of indenting JSON input. | |
| +// Empirically, the growth factor was measured to be between 1.4x to 1.8x | |
| +// for some set of compacted JSON with the indent being a single tab. | |
| +// Specify a growth factor slightly larger than what is observed | |
| +// to reduce probability of allocation in appendIndent. | |
| +// A factor no higher than 2 ensures that wasted space never exceeds 50%. | |
| +const indentGrowthFactor = 2 | |
| + | |
| +// Indent appends to dst an indented form of the JSON-encoded src. | |
| +// Each element in a JSON object or array begins on a new, | |
| +// indented line beginning with prefix followed by one or more | |
| +// copies of indent according to the indentation nesting. | |
| +// The data appended to dst does not begin with the prefix nor | |
| +// any indentation, to make it easier to embed inside other formatted JSON data. | |
| +// Although leading space characters (space, tab, carriage return, newline) | |
| +// at the beginning of src are dropped, trailing space characters | |
| +// at the end of src are preserved and copied to dst. | |
| +// For example, if src has no trailing spaces, neither will dst; | |
| +// if src ends in a trailing newline, so will dst. | |
| +func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { | |
| + dst.Grow(indentGrowthFactor * len(src)) | |
| + b := dst.AvailableBuffer() | |
| + b, err := appendIndent(b, src, prefix, indent) | |
| + dst.Write(b) | |
| + return err | |
| +} | |
| + | |
| +func appendIndent(dst, src []byte, prefix, indent string) ([]byte, error) { | |
| + origLen := len(dst) | |
| + scan := newScanner() | |
| + defer freeScanner(scan) | |
| + needIndent := false | |
| + depth := 0 | |
| + for _, c := range src { | |
| + scan.bytes++ | |
| + v := scan.step(scan, c) | |
| + if v == scanSkipSpace { | |
| + continue | |
| + } | |
| + if v == scanError { | |
| + break | |
| + } | |
| + if needIndent && v != scanEndObject && v != scanEndArray { | |
| + needIndent = false | |
| + depth++ | |
| + dst = appendNewline(dst, prefix, indent, depth) | |
| + } | |
| + | |
| + // Emit semantically uninteresting bytes | |
| + // (in particular, punctuation in strings) unmodified. | |
| + if v == scanContinue { | |
| + dst = append(dst, c) | |
| + continue | |
| + } | |
| + | |
| + // Add spacing around real punctuation. | |
| + switch c { | |
| + case '{', '[': | |
| + // delay indent so that empty object and array are formatted as {} and []. | |
| + needIndent = true | |
| + dst = append(dst, c) | |
| + case ',': | |
| + dst = append(dst, c) | |
| + dst = appendNewline(dst, prefix, indent, depth) | |
| + case ':': | |
| + dst = append(dst, c, ' ') | |
| + case '}', ']': | |
| + if needIndent { | |
| + // suppress indent in empty object/array | |
| + needIndent = false | |
| + } else { | |
| + depth-- | |
| + dst = appendNewline(dst, prefix, indent, depth) | |
| + } | |
| + dst = append(dst, c) | |
| + default: | |
| + dst = append(dst, c) | |
| + } | |
| + } | |
| + if scan.eof() == scanError { | |
| + return dst[:origLen], scan.err | |
| + } | |
| + return dst, nil | |
| +} | |
| diff --git a/internal/encoding/json/scanner.go b/internal/encoding/json/scanner.go | |
| new file mode 100644 | |
| index 0000000..da6ea2a | |
| --- /dev/null | |
| +++ b/internal/encoding/json/scanner.go | |
| @@ -0,0 +1,610 @@ | |
| +// Copyright 2010 The Go Authors. All rights reserved. | |
| +// Use of this source code is governed by a BSD-style | |
| +// license that can be found in the LICENSE file. | |
| + | |
| +package json | |
| + | |
| +// JSON value parser state machine. | |
| +// Just about at the limit of what is reasonable to write by hand. | |
| +// Some parts are a bit tedious, but overall it nicely factors out the | |
| +// otherwise common code from the multiple scanning functions | |
| +// in this package (Compact, Indent, checkValid, etc). | |
| +// | |
| +// This file starts with two simple examples using the scanner | |
| +// before diving into the scanner itself. | |
| + | |
| +import ( | |
| + "strconv" | |
| + "sync" | |
| +) | |
| + | |
| +// Valid reports whether data is a valid JSON encoding. | |
| +func Valid(data []byte) bool { | |
| + scan := newScanner() | |
| + defer freeScanner(scan) | |
| + return checkValid(data, scan) == nil | |
| +} | |
| + | |
| +// checkValid verifies that data is valid JSON-encoded data. | |
| +// scan is passed in for use by checkValid to avoid an allocation. | |
| +// checkValid returns nil or a SyntaxError. | |
| +func checkValid(data []byte, scan *scanner) error { | |
| + scan.reset() | |
| + for _, c := range data { | |
| + scan.bytes++ | |
| + if scan.step(scan, c) == scanError { | |
| + return scan.err | |
| + } | |
| + } | |
| + if scan.eof() == scanError { | |
| + return scan.err | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +// A SyntaxError is a description of a JSON syntax error. | |
| +// [Unmarshal] will return a SyntaxError if the JSON can't be parsed. | |
| +type SyntaxError struct { | |
| + msg string // description of error | |
| + Offset int64 // error occurred after reading Offset bytes | |
| +} | |
| + | |
| +func (e *SyntaxError) Error() string { return e.msg } | |
| + | |
| +// A scanner is a JSON scanning state machine. | |
| +// Callers call scan.reset and then pass bytes in one at a time | |
| +// by calling scan.step(&scan, c) for each byte. | |
| +// The return value, referred to as an opcode, tells the | |
| +// caller about significant parsing events like beginning | |
| +// and ending literals, objects, and arrays, so that the | |
| +// caller can follow along if it wishes. | |
| +// The return value scanEnd indicates that a single top-level | |
| +// JSON value has been completed, *before* the byte that | |
| +// just got passed in. (The indication must be delayed in order | |
| +// to recognize the end of numbers: is 123 a whole value or | |
| +// the beginning of 12345e+6?). | |
| +type scanner struct { | |
| + // The step is a func to be called to execute the next transition. | |
| + // Also tried using an integer constant and a single func | |
| + // with a switch, but using the func directly was 10% faster | |
| + // on a 64-bit Mac Mini, and it's nicer to read. | |
| + step func(*scanner, byte) int | |
| + | |
| + // Reached end of top-level value. | |
| + endTop bool | |
| + | |
| + // Stack of what we're in the middle of - array values, object keys, object values. | |
| + parseState []int | |
| + | |
| + // Error that happened, if any. | |
| + err error | |
| + | |
| + // total bytes consumed, updated by decoder.Decode (and deliberately | |
| + // not set to zero by scan.reset) | |
| + bytes int64 | |
| +} | |
| + | |
| +var scannerPool = sync.Pool{ | |
| + New: func() any { | |
| + return &scanner{} | |
| + }, | |
| +} | |
| + | |
| +func newScanner() *scanner { | |
| + scan := scannerPool.Get().(*scanner) | |
| + // scan.reset by design doesn't set bytes to zero | |
| + scan.bytes = 0 | |
| + scan.reset() | |
| + return scan | |
| +} | |
| + | |
| +func freeScanner(scan *scanner) { | |
| + // Avoid hanging on to too much memory in extreme cases. | |
| + if len(scan.parseState) > 1024 { | |
| + scan.parseState = nil | |
| + } | |
| + scannerPool.Put(scan) | |
| +} | |
| + | |
| +// These values are returned by the state transition functions | |
| +// assigned to scanner.state and the method scanner.eof. | |
| +// They give details about the current state of the scan that | |
| +// callers might be interested to know about. | |
| +// It is okay to ignore the return value of any particular | |
| +// call to scanner.state: if one call returns scanError, | |
| +// every subsequent call will return scanError too. | |
| +const ( | |
| + // Continue. | |
| + scanContinue = iota // uninteresting byte | |
| + scanBeginLiteral // end implied by next result != scanContinue | |
| + scanBeginObject // begin object | |
| + scanObjectKey // just finished object key (string) | |
| + scanObjectValue // just finished non-last object value | |
| + scanEndObject // end object (implies scanObjectValue if possible) | |
| + scanBeginArray // begin array | |
| + scanArrayValue // just finished array value | |
| + scanEndArray // end array (implies scanArrayValue if possible) | |
| + scanSkipSpace // space byte; can skip; known to be last "continue" result | |
| + | |
| + // Stop. | |
| + scanEnd // top-level value ended *before* this byte; known to be first "stop" result | |
| + scanError // hit an error, scanner.err. | |
| +) | |
| + | |
| +// These values are stored in the parseState stack. | |
| +// They give the current state of a composite value | |
| +// being scanned. If the parser is inside a nested value | |
| +// the parseState describes the nested state, outermost at entry 0. | |
| +const ( | |
| + parseObjectKey = iota // parsing object key (before colon) | |
| + parseObjectValue // parsing object value (after colon) | |
| + parseArrayValue // parsing array value | |
| +) | |
| + | |
| +// This limits the max nesting depth to prevent stack overflow. | |
| +// This is permitted by https://tools.ietf.org/html/rfc7159#section-9 | |
| +const maxNestingDepth = 10000 | |
| + | |
| +// reset prepares the scanner for use. | |
| +// It must be called before calling s.step. | |
| +func (s *scanner) reset() { | |
| + s.step = stateBeginValue | |
| + s.parseState = s.parseState[0:0] | |
| + s.err = nil | |
| + s.endTop = false | |
| +} | |
| + | |
| +// eof tells the scanner that the end of input has been reached. | |
| +// It returns a scan status just as s.step does. | |
| +func (s *scanner) eof() int { | |
| + if s.err != nil { | |
| + return scanError | |
| + } | |
| + if s.endTop { | |
| + return scanEnd | |
| + } | |
| + s.step(s, ' ') | |
| + if s.endTop { | |
| + return scanEnd | |
| + } | |
| + if s.err == nil { | |
| + s.err = &SyntaxError{"unexpected end of JSON input", s.bytes} | |
| + } | |
| + return scanError | |
| +} | |
| + | |
| +// pushParseState pushes a new parse state p onto the parse stack. | |
| +// an error state is returned if maxNestingDepth was exceeded, otherwise successState is returned. | |
| +func (s *scanner) pushParseState(c byte, newParseState int, successState int) int { | |
| + s.parseState = append(s.parseState, newParseState) | |
| + if len(s.parseState) <= maxNestingDepth { | |
| + return successState | |
| + } | |
| + return s.error(c, "exceeded max depth") | |
| +} | |
| + | |
| +// popParseState pops a parse state (already obtained) off the stack | |
| +// and updates s.step accordingly. | |
| +func (s *scanner) popParseState() { | |
| + n := len(s.parseState) - 1 | |
| + s.parseState = s.parseState[0:n] | |
| + if n == 0 { | |
| + s.step = stateEndTop | |
| + s.endTop = true | |
| + } else { | |
| + s.step = stateEndValue | |
| + } | |
| +} | |
| + | |
| +func isSpace(c byte) bool { | |
| + return c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') | |
| +} | |
| + | |
| +// stateBeginValueOrEmpty is the state after reading `[`. | |
| +func stateBeginValueOrEmpty(s *scanner, c byte) int { | |
| + if isSpace(c) { | |
| + return scanSkipSpace | |
| + } | |
| + if c == ']' { | |
| + return stateEndValue(s, c) | |
| + } | |
| + return stateBeginValue(s, c) | |
| +} | |
| + | |
| +// stateBeginValue is the state at the beginning of the input. | |
| +func stateBeginValue(s *scanner, c byte) int { | |
| + if isSpace(c) { | |
| + return scanSkipSpace | |
| + } | |
| + switch c { | |
| + case '{': | |
| + s.step = stateBeginStringOrEmpty | |
| + return s.pushParseState(c, parseObjectKey, scanBeginObject) | |
| + case '[': | |
| + s.step = stateBeginValueOrEmpty | |
| + return s.pushParseState(c, parseArrayValue, scanBeginArray) | |
| + case '"': | |
| + s.step = stateInString | |
| + return scanBeginLiteral | |
| + case '-': | |
| + s.step = stateNeg | |
| + return scanBeginLiteral | |
| + case '0': // beginning of 0.123 | |
| + s.step = state0 | |
| + return scanBeginLiteral | |
| + case 't': // beginning of true | |
| + s.step = stateT | |
| + return scanBeginLiteral | |
| + case 'f': // beginning of false | |
| + s.step = stateF | |
| + return scanBeginLiteral | |
| + case 'n': // beginning of null | |
| + s.step = stateN | |
| + return scanBeginLiteral | |
| + } | |
| + if '1' <= c && c <= '9' { // beginning of 1234.5 | |
| + s.step = state1 | |
| + return scanBeginLiteral | |
| + } | |
| + return s.error(c, "looking for beginning of value") | |
| +} | |
| + | |
| +// stateBeginStringOrEmpty is the state after reading `{`. | |
| +func stateBeginStringOrEmpty(s *scanner, c byte) int { | |
| + if isSpace(c) { | |
| + return scanSkipSpace | |
| + } | |
| + if c == '}' { | |
| + n := len(s.parseState) | |
| + s.parseState[n-1] = parseObjectValue | |
| + return stateEndValue(s, c) | |
| + } | |
| + return stateBeginString(s, c) | |
| +} | |
| + | |
| +// stateBeginString is the state after reading `{"key": value,`. | |
| +func stateBeginString(s *scanner, c byte) int { | |
| + if isSpace(c) { | |
| + return scanSkipSpace | |
| + } | |
| + if c == '"' { | |
| + s.step = stateInString | |
| + return scanBeginLiteral | |
| + } | |
| + return s.error(c, "looking for beginning of object key string") | |
| +} | |
| + | |
| +// stateEndValue is the state after completing a value, | |
| +// such as after reading `{}` or `true` or `["x"`. | |
| +func stateEndValue(s *scanner, c byte) int { | |
| + n := len(s.parseState) | |
| + if n == 0 { | |
| + // Completed top-level before the current byte. | |
| + s.step = stateEndTop | |
| + s.endTop = true | |
| + return stateEndTop(s, c) | |
| + } | |
| + if isSpace(c) { | |
| + s.step = stateEndValue | |
| + return scanSkipSpace | |
| + } | |
| + ps := s.parseState[n-1] | |
| + switch ps { | |
| + case parseObjectKey: | |
| + if c == ':' { | |
| + s.parseState[n-1] = parseObjectValue | |
| + s.step = stateBeginValue | |
| + return scanObjectKey | |
| + } | |
| + return s.error(c, "after object key") | |
| + case parseObjectValue: | |
| + if c == ',' { | |
| + s.parseState[n-1] = parseObjectKey | |
| + s.step = stateBeginString | |
| + return scanObjectValue | |
| + } | |
| + if c == '}' { | |
| + s.popParseState() | |
| + return scanEndObject | |
| + } | |
| + return s.error(c, "after object key:value pair") | |
| + case parseArrayValue: | |
| + if c == ',' { | |
| + s.step = stateBeginValue | |
| + return scanArrayValue | |
| + } | |
| + if c == ']' { | |
| + s.popParseState() | |
| + return scanEndArray | |
| + } | |
| + return s.error(c, "after array element") | |
| + } | |
| + return s.error(c, "") | |
| +} | |
| + | |
| +// stateEndTop is the state after finishing the top-level value, | |
| +// such as after reading `{}` or `[1,2,3]`. | |
| +// Only space characters should be seen now. | |
| +func stateEndTop(s *scanner, c byte) int { | |
| + if !isSpace(c) { | |
| + // Complain about non-space byte on next call. | |
| + s.error(c, "after top-level value") | |
| + } | |
| + return scanEnd | |
| +} | |
| + | |
| +// stateInString is the state after reading `"`. | |
| +func stateInString(s *scanner, c byte) int { | |
| + if c == '"' { | |
| + s.step = stateEndValue | |
| + return scanContinue | |
| + } | |
| + if c == '\\' { | |
| + s.step = stateInStringEsc | |
| + return scanContinue | |
| + } | |
| + if c < 0x20 { | |
| + return s.error(c, "in string literal") | |
| + } | |
| + return scanContinue | |
| +} | |
| + | |
| +// stateInStringEsc is the state after reading `"\` during a quoted string. | |
| +func stateInStringEsc(s *scanner, c byte) int { | |
| + switch c { | |
| + case 'b', 'f', 'n', 'r', 't', '\\', '/', '"': | |
| + s.step = stateInString | |
| + return scanContinue | |
| + case 'u': | |
| + s.step = stateInStringEscU | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in string escape code") | |
| +} | |
| + | |
| +// stateInStringEscU is the state after reading `"\u` during a quoted string. | |
| +func stateInStringEscU(s *scanner, c byte) int { | |
| + if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | |
| + s.step = stateInStringEscU1 | |
| + return scanContinue | |
| + } | |
| + // numbers | |
| + return s.error(c, "in \\u hexadecimal character escape") | |
| +} | |
| + | |
| +// stateInStringEscU1 is the state after reading `"\u1` during a quoted string. | |
| +func stateInStringEscU1(s *scanner, c byte) int { | |
| + if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | |
| + s.step = stateInStringEscU12 | |
| + return scanContinue | |
| + } | |
| + // numbers | |
| + return s.error(c, "in \\u hexadecimal character escape") | |
| +} | |
| + | |
| +// stateInStringEscU12 is the state after reading `"\u12` during a quoted string. | |
| +func stateInStringEscU12(s *scanner, c byte) int { | |
| + if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | |
| + s.step = stateInStringEscU123 | |
| + return scanContinue | |
| + } | |
| + // numbers | |
| + return s.error(c, "in \\u hexadecimal character escape") | |
| +} | |
| + | |
| +// stateInStringEscU123 is the state after reading `"\u123` during a quoted string. | |
| +func stateInStringEscU123(s *scanner, c byte) int { | |
| + if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | |
| + s.step = stateInString | |
| + return scanContinue | |
| + } | |
| + // numbers | |
| + return s.error(c, "in \\u hexadecimal character escape") | |
| +} | |
| + | |
| +// stateNeg is the state after reading `-` during a number. | |
| +func stateNeg(s *scanner, c byte) int { | |
| + if c == '0' { | |
| + s.step = state0 | |
| + return scanContinue | |
| + } | |
| + if '1' <= c && c <= '9' { | |
| + s.step = state1 | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in numeric literal") | |
| +} | |
| + | |
| +// state1 is the state after reading a non-zero integer during a number, | |
| +// such as after reading `1` or `100` but not `0`. | |
| +func state1(s *scanner, c byte) int { | |
| + if '0' <= c && c <= '9' { | |
| + s.step = state1 | |
| + return scanContinue | |
| + } | |
| + return state0(s, c) | |
| +} | |
| + | |
| +// state0 is the state after reading `0` during a number. | |
| +func state0(s *scanner, c byte) int { | |
| + if c == '.' { | |
| + s.step = stateDot | |
| + return scanContinue | |
| + } | |
| + if c == 'e' || c == 'E' { | |
| + s.step = stateE | |
| + return scanContinue | |
| + } | |
| + return stateEndValue(s, c) | |
| +} | |
| + | |
| +// stateDot is the state after reading the integer and decimal point in a number, | |
| +// such as after reading `1.`. | |
| +func stateDot(s *scanner, c byte) int { | |
| + if '0' <= c && c <= '9' { | |
| + s.step = stateDot0 | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "after decimal point in numeric literal") | |
| +} | |
| + | |
| +// stateDot0 is the state after reading the integer, decimal point, and subsequent | |
| +// digits of a number, such as after reading `3.14`. | |
| +func stateDot0(s *scanner, c byte) int { | |
| + if '0' <= c && c <= '9' { | |
| + return scanContinue | |
| + } | |
| + if c == 'e' || c == 'E' { | |
| + s.step = stateE | |
| + return scanContinue | |
| + } | |
| + return stateEndValue(s, c) | |
| +} | |
| + | |
| +// stateE is the state after reading the mantissa and e in a number, | |
| +// such as after reading `314e` or `0.314e`. | |
| +func stateE(s *scanner, c byte) int { | |
| + if c == '+' || c == '-' { | |
| + s.step = stateESign | |
| + return scanContinue | |
| + } | |
| + return stateESign(s, c) | |
| +} | |
| + | |
| +// stateESign is the state after reading the mantissa, e, and sign in a number, | |
| +// such as after reading `314e-` or `0.314e+`. | |
| +func stateESign(s *scanner, c byte) int { | |
| + if '0' <= c && c <= '9' { | |
| + s.step = stateE0 | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in exponent of numeric literal") | |
| +} | |
| + | |
| +// stateE0 is the state after reading the mantissa, e, optional sign, | |
| +// and at least one digit of the exponent in a number, | |
| +// such as after reading `314e-2` or `0.314e+1` or `3.14e0`. | |
| +func stateE0(s *scanner, c byte) int { | |
| + if '0' <= c && c <= '9' { | |
| + return scanContinue | |
| + } | |
| + return stateEndValue(s, c) | |
| +} | |
| + | |
| +// stateT is the state after reading `t`. | |
| +func stateT(s *scanner, c byte) int { | |
| + if c == 'r' { | |
| + s.step = stateTr | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal true (expecting 'r')") | |
| +} | |
| + | |
| +// stateTr is the state after reading `tr`. | |
| +func stateTr(s *scanner, c byte) int { | |
| + if c == 'u' { | |
| + s.step = stateTru | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal true (expecting 'u')") | |
| +} | |
| + | |
| +// stateTru is the state after reading `tru`. | |
| +func stateTru(s *scanner, c byte) int { | |
| + if c == 'e' { | |
| + s.step = stateEndValue | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal true (expecting 'e')") | |
| +} | |
| + | |
| +// stateF is the state after reading `f`. | |
| +func stateF(s *scanner, c byte) int { | |
| + if c == 'a' { | |
| + s.step = stateFa | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal false (expecting 'a')") | |
| +} | |
| + | |
| +// stateFa is the state after reading `fa`. | |
| +func stateFa(s *scanner, c byte) int { | |
| + if c == 'l' { | |
| + s.step = stateFal | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal false (expecting 'l')") | |
| +} | |
| + | |
| +// stateFal is the state after reading `fal`. | |
| +func stateFal(s *scanner, c byte) int { | |
| + if c == 's' { | |
| + s.step = stateFals | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal false (expecting 's')") | |
| +} | |
| + | |
| +// stateFals is the state after reading `fals`. | |
| +func stateFals(s *scanner, c byte) int { | |
| + if c == 'e' { | |
| + s.step = stateEndValue | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal false (expecting 'e')") | |
| +} | |
| + | |
| +// stateN is the state after reading `n`. | |
| +func stateN(s *scanner, c byte) int { | |
| + if c == 'u' { | |
| + s.step = stateNu | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal null (expecting 'u')") | |
| +} | |
| + | |
| +// stateNu is the state after reading `nu`. | |
| +func stateNu(s *scanner, c byte) int { | |
| + if c == 'l' { | |
| + s.step = stateNul | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal null (expecting 'l')") | |
| +} | |
| + | |
| +// stateNul is the state after reading `nul`. | |
| +func stateNul(s *scanner, c byte) int { | |
| + if c == 'l' { | |
| + s.step = stateEndValue | |
| + return scanContinue | |
| + } | |
| + return s.error(c, "in literal null (expecting 'l')") | |
| +} | |
| + | |
| +// stateError is the state after reaching a syntax error, | |
| +// such as after reading `[1}` or `5.1.2`. | |
| +func stateError(s *scanner, c byte) int { | |
| + return scanError | |
| +} | |
| + | |
| +// error records an error and switches to the error state. | |
| +func (s *scanner) error(c byte, context string) int { | |
| + s.step = stateError | |
| + s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes} | |
| + return scanError | |
| +} | |
| + | |
| +// quoteChar formats c as a quoted character literal. | |
| +func quoteChar(c byte) string { | |
| + // special cases - different from quoted strings | |
| + if c == '\'' { | |
| + return `'\''` | |
| + } | |
| + if c == '"' { | |
| + return `'"'` | |
| + } | |
| + | |
| + // use quoted string with different quotation marks | |
| + s := strconv.Quote(string(c)) | |
| + return "'" + s[1:len(s)-1] + "'" | |
| +} | |
| diff --git a/internal/encoding/json/sentinel/null.go b/internal/encoding/json/sentinel/null.go | |
| new file mode 100644 | |
| index 0000000..a811b14 | |
| --- /dev/null | |
| +++ b/internal/encoding/json/sentinel/null.go | |
| @@ -0,0 +1,57 @@ | |
| +package sentinel | |
| + | |
| +import ( | |
| + "github.com/anthropics/anthropic-sdk-go/internal/encoding/json/shims" | |
| + "reflect" | |
| + "sync" | |
| +) | |
| + | |
| +var nullPtrsCache sync.Map // map[reflect.Type]*T | |
| + | |
| +func NullPtr[T any]() *T { | |
| + t := shims.TypeFor[T]() | |
| + ptr, loaded := nullPtrsCache.Load(t) // avoid premature allocation | |
| + if !loaded { | |
| + ptr, _ = nullPtrsCache.LoadOrStore(t, new(T)) | |
| + } | |
| + return (ptr.(*T)) | |
| +} | |
| + | |
| +var nullSlicesCache sync.Map // map[reflect.Type][]T | |
| + | |
| +func NullSlice[T any]() []T { | |
| + t := shims.TypeFor[T]() | |
| + slice, loaded := nullSlicesCache.Load(t) // avoid premature allocation | |
| + if !loaded { | |
| + slice, _ = nullSlicesCache.LoadOrStore(t, []T{}) | |
| + } | |
| + return slice.([]T) | |
| +} | |
| + | |
| +func IsNullPtr[T any](ptr *T) bool { | |
| + nullptr, ok := nullPtrsCache.Load(shims.TypeFor[T]()) | |
| + return ok && ptr == nullptr.(*T) | |
| +} | |
| + | |
| +func IsNullSlice[T any](slice []T) bool { | |
| + nullSlice, ok := nullSlicesCache.Load(shims.TypeFor[T]()) | |
| + return ok && reflect.ValueOf(slice).Pointer() == reflect.ValueOf(nullSlice).Pointer() | |
| +} | |
| + | |
| +// internal only | |
| +func IsValueNullPtr(v reflect.Value) bool { | |
| + if v.Kind() != reflect.Ptr { | |
| + return false | |
| + } | |
| + nullptr, ok := nullPtrsCache.Load(v.Type().Elem()) | |
| + return ok && v.Pointer() == reflect.ValueOf(nullptr).Pointer() | |
| +} | |
| + | |
| +// internal only | |
| +func IsValueNullSlice(v reflect.Value) bool { | |
| + if v.Kind() != reflect.Slice { | |
| + return false | |
| + } | |
| + nullSlice, ok := nullSlicesCache.Load(v.Type().Elem()) | |
| + return ok && v.Pointer() == reflect.ValueOf(nullSlice).Pointer() | |
| +} | |
| diff --git a/internal/encoding/json/sentinel/sentinel_test.go b/internal/encoding/json/sentinel/sentinel_test.go | |
| new file mode 100644 | |
| index 0000000..6d0b17b | |
| --- /dev/null | |
| +++ b/internal/encoding/json/sentinel/sentinel_test.go | |
| @@ -0,0 +1,88 @@ | |
| +package sentinel_test | |
| + | |
| +import ( | |
| + "github.com/anthropics/anthropic-sdk-go/internal/encoding/json/sentinel" | |
| + "reflect" | |
| + "slices" | |
| + "testing" | |
| +) | |
| + | |
| +type Pair struct { | |
| + got bool | |
| + want bool | |
| +} | |
| + | |
| +func TestNullSlice(t *testing.T) { | |
| + var nilSlice []int = nil | |
| + var nonNilSlice []int = []int{1, 2, 3} | |
| + var nullSlice []int = sentinel.NullSlice[int]() | |
| + | |
| + cases := map[string]Pair{ | |
| + "nilSlice": {sentinel.IsNullSlice(nilSlice), false}, | |
| + "nullSlice": {sentinel.IsNullSlice(nullSlice), true}, | |
| + "newNullSlice": {sentinel.IsNullSlice(sentinel.NullSlice[int]()), true}, | |
| + "lenNullSlice": {len(nullSlice) == 0, true}, | |
| + "nilSliceValue": {sentinel.IsValueNullSlice(reflect.ValueOf(nilSlice)), false}, | |
| + "nullSliceValue": {sentinel.IsValueNullSlice(reflect.ValueOf(nullSlice)), true}, | |
| + "compareSlices": {slices.Compare(nilSlice, nullSlice) == 0, true}, | |
| + "compareNonNilSlices": {slices.Compare(nonNilSlice, nullSlice) == 0, false}, | |
| + } | |
| + | |
| + nilSlice = append(nullSlice, 12) | |
| + cases["append_result"] = Pair{sentinel.IsNullSlice(nilSlice), false} | |
| + cases["mutated_result"] = Pair{sentinel.IsNullSlice(nullSlice), true} | |
| + cases["append_result_len"] = Pair{len(nilSlice) == 1, true} | |
| + cases["append_null_slice_len"] = Pair{len(nullSlice) == 0, true} | |
| + | |
| + for name, c := range cases { | |
| + t.Run(name, func(t *testing.T) { | |
| + got, want := c.got, c.want | |
| + if got != want { | |
| + t.Errorf("got %v, want %v", got, want) | |
| + } | |
| + }) | |
| + } | |
| +} | |
| + | |
| +func TestNullPtr(t *testing.T) { | |
| + var s *string = nil | |
| + var i *int = nil | |
| + var slice *[]int = nil | |
| + | |
| + var nullptrStr *string = sentinel.NullPtr[string]() | |
| + var nullptrInt *int = sentinel.NullPtr[int]() | |
| + var nullptrSlice *[]int = sentinel.NullPtr[[]int]() | |
| + | |
| + if *nullptrStr != "" { | |
| + t.Errorf("Failed to safely deref") | |
| + } | |
| + if *nullptrInt != 0 { | |
| + t.Errorf("Failed to safely deref") | |
| + } | |
| + if len(*nullptrSlice) != 0 { | |
| + t.Errorf("Failed to safely deref") | |
| + } | |
| + | |
| + cases := map[string]Pair{ | |
| + "nilStr": {sentinel.IsNullPtr(s), false}, | |
| + "nullStr": {sentinel.IsNullPtr(nullptrStr), true}, | |
| + | |
| + "nilInt": {sentinel.IsNullPtr(i), false}, | |
| + "nullInt": {sentinel.IsNullPtr(nullptrInt), true}, | |
| + | |
| + "nilSlice": {sentinel.IsNullPtr(slice), false}, | |
| + "nullSlice": {sentinel.IsNullPtr(nullptrSlice), true}, | |
| + | |
| + "nilValuePtr": {sentinel.IsValueNullPtr(reflect.ValueOf(i)), false}, | |
| + "nullValuePtr": {sentinel.IsValueNullPtr(reflect.ValueOf(nullptrInt)), true}, | |
| + } | |
| + | |
| + for name, test := range cases { | |
| + t.Run(name, func(t *testing.T) { | |
| + got, want := test.got, test.want | |
| + if got != want { | |
| + t.Errorf("got %v, want %v", got, want) | |
| + } | |
| + }) | |
| + } | |
| +} | |
| diff --git a/internal/encoding/json/shims/shims.go b/internal/encoding/json/shims/shims.go | |
| new file mode 100644 | |
| index 0000000..32316ef | |
| --- /dev/null | |
| +++ b/internal/encoding/json/shims/shims.go | |
| @@ -0,0 +1,111 @@ | |
| +// This package provides shims over Go 1.2{2,3} APIs | |
| +// which are missing from Go 1.21, and used by the Go 1.24 encoding/json package. | |
| +// | |
| +// Inside the vendored package, all shim code has comments that begin look like | |
| +// // SHIM(...): ... | |
| +package shims | |
| + | |
| +import ( | |
| + "encoding/base64" | |
| + "reflect" | |
| + "slices" | |
| +) | |
| + | |
| +type OverflowableType struct{ reflect.Type } | |
| + | |
| +func (t OverflowableType) OverflowInt(x int64) bool { | |
| + k := t.Kind() | |
| + switch k { | |
| + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
| + bitSize := t.Size() * 8 | |
| + trunc := (x << (64 - bitSize)) >> (64 - bitSize) | |
| + return x != trunc | |
| + } | |
| + panic("reflect: OverflowInt of non-int type " + t.String()) | |
| +} | |
| + | |
| +func (t OverflowableType) OverflowUint(x uint64) bool { | |
| + k := t.Kind() | |
| + switch k { | |
| + case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | |
| + bitSize := t.Size() * 8 | |
| + trunc := (x << (64 - bitSize)) >> (64 - bitSize) | |
| + return x != trunc | |
| + } | |
| + panic("reflect: OverflowUint of non-uint type " + t.String()) | |
| +} | |
| + | |
| +// Original src code from Go 1.23 go/src/reflect/type.go (taken 1/9/25) | |
| +/* | |
| + | |
| +func (t *rtype) OverflowInt(x int64) bool { | |
| + k := t.Kind() | |
| + switch k { | |
| + case Int, Int8, Int16, Int32, Int64: | |
| + bitSize := t.Size() * 8 | |
| + trunc := (x << (64 - bitSize)) >> (64 - bitSize) | |
| + return x != trunc | |
| + } | |
| + panic("reflect: OverflowInt of non-int type " + t.String()) | |
| +} | |
| + | |
| +func (t *rtype) OverflowUint(x uint64) bool { | |
| + k := t.Kind() | |
| + switch k { | |
| + case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64: | |
| + bitSize := t.Size() * 8 | |
| + trunc := (x << (64 - bitSize)) >> (64 - bitSize) | |
| + return x != trunc | |
| + } | |
| + panic("reflect: OverflowUint of non-uint type " + t.String()) | |
| +} | |
| + | |
| +*/ | |
| + | |
| +// TypeFor returns the [Type] that represents the type argument T. | |
| +func TypeFor[T any]() reflect.Type { | |
| + var v T | |
| + if t := reflect.TypeOf(v); t != nil { | |
| + return t // optimize for T being a non-interface kind | |
| + } | |
| + return reflect.TypeOf((*T)(nil)).Elem() // only for an interface kind | |
| +} | |
| + | |
| +// Original src code from Go 1.23 go/src/reflect/type.go (taken 1/9/25) | |
| +/* | |
| + | |
| +// TypeFor returns the [Type] that represents the type argument T. | |
| +func TypeFor[T any]() Type { | |
| + var v T | |
| + if t := TypeOf(v); t != nil { | |
| + return t // optimize for T being a non-interface kind | |
| + } | |
| + return TypeOf((*T)(nil)).Elem() // only for an interface kind | |
| +} | |
| + | |
| +*/ | |
| + | |
| +type AppendableStdEncoding struct{ *base64.Encoding } | |
| + | |
| +// AppendEncode appends the base64 encoded src to dst | |
| +// and returns the extended buffer. | |
| +func (enc AppendableStdEncoding) AppendEncode(dst, src []byte) []byte { | |
| + n := enc.EncodedLen(len(src)) | |
| + dst = slices.Grow(dst, n) | |
| + enc.Encode(dst[len(dst):][:n], src) | |
| + return dst[:len(dst)+n] | |
| +} | |
| + | |
| +// Original src code from Go 1.23.4 go/src/encoding/base64/base64.go (taken 1/9/25) | |
| +/* | |
| + | |
| +// AppendEncode appends the base64 encoded src to dst | |
| +// and returns the extended buffer. | |
| +func (enc *Encoding) AppendEncode(dst, src []byte) []byte { | |
| + n := enc.EncodedLen(len(src)) | |
| + dst = slices.Grow(dst, n) | |
| + enc.Encode(dst[len(dst):][:n], src) | |
| + return dst[:len(dst)+n] | |
| +} | |
| + | |
| +*/ | |
| diff --git a/internal/encoding/json/stream.go b/internal/encoding/json/stream.go | |
| new file mode 100644 | |
| index 0000000..e2d9470 | |
| --- /dev/null | |
| +++ b/internal/encoding/json/stream.go | |
| @@ -0,0 +1,512 @@ | |
| +// Copyright 2010 The Go Authors. All rights reserved. | |
| +// Use of this source code is governed by a BSD-style | |
| +// license that can be found in the LICENSE file. | |
| + | |
| +package json | |
| + | |
| +import ( | |
| + "bytes" | |
| + "errors" | |
| + "io" | |
| +) | |
| + | |
| +// A Decoder reads and decodes JSON values from an input stream. | |
| +type Decoder struct { | |
| + r io.Reader | |
| + buf []byte | |
| + d decodeState | |
| + scanp int // start of unread data in buf | |
| + scanned int64 // amount of data already scanned | |
| + scan scanner | |
| + err error | |
| + | |
| + tokenState int | |
| + tokenStack []int | |
| +} | |
| + | |
| +// NewDecoder returns a new decoder that reads from r. | |
| +// | |
| +// The decoder introduces its own buffering and may | |
| +// read data from r beyond the JSON values requested. | |
| +func NewDecoder(r io.Reader) *Decoder { | |
| + return &Decoder{r: r} | |
| +} | |
| + | |
| +// UseNumber causes the Decoder to unmarshal a number into an | |
| +// interface value as a [Number] instead of as a float64. | |
| +func (dec *Decoder) UseNumber() { dec.d.useNumber = true } | |
| + | |
| +// DisallowUnknownFields causes the Decoder to return an error when the destination | |
| +// is a struct and the input contains object keys which do not match any | |
| +// non-ignored, exported fields in the destination. | |
| +func (dec *Decoder) DisallowUnknownFields() { dec.d.disallowUnknownFields = true } | |
| + | |
| +// Decode reads the next JSON-encoded value from its | |
| +// input and stores it in the value pointed to by v. | |
| +// | |
| +// See the documentation for [Unmarshal] for details about | |
| +// the conversion of JSON into a Go value. | |
| +func (dec *Decoder) Decode(v any) error { | |
| + if dec.err != nil { | |
| + return dec.err | |
| + } | |
| + | |
| + if err := dec.tokenPrepareForDecode(); err != nil { | |
| + return err | |
| + } | |
| + | |
| + if !dec.tokenValueAllowed() { | |
| + return &SyntaxError{msg: "not at beginning of value", Offset: dec.InputOffset()} | |
| + } | |
| + | |
| + // Read whole value into buffer. | |
| + n, err := dec.readValue() | |
| + if err != nil { | |
| + return err | |
| + } | |
| + dec.d.init(dec.buf[dec.scanp : dec.scanp+n]) | |
| + dec.scanp += n | |
| + | |
| + // Don't save err from unmarshal into dec.err: | |
| + // the connection is still usable since we read a complete JSON | |
| + // object from it before the error happened. | |
| + err = dec.d.unmarshal(v) | |
| + | |
| + // fixup token streaming state | |
| + dec.tokenValueEnd() | |
| + | |
| + return err | |
| +} | |
| + | |
| +// Buffered returns a reader of the data remaining in the Decoder's | |
| +// buffer. The reader is valid until the next call to [Decoder.Decode]. | |
| +func (dec *Decoder) Buffered() io.Reader { | |
| + return bytes.NewReader(dec.buf[dec.scanp:]) | |
| +} | |
| + | |
| +// readValue reads a JSON value into dec.buf. | |
| +// It returns the length of the encoding. | |
| +func (dec *Decoder) readValue() (int, error) { | |
| + dec.scan.reset() | |
| + | |
| + scanp := dec.scanp | |
| + var err error | |
| +Input: | |
| + // help the compiler see that scanp is never negative, so it can remove | |
| + // some bounds checks below. | |
| + for scanp >= 0 { | |
| + | |
| + // Look in the buffer for a new value. | |
| + for ; scanp < len(dec.buf); scanp++ { | |
| + c := dec.buf[scanp] | |
| + dec.scan.bytes++ | |
| + switch dec.scan.step(&dec.scan, c) { | |
| + case scanEnd: | |
| + // scanEnd is delayed one byte so we decrement | |
| + // the scanner bytes count by 1 to ensure that | |
| + // this value is correct in the next call of Decode. | |
| + dec.scan.bytes-- | |
| + break Input | |
| + case scanEndObject, scanEndArray: | |
| + // scanEnd is delayed one byte. | |
| + // We might block trying to get that byte from src, | |
| + // so instead invent a space byte. | |
| + if stateEndValue(&dec.scan, ' ') == scanEnd { | |
| + scanp++ | |
| + break Input | |
| + } | |
| + case scanError: | |
| + dec.err = dec.scan.err | |
| + return 0, dec.scan.err | |
| + } | |
| + } | |
| + | |
| + // Did the last read have an error? | |
| + // Delayed until now to allow buffer scan. | |
| + if err != nil { | |
| + if err == io.EOF { | |
| + if dec.scan.step(&dec.scan, ' ') == scanEnd { | |
| + break Input | |
| + } | |
| + if nonSpace(dec.buf) { | |
| + err = io.ErrUnexpectedEOF | |
| + } | |
| + } | |
| + dec.err = err | |
| + return 0, err | |
| + } | |
| + | |
| + n := scanp - dec.scanp | |
| + err = dec.refill() | |
| + scanp = dec.scanp + n | |
| + } | |
| + return scanp - dec.scanp, nil | |
| +} | |
| + | |
| +func (dec *Decoder) refill() error { | |
| + // Make room to read more into the buffer. | |
| + // First slide down data already consumed. | |
| + if dec.scanp > 0 { | |
| + dec.scanned += int64(dec.scanp) | |
| + n := copy(dec.buf, dec.buf[dec.scanp:]) | |
| + dec.buf = dec.buf[:n] | |
| + dec.scanp = 0 | |
| + } | |
| + | |
| + // Grow buffer if not large enough. | |
| + const minRead = 512 | |
| + if cap(dec.buf)-len(dec.buf) < minRead { | |
| + newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead) | |
| + copy(newBuf, dec.buf) | |
| + dec.buf = newBuf | |
| + } | |
| + | |
| + // Read. Delay error for next iteration (after scan). | |
| + n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)]) | |
| + dec.buf = dec.buf[0 : len(dec.buf)+n] | |
| + | |
| + return err | |
| +} | |
| + | |
| +func nonSpace(b []byte) bool { | |
| + for _, c := range b { | |
| + if !isSpace(c) { | |
| + return true | |
| + } | |
| + } | |
| + return false | |
| +} | |
| + | |
| +// An Encoder writes JSON values to an output stream. | |
| +type Encoder struct { | |
| + w io.Writer | |
| + err error | |
| + escapeHTML bool | |
| + | |
| + indentBuf []byte | |
| + indentPrefix string | |
| + indentValue string | |
| +} | |
| + | |
| +// NewEncoder returns a new encoder that writes to w. | |
| +func NewEncoder(w io.Writer) *Encoder { | |
| + return &Encoder{w: w, escapeHTML: true} | |
| +} | |
| + | |
| +// Encode writes the JSON encoding of v to the stream, | |
| +// with insignificant space characters elided, | |
| +// followed by a newline character. | |
| +// | |
| +// See the documentation for [Marshal] for details about the | |
| +// conversion of Go values to JSON. | |
| +func (enc *Encoder) Encode(v any) error { | |
| + if enc.err != nil { | |
| + return enc.err | |
| + } | |
| + | |
| + e := newEncodeState() | |
| + defer encodeStatePool.Put(e) | |
| + | |
| + err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML}) | |
| + if err != nil { | |
| + return err | |
| + } | |
| + | |
| + // Terminate each value with a newline. | |
| + // This makes the output look a little nicer | |
| + // when debugging, and some kind of space | |
| + // is required if the encoded value was a number, | |
| + // so that the reader knows there aren't more | |
| + // digits coming. | |
| + e.WriteByte('\n') | |
| + | |
| + b := e.Bytes() | |
| + if enc.indentPrefix != "" || enc.indentValue != "" { | |
| + enc.indentBuf, err = appendIndent(enc.indentBuf[:0], b, enc.indentPrefix, enc.indentValue) | |
| + if err != nil { | |
| + return err | |
| + } | |
| + b = enc.indentBuf | |
| + } | |
| + if _, err = enc.w.Write(b); err != nil { | |
| + enc.err = err | |
| + } | |
| + return err | |
| +} | |
| + | |
| +// SetIndent instructs the encoder to format each subsequent encoded | |
| +// value as if indented by the package-level function Indent(dst, src, prefix, indent). | |
| +// Calling SetIndent("", "") disables indentation. | |
| +func (enc *Encoder) SetIndent(prefix, indent string) { | |
| + enc.indentPrefix = prefix | |
| + enc.indentValue = indent | |
| +} | |
| + | |
| +// SetEscapeHTML specifies whether problematic HTML characters | |
| +// should be escaped inside JSON quoted strings. | |
| +// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e | |
| +// to avoid certain safety problems that can arise when embedding JSON in HTML. | |
| +// | |
| +// In non-HTML settings where the escaping interferes with the readability | |
| +// of the output, SetEscapeHTML(false) disables this behavior. | |
| +func (enc *Encoder) SetEscapeHTML(on bool) { | |
| + enc.escapeHTML = on | |
| +} | |
| + | |
| +// RawMessage is a raw encoded JSON value. | |
| +// It implements [Marshaler] and [Unmarshaler] and can | |
| +// be used to delay JSON decoding or precompute a JSON encoding. | |
| +type RawMessage []byte | |
| + | |
| +// MarshalJSON returns m as the JSON encoding of m. | |
| +func (m RawMessage) MarshalJSON() ([]byte, error) { | |
| + if m == nil { | |
| + return []byte("null"), nil | |
| + } | |
| + return m, nil | |
| +} | |
| + | |
| +// UnmarshalJSON sets *m to a copy of data. | |
| +func (m *RawMessage) UnmarshalJSON(data []byte) error { | |
| + if m == nil { | |
| + return errors.New("json.RawMessage: UnmarshalJSON on nil pointer") | |
| + } | |
| + *m = append((*m)[0:0], data...) | |
| + return nil | |
| +} | |
| + | |
| +var _ Marshaler = (*RawMessage)(nil) | |
| +var _ Unmarshaler = (*RawMessage)(nil) | |
| + | |
| +// A Token holds a value of one of these types: | |
| +// | |
| +// - [Delim], for the four JSON delimiters [ ] { } | |
| +// - bool, for JSON booleans | |
| +// - float64, for JSON numbers | |
| +// - [Number], for JSON numbers | |
| +// - string, for JSON string literals | |
| +// - nil, for JSON null | |
| +type Token any | |
| + | |
| +const ( | |
| + tokenTopValue = iota | |
| + tokenArrayStart | |
| + tokenArrayValue | |
| + tokenArrayComma | |
| + tokenObjectStart | |
| + tokenObjectKey | |
| + tokenObjectColon | |
| + tokenObjectValue | |
| + tokenObjectComma | |
| +) | |
| + | |
| +// advance tokenstate from a separator state to a value state | |
| +func (dec *Decoder) tokenPrepareForDecode() error { | |
| + // Note: Not calling peek before switch, to avoid | |
| + // putting peek into the standard Decode path. | |
| + // peek is only called when using the Token API. | |
| + switch dec.tokenState { | |
| + case tokenArrayComma: | |
| + c, err := dec.peek() | |
| + if err != nil { | |
| + return err | |
| + } | |
| + if c != ',' { | |
| + return &SyntaxError{"expected comma after array element", dec.InputOffset()} | |
| + } | |
| + dec.scanp++ | |
| + dec.tokenState = tokenArrayValue | |
| + case tokenObjectColon: | |
| + c, err := dec.peek() | |
| + if err != nil { | |
| + return err | |
| + } | |
| + if c != ':' { | |
| + return &SyntaxError{"expected colon after object key", dec.InputOffset()} | |
| + } | |
| + dec.scanp++ | |
| + dec.tokenState = tokenObjectValue | |
| + } | |
| + return nil | |
| +} | |
| + | |
| +func (dec *Decoder) tokenValueAllowed() bool { | |
| + switch dec.tokenState { | |
| + case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue: | |
| + return true | |
| + } | |
| + return false | |
| +} | |
| + | |
| +func (dec *Decoder) tokenValueEnd() { | |
| + switch dec.tokenState { | |
| + case tokenArrayStart, tokenArrayValue: | |
| + dec.tokenState = tokenArrayComma | |
| + case tokenObjectValue: | |
| + dec.tokenState = tokenObjectComma | |
| + } | |
| +} | |
| + | |
| +// A Delim is a JSON array or object delimiter, one of [ ] { or }. | |
| +type Delim rune | |
| + | |
| +func (d Delim) String() string { | |
| + return string(d) | |
| +} | |
| + | |
| +// Token returns the next JSON token in the input stream. | |
| +// At the end of the input stream, Token returns nil, [io.EOF]. | |
| +// | |
| +// Token guarantees that the delimiters [ ] { } it returns are | |
| +// properly nested and matched: if Token encounters an unexpected | |
| +// delimiter in the input, it will return an error. | |
| +// | |
| +// The input stream consists of basic JSON values—bool, string, | |
| +// number, and null—along with delimiters [ ] { } of type [Delim] | |
| +// to mark the start and end of arrays and objects. | |
| +// Commas and colons are elided. | |
| +func (dec *Decoder) Token() (Token, error) { | |
| + for { | |
| + c, err := dec.peek() | |
| + if err != nil { | |
| + return nil, err | |
| + } | |
| + switch c { | |
| + case '[': | |
| + if !dec.tokenValueAllowed() { | |
| + return dec.tokenError(c) | |
| + } | |
| + dec.scanp++ | |
| + dec.tokenStack = append(dec.tokenStack, dec.tokenState) | |
| + dec.tokenState = tokenArrayStart | |
| + return Delim('['), nil | |
| + | |
| + case ']': | |
| + if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma { | |
| + return dec.tokenError(c) | |
| + } | |
| + dec.scanp++ | |
| + dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] | |
| + dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] | |
| + dec.tokenValueEnd() | |
| + return Delim(']'), nil | |
| + | |
| + case '{': | |
| + if !dec.tokenValueAllowed() { | |
| + return dec.tokenError(c) | |
| + } | |
| + dec.scanp++ | |
| + dec.tokenStack = append(dec.tokenStack, dec.tokenState) | |
| + dec.tokenState = tokenObjectStart | |
| + return Delim('{'), nil | |
| + | |
| + case '}': | |
| + if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma { | |
| + return dec.tokenError(c) | |
| + } | |
| + dec.scanp++ | |
| + dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] | |
| + dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] | |
| + dec.tokenValueEnd() | |
| + return Delim('}'), nil | |
| + | |
| + case ':': | |
| + if dec.tokenState != tokenObjectColon { | |
| + return dec.tokenError(c) | |
| + } | |
| + dec.scanp++ | |
| + dec.tokenState = tokenObjectValue | |
| + continue | |
| + | |
| + case ',': | |
| + if dec.tokenState == tokenArrayComma { | |
| + dec.scanp++ | |
| + dec.tokenState = tokenArrayValue | |
| + continue | |
| + } | |
| + if dec.tokenState == tokenObjectComma { | |
| + dec.scanp++ | |
| + dec.tokenState = tokenObjectKey | |
| + continue | |
| + } | |
| + return dec.tokenError(c) | |
| + | |
| + case '"': | |
| + if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey { | |
| + var x string | |
| + old := dec.tokenState | |
| + dec.tokenState = tokenTopValue | |
| + err := dec.Decode(&x) | |
| + dec.tokenState = old | |
| + if err != nil { | |
| + return nil, err | |
| + } | |
| + dec.tokenState = tokenObjectColon | |
| + return x, nil | |
| + } | |
| + fallthrough | |
| + | |
| + default: | |
| + if !dec.tokenValueAllowed() { | |
| + return dec.tokenError(c) | |
| + } | |
| + var x any | |
| + if err := dec.Decode(&x); err != nil { | |
| + return nil, err | |
| + } | |
| + return x, nil | |
| + } | |
| + } | |
| +} | |
| + | |
| +func (dec *Decoder) tokenError(c byte) (Token, error) { | |
| + var context string | |
| + switch dec.tokenState { | |
| + case tokenTopValue: | |
| + context = " looking for beginning of value" | |
| + case tokenArrayStart, tokenArrayValue, tokenObjectValue: | |
| + context = " looking for beginning of value" | |
| + case tokenArrayComma: | |
| + context = " after array element" | |
| + case tokenObjectKey: | |
| + context = " looking for beginning of object key string" | |
| + case tokenObjectColon: | |
| + context = " after object key" | |
| + case tokenObjectComma: | |
| + context = " after object key:value pair" | |
| + } | |
| + return nil, &SyntaxError{"invalid character " + quoteChar(c) + context, dec.InputOffset()} | |
| +} | |
| + | |
| +// More reports whether there is another element in the | |
| +// current array or object being parsed. | |
| +func (dec *Decoder) More() bool { | |
| + c, err := dec.peek() | |
| + return err == nil && c != ']' && c != '}' | |
| +} | |
| + | |
| +func (dec *Decoder) peek() (byte, error) { | |
| + var err error | |
| + for { | |
| + for i := dec.scanp; i < len(dec.buf); i++ { | |
| + c := dec.buf[i] | |
| + if isSpace(c) { | |
| + continue | |
| + } | |
| + dec.scanp = i | |
| + return c, nil | |
| + } | |
| + // buffer has been scanned, now report any error | |
| + if err != nil { | |
| + return 0, err | |
| + } | |
| + err = dec.refill() | |
| + } | |
| +} | |
| + | |
| +// InputOffset returns the input stream byte offset of the current decoder position. | |
| +// The offset gives the location of the end of the most recently returned token | |
| +// and the beginning of the next token. | |
| +func (dec *Decoder) InputOffset() int64 { | |
| + return dec.scanned + int64(dec.scanp) | |
| +} | |
| diff --git a/internal/encoding/json/tables.go b/internal/encoding/json/tables.go | |
| new file mode 100644 | |
| index 0000000..10acdc1 | |
| --- /dev/null | |
| +++ b/internal/encoding/json/tables.go | |
| @@ -0,0 +1,218 @@ | |
| +// Copyright 2016 The Go Authors. All rights reserved. | |
| +// Use of this source code is governed by a BSD-style | |
| +// license that can be found in the LICENSE file. | |
| + | |
| +package json | |
| + | |
| +import "unicode/utf8" | |
| + | |
| +// safeSet holds the value true if the ASCII character with the given array | |
| +// position can be represented inside a JSON string without any further | |
| +// escaping. | |
| +// | |
| +// All values are true except for the ASCII control characters (0-31), the | |
| +// double quote ("), and the backslash character ("\"). | |
| +var safeSet = [utf8.RuneSelf]bool{ | |
| + ' ': true, | |
| + '!': true, | |
| + '"': false, | |
| + '#': true, | |
| + '$': true, | |
| + '%': true, | |
| + '&': true, | |
| + '\'': true, | |
| + '(': true, | |
| + ')': true, | |
| + '*': true, | |
| + '+': true, | |
| + ',': true, | |
| + '-': true, | |
| + '.': true, | |
| + '/': true, | |
| + '0': true, | |
| + '1': true, | |
| + '2': true, | |
| + '3': true, | |
| + '4': true, | |
| + '5': true, | |
| + '6': true, | |
| + '7': true, | |
| + '8': true, | |
| + '9': true, | |
| + ':': true, | |
| + ';': true, | |
| + '<': true, | |
| + '=': true, | |
| + '>': true, | |
| + '?': true, | |
| + '@': true, | |
| + 'A': true, | |
| + 'B': true, | |
| + 'C': true, | |
| + 'D': true, | |
| + 'E': true, | |
| + 'F': true, | |
| + 'G': true, | |
| + 'H': true, | |
| + 'I': true, | |
| + 'J': true, | |
| + 'K': true, | |
| + 'L': true, | |
| + 'M': true, | |
| + 'N': true, | |
| + 'O': true, | |
| + 'P': true, | |
| + 'Q': true, | |
| + 'R': true, | |
| + 'S': true, | |
| + 'T': true, | |
| + 'U': true, | |
| + 'V': true, | |
| + 'W': true, | |
| + 'X': true, | |
| + 'Y': true, | |
| + 'Z': true, | |
| + '[': true, | |
| + '\\': false, | |
| + ']': true, | |
| + '^': true, | |
| + '_': true, | |
| + '`': true, | |
| + 'a': true, | |
| + 'b': true, | |
| + 'c': true, | |
| + 'd': true, | |
| + 'e': true, | |
| + 'f': true, | |
| + 'g': true, | |
| + 'h': true, | |
| + 'i': true, | |
| + 'j': true, | |
| + 'k': true, | |
| + 'l': true, | |
| + 'm': true, | |
| + 'n': true, | |
| + 'o': true, | |
| + 'p': true, | |
| + 'q': true, | |
| + 'r': true, | |
| + 's': true, | |
| + 't': true, | |
| + 'u': true, | |
| + 'v': true, | |
| + 'w': true, | |
| + 'x': true, | |
| + 'y': true, | |
| + 'z': true, | |
| + '{': true, | |
| + '|': true, | |
| + '}': true, | |
| + '~': true, | |
| + '\u007f': true, | |
| +} | |
| + | |
| +// htmlSafeSet holds the value true if the ASCII character with the given | |
| +// array position can be safely represented inside a JSON string, embedded | |
| +// inside of HTML <script> tags, without any additional escaping. | |
| +// | |
| +// All values are true except for the ASCII control characters (0-31), the | |
| +// double quote ("), the backslash character ("\"), HTML opening and closing | |
| +// tags ("<" and ">"), and the ampersand ("&"). | |
| +var htmlSafeSet = [utf8.RuneSelf]bool{ | |
| + ' ': true, | |
| + '!': true, | |
| + '"': false, | |
| + '#': true, | |
| + '$': true, | |
| + '%': true, | |
| + '&': false, | |
| + '\'': true, | |
| + '(': true, | |
| + ')': true, | |
| + '*': true, | |
| + '+': true, | |
| + ',': true, | |
| + '-': true, | |
| + '.': true, | |
| + '/': true, | |
| + '0': true, | |
| + '1': true, | |
| + '2': true, | |
| + '3': true, | |
| + '4': true, | |
| + '5': true, | |
| + '6': true, | |
| + '7': true, | |
| + '8': true, | |
| + '9': true, | |
| + ':': true, | |
| + ';': true, | |
| + '<': false, | |
| + '=': true, | |
| + '>': false, | |
| + '?': true, | |
| + '@': true, | |
| + 'A': true, | |
| + 'B': true, | |
| + 'C': true, | |
| + 'D': true, | |
| + 'E': true, | |
| + 'F': true, | |
| + 'G': true, | |
| + 'H': true, | |
| + 'I': true, | |
| + 'J': true, | |
| + 'K': true, | |
| + 'L': true, | |
| + 'M': true, | |
| + 'N': true, | |
| + 'O': true, | |
| + 'P': true, | |
| + 'Q': true, | |
| + 'R': true, | |
| + 'S': true, | |
| + 'T': true, | |
| + 'U': true, | |
| + 'V': true, | |
| + 'W': true, | |
| + 'X': true, | |
| + 'Y': true, | |
| + 'Z': true, | |
| + '[': true, | |
| + '\\': false, | |
| + ']': true, | |
| + '^': true, | |
| + '_': true, | |
| + '`': true, | |
| + 'a': true, | |
| + 'b': true, | |
| + 'c': true, | |
| + 'd': true, | |
| + 'e': true, | |
| + 'f': true, | |
| + 'g': true, | |
| + 'h': true, | |
| + 'i': true, | |
| + 'j': true, | |
| + 'k': true, | |
| + 'l': true, | |
| + 'm': true, | |
| + 'n': true, | |
| + 'o': true, | |
| + 'p': true, | |
| + 'q': true, | |
| + 'r': true, | |
| + 's': true, | |
| + 't': true, | |
| + 'u': true, | |
| + 'v': true, | |
| + 'w': true, | |
| + 'x': true, | |
| + 'y': true, | |
| + 'z': true, | |
| + '{': true, | |
| + '|': true, | |
| + '}': true, | |
| + '~': true, | |
| + '\u007f': true, | |
| +} | |
| diff --git a/internal/encoding/json/tags.go b/internal/encoding/json/tags.go | |
| new file mode 100644 | |
| index 0000000..b490328 | |
| --- /dev/null | |
| +++ b/internal/encoding/json/tags.go | |
| @@ -0,0 +1,38 @@ | |
| +// Copyright 2011 The Go Authors. All rights reserved. | |
| +// Use of this source code is governed by a BSD-style | |
| +// license that can be found in the LICENSE file. | |
| + | |
| +package json | |
| + | |
| +import ( | |
| + "strings" | |
| +) | |
| + | |
| +// tagOptions is the string following a comma in a struct field's "json" | |
| +// tag, or the empty string. It does not include the leading comma. | |
| +type tagOptions string | |
| + | |
| +// parseTag splits a struct field's json tag into its name and | |
| +// comma-separated options. | |
| +func parseTag(tag string) (string, tagOptions) { | |
| + tag, opt, _ := strings.Cut(tag, ",") | |
| + return tag, tagOptions(opt) | |
| +} | |
| + | |
| +// Contains reports whether a comma-separated list of options | |
| +// contains a particular substr flag. substr must be surrounded by a | |
| +// string boundary or commas. | |
| +func (o tagOptions) Contains(optionName string) bool { | |
| + if len(o) == 0 { | |
| + return false | |
| + } | |
| + s := string(o) | |
| + for s != "" { | |
| + var name string | |
| + name, s, _ = strings.Cut(s, ",") | |
| + if name == optionName { | |
| + return true | |
| + } | |
| + } | |
| + return false | |
| +} | |
| diff --git a/internal/encoding/json/time.go b/internal/encoding/json/time.go | |
| new file mode 100644 | |
| index 0000000..46e1a41 | |
| --- /dev/null | |
| +++ b/internal/encoding/json/time.go | |
| @@ -0,0 +1,59 @@ | |
| +// EDIT(begin): custom time marshaler | |
| +package json | |
| + | |
| +import ( | |
| + "github.com/anthropics/anthropic-sdk-go/internal/encoding/json/shims" | |
| + "reflect" | |
| + "time" | |
| +) | |
| + | |
| +type TimeMarshaler interface { | |
| + MarshalJSONWithTimeLayout(string) []byte | |
| +} | |
| + | |
| +var timeType = shims.TypeFor[time.Time]() | |
| + | |
| +const DateFmt = "2006-01-02" | |
| + | |
| +func newTimeEncoder() encoderFunc { | |
| + return func(e *encodeState, v reflect.Value, opts encOpts) { | |
| + t := v.Interface().(time.Time) | |
| + fmtted := t.Format(opts.timefmt) | |
| + if opts.timefmt == "date" { | |
| + fmtted = t.Format(DateFmt) | |
| + } | |
| + // Default to RFC3339 if format is invalid | |
| + if fmtted == "" { | |
| + fmtted = t.Format(time.RFC3339) | |
| + } | |
| + stringEncoder(e, reflect.ValueOf(fmtted), opts) | |
| + } | |
| +} | |
| + | |
| +// Uses continuation passing style, to add the timefmt option to k | |
| +func continueWithTimeFmt(timefmt string, k encoderFunc) encoderFunc { | |
| + return func(e *encodeState, v reflect.Value, opts encOpts) { | |
| + opts.timefmt = timefmt | |
| + k(e, v, opts) | |
| + } | |
| +} | |
| + | |
| +func timeMarshalEncoder(e *encodeState, v reflect.Value, opts encOpts) bool { | |
| + tm, ok := v.Interface().(TimeMarshaler) | |
| + if !ok { | |
| + return false | |
| + } | |
| + | |
| + b := tm.MarshalJSONWithTimeLayout(opts.timefmt) | |
| + if b != nil { | |
| + e.Grow(len(b)) | |
| + out := e.AvailableBuffer() | |
| + out, _ = appendCompact(out, b, opts.escapeHTML) | |
| + e.Buffer.Write(out) | |
| + return true | |
| + } | |
| + | |
| + return false | |
| +} | |
| + | |
| +// EDIT(end) | |
| diff --git a/internal/param/field.go b/internal/param/field.go | |
| index 4d0fd9c..a665f70 100644 | |
| --- a/internal/param/field.go | |
| +++ b/internal/param/field.go | |
| @@ -1,8 +1,6 @@ | |
| package param | |
| -import ( | |
| - "fmt" | |
| -) | |
| +import "fmt" | |
| type FieldLike interface{ field() } | |
| diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go | |
| index bba68f7..1560ad0 100644 | |
| --- a/internal/requestconfig/requestconfig.go | |
| +++ b/internal/requestconfig/requestconfig.go | |
| @@ -10,6 +10,7 @@ import ( | |
| "io" | |
| "math" | |
| "math/rand" | |
| + "mime" | |
| "net/http" | |
| "net/url" | |
| "runtime" | |
| @@ -76,7 +77,17 @@ func getPlatformProperties() map[string]string { | |
| } | |
| } | |
| -func NewRequestConfig(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...func(*RequestConfig) error) (*RequestConfig, error) { | |
| +type RequestOption interface { | |
| + Apply(*RequestConfig) error | |
| +} | |
| + | |
| +type RequestOptionFunc func(*RequestConfig) error | |
| +type PreRequestOptionFunc func(*RequestConfig) error | |
| + | |
| +func (s RequestOptionFunc) Apply(r *RequestConfig) error { return s(r) } | |
| +func (s PreRequestOptionFunc) Apply(r *RequestConfig) error { return s(r) } | |
| + | |
| +func NewRequestConfig(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...RequestOption) (*RequestConfig, error) { | |
| var reader io.Reader | |
| contentType := "application/json" | |
| @@ -176,7 +187,7 @@ func NewRequestConfig(ctx context.Context, method string, u string, body interfa | |
| // RequestConfig represents all the state related to one request. | |
| // | |
| // Editing the variables inside RequestConfig directly is unstable api. Prefer | |
| -// composing func(\*RequestConfig) error instead if possible. | |
| +// composing the RequestOption instead if possible. | |
| type RequestConfig struct { | |
| MaxRetries int | |
| RequestTimeout time.Duration | |
| @@ -223,7 +234,7 @@ func shouldRetry(req *http.Request, res *http.Response) bool { | |
| return true | |
| } | |
| - // If the header explictly wants a retry behavior, respect that over the | |
| + // If the header explicitly wants a retry behavior, respect that over the | |
| // http status code. | |
| if res.Header.Get("x-should-retry") == "true" { | |
| return true | |
| @@ -388,7 +399,6 @@ func (cfg *RequestConfig) Execute() (err error) { | |
| // Don't send the current retry count in the headers if the caller modified the header defaults. | |
| shouldSendRetryCount := cfg.Request.Header.Get("X-Stainless-Retry-Count") == "0" | |
| - var req *http.Request | |
| var res *http.Response | |
| var cancel context.CancelFunc | |
| for retryCount := 0; retryCount <= cfg.MaxRetries; retryCount += 1 { | |
| @@ -403,7 +413,7 @@ func (cfg *RequestConfig) Execute() (err error) { | |
| }() | |
| } | |
| - req = cfg.Request.Clone(ctx) | |
| + req := cfg.Request.Clone(ctx) | |
| if shouldSendRetryCount { | |
| req.Header.Set("X-Stainless-Retry-Count", strconv.Itoa(retryCount)) | |
| } | |
| @@ -460,7 +470,7 @@ func (cfg *RequestConfig) Execute() (err error) { | |
| res.Body = io.NopCloser(bytes.NewBuffer(contents)) | |
| // Load the contents into the error format if it is provided. | |
| - aerr := apierror.Error{Request: req, Response: res, StatusCode: res.StatusCode} | |
| + aerr := apierror.Error{Request: cfg.Request, Response: res, StatusCode: res.StatusCode} | |
| err = aerr.UnmarshalJSON(contents) | |
| if err != nil { | |
| return err | |
| @@ -487,7 +497,8 @@ func (cfg *RequestConfig) Execute() (err error) { | |
| // If we are not json, return plaintext | |
| contentType := res.Header.Get("content-type") | |
| - isJSON := strings.Contains(contentType, "application/json") || strings.Contains(contentType, "application/vnd.api+json") | |
| + mediaType, _, _ := mime.ParseMediaType(contentType) | |
| + isJSON := strings.Contains(mediaType, "application/json") || strings.HasSuffix(mediaType, "+json") | |
| if !isJSON { | |
| switch dst := cfg.ResponseBodyInto.(type) { | |
| case *string: | |
| @@ -498,7 +509,7 @@ func (cfg *RequestConfig) Execute() (err error) { | |
| case *[]byte: | |
| *dst = contents | |
| default: | |
| - return fmt.Errorf("expected destination type of 'string' or '[]byte' for responses with content-type that is not 'application/json'") | |
| + return fmt.Errorf("expected destination type of 'string' or '[]byte' for responses with content-type '%s' that is not 'application/json'", contentType) | |
| } | |
| return nil | |
| } | |
| @@ -511,13 +522,13 @@ func (cfg *RequestConfig) Execute() (err error) { | |
| err = json.NewDecoder(bytes.NewReader(contents)).Decode(cfg.ResponseBodyInto) | |
| if err != nil { | |
| - err = fmt.Errorf("error parsing response json: %w", err) | |
| + return fmt.Errorf("error parsing response json: %w", err) | |
| } | |
| return nil | |
| } | |
| -func ExecuteNewRequest(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...func(*RequestConfig) error) error { | |
| +func ExecuteNewRequest(ctx context.Context, method string, u string, body interface{}, dst interface{}, opts ...RequestOption) error { | |
| cfg, err := NewRequestConfig(ctx, method, u, body, dst, opts...) | |
| if err != nil { | |
| return err | |
| @@ -552,12 +563,27 @@ func (cfg *RequestConfig) Clone(ctx context.Context) *RequestConfig { | |
| return new | |
| } | |
| -func (cfg *RequestConfig) Apply(opts ...func(*RequestConfig) error) error { | |
| +func (cfg *RequestConfig) Apply(opts ...RequestOption) error { | |
| for _, opt := range opts { | |
| - err := opt(cfg) | |
| + err := opt.Apply(cfg) | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| + | |
| +func PreRequestOptions(opts ...RequestOption) (RequestConfig, error) { | |
| + cfg := RequestConfig{} | |
| + for _, opt := range opts { | |
| + if _, ok := opt.(PreRequestOptionFunc); !ok { | |
| + continue | |
| + } | |
| + | |
| + err := opt.Apply(&cfg) | |
| + if err != nil { | |
| + return cfg, err | |
| + } | |
| + } | |
| + return cfg, nil | |
| +} | |
| diff --git a/internal/version.go b/internal/version.go | |
| index 1e49ee4..7fd82e7 100644 | |
| --- a/internal/version.go | |
| +++ b/internal/version.go | |
| @@ -2,4 +2,4 @@ | |
| package internal | |
| -const PackageVersion = "0.0.1-alpha.0" | |
| +const PackageVersion = "0.2.0-beta.3" // x-release-please-version | |
| diff --git a/message.go b/message.go | |
| index 7ec0d60..ec639a9 100644 | |
| --- a/message.go | |
| +++ b/message.go | |
| @@ -8,13 +8,14 @@ import ( | |
| "fmt" | |
| "net/http" | |
| "reflect" | |
| - "time" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apijson" | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| "github.com/anthropics/anthropic-sdk-go/internal/requestconfig" | |
| "github.com/anthropics/anthropic-sdk-go/option" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| "github.com/anthropics/anthropic-sdk-go/packages/ssestream" | |
| + "github.com/anthropics/anthropic-sdk-go/shared/constant" | |
| "github.com/tidwall/gjson" | |
| ) | |
| @@ -26,14 +27,14 @@ import ( | |
| // the [NewMessageService] method instead. | |
| type MessageService struct { | |
| Options []option.RequestOption | |
| - Batches *MessageBatchService | |
| + Batches MessageBatchService | |
| } | |
| // NewMessageService 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 NewMessageService(opts ...option.RequestOption) (r *MessageService) { | |
| - r = &MessageService{} | |
| +func NewMessageService(opts ...option.RequestOption) (r MessageService) { | |
| + r = MessageService{} | |
| r.Options = opts | |
| r.Batches = NewMessageBatchService(opts...) | |
| return | |
| @@ -51,38 +52,10 @@ func NewMessageService(opts ...option.RequestOption) (r *MessageService) { | |
| func (r *MessageService) New(ctx context.Context, body MessageNewParams, opts ...option.RequestOption) (res *Message, err error) { | |
| opts = append(r.Options[:], opts...) | |
| path := "v1/messages" | |
| - | |
| - cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodPost, path, body, &res, opts...) | |
| - if err != nil { | |
| - return | |
| - } | |
| - | |
| - err = checkLongRequest(ctx, cfg, int(body.MaxTokens.Value)) | |
| - if err != nil { | |
| - return | |
| - } | |
| - | |
| - err = cfg.Execute() | |
| + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) | |
| return | |
| } | |
| -// Return an error early if the request is expected to take enough time that its likely to be dropped and the | |
| -// user hasn't explicitly configured their own timeout. | |
| -func checkLongRequest(ctx context.Context, cfg *requestconfig.RequestConfig, maxTokens int) error { | |
| - _, hasDeadline := ctx.Deadline() | |
| - if !hasDeadline && cfg.RequestTimeout == time.Duration(0) && maxTokens != 0 { | |
| - maximumTime := 60 * 60 | |
| - defaultTime := 60 * 10 | |
| - expectedTime := maximumTime * int(maxTokens) / 128_000 | |
| - if expectedTime > defaultTime { | |
| - return fmt.Errorf("Streaming is strongly recommended for operations that may take longer than 10 minutes. See https://github.com/anthropics/anthropic-sdk-go#long-requests") | |
| - } | |
| - } | |
| - | |
| - return nil | |
| - | |
| -} | |
| - | |
| // Send a structured list of input messages with text and/or image content, and the | |
| // model will generate the next message in the conversation. | |
| // | |
| @@ -92,7 +65,7 @@ func checkLongRequest(ctx context.Context, cfg *requestconfig.RequestConfig, max | |
| // Learn more about the Messages API in our [user guide](/en/docs/initial-setup) | |
| // | |
| // Note: If you choose to set a timeout for this request, we recommend 10 minutes. | |
| -func (r *MessageService) NewStreaming(ctx context.Context, body MessageNewParams, opts ...option.RequestOption) (stream *ssestream.Stream[MessageStreamEvent]) { | |
| +func (r *MessageService) NewStreaming(ctx context.Context, body MessageNewParams, opts ...option.RequestOption) (stream *ssestream.Stream[MessageStreamEventUnion]) { | |
| var ( | |
| raw *http.Response | |
| err error | |
| @@ -101,7 +74,7 @@ func (r *MessageService) NewStreaming(ctx context.Context, body MessageNewParams | |
| opts = append([]option.RequestOption{option.WithJSONSet("stream", true)}, opts...) | |
| path := "v1/messages" | |
| err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &raw, opts...) | |
| - return ssestream.NewStream[MessageStreamEvent](ssestream.NewDecoder(raw), err) | |
| + return ssestream.NewStream[MessageStreamEventUnion](ssestream.NewDecoder(raw), err) | |
| } | |
| // Count the number of tokens in a Message. | |
| @@ -118,18 +91,24 @@ func (r *MessageService) CountTokens(ctx context.Context, body MessageCountToken | |
| return | |
| } | |
| +// The properties Data, MediaType, Type are required. | |
| type Base64ImageSourceParam struct { | |
| - Data param.Field[string] `json:"data,required" format:"byte"` | |
| - MediaType param.Field[Base64ImageSourceMediaType] `json:"media_type,required"` | |
| - Type param.Field[Base64ImageSourceType] `json:"type,required"` | |
| + Data string `json:"data,required" format:"byte"` | |
| + // Any of "image/jpeg", "image/png", "image/gif", "image/webp". | |
| + MediaType Base64ImageSourceMediaType `json:"media_type,omitzero,required"` | |
| + // This field can be elided, and will marshal its zero value as "base64". | |
| + Type constant.Base64 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f Base64ImageSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r Base64ImageSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow Base64ImageSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r Base64ImageSourceParam) implementsImageBlockParamSourceUnion() {} | |
| - | |
| type Base64ImageSourceMediaType string | |
| const ( | |
| @@ -139,955 +118,1128 @@ const ( | |
| Base64ImageSourceMediaTypeImageWebP Base64ImageSourceMediaType = "image/webp" | |
| ) | |
| -func (r Base64ImageSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case Base64ImageSourceMediaTypeImageJPEG, Base64ImageSourceMediaTypeImagePNG, Base64ImageSourceMediaTypeImageGIF, Base64ImageSourceMediaTypeImageWebP: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type Base64ImageSourceType string | |
| - | |
| -const ( | |
| - Base64ImageSourceTypeBase64 Base64ImageSourceType = "base64" | |
| -) | |
| - | |
| -func (r Base64ImageSourceType) IsKnown() bool { | |
| - switch r { | |
| - case Base64ImageSourceTypeBase64: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| +// The properties Data, MediaType, Type are required. | |
| type Base64PDFSourceParam struct { | |
| - Data param.Field[string] `json:"data,required" format:"byte"` | |
| - MediaType param.Field[Base64PDFSourceMediaType] `json:"media_type,required"` | |
| - Type param.Field[Base64PDFSourceType] `json:"type,required"` | |
| + Data string `json:"data,required" format:"byte"` | |
| + // This field can be elided, and will marshal its zero value as "application/pdf". | |
| + MediaType constant.ApplicationPDF `json:"media_type,required"` | |
| + // This field can be elided, and will marshal its zero value as "base64". | |
| + Type constant.Base64 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f Base64PDFSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r Base64PDFSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow Base64PDFSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r Base64PDFSourceParam) implementsDocumentBlockParamSourceUnion() {} | |
| - | |
| -type Base64PDFSourceMediaType string | |
| - | |
| -const ( | |
| - Base64PDFSourceMediaTypeApplicationPDF Base64PDFSourceMediaType = "application/pdf" | |
| -) | |
| - | |
| -func (r Base64PDFSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case Base64PDFSourceMediaTypeApplicationPDF: | |
| - return true | |
| - } | |
| - return false | |
| +// The property Type is required. | |
| +type CacheControlEphemeralParam struct { | |
| + // This field can be elided, and will marshal its zero value as "ephemeral". | |
| + Type constant.Ephemeral `json:"type,required"` | |
| + paramObj | |
| } | |
| -type Base64PDFSourceType string | |
| - | |
| -const ( | |
| - Base64PDFSourceTypeBase64 Base64PDFSourceType = "base64" | |
| -) | |
| - | |
| -func (r Base64PDFSourceType) IsKnown() bool { | |
| - switch r { | |
| - case Base64PDFSourceTypeBase64: | |
| - return true | |
| - } | |
| - return false | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f CacheControlEphemeralParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r CacheControlEphemeralParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow CacheControlEphemeralParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -type CacheControlEphemeralParam struct { | |
| - Type param.Field[CacheControlEphemeralType] `json:"type,required"` | |
| +type CitationCharLocation struct { | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + DocumentTitle string `json:"document_title,required"` | |
| + EndCharIndex int64 `json:"end_char_index,required"` | |
| + StartCharIndex int64 `json:"start_char_index,required"` | |
| + Type constant.CharLocation `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndCharIndex resp.Field | |
| + StartCharIndex resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r CitationCharLocation) RawJSON() string { return r.JSON.raw } | |
| +func (r *CitationCharLocation) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r CacheControlEphemeralParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// The properties CitedText, DocumentIndex, DocumentTitle, EndCharIndex, | |
| +// StartCharIndex, Type are required. | |
| +type CitationCharLocationParam struct { | |
| + DocumentTitle param.Opt[string] `json:"document_title,omitzero,required"` | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + EndCharIndex int64 `json:"end_char_index,required"` | |
| + StartCharIndex int64 `json:"start_char_index,required"` | |
| + // This field can be elided, and will marshal its zero value as "char_location". | |
| + Type constant.CharLocation `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f CitationCharLocationParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r CitationCharLocationParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow CitationCharLocationParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -type CacheControlEphemeralType string | |
| - | |
| -const ( | |
| - CacheControlEphemeralTypeEphemeral CacheControlEphemeralType = "ephemeral" | |
| -) | |
| +type CitationContentBlockLocation struct { | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + DocumentTitle string `json:"document_title,required"` | |
| + EndBlockIndex int64 `json:"end_block_index,required"` | |
| + StartBlockIndex int64 `json:"start_block_index,required"` | |
| + Type constant.ContentBlockLocation `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndBlockIndex resp.Field | |
| + StartBlockIndex resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r CitationContentBlockLocation) RawJSON() string { return r.JSON.raw } | |
| +func (r *CitationContentBlockLocation) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r CacheControlEphemeralType) IsKnown() bool { | |
| - switch r { | |
| - case CacheControlEphemeralTypeEphemeral: | |
| - return true | |
| - } | |
| - return false | |
| +// The properties CitedText, DocumentIndex, DocumentTitle, EndBlockIndex, | |
| +// StartBlockIndex, Type are required. | |
| +type CitationContentBlockLocationParam struct { | |
| + DocumentTitle param.Opt[string] `json:"document_title,omitzero,required"` | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + EndBlockIndex int64 `json:"end_block_index,required"` | |
| + StartBlockIndex int64 `json:"start_block_index,required"` | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "content_block_location". | |
| + Type constant.ContentBlockLocation `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f CitationContentBlockLocationParam) IsPresent() bool { | |
| + return !param.IsOmitted(f) && !f.IsNull() | |
| +} | |
| +func (r CitationContentBlockLocationParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow CitationContentBlockLocationParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -type CitationCharLocation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - EndCharIndex int64 `json:"end_char_index,required"` | |
| - StartCharIndex int64 `json:"start_char_index,required"` | |
| - Type CitationCharLocationType `json:"type,required"` | |
| - JSON citationCharLocationJSON `json:"-"` | |
| -} | |
| - | |
| -// citationCharLocationJSON contains the JSON metadata for the struct | |
| -// [CitationCharLocation] | |
| -type citationCharLocationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - EndCharIndex apijson.Field | |
| - StartCharIndex apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *CitationCharLocation) UnmarshalJSON(data []byte) (err error) { | |
| +type CitationPageLocation struct { | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + DocumentTitle string `json:"document_title,required"` | |
| + EndPageNumber int64 `json:"end_page_number,required"` | |
| + StartPageNumber int64 `json:"start_page_number,required"` | |
| + Type constant.PageLocation `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndPageNumber resp.Field | |
| + StartPageNumber resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r CitationPageLocation) RawJSON() string { return r.JSON.raw } | |
| +func (r *CitationPageLocation) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r citationCharLocationJSON) RawJSON() string { | |
| - return r.raw | |
| +// The properties CitedText, DocumentIndex, DocumentTitle, EndPageNumber, | |
| +// StartPageNumber, Type are required. | |
| +type CitationPageLocationParam struct { | |
| + DocumentTitle param.Opt[string] `json:"document_title,omitzero,required"` | |
| + CitedText string `json:"cited_text,required"` | |
| + DocumentIndex int64 `json:"document_index,required"` | |
| + EndPageNumber int64 `json:"end_page_number,required"` | |
| + StartPageNumber int64 `json:"start_page_number,required"` | |
| + // This field can be elided, and will marshal its zero value as "page_location". | |
| + Type constant.PageLocation `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f CitationPageLocationParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r CitationPageLocationParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow CitationPageLocationParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r CitationCharLocation) implementsCitationsDeltaCitation() {} | |
| - | |
| -func (r CitationCharLocation) implementsTextCitation() {} | |
| +type CitationsConfigParam struct { | |
| + Enabled param.Opt[bool] `json:"enabled,omitzero"` | |
| + paramObj | |
| +} | |
| -type CitationCharLocationType string | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f CitationsConfigParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r CitationsConfigParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow CitationsConfigParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| +} | |
| -const ( | |
| - CitationCharLocationTypeCharLocation CitationCharLocationType = "char_location" | |
| -) | |
| +type CitationsDelta struct { | |
| + Citation CitationsDeltaCitationUnion `json:"citation,required"` | |
| + Type constant.CitationsDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Citation resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r CitationsDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *CitationsDelta) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r CitationCharLocationType) IsKnown() bool { | |
| - switch r { | |
| - case CitationCharLocationTypeCharLocation: | |
| - return true | |
| +// CitationsDeltaCitationUnion contains all possible properties and values from | |
| +// [CitationCharLocation], [CitationPageLocation], [CitationContentBlockLocation]. | |
| +// | |
| +// Use the [CitationsDeltaCitationUnion.AsAny] method to switch on the variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type CitationsDeltaCitationUnion struct { | |
| + CitedText string `json:"cited_text"` | |
| + DocumentIndex int64 `json:"document_index"` | |
| + DocumentTitle string `json:"document_title"` | |
| + // This field is from variant [CitationCharLocation]. | |
| + EndCharIndex int64 `json:"end_char_index"` | |
| + // This field is from variant [CitationCharLocation]. | |
| + StartCharIndex int64 `json:"start_char_index"` | |
| + // Any of "char_location", "page_location", "content_block_location". | |
| + Type string `json:"type"` | |
| + // This field is from variant [CitationPageLocation]. | |
| + EndPageNumber int64 `json:"end_page_number"` | |
| + // This field is from variant [CitationPageLocation]. | |
| + StartPageNumber int64 `json:"start_page_number"` | |
| + // This field is from variant [CitationContentBlockLocation]. | |
| + EndBlockIndex int64 `json:"end_block_index"` | |
| + // This field is from variant [CitationContentBlockLocation]. | |
| + StartBlockIndex int64 `json:"start_block_index"` | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndCharIndex resp.Field | |
| + StartCharIndex resp.Field | |
| + Type resp.Field | |
| + EndPageNumber resp.Field | |
| + StartPageNumber resp.Field | |
| + EndBlockIndex resp.Field | |
| + StartBlockIndex resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := CitationsDeltaCitationUnion.AsAny().(type) { | |
| +// case CitationCharLocation: | |
| +// case CitationPageLocation: | |
| +// case CitationContentBlockLocation: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u CitationsDeltaCitationUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "char_location": | |
| + return u.AsResponseCharLocationCitation() | |
| + case "page_location": | |
| + return u.AsResponsePageLocationCitation() | |
| + case "content_block_location": | |
| + return u.AsResponseContentBlockLocationCitation() | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type CitationCharLocationParam struct { | |
| - CitedText param.Field[string] `json:"cited_text,required"` | |
| - DocumentIndex param.Field[int64] `json:"document_index,required"` | |
| - DocumentTitle param.Field[string] `json:"document_title,required"` | |
| - EndCharIndex param.Field[int64] `json:"end_char_index,required"` | |
| - StartCharIndex param.Field[int64] `json:"start_char_index,required"` | |
| - Type param.Field[CitationCharLocationParamType] `json:"type,required"` | |
| +func (u CitationsDeltaCitationUnion) AsResponseCharLocationCitation() (v CitationCharLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r CitationCharLocationParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +func (u CitationsDeltaCitationUnion) AsResponsePageLocationCitation() (v CitationPageLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r CitationCharLocationParam) implementsTextCitationParamUnion() {} | |
| +func (u CitationsDeltaCitationUnion) AsResponseContentBlockLocationCitation() (v CitationContentBlockLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| +} | |
| -type CitationCharLocationParamType string | |
| +// Returns the unmodified JSON received from the API | |
| +func (u CitationsDeltaCitationUnion) RawJSON() string { return u.JSON.raw } | |
| -const ( | |
| - CitationCharLocationParamTypeCharLocation CitationCharLocationParamType = "char_location" | |
| -) | |
| +func (r *CitationsDeltaCitationUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r CitationCharLocationParamType) IsKnown() bool { | |
| - switch r { | |
| - case CitationCharLocationParamTypeCharLocation: | |
| - return true | |
| +// ContentBlockUnion contains all possible properties and values from [TextBlock], | |
| +// [ToolUseBlock], [ThinkingBlock], [RedactedThinkingBlock]. | |
| +// | |
| +// Use the [ContentBlockUnion.AsAny] method to switch on the variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type ContentBlockUnion struct { | |
| + // This field is from variant [TextBlock]. | |
| + Citations []TextCitationUnion `json:"citations"` | |
| + // This field is from variant [TextBlock]. | |
| + Text string `json:"text"` | |
| + // Any of "text", "tool_use", "thinking", "redacted_thinking". | |
| + Type string `json:"type"` | |
| + // This field is from variant [ToolUseBlock]. | |
| + ID string `json:"id"` | |
| + // This field is from variant [ToolUseBlock]. | |
| + Input json.RawMessage `json:"input"` | |
| + // This field is from variant [ToolUseBlock]. | |
| + Name string `json:"name"` | |
| + // This field is from variant [ThinkingBlock]. | |
| + Signature string `json:"signature"` | |
| + // This field is from variant [ThinkingBlock]. | |
| + Thinking string `json:"thinking"` | |
| + // This field is from variant [RedactedThinkingBlock]. | |
| + Data string `json:"data"` | |
| + JSON struct { | |
| + Citations resp.Field | |
| + Text resp.Field | |
| + Type resp.Field | |
| + ID resp.Field | |
| + Input resp.Field | |
| + Name resp.Field | |
| + Signature resp.Field | |
| + Thinking resp.Field | |
| + Data resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +func (r ContentBlockUnion) ToParam() ContentBlockParamUnion { | |
| + switch variant := r.AsAny().(type) { | |
| + case TextBlock: | |
| + p := variant.ToParam() | |
| + return ContentBlockParamUnion{OfRequestTextBlock: &p} | |
| + case ToolUseBlock: | |
| + p := variant.ToParam() | |
| + return ContentBlockParamUnion{OfRequestToolUseBlock: &p} | |
| + case ThinkingBlock: | |
| + p := variant.ToParam() | |
| + return ContentBlockParamUnion{OfRequestThinkingBlock: &p} | |
| + case RedactedThinkingBlock: | |
| + p := variant.ToParam() | |
| + return ContentBlockParamUnion{OfRequestRedactedThinkingBlock: &p} | |
| + } | |
| + return ContentBlockParamUnion{} | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := ContentBlockUnion.AsAny().(type) { | |
| +// case TextBlock: | |
| +// case ToolUseBlock: | |
| +// case ThinkingBlock: | |
| +// case RedactedThinkingBlock: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u ContentBlockUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "text": | |
| + return u.AsResponseTextBlock() | |
| + case "tool_use": | |
| + return u.AsResponseToolUseBlock() | |
| + case "thinking": | |
| + return u.AsResponseThinkingBlock() | |
| + case "redacted_thinking": | |
| + return u.AsResponseRedactedThinkingBlock() | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type CitationContentBlockLocation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - EndBlockIndex int64 `json:"end_block_index,required"` | |
| - StartBlockIndex int64 `json:"start_block_index,required"` | |
| - Type CitationContentBlockLocationType `json:"type,required"` | |
| - JSON citationContentBlockLocationJSON `json:"-"` | |
| -} | |
| - | |
| -// citationContentBlockLocationJSON contains the JSON metadata for the struct | |
| -// [CitationContentBlockLocation] | |
| -type citationContentBlockLocationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - EndBlockIndex apijson.Field | |
| - StartBlockIndex apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *CitationContentBlockLocation) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +func (u ContentBlockUnion) AsResponseTextBlock() (v TextBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r citationContentBlockLocationJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u ContentBlockUnion) AsResponseToolUseBlock() (v ToolUseBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r CitationContentBlockLocation) implementsCitationsDeltaCitation() {} | |
| +func (u ContentBlockUnion) AsResponseThinkingBlock() (v ThinkingBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| +} | |
| -func (r CitationContentBlockLocation) implementsTextCitation() {} | |
| +func (u ContentBlockUnion) AsResponseRedactedThinkingBlock() (v RedactedThinkingBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| +} | |
| -type CitationContentBlockLocationType string | |
| +// Returns the unmodified JSON received from the API | |
| +func (u ContentBlockUnion) RawJSON() string { return u.JSON.raw } | |
| -const ( | |
| - CitationContentBlockLocationTypeContentBlockLocation CitationContentBlockLocationType = "content_block_location" | |
| -) | |
| +func (r *ContentBlockUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| + | |
| +func ContentBlockParamOfRequestTextBlock(text string) ContentBlockParamUnion { | |
| + var variant TextBlockParam | |
| + variant.Text = text | |
| + return ContentBlockParamUnion{OfRequestTextBlock: &variant} | |
| +} | |
| -func (r CitationContentBlockLocationType) IsKnown() bool { | |
| - switch r { | |
| - case CitationContentBlockLocationTypeContentBlockLocation: | |
| - return true | |
| +func ContentBlockParamOfRequestImageBlock[T Base64ImageSourceParam | URLImageSourceParam](source T) ContentBlockParamUnion { | |
| + var variant ImageBlockParam | |
| + switch v := any(source).(type) { | |
| + case Base64ImageSourceParam: | |
| + variant.Source.OfBase64ImageSource = &v | |
| + case URLImageSourceParam: | |
| + variant.Source.OfURLImageSource = &v | |
| } | |
| - return false | |
| + return ContentBlockParamUnion{OfRequestImageBlock: &variant} | |
| } | |
| -type CitationContentBlockLocationParam struct { | |
| - CitedText param.Field[string] `json:"cited_text,required"` | |
| - DocumentIndex param.Field[int64] `json:"document_index,required"` | |
| - DocumentTitle param.Field[string] `json:"document_title,required"` | |
| - EndBlockIndex param.Field[int64] `json:"end_block_index,required"` | |
| - StartBlockIndex param.Field[int64] `json:"start_block_index,required"` | |
| - Type param.Field[CitationContentBlockLocationParamType] `json:"type,required"` | |
| +func ContentBlockParamOfRequestToolUseBlock(id string, input interface{}, name string) ContentBlockParamUnion { | |
| + var variant ToolUseBlockParam | |
| + variant.ID = id | |
| + variant.Input = input | |
| + variant.Name = name | |
| + return ContentBlockParamUnion{OfRequestToolUseBlock: &variant} | |
| } | |
| -func (r CitationContentBlockLocationParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +func ContentBlockParamOfRequestToolResultBlock(toolUseID string) ContentBlockParamUnion { | |
| + var variant ToolResultBlockParam | |
| + variant.ToolUseID = toolUseID | |
| + return ContentBlockParamUnion{OfRequestToolResultBlock: &variant} | |
| } | |
| -func (r CitationContentBlockLocationParam) implementsTextCitationParamUnion() {} | |
| +func ContentBlockParamOfRequestDocumentBlock[ | |
| + T Base64PDFSourceParam | PlainTextSourceParam | ContentBlockSourceParam | URLPDFSourceParam, | |
| +](source T) ContentBlockParamUnion { | |
| + var variant DocumentBlockParam | |
| + switch v := any(source).(type) { | |
| + case Base64PDFSourceParam: | |
| + variant.Source.OfBase64PDFSource = &v | |
| + case PlainTextSourceParam: | |
| + variant.Source.OfPlainTextSource = &v | |
| + case ContentBlockSourceParam: | |
| + variant.Source.OfContentBlockSource = &v | |
| + case URLPDFSourceParam: | |
| + variant.Source.OfUrlpdfSource = &v | |
| + } | |
| + return ContentBlockParamUnion{OfRequestDocumentBlock: &variant} | |
| +} | |
| -type CitationContentBlockLocationParamType string | |
| +func ContentBlockParamOfRequestThinkingBlock(signature string, thinking string) ContentBlockParamUnion { | |
| + var variant ThinkingBlockParam | |
| + variant.Signature = signature | |
| + variant.Thinking = thinking | |
| + return ContentBlockParamUnion{OfRequestThinkingBlock: &variant} | |
| +} | |
| -const ( | |
| - CitationContentBlockLocationParamTypeContentBlockLocation CitationContentBlockLocationParamType = "content_block_location" | |
| -) | |
| +func ContentBlockParamOfRequestRedactedThinkingBlock(data string) ContentBlockParamUnion { | |
| + var variant RedactedThinkingBlockParam | |
| + variant.Data = data | |
| + return ContentBlockParamUnion{OfRequestRedactedThinkingBlock: &variant} | |
| +} | |
| -func (r CitationContentBlockLocationParamType) IsKnown() bool { | |
| - switch r { | |
| - case CitationContentBlockLocationParamTypeContentBlockLocation: | |
| - return true | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type ContentBlockParamUnion struct { | |
| + OfRequestTextBlock *TextBlockParam `json:",omitzero,inline"` | |
| + OfRequestImageBlock *ImageBlockParam `json:",omitzero,inline"` | |
| + OfRequestToolUseBlock *ToolUseBlockParam `json:",omitzero,inline"` | |
| + OfRequestToolResultBlock *ToolResultBlockParam `json:",omitzero,inline"` | |
| + OfRequestDocumentBlock *DocumentBlockParam `json:",omitzero,inline"` | |
| + OfRequestThinkingBlock *ThinkingBlockParam `json:",omitzero,inline"` | |
| + OfRequestRedactedThinkingBlock *RedactedThinkingBlockParam `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u ContentBlockParamUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u ContentBlockParamUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[ContentBlockParamUnion](u.OfRequestTextBlock, | |
| + u.OfRequestImageBlock, | |
| + u.OfRequestToolUseBlock, | |
| + u.OfRequestToolResultBlock, | |
| + u.OfRequestDocumentBlock, | |
| + u.OfRequestThinkingBlock, | |
| + u.OfRequestRedactedThinkingBlock) | |
| +} | |
| + | |
| +func (u *ContentBlockParamUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfRequestTextBlock) { | |
| + return u.OfRequestTextBlock | |
| + } else if !param.IsOmitted(u.OfRequestImageBlock) { | |
| + return u.OfRequestImageBlock | |
| + } else if !param.IsOmitted(u.OfRequestToolUseBlock) { | |
| + return u.OfRequestToolUseBlock | |
| + } else if !param.IsOmitted(u.OfRequestToolResultBlock) { | |
| + return u.OfRequestToolResultBlock | |
| + } else if !param.IsOmitted(u.OfRequestDocumentBlock) { | |
| + return u.OfRequestDocumentBlock | |
| + } else if !param.IsOmitted(u.OfRequestThinkingBlock) { | |
| + return u.OfRequestThinkingBlock | |
| + } else if !param.IsOmitted(u.OfRequestRedactedThinkingBlock) { | |
| + return u.OfRequestRedactedThinkingBlock | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type CitationPageLocation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - EndPageNumber int64 `json:"end_page_number,required"` | |
| - StartPageNumber int64 `json:"start_page_number,required"` | |
| - Type CitationPageLocationType `json:"type,required"` | |
| - JSON citationPageLocationJSON `json:"-"` | |
| -} | |
| - | |
| -// citationPageLocationJSON contains the JSON metadata for the struct | |
| -// [CitationPageLocation] | |
| -type citationPageLocationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - EndPageNumber apijson.Field | |
| - StartPageNumber apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *CitationPageLocation) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetText() *string { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return &vt.Text | |
| + } | |
| + return nil | |
| } | |
| -func (r citationPageLocationJSON) RawJSON() string { | |
| - return r.raw | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetID() *string { | |
| + if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return &vt.ID | |
| + } | |
| + return nil | |
| } | |
| -func (r CitationPageLocation) implementsCitationsDeltaCitation() {} | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetInput() *interface{} { | |
| + if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return &vt.Input | |
| + } | |
| + return nil | |
| +} | |
| -func (r CitationPageLocation) implementsTextCitation() {} | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetName() *string { | |
| + if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return &vt.Name | |
| + } | |
| + return nil | |
| +} | |
| -type CitationPageLocationType string | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetToolUseID() *string { | |
| + if vt := u.OfRequestToolResultBlock; vt != nil { | |
| + return &vt.ToolUseID | |
| + } | |
| + return nil | |
| +} | |
| -const ( | |
| - CitationPageLocationTypePageLocation CitationPageLocationType = "page_location" | |
| -) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetContent() *[]ToolResultBlockParamContentUnion { | |
| + if vt := u.OfRequestToolResultBlock; vt != nil { | |
| + return &vt.Content | |
| + } | |
| + return nil | |
| +} | |
| -func (r CitationPageLocationType) IsKnown() bool { | |
| - switch r { | |
| - case CitationPageLocationTypePageLocation: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetIsError() *bool { | |
| + if vt := u.OfRequestToolResultBlock; vt != nil && vt.IsError.IsPresent() { | |
| + return &vt.IsError.Value | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type CitationPageLocationParam struct { | |
| - CitedText param.Field[string] `json:"cited_text,required"` | |
| - DocumentIndex param.Field[int64] `json:"document_index,required"` | |
| - DocumentTitle param.Field[string] `json:"document_title,required"` | |
| - EndPageNumber param.Field[int64] `json:"end_page_number,required"` | |
| - StartPageNumber param.Field[int64] `json:"start_page_number,required"` | |
| - Type param.Field[CitationPageLocationParamType] `json:"type,required"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetContext() *string { | |
| + if vt := u.OfRequestDocumentBlock; vt != nil && vt.Context.IsPresent() { | |
| + return &vt.Context.Value | |
| + } | |
| + return nil | |
| } | |
| -func (r CitationPageLocationParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetTitle() *string { | |
| + if vt := u.OfRequestDocumentBlock; vt != nil && vt.Title.IsPresent() { | |
| + return &vt.Title.Value | |
| + } | |
| + return nil | |
| } | |
| -func (r CitationPageLocationParam) implementsTextCitationParamUnion() {} | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetSignature() *string { | |
| + if vt := u.OfRequestThinkingBlock; vt != nil { | |
| + return &vt.Signature | |
| + } | |
| + return nil | |
| +} | |
| -type CitationPageLocationParamType string | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetThinking() *string { | |
| + if vt := u.OfRequestThinkingBlock; vt != nil { | |
| + return &vt.Thinking | |
| + } | |
| + return nil | |
| +} | |
| -const ( | |
| - CitationPageLocationParamTypePageLocation CitationPageLocationParamType = "page_location" | |
| -) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetData() *string { | |
| + if vt := u.OfRequestRedactedThinkingBlock; vt != nil { | |
| + return &vt.Data | |
| + } | |
| + return nil | |
| +} | |
| -func (r CitationPageLocationParamType) IsKnown() bool { | |
| - switch r { | |
| - case CitationPageLocationParamTypePageLocation: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ContentBlockParamUnion) GetType() *string { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestImageBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestToolResultBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestDocumentBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestThinkingBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestRedactedThinkingBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type CitationsConfigParam struct { | |
| - Enabled param.Field[bool] `json:"enabled"` | |
| +// Returns a pointer to the underlying variant's CacheControl property, if present. | |
| +func (u ContentBlockParamUnion) GetCacheControl() *CacheControlEphemeralParam { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestImageBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestToolUseBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestToolResultBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestDocumentBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } | |
| + return nil | |
| } | |
| -func (r CitationsConfigParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a subunion which exports methods to access subproperties | |
| +// | |
| +// Or use AsAny() to get the underlying value | |
| +func (u ContentBlockParamUnion) GetCitations() (res contentBlockParamUnionCitations) { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + res.ofTextBlockCitations = &vt.Citations | |
| + } else if vt := u.OfRequestDocumentBlock; vt != nil { | |
| + res.ofCitationsConfig = &vt.Citations | |
| + } | |
| + return | |
| } | |
| -type CitationsDelta struct { | |
| - Citation CitationsDeltaCitation `json:"citation,required"` | |
| - Type CitationsDeltaType `json:"type,required"` | |
| - JSON citationsDeltaJSON `json:"-"` | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type contentBlockParamUnionCitations struct { | |
| + ofTextBlockCitations *[]TextCitationParamUnion | |
| + ofCitationsConfig *CitationsConfigParam | |
| } | |
| -// citationsDeltaJSON contains the JSON metadata for the struct [CitationsDelta] | |
| -type citationsDeltaJSON struct { | |
| - Citation apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +// Use the following switch statement to get the type of the union: | |
| +// | |
| +// switch u.AsAny().(type) { | |
| +// case *[]anthropic.TextCitationParamUnion: | |
| +// case *anthropic.CitationsConfigParam: | |
| +// default: | |
| +// fmt.Errorf("not present") | |
| +// } | |
| +func (u contentBlockParamUnionCitations) AsAny() any { | |
| + if !param.IsOmitted(u.ofTextBlockCitations) { | |
| + return u.ofTextBlockCitations | |
| + } else if !param.IsOmitted(u.ofCitationsConfig) { | |
| + return u.ofCitationsConfig | |
| + } | |
| + return nil | |
| } | |
| -func (r *CitationsDelta) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u contentBlockParamUnionCitations) GetEnabled() *bool { | |
| + if vt := u.ofCitationsConfig; vt != nil && vt.Enabled.IsPresent() { | |
| + return &vt.Enabled.Value | |
| + } | |
| + return nil | |
| } | |
| -func (r citationsDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| +// Returns a subunion which exports methods to access subproperties | |
| +// | |
| +// Or use AsAny() to get the underlying value | |
| +func (u ContentBlockParamUnion) GetSource() (res contentBlockParamUnionSource) { | |
| + if vt := u.OfRequestImageBlock; vt != nil { | |
| + res.ofImageBlockSource = &vt.Source | |
| + } else if vt := u.OfRequestDocumentBlock; vt != nil { | |
| + res.ofDocumentBlockSource = &vt.Source | |
| + } | |
| + return | |
| } | |
| -func (r CitationsDelta) implementsContentBlockDeltaEventDelta() {} | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type contentBlockParamUnionSource struct { | |
| + ofImageBlockSource *ImageBlockParamSourceUnion | |
| + ofDocumentBlockSource *DocumentBlockParamSourceUnion | |
| +} | |
| -type CitationsDeltaCitation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - Type CitationsDeltaCitationType `json:"type,required"` | |
| - EndBlockIndex int64 `json:"end_block_index"` | |
| - EndCharIndex int64 `json:"end_char_index"` | |
| - EndPageNumber int64 `json:"end_page_number"` | |
| - StartBlockIndex int64 `json:"start_block_index"` | |
| - StartCharIndex int64 `json:"start_char_index"` | |
| - StartPageNumber int64 `json:"start_page_number"` | |
| - JSON citationsDeltaCitationJSON `json:"-"` | |
| - union CitationsDeltaCitationUnion | |
| +// Use the following switch statement to get the type of the union: | |
| +// | |
| +// switch u.AsAny().(type) { | |
| +// case *anthropic.Base64ImageSourceParam: | |
| +// case *anthropic.URLImageSourceParam: | |
| +// case *anthropic.Base64PDFSourceParam: | |
| +// case *anthropic.PlainTextSourceParam: | |
| +// case *anthropic.ContentBlockSourceParam: | |
| +// case *anthropic.URLPDFSourceParam: | |
| +// default: | |
| +// fmt.Errorf("not present") | |
| +// } | |
| +func (u contentBlockParamUnionSource) AsAny() any { | |
| + if !param.IsOmitted(u.ofImageBlockSource) { | |
| + return u.ofImageBlockSource.asAny() | |
| + } else if !param.IsOmitted(u.ofDocumentBlockSource) { | |
| + return u.ofDocumentBlockSource.asAny() | |
| + } | |
| + return nil | |
| } | |
| -// citationsDeltaCitationJSON contains the JSON metadata for the struct | |
| -// [CitationsDeltaCitation] | |
| -type citationsDeltaCitationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - Type apijson.Field | |
| - EndBlockIndex apijson.Field | |
| - EndCharIndex apijson.Field | |
| - EndPageNumber apijson.Field | |
| - StartBlockIndex apijson.Field | |
| - StartCharIndex apijson.Field | |
| - StartPageNumber apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u contentBlockParamUnionSource) GetContent() *ContentBlockSourceContentUnionParam { | |
| + if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetContent() | |
| + } | |
| + return nil | |
| } | |
| -func (r citationsDeltaCitationJSON) RawJSON() string { | |
| - return r.raw | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u contentBlockParamUnionSource) GetData() *string { | |
| + if u.ofImageBlockSource != nil { | |
| + return u.ofImageBlockSource.GetData() | |
| + } else if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetData() | |
| + } else if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetData() | |
| + } | |
| + return nil | |
| } | |
| -func (r *CitationsDeltaCitation) UnmarshalJSON(data []byte) (err error) { | |
| - *r = CitationsDeltaCitation{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u contentBlockParamUnionSource) GetMediaType() *string { | |
| + if u.ofImageBlockSource != nil { | |
| + return u.ofImageBlockSource.GetMediaType() | |
| + } else if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetMediaType() | |
| + } else if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetMediaType() | |
| } | |
| - return apijson.Port(r.union, &r) | |
| + return nil | |
| } | |
| -// AsUnion returns a [CitationsDeltaCitationUnion] interface which you can cast to | |
| -// the specific types for more type safety. | |
| -// | |
| -// Possible runtime types of the union are [CitationCharLocation], | |
| -// [CitationPageLocation], [CitationContentBlockLocation]. | |
| -func (r CitationsDeltaCitation) AsUnion() CitationsDeltaCitationUnion { | |
| - return r.union | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u contentBlockParamUnionSource) GetType() *string { | |
| + if u.ofImageBlockSource != nil { | |
| + return u.ofImageBlockSource.GetType() | |
| + } else if u.ofImageBlockSource != nil { | |
| + return u.ofImageBlockSource.GetType() | |
| + } else if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetType() | |
| + } else if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetType() | |
| + } else if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetType() | |
| + } else if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetType() | |
| + } | |
| + return nil | |
| } | |
| -// Union satisfied by [CitationCharLocation], [CitationPageLocation] or | |
| -// [CitationContentBlockLocation]. | |
| -type CitationsDeltaCitationUnion interface { | |
| - implementsCitationsDeltaCitation() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u contentBlockParamUnionSource) GetURL() *string { | |
| + if u.ofImageBlockSource != nil { | |
| + return u.ofImageBlockSource.GetURL() | |
| + } else if u.ofDocumentBlockSource != nil { | |
| + return u.ofDocumentBlockSource.GetURL() | |
| + } | |
| + return nil | |
| } | |
| func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*CitationsDeltaCitationUnion)(nil)).Elem(), | |
| + apijson.RegisterUnion[ContentBlockParamUnion]( | |
| "type", | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(CitationCharLocation{}), | |
| - DiscriminatorValue: "char_location", | |
| + Type: reflect.TypeOf(TextBlockParam{}), | |
| + DiscriminatorValue: "text", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(CitationPageLocation{}), | |
| - DiscriminatorValue: "page_location", | |
| + Type: reflect.TypeOf(ImageBlockParam{}), | |
| + DiscriminatorValue: "image", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(CitationContentBlockLocation{}), | |
| - DiscriminatorValue: "content_block_location", | |
| + Type: reflect.TypeOf(ToolUseBlockParam{}), | |
| + DiscriminatorValue: "tool_use", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(ToolResultBlockParam{}), | |
| + DiscriminatorValue: "tool_result", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(DocumentBlockParam{}), | |
| + DiscriminatorValue: "document", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(ThinkingBlockParam{}), | |
| + DiscriminatorValue: "thinking", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(RedactedThinkingBlockParam{}), | |
| + DiscriminatorValue: "redacted_thinking", | |
| }, | |
| ) | |
| } | |
| -type CitationsDeltaCitationType string | |
| - | |
| -const ( | |
| - CitationsDeltaCitationTypeCharLocation CitationsDeltaCitationType = "char_location" | |
| - CitationsDeltaCitationTypePageLocation CitationsDeltaCitationType = "page_location" | |
| - CitationsDeltaCitationTypeContentBlockLocation CitationsDeltaCitationType = "content_block_location" | |
| -) | |
| +// The properties Content, Type are required. | |
| +type ContentBlockSourceParam struct { | |
| + Content ContentBlockSourceContentUnionParam `json:"content,omitzero,required"` | |
| + // This field can be elided, and will marshal its zero value as "content". | |
| + Type constant.Content `json:"type,required"` | |
| + paramObj | |
| +} | |
| -func (r CitationsDeltaCitationType) IsKnown() bool { | |
| - switch r { | |
| - case CitationsDeltaCitationTypeCharLocation, CitationsDeltaCitationTypePageLocation, CitationsDeltaCitationTypeContentBlockLocation: | |
| - return true | |
| - } | |
| - return false | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ContentBlockSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r ContentBlockSourceParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow ContentBlockSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -type CitationsDeltaType string | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type ContentBlockSourceContentUnionParam struct { | |
| + OfString param.Opt[string] `json:",omitzero,inline"` | |
| + OfContentBlockSourceContent []ContentBlockSourceContentUnionParam `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| -const ( | |
| - CitationsDeltaTypeCitationsDelta CitationsDeltaType = "citations_delta" | |
| -) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u ContentBlockSourceContentUnionParam) IsPresent() bool { | |
| + return !param.IsOmitted(u) && !u.IsNull() | |
| +} | |
| +func (u ContentBlockSourceContentUnionParam) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[ContentBlockSourceContentUnionParam](u.OfString, u.OfContentBlockSourceContent) | |
| +} | |
| -func (r CitationsDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case CitationsDeltaTypeCitationsDelta: | |
| - return true | |
| +func (u *ContentBlockSourceContentUnionParam) asAny() any { | |
| + if !param.IsOmitted(u.OfString) { | |
| + return &u.OfString.Value | |
| + } else if !param.IsOmitted(u.OfContentBlockSourceContent) { | |
| + return &u.OfContentBlockSourceContent | |
| } | |
| - return false | |
| + return nil | |
| +} | |
| + | |
| +// The properties Source, Type are required. | |
| +type DocumentBlockParam struct { | |
| + Source DocumentBlockParamSourceUnion `json:"source,omitzero,required"` | |
| + Context param.Opt[string] `json:"context,omitzero"` | |
| + Title param.Opt[string] `json:"title,omitzero"` | |
| + CacheControl CacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + Citations CitationsConfigParam `json:"citations,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "document". | |
| + Type constant.Document `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f DocumentBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r DocumentBlockParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow DocumentBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -type ContentBlock struct { | |
| - Type ContentBlockType `json:"type,required"` | |
| - ID string `json:"id"` | |
| - // This field can have the runtime type of [[]TextCitation]. | |
| - Citations interface{} `json:"citations"` | |
| - Data string `json:"data"` | |
| - // This field can have the runtime type of [interface{}]. | |
| - Input json.RawMessage `json:"input"` | |
| - Name string `json:"name"` | |
| - Signature string `json:"signature"` | |
| - Text string `json:"text"` | |
| - Thinking string `json:"thinking"` | |
| - JSON contentBlockJSON `json:"-"` | |
| - union ContentBlockUnion | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type DocumentBlockParamSourceUnion struct { | |
| + OfBase64PDFSource *Base64PDFSourceParam `json:",omitzero,inline"` | |
| + OfPlainTextSource *PlainTextSourceParam `json:",omitzero,inline"` | |
| + OfContentBlockSource *ContentBlockSourceParam `json:",omitzero,inline"` | |
| + OfUrlpdfSource *URLPDFSourceParam `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u DocumentBlockParamSourceUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u DocumentBlockParamSourceUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[DocumentBlockParamSourceUnion](u.OfBase64PDFSource, u.OfPlainTextSource, u.OfContentBlockSource, u.OfUrlpdfSource) | |
| +} | |
| + | |
| +func (u *DocumentBlockParamSourceUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfBase64PDFSource) { | |
| + return u.OfBase64PDFSource | |
| + } else if !param.IsOmitted(u.OfPlainTextSource) { | |
| + return u.OfPlainTextSource | |
| + } else if !param.IsOmitted(u.OfContentBlockSource) { | |
| + return u.OfContentBlockSource | |
| + } else if !param.IsOmitted(u.OfUrlpdfSource) { | |
| + return u.OfUrlpdfSource | |
| + } | |
| + return nil | |
| } | |
| -// contentBlockJSON contains the JSON metadata for the struct [ContentBlock] | |
| -type contentBlockJSON struct { | |
| - Type apijson.Field | |
| - ID apijson.Field | |
| - Citations apijson.Field | |
| - Data apijson.Field | |
| - Input apijson.Field | |
| - Name apijson.Field | |
| - Signature apijson.Field | |
| - Text apijson.Field | |
| - Thinking apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u DocumentBlockParamSourceUnion) GetContent() *ContentBlockSourceContentUnionParam { | |
| + if vt := u.OfContentBlockSource; vt != nil { | |
| + return &vt.Content | |
| + } | |
| + return nil | |
| } | |
| -func (r contentBlockJSON) RawJSON() string { | |
| - return r.raw | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u DocumentBlockParamSourceUnion) GetURL() *string { | |
| + if vt := u.OfUrlpdfSource; vt != nil { | |
| + return &vt.URL | |
| + } | |
| + return nil | |
| } | |
| -func (r *ContentBlock) UnmarshalJSON(data []byte) (err error) { | |
| - *r = ContentBlock{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u DocumentBlockParamSourceUnion) GetData() *string { | |
| + if vt := u.OfBase64PDFSource; vt != nil { | |
| + return (*string)(&vt.Data) | |
| + } else if vt := u.OfPlainTextSource; vt != nil { | |
| + return (*string)(&vt.Data) | |
| } | |
| - return apijson.Port(r.union, &r) | |
| + return nil | |
| } | |
| -// AsUnion returns a [ContentBlockUnion] interface which you can cast to the | |
| -// specific types for more type safety. | |
| -// | |
| -// Possible runtime types of the union are [TextBlock], [ToolUseBlock], | |
| -// [ThinkingBlock], [RedactedThinkingBlock]. | |
| -func (r ContentBlock) AsUnion() ContentBlockUnion { | |
| - return r.union | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u DocumentBlockParamSourceUnion) GetMediaType() *string { | |
| + if vt := u.OfBase64PDFSource; vt != nil { | |
| + return (*string)(&vt.MediaType) | |
| + } else if vt := u.OfPlainTextSource; vt != nil { | |
| + return (*string)(&vt.MediaType) | |
| + } | |
| + return nil | |
| } | |
| -// Union satisfied by [TextBlock], [ToolUseBlock], [ThinkingBlock] or | |
| -// [RedactedThinkingBlock]. | |
| -type ContentBlockUnion interface { | |
| - implementsContentBlock() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u DocumentBlockParamSourceUnion) GetType() *string { | |
| + if vt := u.OfBase64PDFSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfPlainTextSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfContentBlockSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfUrlpdfSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*ContentBlockUnion)(nil)).Elem(), | |
| + apijson.RegisterUnion[DocumentBlockParamSourceUnion]( | |
| "type", | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(TextBlock{}), | |
| - DiscriminatorValue: "text", | |
| + Type: reflect.TypeOf(Base64PDFSourceParam{}), | |
| + DiscriminatorValue: "base64", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(ToolUseBlock{}), | |
| - DiscriminatorValue: "tool_use", | |
| + Type: reflect.TypeOf(PlainTextSourceParam{}), | |
| + DiscriminatorValue: "text", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(ThinkingBlock{}), | |
| - DiscriminatorValue: "thinking", | |
| + Type: reflect.TypeOf(ContentBlockSourceParam{}), | |
| + DiscriminatorValue: "content", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(RedactedThinkingBlock{}), | |
| - DiscriminatorValue: "redacted_thinking", | |
| + Type: reflect.TypeOf(URLPDFSourceParam{}), | |
| + DiscriminatorValue: "url", | |
| }, | |
| ) | |
| } | |
| -type ContentBlockType string | |
| - | |
| -const ( | |
| - ContentBlockTypeText ContentBlockType = "text" | |
| - ContentBlockTypeToolUse ContentBlockType = "tool_use" | |
| - ContentBlockTypeThinking ContentBlockType = "thinking" | |
| - ContentBlockTypeRedactedThinking ContentBlockType = "redacted_thinking" | |
| -) | |
| - | |
| -func (r ContentBlockType) IsKnown() bool { | |
| - switch r { | |
| - case ContentBlockTypeText, ContentBlockTypeToolUse, ContentBlockTypeThinking, ContentBlockTypeRedactedThinking: | |
| - return true | |
| +// The properties Source, Type are required. | |
| +type ImageBlockParam struct { | |
| + Source ImageBlockParamSourceUnion `json:"source,omitzero,required"` | |
| + CacheControl CacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "image". | |
| + Type constant.Image `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +func NewImageBlockBase64(mediaType string, encodedData string) ContentBlockParamUnion { | |
| + return ContentBlockParamUnion{ | |
| + OfRequestImageBlock: &ImageBlockParam{ | |
| + Source: ImageBlockParamSourceUnion{ | |
| + OfBase64ImageSource: &Base64ImageSourceParam{ | |
| + Data: encodedData, | |
| + MediaType: Base64ImageSourceMediaType(mediaType), | |
| + }, | |
| + }, | |
| + }, | |
| } | |
| - return false | |
| } | |
| -type ContentBlockParam struct { | |
| - Type param.Field[ContentBlockParamType] `json:"type,required"` | |
| - ID param.Field[string] `json:"id"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| - Citations param.Field[interface{}] `json:"citations"` | |
| - Content param.Field[interface{}] `json:"content"` | |
| - Context param.Field[string] `json:"context"` | |
| - Data param.Field[string] `json:"data"` | |
| - Input param.Field[interface{}] `json:"input"` | |
| - IsError param.Field[bool] `json:"is_error"` | |
| - Name param.Field[string] `json:"name"` | |
| - Signature param.Field[string] `json:"signature"` | |
| - Source param.Field[interface{}] `json:"source"` | |
| - Text param.Field[string] `json:"text"` | |
| - Thinking param.Field[string] `json:"thinking"` | |
| - Title param.Field[string] `json:"title"` | |
| - ToolUseID param.Field[string] `json:"tool_use_id"` | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ImageBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r ImageBlockParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow ImageBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r ContentBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type ImageBlockParamSourceUnion struct { | |
| + OfBase64ImageSource *Base64ImageSourceParam `json:",omitzero,inline"` | |
| + OfURLImageSource *URLImageSourceParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -func (r ContentBlockParam) implementsContentBlockParamUnion() {} | |
| - | |
| -// Satisfied by [TextBlockParam], [ImageBlockParam], [ToolUseBlockParam], | |
| -// [ToolResultBlockParam], [DocumentBlockParam], [ThinkingBlockParam], | |
| -// [RedactedThinkingBlockParam], [ContentBlockParam]. | |
| -type ContentBlockParamUnion interface { | |
| - implementsContentBlockParamUnion() | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u ImageBlockParamSourceUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u ImageBlockParamSourceUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[ImageBlockParamSourceUnion](u.OfBase64ImageSource, u.OfURLImageSource) | |
| } | |
| -type ContentBlockParamType string | |
| - | |
| -const ( | |
| - ContentBlockParamTypeText ContentBlockParamType = "text" | |
| - ContentBlockParamTypeImage ContentBlockParamType = "image" | |
| - ContentBlockParamTypeToolUse ContentBlockParamType = "tool_use" | |
| - ContentBlockParamTypeToolResult ContentBlockParamType = "tool_result" | |
| - ContentBlockParamTypeDocument ContentBlockParamType = "document" | |
| - ContentBlockParamTypeThinking ContentBlockParamType = "thinking" | |
| - ContentBlockParamTypeRedactedThinking ContentBlockParamType = "redacted_thinking" | |
| -) | |
| - | |
| -func (r ContentBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case ContentBlockParamTypeText, ContentBlockParamTypeImage, ContentBlockParamTypeToolUse, ContentBlockParamTypeToolResult, ContentBlockParamTypeDocument, ContentBlockParamTypeThinking, ContentBlockParamTypeRedactedThinking: | |
| - return true | |
| +func (u *ImageBlockParamSourceUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfBase64ImageSource) { | |
| + return u.OfBase64ImageSource | |
| + } else if !param.IsOmitted(u.OfURLImageSource) { | |
| + return u.OfURLImageSource | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type ContentBlockSourceParam struct { | |
| - Content param.Field[ContentBlockSourceContentUnionParam] `json:"content,required"` | |
| - Type param.Field[ContentBlockSourceType] `json:"type,required"` | |
| -} | |
| - | |
| -func (r ContentBlockSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ContentBlockSourceParam) implementsDocumentBlockParamSourceUnion() {} | |
| - | |
| -// Satisfied by [shared.UnionString], | |
| -// [ContentBlockSourceContentContentBlockSourceContentParam]. | |
| -type ContentBlockSourceContentUnionParam interface { | |
| - ImplementsContentBlockSourceContentUnionParam() | |
| -} | |
| - | |
| -type ContentBlockSourceContentContentBlockSourceContentParam []ContentBlockSourceContentUnionParam | |
| - | |
| -func (r ContentBlockSourceContentContentBlockSourceContentParam) ImplementsContentBlockSourceContentUnionParam() { | |
| -} | |
| - | |
| -type ContentBlockSourceType string | |
| - | |
| -const ( | |
| - ContentBlockSourceTypeContent ContentBlockSourceType = "content" | |
| -) | |
| - | |
| -func (r ContentBlockSourceType) IsKnown() bool { | |
| - switch r { | |
| - case ContentBlockSourceTypeContent: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type DocumentBlockParam struct { | |
| - Source param.Field[DocumentBlockParamSourceUnion] `json:"source,required"` | |
| - Type param.Field[DocumentBlockParamType] `json:"type,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| - Citations param.Field[CitationsConfigParam] `json:"citations"` | |
| - Context param.Field[string] `json:"context"` | |
| - Title param.Field[string] `json:"title"` | |
| -} | |
| - | |
| -func (r DocumentBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r DocumentBlockParam) implementsContentBlockParamUnion() {} | |
| - | |
| -type DocumentBlockParamSource struct { | |
| - Type param.Field[DocumentBlockParamSourceType] `json:"type,required"` | |
| - Content param.Field[interface{}] `json:"content"` | |
| - Data param.Field[string] `json:"data" format:"byte"` | |
| - MediaType param.Field[DocumentBlockParamSourceMediaType] `json:"media_type"` | |
| - URL param.Field[string] `json:"url"` | |
| -} | |
| - | |
| -func (r DocumentBlockParamSource) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r DocumentBlockParamSource) implementsDocumentBlockParamSourceUnion() {} | |
| - | |
| -// Satisfied by [Base64PDFSourceParam], [PlainTextSourceParam], | |
| -// [ContentBlockSourceParam], [URLPDFSourceParam], [DocumentBlockParamSource]. | |
| -type DocumentBlockParamSourceUnion interface { | |
| - implementsDocumentBlockParamSourceUnion() | |
| -} | |
| - | |
| -type DocumentBlockParamSourceType string | |
| - | |
| -const ( | |
| - DocumentBlockParamSourceTypeBase64 DocumentBlockParamSourceType = "base64" | |
| - DocumentBlockParamSourceTypeText DocumentBlockParamSourceType = "text" | |
| - DocumentBlockParamSourceTypeContent DocumentBlockParamSourceType = "content" | |
| - DocumentBlockParamSourceTypeURL DocumentBlockParamSourceType = "url" | |
| -) | |
| - | |
| -func (r DocumentBlockParamSourceType) IsKnown() bool { | |
| - switch r { | |
| - case DocumentBlockParamSourceTypeBase64, DocumentBlockParamSourceTypeText, DocumentBlockParamSourceTypeContent, DocumentBlockParamSourceTypeURL: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type DocumentBlockParamSourceMediaType string | |
| - | |
| -const ( | |
| - DocumentBlockParamSourceMediaTypeApplicationPDF DocumentBlockParamSourceMediaType = "application/pdf" | |
| - DocumentBlockParamSourceMediaTypeTextPlain DocumentBlockParamSourceMediaType = "text/plain" | |
| -) | |
| - | |
| -func (r DocumentBlockParamSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case DocumentBlockParamSourceMediaTypeApplicationPDF, DocumentBlockParamSourceMediaTypeTextPlain: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type DocumentBlockParamType string | |
| - | |
| -const ( | |
| - DocumentBlockParamTypeDocument DocumentBlockParamType = "document" | |
| -) | |
| - | |
| -func (r DocumentBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case DocumentBlockParamTypeDocument: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ImageBlockParamSourceUnion) GetData() *string { | |
| + if vt := u.OfBase64ImageSource; vt != nil { | |
| + return &vt.Data | |
| } | |
| - return false | |
| -} | |
| - | |
| -type ImageBlockParam struct { | |
| - Source param.Field[ImageBlockParamSourceUnion] `json:"source,required"` | |
| - Type param.Field[ImageBlockParamType] `json:"type,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| + return nil | |
| } | |
| -func NewImageBlockBase64(mediaType string, encodedData string) ImageBlockParam { | |
| - return ImageBlockParam{ | |
| - Type: F(ImageBlockParamTypeImage), | |
| - Source: F(ImageBlockParamSourceUnion(ImageBlockParamSource{ | |
| - Type: F(ImageBlockParamSourceTypeBase64), | |
| - Data: F(encodedData), | |
| - MediaType: F(ImageBlockParamSourceMediaType(mediaType)), | |
| - })), | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ImageBlockParamSourceUnion) GetMediaType() *string { | |
| + if vt := u.OfBase64ImageSource; vt != nil { | |
| + return (*string)(&vt.MediaType) | |
| } | |
| + return nil | |
| } | |
| -func (r ImageBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ImageBlockParam) implementsContentBlockParamUnion() {} | |
| - | |
| -func (r ImageBlockParam) implementsContentBlockSourceContentUnionParam() {} | |
| - | |
| -func (r ImageBlockParam) implementsToolResultBlockParamContentUnion() {} | |
| - | |
| -type ImageBlockParamSource struct { | |
| - Type param.Field[ImageBlockParamSourceType] `json:"type,required"` | |
| - Data param.Field[string] `json:"data" format:"byte"` | |
| - MediaType param.Field[ImageBlockParamSourceMediaType] `json:"media_type"` | |
| - URL param.Field[string] `json:"url"` | |
| -} | |
| - | |
| -func (r ImageBlockParamSource) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ImageBlockParamSource) implementsImageBlockParamSourceUnion() {} | |
| - | |
| -// Satisfied by [Base64ImageSourceParam], [URLImageSourceParam], | |
| -// [ImageBlockParamSource]. | |
| -type ImageBlockParamSourceUnion interface { | |
| - implementsImageBlockParamSourceUnion() | |
| -} | |
| - | |
| -type ImageBlockParamSourceType string | |
| - | |
| -const ( | |
| - ImageBlockParamSourceTypeBase64 ImageBlockParamSourceType = "base64" | |
| - ImageBlockParamSourceTypeURL ImageBlockParamSourceType = "url" | |
| -) | |
| - | |
| -func (r ImageBlockParamSourceType) IsKnown() bool { | |
| - switch r { | |
| - case ImageBlockParamSourceTypeBase64, ImageBlockParamSourceTypeURL: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ImageBlockParamSourceUnion) GetURL() *string { | |
| + if vt := u.OfURLImageSource; vt != nil { | |
| + return &vt.URL | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type ImageBlockParamSourceMediaType string | |
| - | |
| -const ( | |
| - ImageBlockParamSourceMediaTypeImageJPEG ImageBlockParamSourceMediaType = "image/jpeg" | |
| - ImageBlockParamSourceMediaTypeImagePNG ImageBlockParamSourceMediaType = "image/png" | |
| - ImageBlockParamSourceMediaTypeImageGIF ImageBlockParamSourceMediaType = "image/gif" | |
| - ImageBlockParamSourceMediaTypeImageWebP ImageBlockParamSourceMediaType = "image/webp" | |
| -) | |
| - | |
| -func (r ImageBlockParamSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case ImageBlockParamSourceMediaTypeImageJPEG, ImageBlockParamSourceMediaTypeImagePNG, ImageBlockParamSourceMediaTypeImageGIF, ImageBlockParamSourceMediaTypeImageWebP: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ImageBlockParamSourceUnion) GetType() *string { | |
| + if vt := u.OfBase64ImageSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfURLImageSource; vt != nil { | |
| + return (*string)(&vt.Type) | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type ImageBlockParamType string | |
| - | |
| -const ( | |
| - ImageBlockParamTypeImage ImageBlockParamType = "image" | |
| -) | |
| - | |
| -func (r ImageBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case ImageBlockParamTypeImage: | |
| - return true | |
| - } | |
| - return false | |
| +func init() { | |
| + apijson.RegisterUnion[ImageBlockParamSourceUnion]( | |
| + "type", | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(Base64ImageSourceParam{}), | |
| + DiscriminatorValue: "base64", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(URLImageSourceParam{}), | |
| + DiscriminatorValue: "url", | |
| + }, | |
| + ) | |
| } | |
| type InputJSONDelta struct { | |
| - PartialJSON string `json:"partial_json,required"` | |
| - Type InputJSONDeltaType `json:"type,required"` | |
| - JSON inputJSONDeltaJSON `json:"-"` | |
| -} | |
| - | |
| -// inputJSONDeltaJSON contains the JSON metadata for the struct [InputJSONDelta] | |
| -type inputJSONDeltaJSON struct { | |
| - PartialJSON apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *InputJSONDelta) UnmarshalJSON(data []byte) (err error) { | |
| + PartialJSON string `json:"partial_json,required"` | |
| + Type constant.InputJSONDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + PartialJSON resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r InputJSONDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *InputJSONDelta) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r inputJSONDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r InputJSONDelta) implementsContentBlockDeltaEventDelta() {} | |
| - | |
| -type InputJSONDeltaType string | |
| - | |
| -const ( | |
| - InputJSONDeltaTypeInputJSONDelta InputJSONDeltaType = "input_json_delta" | |
| -) | |
| - | |
| -func (r InputJSONDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case InputJSONDeltaTypeInputJSONDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -// 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 (a *Message) Accumulate(event MessageStreamEvent) error { | |
| - if a == nil { | |
| - *a = Message{} | |
| - } | |
| - | |
| - switch event := event.AsUnion().(type) { | |
| - case MessageStartEvent: | |
| - *a = event.Message | |
| - | |
| - case MessageDeltaEvent: | |
| - a.StopReason = MessageStopReason(event.Delta.StopReason) | |
| - a.JSON.StopReason = event.Delta.JSON.StopReason | |
| - a.StopSequence = event.Delta.StopSequence | |
| - a.JSON.StopSequence = event.Delta.JSON.StopSequence | |
| - a.Usage.OutputTokens = event.Usage.OutputTokens | |
| - a.Usage.JSON.OutputTokens = event.Usage.JSON.OutputTokens | |
| - | |
| - case MessageStopEvent: | |
| - | |
| - case ContentBlockStartEvent: | |
| - a.Content = append(a.Content, ContentBlock{}) | |
| - err := a.Content[len(a.Content)-1].UnmarshalJSON([]byte(event.ContentBlock.JSON.RawJSON())) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - | |
| - case ContentBlockDeltaEvent: | |
| - if len(a.Content) == 0 { | |
| - return fmt.Errorf("received event of type %s but there was no content block", event.Type) | |
| - } | |
| - switch delta := event.Delta.AsUnion().(type) { | |
| - case TextDelta: | |
| - cb := &a.Content[len(a.Content)-1] | |
| - cb.Text += delta.Text | |
| - if tb, ok := cb.union.(TextBlock); ok { | |
| - tb.Text = cb.Text | |
| - cb.union = tb | |
| - } | |
| - | |
| - case InputJSONDelta: | |
| - cb := &a.Content[len(a.Content)-1] | |
| - if string(cb.Input) == "{}" { | |
| - cb.Input = json.RawMessage{} | |
| - } | |
| - cb.Input = append(cb.Input, []byte(delta.PartialJSON)...) | |
| - if tb, ok := cb.union.(ToolUseBlock); ok { | |
| - tb.Input = cb.Input | |
| - cb.union = tb | |
| - } | |
| - case ThinkingDelta: | |
| - cb := &a.Content[len(a.Content)-1] | |
| - cb.Thinking += delta.Thinking | |
| - if tb, ok := cb.union.(ThinkingBlock); ok { | |
| - tb.Thinking = cb.Thinking | |
| - cb.union = tb | |
| - } | |
| - case SignatureDelta: | |
| - cb := &a.Content[len(a.Content)-1] | |
| - cb.Signature += delta.Signature | |
| - if tb, ok := cb.union.(ThinkingBlock); ok { | |
| - tb.Signature = cb.Signature | |
| - cb.union = tb | |
| - } | |
| - } | |
| - | |
| - case ContentBlockStopEvent: | |
| - if len(a.Content) == 0 { | |
| - return fmt.Errorf("received event of type %s but there was no content block", event.Type) | |
| - } | |
| - } | |
| - | |
| - return nil | |
| -} | |
| - | |
| -// ToParam converts a Message to a MessageParam, which can be used when constructing a new | |
| -// Create | |
| type Message struct { | |
| // Unique object identifier. | |
| // | |
| @@ -1127,7 +1279,7 @@ type Message struct { | |
| // ```json | |
| // [{ "type": "text", "text": "B)" }] | |
| // ``` | |
| - Content []ContentBlock `json:"content,required"` | |
| + Content []ContentBlockUnion `json:"content,required"` | |
| // The model that will complete your prompt.\n\nSee | |
| // [models](https://docs.anthropic.com/en/docs/models-overview) for additional | |
| // details and options. | |
| @@ -1135,7 +1287,7 @@ type Message struct { | |
| // Conversational role of the generated message. | |
| // | |
| // This will always be `"assistant"`. | |
| - Role MessageRole `json:"role,required"` | |
| + Role constant.Assistant `json:"role,required"` | |
| // The reason that we stopped. | |
| // | |
| // This may be one the following values: | |
| @@ -1147,16 +1299,18 @@ type Message struct { | |
| // | |
| // In non-streaming mode this value is always non-null. In streaming mode, it is | |
| // null in the `message_start` event and non-null otherwise. | |
| - StopReason MessageStopReason `json:"stop_reason,required,nullable"` | |
| + // | |
| + // Any of "end_turn", "max_tokens", "stop_sequence", "tool_use". | |
| + StopReason MessageStopReason `json:"stop_reason,required"` | |
| // Which custom stop sequence was generated, if any. | |
| // | |
| // This value will be a non-null string if one of your custom stop sequences was | |
| // generated. | |
| - StopSequence string `json:"stop_sequence,required,nullable"` | |
| + StopSequence string `json:"stop_sequence,required"` | |
| // Object type. | |
| // | |
| // For Messages, this is always `"message"`. | |
| - Type MessageType `json:"type,required"` | |
| + Type constant.Message `json:"type,required"` | |
| // Billing and rate-limit usage. | |
| // | |
| // Anthropic's API bills and rate-limits by token counts, as tokens represent the | |
| @@ -1172,111 +1326,37 @@ type Message struct { | |
| // | |
| // Total input tokens in a request is the summation of `input_tokens`, | |
| // `cache_creation_input_tokens`, and `cache_read_input_tokens`. | |
| - Usage Usage `json:"usage,required"` | |
| - JSON messageJSON `json:"-"` | |
| -} | |
| - | |
| -// messageJSON contains the JSON metadata for the struct [Message] | |
| -type messageJSON struct { | |
| - ID apijson.Field | |
| - Content apijson.Field | |
| - Model apijson.Field | |
| - Role apijson.Field | |
| - StopReason apijson.Field | |
| - StopSequence apijson.Field | |
| - Type apijson.Field | |
| - Usage apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -// ToParam converts a Message to a MessageParam which can be used when making another network | |
| -// request. This is useful when interacting with Claude conversationally or when tool calling. | |
| -// | |
| -// messages := []anthropic.MessageParam{ | |
| -// anthropic.NewUserMessage(anthropic.NewTextBlock("What is my first name?")), | |
| -// } | |
| -// | |
| -// message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| -// MaxTokens: anthropic.F(int64(1024)), | |
| -// Messages: anthropic.F(messages), | |
| -// Model: anthropic.F(anthropic.ModelClaude_3_5_Sonnet_20240620), | |
| -// }) | |
| -// | |
| -// 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{ | |
| -// MaxTokens: anthropic.F(int64(1024)), | |
| -// Messages: anthropic.F(messages), | |
| -// Model: anthropic.F(anthropic.ModelClaude_3_5_Sonnet_20240620), | |
| -// }) | |
| -func (r *Message) ToParam() MessageParam { | |
| - content := []ContentBlockParamUnion{} | |
| - | |
| - for _, block := range r.Content { | |
| - content = append(content, ContentBlockParam{ | |
| - Type: F(ContentBlockParamType(block.Type)), | |
| - ID: param.Field[string]{ | |
| - Value: block.ID, | |
| - Present: !block.JSON.ID.IsNull(), | |
| - }, | |
| - Text: param.Field[string]{ | |
| - Value: block.Text, | |
| - Present: !block.JSON.Text.IsNull(), | |
| - }, | |
| - Name: param.Field[string]{ | |
| - Value: block.Name, | |
| - Present: !block.JSON.Name.IsNull(), | |
| - }, | |
| - Input: param.Field[interface{}]{ | |
| - Value: block.Input, | |
| - Present: len(block.Input) > 0 && !block.JSON.Input.IsNull(), | |
| - }, | |
| - Thinking: param.Field[string]{ | |
| - Value: block.Thinking, | |
| - Present: !block.JSON.Thinking.IsNull(), | |
| - }, | |
| - Signature: param.Field[string]{ | |
| - Value: block.Signature, | |
| - Present: !block.JSON.Signature.IsNull(), | |
| - }, | |
| - }) | |
| - } | |
| - | |
| - message := MessageParam{ | |
| - Role: F(MessageParamRole(r.Role)), | |
| - Content: F(content), | |
| - } | |
| - | |
| - return message | |
| -} | |
| - | |
| -func (r *Message) UnmarshalJSON(data []byte) (err error) { | |
| + Usage Usage `json:"usage,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + Content resp.Field | |
| + Model resp.Field | |
| + Role resp.Field | |
| + StopReason resp.Field | |
| + StopSequence resp.Field | |
| + Type resp.Field | |
| + Usage resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r Message) RawJSON() string { return r.JSON.raw } | |
| +func (r *Message) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -// Conversational role of the generated message. | |
| -// | |
| -// This will always be `"assistant"`. | |
| -type MessageRole string | |
| - | |
| -const ( | |
| - MessageRoleAssistant MessageRole = "assistant" | |
| -) | |
| - | |
| -func (r MessageRole) IsKnown() bool { | |
| - switch r { | |
| - case MessageRoleAssistant: | |
| - return true | |
| +func (r Message) ToParam() MessageParam { | |
| + var p MessageParam | |
| + p.Role = MessageParamRole(r.Role) | |
| + p.Content = make([]ContentBlockParamUnion, len(r.Content)) | |
| + for i, c := range r.Content { | |
| + p.Content[i] = c.ToParam() | |
| } | |
| - return false | |
| + return p | |
| } | |
| // The reason that we stopped. | |
| @@ -1299,118 +1379,137 @@ const ( | |
| MessageStopReasonToolUse MessageStopReason = "tool_use" | |
| ) | |
| -func (r MessageStopReason) IsKnown() bool { | |
| - switch r { | |
| - case MessageStopReasonEndTurn, MessageStopReasonMaxTokens, MessageStopReasonStopSequence, MessageStopReasonToolUse: | |
| - return true | |
| - } | |
| - return false | |
| +func MessageCountTokensToolParamOfTool(inputSchema ToolInputSchemaParam, name string) MessageCountTokensToolUnionParam { | |
| + var variant ToolParam | |
| + variant.InputSchema = inputSchema | |
| + variant.Name = name | |
| + return MessageCountTokensToolUnionParam{OfTool: &variant} | |
| } | |
| -// Object type. | |
| +// Only one field can be non-zero. | |
| // | |
| -// For Messages, this is always `"message"`. | |
| -type MessageType string | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type MessageCountTokensToolUnionParam struct { | |
| + OfTool *ToolParam `json:",omitzero,inline"` | |
| + OfBashTool20250124 *ToolBash20250124Param `json:",omitzero,inline"` | |
| + OfTextEditor20250124 *ToolTextEditor20250124Param `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| -const ( | |
| - MessageTypeMessage MessageType = "message" | |
| -) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u MessageCountTokensToolUnionParam) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u MessageCountTokensToolUnionParam) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[MessageCountTokensToolUnionParam](u.OfTool, u.OfBashTool20250124, u.OfTextEditor20250124) | |
| +} | |
| -func (r MessageType) IsKnown() bool { | |
| - switch r { | |
| - case MessageTypeMessage: | |
| - return true | |
| +func (u *MessageCountTokensToolUnionParam) asAny() any { | |
| + if !param.IsOmitted(u.OfTool) { | |
| + return u.OfTool | |
| + } else if !param.IsOmitted(u.OfBashTool20250124) { | |
| + return u.OfBashTool20250124 | |
| + } else if !param.IsOmitted(u.OfTextEditor20250124) { | |
| + return u.OfTextEditor20250124 | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type MessageCountTokensToolParam struct { | |
| - // Name of the tool. | |
| - // | |
| - // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[string] `json:"name,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| - // Description of what this tool does. | |
| - // | |
| - // Tool descriptions should be as detailed as possible. The more information that | |
| - // the model has about what the tool is and how to use it, the better it will | |
| - // perform. You can use natural language descriptions to reinforce important | |
| - // aspects of the tool input JSON schema. | |
| - Description param.Field[string] `json:"description"` | |
| - InputSchema param.Field[interface{}] `json:"input_schema"` | |
| - Type param.Field[MessageCountTokensToolType] `json:"type"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u MessageCountTokensToolUnionParam) GetInputSchema() *ToolInputSchemaParam { | |
| + if vt := u.OfTool; vt != nil { | |
| + return &vt.InputSchema | |
| + } | |
| + return nil | |
| } | |
| -func (r MessageCountTokensToolParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u MessageCountTokensToolUnionParam) GetDescription() *string { | |
| + if vt := u.OfTool; vt != nil && vt.Description.IsPresent() { | |
| + return &vt.Description.Value | |
| + } | |
| + return nil | |
| } | |
| -func (r MessageCountTokensToolParam) implementsMessageCountTokensToolUnionParam() {} | |
| - | |
| -// Satisfied by [ToolParam], [ToolBash20250124Param], | |
| -// [ToolTextEditor20250124Param], [MessageCountTokensToolParam]. | |
| -type MessageCountTokensToolUnionParam interface { | |
| - implementsMessageCountTokensToolUnionParam() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u MessageCountTokensToolUnionParam) GetName() *string { | |
| + if vt := u.OfTool; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } | |
| + return nil | |
| } | |
| -type MessageCountTokensToolType string | |
| - | |
| -const ( | |
| - MessageCountTokensToolTypeBash20250124 MessageCountTokensToolType = "bash_20250124" | |
| - MessageCountTokensToolTypeTextEditor20250124 MessageCountTokensToolType = "text_editor_20250124" | |
| -) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u MessageCountTokensToolUnionParam) GetType() *string { | |
| + if vt := u.OfBashTool20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| +} | |
| -func (r MessageCountTokensToolType) IsKnown() bool { | |
| - switch r { | |
| - case MessageCountTokensToolTypeBash20250124, MessageCountTokensToolTypeTextEditor20250124: | |
| - return true | |
| +// Returns a pointer to the underlying variant's CacheControl property, if present. | |
| +func (u MessageCountTokensToolUnionParam) GetCacheControl() *CacheControlEphemeralParam { | |
| + if vt := u.OfTool; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return &vt.CacheControl | |
| } | |
| - return false | |
| + return nil | |
| } | |
| type MessageDeltaUsage struct { | |
| // The cumulative number of output tokens which were used. | |
| - OutputTokens int64 `json:"output_tokens,required"` | |
| - JSON messageDeltaUsageJSON `json:"-"` | |
| -} | |
| - | |
| -// messageDeltaUsageJSON contains the JSON metadata for the struct | |
| -// [MessageDeltaUsage] | |
| -type messageDeltaUsageJSON struct { | |
| - OutputTokens apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageDeltaUsage) UnmarshalJSON(data []byte) (err error) { | |
| + OutputTokens int64 `json:"output_tokens,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + OutputTokens resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageDeltaUsage) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageDeltaUsage) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageDeltaUsageJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| +// The properties Content, Role are required. | |
| type MessageParam struct { | |
| - Content param.Field[[]ContentBlockParamUnion] `json:"content,required"` | |
| - Role param.Field[MessageParamRole] `json:"role,required"` | |
| + Content []ContentBlockParamUnion `json:"content,omitzero,required"` | |
| + // Any of "user", "assistant". | |
| + Role MessageParamRole `json:"role,omitzero,required"` | |
| + paramObj | |
| } | |
| func NewUserMessage(blocks ...ContentBlockParamUnion) MessageParam { | |
| return MessageParam{ | |
| - Role: F(MessageParamRoleUser), | |
| - Content: F(blocks), | |
| + Role: MessageParamRoleUser, | |
| + Content: blocks, | |
| } | |
| } | |
| func NewAssistantMessage(blocks ...ContentBlockParamUnion) MessageParam { | |
| return MessageParam{ | |
| - Role: F(MessageParamRoleAssistant), | |
| - Content: F(blocks), | |
| + Role: MessageParamRoleAssistant, | |
| + Content: blocks, | |
| } | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f MessageParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r MessageParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow MessageParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type MessageParamRole string | |
| @@ -1420,48 +1519,41 @@ const ( | |
| MessageParamRoleAssistant MessageParamRole = "assistant" | |
| ) | |
| -func (r MessageParamRole) IsKnown() bool { | |
| - switch r { | |
| - case MessageParamRoleUser, MessageParamRoleAssistant: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type MessageTokensCount struct { | |
| // The total number of tokens across the provided list of messages, system prompt, | |
| // and tools. | |
| - InputTokens int64 `json:"input_tokens,required"` | |
| - JSON messageTokensCountJSON `json:"-"` | |
| -} | |
| - | |
| -// messageTokensCountJSON contains the JSON metadata for the struct | |
| -// [MessageTokensCount] | |
| -type messageTokensCountJSON struct { | |
| - InputTokens apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageTokensCount) UnmarshalJSON(data []byte) (err error) { | |
| + InputTokens int64 `json:"input_tokens,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + InputTokens resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageTokensCount) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageTokensCount) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageTokensCountJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| type MetadataParam struct { | |
| // An external identifier for the user who is associated with the request. | |
| // | |
| // This should be a uuid, hash value, or other opaque identifier. Anthropic may use | |
| // this id to help detect abuse. Do not include any identifying information such as | |
| // name, email address, or phone number. | |
| - UserID param.Field[string] `json:"user_id"` | |
| + UserID param.Opt[string] `json:"user_id,omitzero"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f MetadataParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r MetadataParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow MetadataParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| // The model that will complete your prompt.\n\nSee | |
| @@ -1494,377 +1586,272 @@ const ( | |
| ModelClaude_2_0 Model = "claude-2.0" | |
| ) | |
| +// The properties Data, MediaType, Type are required. | |
| type PlainTextSourceParam struct { | |
| - Data param.Field[string] `json:"data,required"` | |
| - MediaType param.Field[PlainTextSourceMediaType] `json:"media_type,required"` | |
| - Type param.Field[PlainTextSourceType] `json:"type,required"` | |
| + Data string `json:"data,required"` | |
| + // This field can be elided, and will marshal its zero value as "text/plain". | |
| + MediaType constant.TextPlain `json:"media_type,required"` | |
| + // This field can be elided, and will marshal its zero value as "text". | |
| + Type constant.Text `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f PlainTextSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r PlainTextSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow PlainTextSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r PlainTextSourceParam) implementsDocumentBlockParamSourceUnion() {} | |
| - | |
| -type PlainTextSourceMediaType string | |
| - | |
| -const ( | |
| - PlainTextSourceMediaTypeTextPlain PlainTextSourceMediaType = "text/plain" | |
| -) | |
| +type ContentBlockDeltaEvent struct { | |
| + Delta ContentBlockDeltaEventDeltaUnion `json:"delta,required"` | |
| + Index int64 `json:"index,required"` | |
| + Type constant.ContentBlockDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Delta resp.Field | |
| + Index resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r ContentBlockDeltaEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *ContentBlockDeltaEvent) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r PlainTextSourceMediaType) IsKnown() bool { | |
| - switch r { | |
| - case PlainTextSourceMediaTypeTextPlain: | |
| - return true | |
| +// ContentBlockDeltaEventDeltaUnion contains all possible properties and values | |
| +// from [TextDelta], [InputJSONDelta], [CitationsDelta], [ThinkingDelta], | |
| +// [SignatureDelta]. | |
| +// | |
| +// Use the [ContentBlockDeltaEventDeltaUnion.AsAny] method to switch on the | |
| +// variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type ContentBlockDeltaEventDeltaUnion struct { | |
| + // This field is from variant [TextDelta]. | |
| + Text string `json:"text"` | |
| + // Any of "text_delta", "input_json_delta", "citations_delta", "thinking_delta", | |
| + // "signature_delta". | |
| + Type string `json:"type"` | |
| + // This field is from variant [InputJSONDelta]. | |
| + PartialJSON string `json:"partial_json"` | |
| + // This field is from variant [CitationsDelta]. | |
| + Citation CitationsDeltaCitationUnion `json:"citation"` | |
| + // This field is from variant [ThinkingDelta]. | |
| + Thinking string `json:"thinking"` | |
| + // This field is from variant [SignatureDelta]. | |
| + Signature string `json:"signature"` | |
| + JSON struct { | |
| + Text resp.Field | |
| + Type resp.Field | |
| + PartialJSON resp.Field | |
| + Citation resp.Field | |
| + Thinking resp.Field | |
| + Signature resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := ContentBlockDeltaEventDeltaUnion.AsAny().(type) { | |
| +// case TextDelta: | |
| +// case InputJSONDelta: | |
| +// case CitationsDelta: | |
| +// case ThinkingDelta: | |
| +// case SignatureDelta: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u ContentBlockDeltaEventDeltaUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "text_delta": | |
| + return u.AsTextContentBlockDelta() | |
| + case "input_json_delta": | |
| + return u.AsInputJSONContentBlockDelta() | |
| + case "citations_delta": | |
| + return u.AsCitationsDelta() | |
| + case "thinking_delta": | |
| + return u.AsThinkingContentBlockDelta() | |
| + case "signature_delta": | |
| + return u.AsSignatureContentBlockDelta() | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type PlainTextSourceType string | |
| - | |
| -const ( | |
| - PlainTextSourceTypeText PlainTextSourceType = "text" | |
| -) | |
| - | |
| -func (r PlainTextSourceType) IsKnown() bool { | |
| - switch r { | |
| - case PlainTextSourceTypeText: | |
| - return true | |
| - } | |
| - return false | |
| +func (u ContentBlockDeltaEventDeltaUnion) AsTextContentBlockDelta() (v TextDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type ContentBlockDeltaEvent struct { | |
| - Delta ContentBlockDeltaEventDelta `json:"delta,required"` | |
| - Index int64 `json:"index,required"` | |
| - Type ContentBlockDeltaEventType `json:"type,required"` | |
| - JSON contentBlockDeltaEventJSON `json:"-"` | |
| +func (u ContentBlockDeltaEventDeltaUnion) AsInputJSONContentBlockDelta() (v InputJSONDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// contentBlockDeltaEventJSON contains the JSON metadata for the struct | |
| -// [ContentBlockDeltaEvent] | |
| -type contentBlockDeltaEventJSON struct { | |
| - Delta apijson.Field | |
| - Index apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func (u ContentBlockDeltaEventDeltaUnion) AsCitationsDelta() (v CitationsDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r *ContentBlockDeltaEvent) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +func (u ContentBlockDeltaEventDeltaUnion) AsThinkingContentBlockDelta() (v ThinkingDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r contentBlockDeltaEventJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u ContentBlockDeltaEventDeltaUnion) AsSignatureContentBlockDelta() (v SignatureDelta) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r ContentBlockDeltaEvent) implementsMessageStreamEvent() {} | |
| +// Returns the unmodified JSON received from the API | |
| +func (u ContentBlockDeltaEventDeltaUnion) RawJSON() string { return u.JSON.raw } | |
| -type ContentBlockDeltaEventDelta struct { | |
| - Type ContentBlockDeltaEventDeltaType `json:"type,required"` | |
| - // This field can have the runtime type of [CitationsDeltaCitation]. | |
| - Citation interface{} `json:"citation"` | |
| - PartialJSON string `json:"partial_json"` | |
| - Signature string `json:"signature"` | |
| - Text string `json:"text"` | |
| - Thinking string `json:"thinking"` | |
| - JSON contentBlockDeltaEventDeltaJSON `json:"-"` | |
| - union ContentBlockDeltaEventDeltaUnion | |
| +func (r *ContentBlockDeltaEventDeltaUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -// contentBlockDeltaEventDeltaJSON contains the JSON metadata for the struct | |
| -// [ContentBlockDeltaEventDelta] | |
| -type contentBlockDeltaEventDeltaJSON struct { | |
| - Type apijson.Field | |
| - Citation apijson.Field | |
| - PartialJSON apijson.Field | |
| - Signature apijson.Field | |
| - Text apijson.Field | |
| - Thinking apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +type ContentBlockStartEvent struct { | |
| + ContentBlock ContentBlockStartEventContentBlockUnion `json:"content_block,required"` | |
| + Index int64 `json:"index,required"` | |
| + Type constant.ContentBlockStart `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ContentBlock resp.Field | |
| + Index resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r ContentBlockStartEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *ContentBlockStartEvent) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r contentBlockDeltaEventDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r *ContentBlockDeltaEventDelta) UnmarshalJSON(data []byte) (err error) { | |
| - *r = ContentBlockDeltaEventDelta{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| -} | |
| - | |
| -// AsUnion returns a [ContentBlockDeltaEventDeltaUnion] interface which you can | |
| -// cast to the specific types for more type safety. | |
| +// ContentBlockStartEventContentBlockUnion contains all possible properties and | |
| +// values from [TextBlock], [ToolUseBlock], [ThinkingBlock], | |
| +// [RedactedThinkingBlock]. | |
| // | |
| -// Possible runtime types of the union are [TextDelta], [InputJSONDelta], | |
| -// [CitationsDelta], [ThinkingDelta], [SignatureDelta]. | |
| -func (r ContentBlockDeltaEventDelta) AsUnion() ContentBlockDeltaEventDeltaUnion { | |
| - return r.union | |
| -} | |
| - | |
| -// Union satisfied by [TextDelta], [InputJSONDelta], [CitationsDelta], | |
| -// [ThinkingDelta] or [SignatureDelta]. | |
| -type ContentBlockDeltaEventDeltaUnion interface { | |
| - implementsContentBlockDeltaEventDelta() | |
| -} | |
| - | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*ContentBlockDeltaEventDeltaUnion)(nil)).Elem(), | |
| - "type", | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(TextDelta{}), | |
| - DiscriminatorValue: "text_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(InputJSONDelta{}), | |
| - DiscriminatorValue: "input_json_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(CitationsDelta{}), | |
| - DiscriminatorValue: "citations_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(ThinkingDelta{}), | |
| - DiscriminatorValue: "thinking_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(SignatureDelta{}), | |
| - DiscriminatorValue: "signature_delta", | |
| - }, | |
| - ) | |
| -} | |
| - | |
| -type ContentBlockDeltaEventDeltaType string | |
| - | |
| -const ( | |
| - ContentBlockDeltaEventDeltaTypeTextDelta ContentBlockDeltaEventDeltaType = "text_delta" | |
| - ContentBlockDeltaEventDeltaTypeInputJSONDelta ContentBlockDeltaEventDeltaType = "input_json_delta" | |
| - ContentBlockDeltaEventDeltaTypeCitationsDelta ContentBlockDeltaEventDeltaType = "citations_delta" | |
| - ContentBlockDeltaEventDeltaTypeThinkingDelta ContentBlockDeltaEventDeltaType = "thinking_delta" | |
| - ContentBlockDeltaEventDeltaTypeSignatureDelta ContentBlockDeltaEventDeltaType = "signature_delta" | |
| -) | |
| - | |
| -func (r ContentBlockDeltaEventDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case ContentBlockDeltaEventDeltaTypeTextDelta, ContentBlockDeltaEventDeltaTypeInputJSONDelta, ContentBlockDeltaEventDeltaTypeCitationsDelta, ContentBlockDeltaEventDeltaTypeThinkingDelta, ContentBlockDeltaEventDeltaTypeSignatureDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type ContentBlockDeltaEventType string | |
| - | |
| -const ( | |
| - ContentBlockDeltaEventTypeContentBlockDelta ContentBlockDeltaEventType = "content_block_delta" | |
| -) | |
| - | |
| -func (r ContentBlockDeltaEventType) IsKnown() bool { | |
| - switch r { | |
| - case ContentBlockDeltaEventTypeContentBlockDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type ContentBlockStartEvent struct { | |
| - ContentBlock ContentBlockStartEventContentBlock `json:"content_block,required"` | |
| - Index int64 `json:"index,required"` | |
| - Type ContentBlockStartEventType `json:"type,required"` | |
| - JSON contentBlockStartEventJSON `json:"-"` | |
| -} | |
| - | |
| -// contentBlockStartEventJSON contains the JSON metadata for the struct | |
| -// [ContentBlockStartEvent] | |
| -type contentBlockStartEventJSON struct { | |
| - ContentBlock apijson.Field | |
| - Index apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *ContentBlockStartEvent) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| -} | |
| - | |
| -func (r contentBlockStartEventJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r ContentBlockStartEvent) implementsMessageStreamEvent() {} | |
| - | |
| -type ContentBlockStartEventContentBlock struct { | |
| - Type ContentBlockStartEventContentBlockType `json:"type,required"` | |
| - ID string `json:"id"` | |
| - // This field can have the runtime type of [[]TextCitation]. | |
| - Citations interface{} `json:"citations"` | |
| - Data string `json:"data"` | |
| - // This field can have the runtime type of [interface{}]. | |
| - Input json.RawMessage `json:"input"` | |
| - Name string `json:"name"` | |
| - Signature string `json:"signature"` | |
| - Text string `json:"text"` | |
| - Thinking string `json:"thinking"` | |
| - JSON contentBlockStartEventContentBlockJSON `json:"-"` | |
| - union ContentBlockStartEventContentBlockUnion | |
| -} | |
| - | |
| -// contentBlockStartEventContentBlockJSON contains the JSON metadata for the struct | |
| -// [ContentBlockStartEventContentBlock] | |
| -type contentBlockStartEventContentBlockJSON struct { | |
| - Type apijson.Field | |
| - ID apijson.Field | |
| - Citations apijson.Field | |
| - Data apijson.Field | |
| - Input apijson.Field | |
| - Name apijson.Field | |
| - Signature apijson.Field | |
| - Text apijson.Field | |
| - Thinking apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r contentBlockStartEventContentBlockJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r *ContentBlockStartEventContentBlock) UnmarshalJSON(data []byte) (err error) { | |
| - *r = ContentBlockStartEventContentBlock{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| +// Use the [ContentBlockStartEventContentBlockUnion.AsAny] method to switch on the | |
| +// variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type ContentBlockStartEventContentBlockUnion struct { | |
| + // This field is from variant [TextBlock]. | |
| + Citations []TextCitationUnion `json:"citations"` | |
| + // This field is from variant [TextBlock]. | |
| + Text string `json:"text"` | |
| + // Any of "text", "tool_use", "thinking", "redacted_thinking". | |
| + Type string `json:"type"` | |
| + // This field is from variant [ToolUseBlock]. | |
| + ID string `json:"id"` | |
| + // This field is from variant [ToolUseBlock]. | |
| + Input interface{} `json:"input"` | |
| + // This field is from variant [ToolUseBlock]. | |
| + Name string `json:"name"` | |
| + // This field is from variant [ThinkingBlock]. | |
| + Signature string `json:"signature"` | |
| + // This field is from variant [ThinkingBlock]. | |
| + Thinking string `json:"thinking"` | |
| + // This field is from variant [RedactedThinkingBlock]. | |
| + Data string `json:"data"` | |
| + JSON struct { | |
| + Citations resp.Field | |
| + Text resp.Field | |
| + Type resp.Field | |
| + ID resp.Field | |
| + Input resp.Field | |
| + Name resp.Field | |
| + Signature resp.Field | |
| + Thinking resp.Field | |
| + Data resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := ContentBlockStartEventContentBlockUnion.AsAny().(type) { | |
| +// case TextBlock: | |
| +// case ToolUseBlock: | |
| +// case ThinkingBlock: | |
| +// case RedactedThinkingBlock: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u ContentBlockStartEventContentBlockUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "text": | |
| + return u.AsResponseTextBlock() | |
| + case "tool_use": | |
| + return u.AsResponseToolUseBlock() | |
| + case "thinking": | |
| + return u.AsResponseThinkingBlock() | |
| + case "redacted_thinking": | |
| + return u.AsResponseRedactedThinkingBlock() | |
| } | |
| - return apijson.Port(r.union, &r) | |
| + return nil | |
| } | |
| -// AsUnion returns a [ContentBlockStartEventContentBlockUnion] interface which you | |
| -// can cast to the specific types for more type safety. | |
| -// | |
| -// Possible runtime types of the union are [TextBlock], [ToolUseBlock], | |
| -// [ThinkingBlock], [RedactedThinkingBlock]. | |
| -func (r ContentBlockStartEventContentBlock) AsUnion() ContentBlockStartEventContentBlockUnion { | |
| - return r.union | |
| +func (u ContentBlockStartEventContentBlockUnion) AsResponseTextBlock() (v TextBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// Union satisfied by [TextBlock], [ToolUseBlock], [ThinkingBlock] or | |
| -// [RedactedThinkingBlock]. | |
| -type ContentBlockStartEventContentBlockUnion interface { | |
| - implementsContentBlockStartEventContentBlock() | |
| +func (u ContentBlockStartEventContentBlockUnion) AsResponseToolUseBlock() (v ToolUseBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*ContentBlockStartEventContentBlockUnion)(nil)).Elem(), | |
| - "type", | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(TextBlock{}), | |
| - DiscriminatorValue: "text", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(ToolUseBlock{}), | |
| - DiscriminatorValue: "tool_use", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(ThinkingBlock{}), | |
| - DiscriminatorValue: "thinking", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(RedactedThinkingBlock{}), | |
| - DiscriminatorValue: "redacted_thinking", | |
| - }, | |
| - ) | |
| +func (u ContentBlockStartEventContentBlockUnion) AsResponseThinkingBlock() (v ThinkingBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type ContentBlockStartEventContentBlockType string | |
| - | |
| -const ( | |
| - ContentBlockStartEventContentBlockTypeText ContentBlockStartEventContentBlockType = "text" | |
| - ContentBlockStartEventContentBlockTypeToolUse ContentBlockStartEventContentBlockType = "tool_use" | |
| - ContentBlockStartEventContentBlockTypeThinking ContentBlockStartEventContentBlockType = "thinking" | |
| - ContentBlockStartEventContentBlockTypeRedactedThinking ContentBlockStartEventContentBlockType = "redacted_thinking" | |
| -) | |
| - | |
| -func (r ContentBlockStartEventContentBlockType) IsKnown() bool { | |
| - switch r { | |
| - case ContentBlockStartEventContentBlockTypeText, ContentBlockStartEventContentBlockTypeToolUse, ContentBlockStartEventContentBlockTypeThinking, ContentBlockStartEventContentBlockTypeRedactedThinking: | |
| - return true | |
| - } | |
| - return false | |
| +func (u ContentBlockStartEventContentBlockUnion) AsResponseRedactedThinkingBlock() (v RedactedThinkingBlock) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type ContentBlockStartEventType string | |
| +// Returns the unmodified JSON received from the API | |
| +func (u ContentBlockStartEventContentBlockUnion) RawJSON() string { return u.JSON.raw } | |
| -const ( | |
| - ContentBlockStartEventTypeContentBlockStart ContentBlockStartEventType = "content_block_start" | |
| -) | |
| - | |
| -func (r ContentBlockStartEventType) IsKnown() bool { | |
| - switch r { | |
| - case ContentBlockStartEventTypeContentBlockStart: | |
| - return true | |
| - } | |
| - return false | |
| +func (r *ContentBlockStartEventContentBlockUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| type ContentBlockStopEvent struct { | |
| Index int64 `json:"index,required"` | |
| - Type ContentBlockStopEventType `json:"type,required"` | |
| - JSON contentBlockStopEventJSON `json:"-"` | |
| -} | |
| - | |
| -// contentBlockStopEventJSON contains the JSON metadata for the struct | |
| -// [ContentBlockStopEvent] | |
| -type contentBlockStopEventJSON struct { | |
| - Index apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *ContentBlockStopEvent) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.ContentBlockStop `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Index resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r ContentBlockStopEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *ContentBlockStopEvent) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r contentBlockStopEventJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r ContentBlockStopEvent) implementsMessageStreamEvent() {} | |
| - | |
| -type ContentBlockStopEventType string | |
| - | |
| -const ( | |
| - ContentBlockStopEventTypeContentBlockStop ContentBlockStopEventType = "content_block_stop" | |
| -) | |
| - | |
| -func (r ContentBlockStopEventType) IsKnown() bool { | |
| - switch r { | |
| - case ContentBlockStopEventTypeContentBlockStop: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type MessageDeltaEvent struct { | |
| Delta MessageDeltaEventDelta `json:"delta,required"` | |
| - Type MessageDeltaEventType `json:"type,required"` | |
| + Type constant.MessageDelta `json:"type,required"` | |
| // Billing and rate-limit usage. | |
| // | |
| // Anthropic's API bills and rate-limits by token counts, as tokens represent the | |
| @@ -1880,744 +1867,748 @@ type MessageDeltaEvent struct { | |
| // | |
| // Total input tokens in a request is the summation of `input_tokens`, | |
| // `cache_creation_input_tokens`, and `cache_read_input_tokens`. | |
| - Usage MessageDeltaUsage `json:"usage,required"` | |
| - JSON messageDeltaEventJSON `json:"-"` | |
| -} | |
| - | |
| -// messageDeltaEventJSON contains the JSON metadata for the struct | |
| -// [MessageDeltaEvent] | |
| -type messageDeltaEventJSON struct { | |
| - Delta apijson.Field | |
| - Type apijson.Field | |
| - Usage apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageDeltaEvent) UnmarshalJSON(data []byte) (err error) { | |
| + Usage MessageDeltaUsage `json:"usage,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Delta resp.Field | |
| + Type resp.Field | |
| + Usage resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageDeltaEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageDeltaEvent) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageDeltaEventJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r MessageDeltaEvent) implementsMessageStreamEvent() {} | |
| - | |
| type MessageDeltaEventDelta struct { | |
| - StopReason MessageDeltaEventDeltaStopReason `json:"stop_reason,required,nullable"` | |
| - StopSequence string `json:"stop_sequence,required,nullable"` | |
| - JSON messageDeltaEventDeltaJSON `json:"-"` | |
| -} | |
| - | |
| -// messageDeltaEventDeltaJSON contains the JSON metadata for the struct | |
| -// [MessageDeltaEventDelta] | |
| -type messageDeltaEventDeltaJSON struct { | |
| - StopReason apijson.Field | |
| - StopSequence apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageDeltaEventDelta) UnmarshalJSON(data []byte) (err error) { | |
| + // Any of "end_turn", "max_tokens", "stop_sequence", "tool_use". | |
| + StopReason string `json:"stop_reason,required"` | |
| + StopSequence string `json:"stop_sequence,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + StopReason resp.Field | |
| + StopSequence resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageDeltaEventDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageDeltaEventDelta) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageDeltaEventDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -type MessageDeltaEventDeltaStopReason string | |
| - | |
| -const ( | |
| - MessageDeltaEventDeltaStopReasonEndTurn MessageDeltaEventDeltaStopReason = "end_turn" | |
| - MessageDeltaEventDeltaStopReasonMaxTokens MessageDeltaEventDeltaStopReason = "max_tokens" | |
| - MessageDeltaEventDeltaStopReasonStopSequence MessageDeltaEventDeltaStopReason = "stop_sequence" | |
| - MessageDeltaEventDeltaStopReasonToolUse MessageDeltaEventDeltaStopReason = "tool_use" | |
| -) | |
| - | |
| -func (r MessageDeltaEventDeltaStopReason) IsKnown() bool { | |
| - switch r { | |
| - case MessageDeltaEventDeltaStopReasonEndTurn, MessageDeltaEventDeltaStopReasonMaxTokens, MessageDeltaEventDeltaStopReasonStopSequence, MessageDeltaEventDeltaStopReasonToolUse: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type MessageDeltaEventType string | |
| - | |
| -const ( | |
| - MessageDeltaEventTypeMessageDelta MessageDeltaEventType = "message_delta" | |
| -) | |
| - | |
| -func (r MessageDeltaEventType) IsKnown() bool { | |
| - switch r { | |
| - case MessageDeltaEventTypeMessageDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type MessageStartEvent struct { | |
| Message Message `json:"message,required"` | |
| - Type MessageStartEventType `json:"type,required"` | |
| - JSON messageStartEventJSON `json:"-"` | |
| -} | |
| - | |
| -// messageStartEventJSON contains the JSON metadata for the struct | |
| -// [MessageStartEvent] | |
| -type messageStartEventJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageStartEvent) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.MessageStart `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageStartEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageStartEvent) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageStartEventJSON) RawJSON() string { | |
| - return r.raw | |
| +type MessageStopEvent struct { | |
| + Type constant.MessageStop `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageStopEvent) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageStopEvent) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r MessageStartEvent) implementsMessageStreamEvent() {} | |
| - | |
| -type MessageStartEventType string | |
| - | |
| -const ( | |
| - MessageStartEventTypeMessageStart MessageStartEventType = "message_start" | |
| -) | |
| - | |
| -func (r MessageStartEventType) IsKnown() bool { | |
| - switch r { | |
| - case MessageStartEventTypeMessageStart: | |
| - return true | |
| +// MessageStreamEventUnion contains all possible properties and values from | |
| +// [MessageStartEvent], [MessageDeltaEvent], [MessageStopEvent], | |
| +// [ContentBlockStartEvent], [ContentBlockDeltaEvent], [ContentBlockStopEvent]. | |
| +// | |
| +// Use the [MessageStreamEventUnion.AsAny] method to switch on the variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type MessageStreamEventUnion struct { | |
| + // This field is from variant [MessageStartEvent]. | |
| + Message Message `json:"message"` | |
| + // Any of "message_start", "message_delta", "message_stop", "content_block_start", | |
| + // "content_block_delta", "content_block_stop". | |
| + Type string `json:"type"` | |
| + // This field is a union of [MessageDeltaEventDelta], | |
| + // [ContentBlockDeltaEventDeltaUnion] | |
| + Delta MessageStreamEventUnionDelta `json:"delta"` | |
| + // This field is from variant [MessageDeltaEvent]. | |
| + Usage MessageDeltaUsage `json:"usage"` | |
| + // This field is from variant [ContentBlockStartEvent]. | |
| + ContentBlock ContentBlockStartEventContentBlockUnion `json:"content_block"` | |
| + Index int64 `json:"index"` | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + Delta resp.Field | |
| + Usage resp.Field | |
| + ContentBlock resp.Field | |
| + Index resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := MessageStreamEventUnion.AsAny().(type) { | |
| +// case MessageStartEvent: | |
| +// case MessageDeltaEvent: | |
| +// case MessageStopEvent: | |
| +// case ContentBlockStartEvent: | |
| +// case ContentBlockDeltaEvent: | |
| +// case ContentBlockStopEvent: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u MessageStreamEventUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "message_start": | |
| + return u.AsMessageStartEvent() | |
| + case "message_delta": | |
| + return u.AsMessageDeltaEvent() | |
| + case "message_stop": | |
| + return u.AsMessageStopEvent() | |
| + case "content_block_start": | |
| + return u.AsContentBlockStartEvent() | |
| + case "content_block_delta": | |
| + return u.AsContentBlockDeltaEvent() | |
| + case "content_block_stop": | |
| + return u.AsContentBlockStopEvent() | |
| } | |
| - return false | |
| -} | |
| - | |
| -type MessageStopEvent struct { | |
| - Type MessageStopEventType `json:"type,required"` | |
| - JSON messageStopEventJSON `json:"-"` | |
| + return nil | |
| } | |
| -// messageStopEventJSON contains the JSON metadata for the struct | |
| -// [MessageStopEvent] | |
| -type messageStopEventJSON struct { | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func (u MessageStreamEventUnion) AsMessageStartEvent() (v MessageStartEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r *MessageStopEvent) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +func (u MessageStreamEventUnion) AsMessageDeltaEvent() (v MessageDeltaEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r messageStopEventJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u MessageStreamEventUnion) AsMessageStopEvent() (v MessageStopEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r MessageStopEvent) implementsMessageStreamEvent() {} | |
| - | |
| -type MessageStopEventType string | |
| - | |
| -const ( | |
| - MessageStopEventTypeMessageStop MessageStopEventType = "message_stop" | |
| -) | |
| - | |
| -func (r MessageStopEventType) IsKnown() bool { | |
| - switch r { | |
| - case MessageStopEventTypeMessageStop: | |
| - return true | |
| - } | |
| - return false | |
| +func (u MessageStreamEventUnion) AsContentBlockStartEvent() (v ContentBlockStartEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type MessageStreamEvent struct { | |
| - Type MessageStreamEventType `json:"type,required"` | |
| - // This field can have the runtime type of [ContentBlockStartEventContentBlock]. | |
| - ContentBlock interface{} `json:"content_block"` | |
| - // This field can have the runtime type of [MessageDeltaEventDelta], | |
| - // [ContentBlockDeltaEventDelta]. | |
| - Delta interface{} `json:"delta"` | |
| - Index int64 `json:"index"` | |
| - Message Message `json:"message"` | |
| - // Billing and rate-limit usage. | |
| - // | |
| - // Anthropic's API bills and rate-limits by token counts, as tokens represent the | |
| - // underlying cost to our systems. | |
| - // | |
| - // Under the hood, the API transforms requests into a format suitable for the | |
| - // model. The model's output then goes through a parsing stage before becoming an | |
| - // API response. As a result, the token counts in `usage` will not match one-to-one | |
| - // with the exact visible content of an API request or response. | |
| - // | |
| - // For example, `output_tokens` will be non-zero, even for an empty string response | |
| - // from Claude. | |
| - // | |
| - // Total input tokens in a request is the summation of `input_tokens`, | |
| - // `cache_creation_input_tokens`, and `cache_read_input_tokens`. | |
| - Usage MessageDeltaUsage `json:"usage"` | |
| - JSON messageStreamEventJSON `json:"-"` | |
| - union MessageStreamEventUnion | |
| +func (u MessageStreamEventUnion) AsContentBlockDeltaEvent() (v ContentBlockDeltaEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// messageStreamEventJSON contains the JSON metadata for the struct | |
| -// [MessageStreamEvent] | |
| -type messageStreamEventJSON struct { | |
| - Type apijson.Field | |
| - ContentBlock apijson.Field | |
| - Delta apijson.Field | |
| - Index apijson.Field | |
| - Message apijson.Field | |
| - Usage apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func (u MessageStreamEventUnion) AsContentBlockStopEvent() (v ContentBlockStopEvent) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r messageStreamEventJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| +// Returns the unmodified JSON received from the API | |
| +func (u MessageStreamEventUnion) RawJSON() string { return u.JSON.raw } | |
| -func (r *MessageStreamEvent) UnmarshalJSON(data []byte) (err error) { | |
| - *r = MessageStreamEvent{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| +func (r *MessageStreamEventUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -// AsUnion returns a [MessageStreamEventUnion] interface which you can cast to the | |
| -// specific types for more type safety. | |
| +// MessageStreamEventUnionDelta is an implicit subunion of | |
| +// [MessageStreamEventUnion]. MessageStreamEventUnionDelta provides convenient | |
| +// access to the sub-properties of the union. | |
| // | |
| -// Possible runtime types of the union are [MessageStartEvent], | |
| -// [MessageDeltaEvent], [MessageStopEvent], [ContentBlockStartEvent], | |
| -// [ContentBlockDeltaEvent], [ContentBlockStopEvent]. | |
| -func (r MessageStreamEvent) AsUnion() MessageStreamEventUnion { | |
| - return r.union | |
| -} | |
| - | |
| -// Union satisfied by [MessageStartEvent], [MessageDeltaEvent], [MessageStopEvent], | |
| -// [ContentBlockStartEvent], [ContentBlockDeltaEvent] or [ContentBlockStopEvent]. | |
| -type MessageStreamEventUnion interface { | |
| - implementsMessageStreamEvent() | |
| -} | |
| - | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*MessageStreamEventUnion)(nil)).Elem(), | |
| - "type", | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(MessageStartEvent{}), | |
| - DiscriminatorValue: "message_start", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(MessageDeltaEvent{}), | |
| - DiscriminatorValue: "message_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(MessageStopEvent{}), | |
| - DiscriminatorValue: "message_stop", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(ContentBlockStartEvent{}), | |
| - DiscriminatorValue: "content_block_start", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(ContentBlockDeltaEvent{}), | |
| - DiscriminatorValue: "content_block_delta", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(ContentBlockStopEvent{}), | |
| - DiscriminatorValue: "content_block_stop", | |
| - }, | |
| - ) | |
| +// For type safety it is recommended to directly use a variant of the | |
| +// [MessageStreamEventUnion]. | |
| +type MessageStreamEventUnionDelta struct { | |
| + // This field is from variant [MessageDeltaEventDelta]. | |
| + StopReason string `json:"stop_reason"` | |
| + // This field is from variant [MessageDeltaEventDelta]. | |
| + StopSequence string `json:"stop_sequence"` | |
| + // This field is from variant [ContentBlockDeltaEventDeltaUnion]. | |
| + Text string `json:"text"` | |
| + Type string `json:"type"` | |
| + // This field is from variant [ContentBlockDeltaEventDeltaUnion]. | |
| + PartialJSON string `json:"partial_json"` | |
| + // This field is from variant [ContentBlockDeltaEventDeltaUnion]. | |
| + Citation CitationsDeltaCitationUnion `json:"citation"` | |
| + // This field is from variant [ContentBlockDeltaEventDeltaUnion]. | |
| + Thinking string `json:"thinking"` | |
| + // This field is from variant [ContentBlockDeltaEventDeltaUnion]. | |
| + Signature string `json:"signature"` | |
| + JSON struct { | |
| + StopReason resp.Field | |
| + StopSequence resp.Field | |
| + Text resp.Field | |
| + Type resp.Field | |
| + PartialJSON resp.Field | |
| + Citation resp.Field | |
| + Thinking resp.Field | |
| + Signature resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +func (r *MessageStreamEventUnionDelta) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| -type MessageStreamEventType string | |
| +// 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 *Message) Accumulate(event MessageStreamEventUnion) error { | |
| + if acc == nil { | |
| + return fmt.Errorf("accumulate: cannot accumlate into nil Message") | |
| + } | |
| -const ( | |
| - MessageStreamEventTypeMessageStart MessageStreamEventType = "message_start" | |
| - MessageStreamEventTypeMessageDelta MessageStreamEventType = "message_delta" | |
| - MessageStreamEventTypeMessageStop MessageStreamEventType = "message_stop" | |
| - MessageStreamEventTypeContentBlockStart MessageStreamEventType = "content_block_start" | |
| - MessageStreamEventTypeContentBlockDelta MessageStreamEventType = "content_block_delta" | |
| - MessageStreamEventTypeContentBlockStop MessageStreamEventType = "content_block_stop" | |
| -) | |
| + switch event := event.AsAny().(type) { | |
| + case MessageStartEvent: | |
| + *acc = event.Message | |
| + case MessageDeltaEvent: | |
| + acc.StopReason = MessageStopReason(event.Delta.StopReason) | |
| + acc.StopSequence = event.Delta.StopSequence | |
| + acc.Usage.OutputTokens = event.Usage.OutputTokens | |
| -func (r MessageStreamEventType) IsKnown() bool { | |
| - switch r { | |
| - case MessageStreamEventTypeMessageStart, MessageStreamEventTypeMessageDelta, MessageStreamEventTypeMessageStop, MessageStreamEventTypeContentBlockStart, MessageStreamEventTypeContentBlockDelta, MessageStreamEventTypeContentBlockStop: | |
| - return true | |
| + // acc.JSON.StopReason = event.Delta.JSON.StopReason | |
| + // acc.JSON.StopSequence = event.Delta.JSON.StopSequence | |
| + // acc.Usage.JSON.OutputTokens = event.Usage.JSON.OutputTokens | |
| + case MessageStopEvent: | |
| + accJson, err := json.Marshal(acc) | |
| + if err != nil { | |
| + return fmt.Errorf("error converting content block to JSON: %w", err) | |
| + } | |
| + acc.JSON.raw = string(accJson) | |
| + case ContentBlockStartEvent: | |
| + acc.Content = append(acc.Content, ContentBlockUnion{}) | |
| + err := acc.Content[len(acc.Content)-1].UnmarshalJSON([]byte(event.ContentBlock.RawJSON())) | |
| + if err != nil { | |
| + return err | |
| + } | |
| + case ContentBlockDeltaEvent: | |
| + 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 TextDelta: | |
| + cb.Text += delta.Text | |
| + case InputJSONDelta: | |
| + if string(cb.Input) == "{}" { | |
| + cb.Input = json.RawMessage{} | |
| + } | |
| + cb.Input = append(cb.Input, []byte(delta.PartialJSON)...) | |
| + case ThinkingDelta: | |
| + cb.Thinking += delta.Thinking | |
| + case SignatureDelta: | |
| + cb.Signature += delta.Signature | |
| + } | |
| + case ContentBlockStopEvent: | |
| + 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 false | |
| + | |
| + return nil | |
| } | |
| type RedactedThinkingBlock struct { | |
| Data string `json:"data,required"` | |
| - Type RedactedThinkingBlockType `json:"type,required"` | |
| - JSON redactedThinkingBlockJSON `json:"-"` | |
| -} | |
| - | |
| -// redactedThinkingBlockJSON contains the JSON metadata for the struct | |
| -// [RedactedThinkingBlock] | |
| -type redactedThinkingBlockJSON struct { | |
| - Data apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *RedactedThinkingBlock) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.RedactedThinking `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Data resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r RedactedThinkingBlock) RawJSON() string { return r.JSON.raw } | |
| +func (r *RedactedThinkingBlock) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r redactedThinkingBlockJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r RedactedThinkingBlock) implementsContentBlock() {} | |
| - | |
| -func (r RedactedThinkingBlock) implementsContentBlockStartEventContentBlock() {} | |
| - | |
| -type RedactedThinkingBlockType string | |
| - | |
| -const ( | |
| - RedactedThinkingBlockTypeRedactedThinking RedactedThinkingBlockType = "redacted_thinking" | |
| -) | |
| - | |
| -func (r RedactedThinkingBlockType) IsKnown() bool { | |
| - switch r { | |
| - case RedactedThinkingBlockTypeRedactedThinking: | |
| - return true | |
| - } | |
| - return false | |
| +func (r RedactedThinkingBlock) ToParam() RedactedThinkingBlockParam { | |
| + var p RedactedThinkingBlockParam | |
| + p.Type = r.Type | |
| + p.Data = r.Data | |
| + return p | |
| } | |
| +// The properties Data, Type are required. | |
| type RedactedThinkingBlockParam struct { | |
| - Data param.Field[string] `json:"data,required"` | |
| - Type param.Field[RedactedThinkingBlockParamType] `json:"type,required"` | |
| + Data string `json:"data,required"` | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "redacted_thinking". | |
| + Type constant.RedactedThinking `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f RedactedThinkingBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r RedactedThinkingBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow RedactedThinkingBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r RedactedThinkingBlockParam) implementsContentBlockParamUnion() {} | |
| - | |
| -type RedactedThinkingBlockParamType string | |
| +type SignatureDelta struct { | |
| + Signature string `json:"signature,required"` | |
| + Type constant.SignatureDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Signature resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r SignatureDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *SignatureDelta) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -const ( | |
| - RedactedThinkingBlockParamTypeRedactedThinking RedactedThinkingBlockParamType = "redacted_thinking" | |
| -) | |
| +type TextBlock struct { | |
| + // Citations supporting the text block. | |
| + // | |
| + // The type of citation returned will depend on the type of document being cited. | |
| + // Citing a PDF results in `page_location`, plain text results in `char_location`, | |
| + // and content document results in `content_block_location`. | |
| + Citations []TextCitationUnion `json:"citations,required"` | |
| + Text string `json:"text,required"` | |
| + Type constant.Text `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Citations resp.Field | |
| + Text resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r TextBlock) RawJSON() string { return r.JSON.raw } | |
| +func (r *TextBlock) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r RedactedThinkingBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case RedactedThinkingBlockParamTypeRedactedThinking: | |
| - return true | |
| +func (r TextBlock) ToParam() TextBlockParam { | |
| + var p TextBlockParam | |
| + p.Type = r.Type | |
| + p.Text = r.Text | |
| + p.Citations = make([]TextCitationParamUnion, len(r.Citations)) | |
| + for i, citation := range r.Citations { | |
| + switch citationVariant := citation.AsAny().(type) { | |
| + case CitationCharLocation: | |
| + var citationParam CitationCharLocationParam | |
| + citationParam.Type = citationVariant.Type | |
| + citationParam.DocumentTitle = toParam(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle) | |
| + citationParam.CitedText = citationVariant.CitedText | |
| + citationParam.DocumentIndex = citationVariant.DocumentIndex | |
| + citationParam.EndCharIndex = citationVariant.EndCharIndex | |
| + citationParam.StartCharIndex = citationVariant.StartCharIndex | |
| + p.Citations[i] = TextCitationParamUnion{OfRequestCharLocationCitation: &citationParam} | |
| + case CitationPageLocation: | |
| + var citationParam CitationPageLocationParam | |
| + citationParam.Type = citationVariant.Type | |
| + citationParam.DocumentTitle = toParam(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle) | |
| + citationParam.DocumentIndex = citationVariant.DocumentIndex | |
| + citationParam.EndPageNumber = citationVariant.EndPageNumber | |
| + citationParam.StartPageNumber = citationVariant.StartPageNumber | |
| + p.Citations[i] = TextCitationParamUnion{OfRequestPageLocationCitation: &citationParam} | |
| + case CitationContentBlockLocation: | |
| + var citationParam CitationContentBlockLocationParam | |
| + citationParam.Type = citationVariant.Type | |
| + citationParam.DocumentTitle = toParam(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle) | |
| + citationParam.CitedText = citationVariant.CitedText | |
| + citationParam.DocumentIndex = citationVariant.DocumentIndex | |
| + citationParam.EndBlockIndex = citationVariant.EndBlockIndex | |
| + citationParam.StartBlockIndex = citationVariant.StartBlockIndex | |
| + p.Citations[i] = TextCitationParamUnion{OfRequestContentBlockLocationCitation: &citationParam} | |
| + } | |
| } | |
| - return false | |
| + return p | |
| } | |
| -type SignatureDelta struct { | |
| - Signature string `json:"signature,required"` | |
| - Type SignatureDeltaType `json:"type,required"` | |
| - JSON signatureDeltaJSON `json:"-"` | |
| +// The properties Text, Type are required. | |
| +type TextBlockParam struct { | |
| + Text string `json:"text,required"` | |
| + Citations []TextCitationParamUnion `json:"citations,omitzero"` | |
| + CacheControl CacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "text". | |
| + Type constant.Text `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +func NewTextBlock(text string) ContentBlockParamUnion { | |
| + return ContentBlockParamUnion{ | |
| + OfRequestTextBlock: &TextBlockParam{ | |
| + Text: text, | |
| + }, | |
| + } | |
| } | |
| -// signatureDeltaJSON contains the JSON metadata for the struct [SignatureDelta] | |
| -type signatureDeltaJSON struct { | |
| - Signature apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f TextBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r TextBlockParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow TextBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r *SignatureDelta) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +// TextCitationUnion contains all possible properties and values from | |
| +// [CitationCharLocation], [CitationPageLocation], [CitationContentBlockLocation]. | |
| +// | |
| +// Use the [TextCitationUnion.AsAny] method to switch on the variant. | |
| +// | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type TextCitationUnion struct { | |
| + CitedText string `json:"cited_text"` | |
| + DocumentIndex int64 `json:"document_index"` | |
| + DocumentTitle string `json:"document_title"` | |
| + // This field is from variant [CitationCharLocation]. | |
| + EndCharIndex int64 `json:"end_char_index"` | |
| + // This field is from variant [CitationCharLocation]. | |
| + StartCharIndex int64 `json:"start_char_index"` | |
| + // Any of "char_location", "page_location", "content_block_location". | |
| + Type string `json:"type"` | |
| + // This field is from variant [CitationPageLocation]. | |
| + EndPageNumber int64 `json:"end_page_number"` | |
| + // This field is from variant [CitationPageLocation]. | |
| + StartPageNumber int64 `json:"start_page_number"` | |
| + // This field is from variant [CitationContentBlockLocation]. | |
| + EndBlockIndex int64 `json:"end_block_index"` | |
| + // This field is from variant [CitationContentBlockLocation]. | |
| + StartBlockIndex int64 `json:"start_block_index"` | |
| + JSON struct { | |
| + CitedText resp.Field | |
| + DocumentIndex resp.Field | |
| + DocumentTitle resp.Field | |
| + EndCharIndex resp.Field | |
| + StartCharIndex resp.Field | |
| + Type resp.Field | |
| + EndPageNumber resp.Field | |
| + StartPageNumber resp.Field | |
| + EndBlockIndex resp.Field | |
| + StartBlockIndex resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| +// | |
| +// switch variant := TextCitationUnion.AsAny().(type) { | |
| +// case CitationCharLocation: | |
| +// case CitationPageLocation: | |
| +// case CitationContentBlockLocation: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u TextCitationUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "char_location": | |
| + return u.AsResponseCharLocationCitation() | |
| + case "page_location": | |
| + return u.AsResponsePageLocationCitation() | |
| + case "content_block_location": | |
| + return u.AsResponseContentBlockLocationCitation() | |
| + } | |
| + return nil | |
| } | |
| -func (r signatureDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u TextCitationUnion) AsResponseCharLocationCitation() (v CitationCharLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r SignatureDelta) implementsContentBlockDeltaEventDelta() {} | |
| - | |
| -type SignatureDeltaType string | |
| - | |
| -const ( | |
| - SignatureDeltaTypeSignatureDelta SignatureDeltaType = "signature_delta" | |
| -) | |
| - | |
| -func (r SignatureDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case SignatureDeltaTypeSignatureDelta: | |
| - return true | |
| - } | |
| - return false | |
| +func (u TextCitationUnion) AsResponsePageLocationCitation() (v CitationPageLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -type TextBlock struct { | |
| - // Citations supporting the text block. | |
| - // | |
| - // The type of citation returned will depend on the type of document being cited. | |
| - // Citing a PDF results in `page_location`, plain text results in `char_location`, | |
| - // and content document results in `content_block_location`. | |
| - Citations []TextCitation `json:"citations,required,nullable"` | |
| - Text string `json:"text,required"` | |
| - Type TextBlockType `json:"type,required"` | |
| - JSON textBlockJSON `json:"-"` | |
| +func (u TextCitationUnion) AsResponseContentBlockLocationCitation() (v CitationContentBlockLocation) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// textBlockJSON contains the JSON metadata for the struct [TextBlock] | |
| -type textBlockJSON struct { | |
| - Citations apijson.Field | |
| - Text apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| +// Returns the unmodified JSON received from the API | |
| +func (u TextCitationUnion) RawJSON() string { return u.JSON.raw } | |
| -func (r *TextBlock) UnmarshalJSON(data []byte) (err error) { | |
| +func (r *TextCitationUnion) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r textBlockJSON) RawJSON() string { | |
| - return r.raw | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type TextCitationParamUnion struct { | |
| + OfRequestCharLocationCitation *CitationCharLocationParam `json:",omitzero,inline"` | |
| + OfRequestPageLocationCitation *CitationPageLocationParam `json:",omitzero,inline"` | |
| + OfRequestContentBlockLocationCitation *CitationContentBlockLocationParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -func (r TextBlock) implementsContentBlock() {} | |
| - | |
| -func (r TextBlock) implementsContentBlockStartEventContentBlock() {} | |
| - | |
| -type TextBlockType string | |
| - | |
| -const ( | |
| - TextBlockTypeText TextBlockType = "text" | |
| -) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u TextCitationParamUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u TextCitationParamUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[TextCitationParamUnion](u.OfRequestCharLocationCitation, u.OfRequestPageLocationCitation, u.OfRequestContentBlockLocationCitation) | |
| +} | |
| -func (r TextBlockType) IsKnown() bool { | |
| - switch r { | |
| - case TextBlockTypeText: | |
| - return true | |
| +func (u *TextCitationParamUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfRequestCharLocationCitation) { | |
| + return u.OfRequestCharLocationCitation | |
| + } else if !param.IsOmitted(u.OfRequestPageLocationCitation) { | |
| + return u.OfRequestPageLocationCitation | |
| + } else if !param.IsOmitted(u.OfRequestContentBlockLocationCitation) { | |
| + return u.OfRequestContentBlockLocationCitation | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type TextBlockParam struct { | |
| - Text param.Field[string] `json:"text,required"` | |
| - Type param.Field[TextBlockParamType] `json:"type,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| - Citations param.Field[[]TextCitationParamUnion] `json:"citations"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetEndCharIndex() *int64 { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return &vt.EndCharIndex | |
| + } | |
| + return nil | |
| } | |
| -func NewTextBlock(text string) TextBlockParam { | |
| - return TextBlockParam{ | |
| - Text: F(text), | |
| - Type: F(TextBlockParamTypeText), | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetStartCharIndex() *int64 { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return &vt.StartCharIndex | |
| } | |
| + return nil | |
| } | |
| -func (r TextBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetEndPageNumber() *int64 { | |
| + if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return &vt.EndPageNumber | |
| + } | |
| + return nil | |
| } | |
| -func (r TextBlockParam) implementsContentBlockParamUnion() {} | |
| - | |
| -func (r TextBlockParam) implementsContentBlockSourceContentUnionParam() {} | |
| - | |
| -func (r TextBlockParam) implementsToolResultBlockParamContentUnion() {} | |
| - | |
| -type TextBlockParamType string | |
| - | |
| -const ( | |
| - TextBlockParamTypeText TextBlockParamType = "text" | |
| -) | |
| - | |
| -func (r TextBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case TextBlockParamTypeText: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetStartPageNumber() *int64 { | |
| + if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return &vt.StartPageNumber | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type TextCitation struct { | |
| - CitedText string `json:"cited_text,required"` | |
| - DocumentIndex int64 `json:"document_index,required"` | |
| - DocumentTitle string `json:"document_title,required,nullable"` | |
| - Type TextCitationType `json:"type,required"` | |
| - EndBlockIndex int64 `json:"end_block_index"` | |
| - EndCharIndex int64 `json:"end_char_index"` | |
| - EndPageNumber int64 `json:"end_page_number"` | |
| - StartBlockIndex int64 `json:"start_block_index"` | |
| - StartCharIndex int64 `json:"start_char_index"` | |
| - StartPageNumber int64 `json:"start_page_number"` | |
| - JSON textCitationJSON `json:"-"` | |
| - union TextCitationUnion | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetEndBlockIndex() *int64 { | |
| + if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return &vt.EndBlockIndex | |
| + } | |
| + return nil | |
| } | |
| -// textCitationJSON contains the JSON metadata for the struct [TextCitation] | |
| -type textCitationJSON struct { | |
| - CitedText apijson.Field | |
| - DocumentIndex apijson.Field | |
| - DocumentTitle apijson.Field | |
| - Type apijson.Field | |
| - EndBlockIndex apijson.Field | |
| - EndCharIndex apijson.Field | |
| - EndPageNumber apijson.Field | |
| - StartBlockIndex apijson.Field | |
| - StartCharIndex apijson.Field | |
| - StartPageNumber apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetStartBlockIndex() *int64 { | |
| + if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return &vt.StartBlockIndex | |
| + } | |
| + return nil | |
| } | |
| -func (r textCitationJSON) RawJSON() string { | |
| - return r.raw | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetCitedText() *string { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return (*string)(&vt.CitedText) | |
| + } else if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return (*string)(&vt.CitedText) | |
| + } else if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return (*string)(&vt.CitedText) | |
| + } | |
| + return nil | |
| } | |
| -func (r *TextCitation) UnmarshalJSON(data []byte) (err error) { | |
| - *r = TextCitation{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetDocumentIndex() *int64 { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return (*int64)(&vt.DocumentIndex) | |
| + } else if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return (*int64)(&vt.DocumentIndex) | |
| + } else if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return (*int64)(&vt.DocumentIndex) | |
| } | |
| - return apijson.Port(r.union, &r) | |
| + return nil | |
| } | |
| -// AsUnion returns a [TextCitationUnion] interface which you can cast to the | |
| -// specific types for more type safety. | |
| -// | |
| -// Possible runtime types of the union are [CitationCharLocation], | |
| -// [CitationPageLocation], [CitationContentBlockLocation]. | |
| -func (r TextCitation) AsUnion() TextCitationUnion { | |
| - return r.union | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetDocumentTitle() *string { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil && vt.DocumentTitle.IsPresent() { | |
| + return &vt.DocumentTitle.Value | |
| + } else if vt := u.OfRequestPageLocationCitation; vt != nil && vt.DocumentTitle.IsPresent() { | |
| + return &vt.DocumentTitle.Value | |
| + } else if vt := u.OfRequestContentBlockLocationCitation; vt != nil && vt.DocumentTitle.IsPresent() { | |
| + return &vt.DocumentTitle.Value | |
| + } | |
| + return nil | |
| } | |
| -// Union satisfied by [CitationCharLocation], [CitationPageLocation] or | |
| -// [CitationContentBlockLocation]. | |
| -type TextCitationUnion interface { | |
| - implementsTextCitation() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u TextCitationParamUnion) GetType() *string { | |
| + if vt := u.OfRequestCharLocationCitation; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestPageLocationCitation; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestContentBlockLocationCitation; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*TextCitationUnion)(nil)).Elem(), | |
| + apijson.RegisterUnion[TextCitationParamUnion]( | |
| "type", | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(CitationCharLocation{}), | |
| + Type: reflect.TypeOf(CitationCharLocationParam{}), | |
| DiscriminatorValue: "char_location", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(CitationPageLocation{}), | |
| + Type: reflect.TypeOf(CitationPageLocationParam{}), | |
| DiscriminatorValue: "page_location", | |
| }, | |
| apijson.UnionVariant{ | |
| TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(CitationContentBlockLocation{}), | |
| + Type: reflect.TypeOf(CitationContentBlockLocationParam{}), | |
| DiscriminatorValue: "content_block_location", | |
| }, | |
| ) | |
| } | |
| -type TextCitationType string | |
| - | |
| -const ( | |
| - TextCitationTypeCharLocation TextCitationType = "char_location" | |
| - TextCitationTypePageLocation TextCitationType = "page_location" | |
| - TextCitationTypeContentBlockLocation TextCitationType = "content_block_location" | |
| -) | |
| - | |
| -func (r TextCitationType) IsKnown() bool { | |
| - switch r { | |
| - case TextCitationTypeCharLocation, TextCitationTypePageLocation, TextCitationTypeContentBlockLocation: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -type TextCitationParam struct { | |
| - CitedText param.Field[string] `json:"cited_text,required"` | |
| - DocumentIndex param.Field[int64] `json:"document_index,required"` | |
| - DocumentTitle param.Field[string] `json:"document_title,required"` | |
| - Type param.Field[TextCitationParamType] `json:"type,required"` | |
| - EndBlockIndex param.Field[int64] `json:"end_block_index"` | |
| - EndCharIndex param.Field[int64] `json:"end_char_index"` | |
| - EndPageNumber param.Field[int64] `json:"end_page_number"` | |
| - StartBlockIndex param.Field[int64] `json:"start_block_index"` | |
| - StartCharIndex param.Field[int64] `json:"start_char_index"` | |
| - StartPageNumber param.Field[int64] `json:"start_page_number"` | |
| -} | |
| - | |
| -func (r TextCitationParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r TextCitationParam) implementsTextCitationParamUnion() {} | |
| - | |
| -// Satisfied by [CitationCharLocationParam], [CitationPageLocationParam], | |
| -// [CitationContentBlockLocationParam], [TextCitationParam]. | |
| -type TextCitationParamUnion interface { | |
| - implementsTextCitationParamUnion() | |
| -} | |
| - | |
| -type TextCitationParamType string | |
| - | |
| -const ( | |
| - TextCitationParamTypeCharLocation TextCitationParamType = "char_location" | |
| - TextCitationParamTypePageLocation TextCitationParamType = "page_location" | |
| - TextCitationParamTypeContentBlockLocation TextCitationParamType = "content_block_location" | |
| -) | |
| - | |
| -func (r TextCitationParamType) IsKnown() bool { | |
| - switch r { | |
| - case TextCitationParamTypeCharLocation, TextCitationParamTypePageLocation, TextCitationParamTypeContentBlockLocation: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type TextDelta struct { | |
| - Text string `json:"text,required"` | |
| - Type TextDeltaType `json:"type,required"` | |
| - JSON textDeltaJSON `json:"-"` | |
| -} | |
| - | |
| -// textDeltaJSON contains the JSON metadata for the struct [TextDelta] | |
| -type textDeltaJSON struct { | |
| - Text apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *TextDelta) UnmarshalJSON(data []byte) (err error) { | |
| + Text string `json:"text,required"` | |
| + Type constant.TextDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Text resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r TextDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *TextDelta) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r textDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r TextDelta) implementsContentBlockDeltaEventDelta() {} | |
| - | |
| -type TextDeltaType string | |
| - | |
| -const ( | |
| - TextDeltaTypeTextDelta TextDeltaType = "text_delta" | |
| -) | |
| - | |
| -func (r TextDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case TextDeltaTypeTextDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type ThinkingBlock struct { | |
| Signature string `json:"signature,required"` | |
| Thinking string `json:"thinking,required"` | |
| - Type ThinkingBlockType `json:"type,required"` | |
| - JSON thinkingBlockJSON `json:"-"` | |
| -} | |
| - | |
| -// thinkingBlockJSON contains the JSON metadata for the struct [ThinkingBlock] | |
| -type thinkingBlockJSON struct { | |
| - Signature apijson.Field | |
| - Thinking apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *ThinkingBlock) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.Thinking `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Signature resp.Field | |
| + Thinking resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r ThinkingBlock) RawJSON() string { return r.JSON.raw } | |
| +func (r *ThinkingBlock) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r thinkingBlockJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r ThinkingBlock) implementsContentBlock() {} | |
| - | |
| -func (r ThinkingBlock) implementsContentBlockStartEventContentBlock() {} | |
| - | |
| -type ThinkingBlockType string | |
| - | |
| -const ( | |
| - ThinkingBlockTypeThinking ThinkingBlockType = "thinking" | |
| -) | |
| - | |
| -func (r ThinkingBlockType) IsKnown() bool { | |
| - switch r { | |
| - case ThinkingBlockTypeThinking: | |
| - return true | |
| - } | |
| - return false | |
| +func (r ThinkingBlock) ToParam() ThinkingBlockParam { | |
| + var p ThinkingBlockParam | |
| + p.Type = r.Type | |
| + p.Signature = r.Signature | |
| + p.Thinking = r.Thinking | |
| + return p | |
| } | |
| +// The properties Signature, Thinking, Type are required. | |
| type ThinkingBlockParam struct { | |
| - Signature param.Field[string] `json:"signature,required"` | |
| - Thinking param.Field[string] `json:"thinking,required"` | |
| - Type param.Field[ThinkingBlockParamType] `json:"type,required"` | |
| + Signature string `json:"signature,required"` | |
| + Thinking string `json:"thinking,required"` | |
| + // This field can be elided, and will marshal its zero value as "thinking". | |
| + Type constant.Thinking `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ThinkingBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ThinkingBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ThinkingBlockParam) implementsContentBlockParamUnion() {} | |
| - | |
| -type ThinkingBlockParamType string | |
| - | |
| -const ( | |
| - ThinkingBlockParamTypeThinking ThinkingBlockParamType = "thinking" | |
| -) | |
| - | |
| -func (r ThinkingBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case ThinkingBlockParamTypeThinking: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow ThinkingBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The property Type is required. | |
| type ThinkingConfigDisabledParam struct { | |
| - Type param.Field[ThinkingConfigDisabledType] `json:"type,required"` | |
| + // This field can be elided, and will marshal its zero value as "disabled". | |
| + Type constant.Disabled `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ThinkingConfigDisabledParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ThinkingConfigDisabledParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ThinkingConfigDisabledParam) implementsThinkingConfigParamUnion() {} | |
| - | |
| -type ThinkingConfigDisabledType string | |
| - | |
| -const ( | |
| - ThinkingConfigDisabledTypeDisabled ThinkingConfigDisabledType = "disabled" | |
| -) | |
| - | |
| -func (r ThinkingConfigDisabledType) IsKnown() bool { | |
| - switch r { | |
| - case ThinkingConfigDisabledTypeDisabled: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow ThinkingConfigDisabledParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties BudgetTokens, Type are required. | |
| type ThinkingConfigEnabledParam struct { | |
| // Determines how many tokens Claude can use for its internal reasoning process. | |
| // Larger budgets can enable more thorough analysis for complex problems, improving | |
| @@ -2628,718 +2619,694 @@ type ThinkingConfigEnabledParam struct { | |
| // See | |
| // [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| // for details. | |
| - BudgetTokens param.Field[int64] `json:"budget_tokens,required"` | |
| - Type param.Field[ThinkingConfigEnabledType] `json:"type,required"` | |
| + BudgetTokens int64 `json:"budget_tokens,required"` | |
| + // This field can be elided, and will marshal its zero value as "enabled". | |
| + Type constant.Enabled `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ThinkingConfigEnabledParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ThinkingConfigEnabledParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow ThinkingConfigEnabledParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r ThinkingConfigEnabledParam) implementsThinkingConfigParamUnion() {} | |
| - | |
| -type ThinkingConfigEnabledType string | |
| - | |
| -const ( | |
| - ThinkingConfigEnabledTypeEnabled ThinkingConfigEnabledType = "enabled" | |
| -) | |
| - | |
| -func (r ThinkingConfigEnabledType) IsKnown() bool { | |
| - switch r { | |
| - case ThinkingConfigEnabledTypeEnabled: | |
| - return true | |
| - } | |
| - return false | |
| +func ThinkingConfigParamOfThinkingConfigEnabled(budgetTokens int64) ThinkingConfigParamUnion { | |
| + var variant ThinkingConfigEnabledParam | |
| + variant.BudgetTokens = budgetTokens | |
| + return ThinkingConfigParamUnion{OfThinkingConfigEnabled: &variant} | |
| } | |
| -// Configuration for enabling Claude's extended thinking. | |
| +// Only one field can be non-zero. | |
| // | |
| -// 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.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| -// for details. | |
| -type ThinkingConfigParam struct { | |
| - Type param.Field[ThinkingConfigParamType] `json:"type,required"` | |
| - // Determines how many tokens Claude can use for its internal reasoning process. | |
| - // Larger budgets can enable more thorough analysis for complex problems, improving | |
| - // response quality. | |
| - // | |
| - // Must be ≥1024 and less than `max_tokens`. | |
| - // | |
| - // See | |
| - // [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| - // for details. | |
| - BudgetTokens param.Field[int64] `json:"budget_tokens"` | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type ThinkingConfigParamUnion struct { | |
| + OfThinkingConfigEnabled *ThinkingConfigEnabledParam `json:",omitzero,inline"` | |
| + OfThinkingConfigDisabled *ThinkingConfigDisabledParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -func (r ThinkingConfigParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u ThinkingConfigParamUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u ThinkingConfigParamUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[ThinkingConfigParamUnion](u.OfThinkingConfigEnabled, u.OfThinkingConfigDisabled) | |
| } | |
| -func (r ThinkingConfigParam) implementsThinkingConfigParamUnion() {} | |
| - | |
| -// 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.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| -// for details. | |
| -// | |
| -// Satisfied by [ThinkingConfigEnabledParam], [ThinkingConfigDisabledParam], | |
| -// [ThinkingConfigParam]. | |
| -type ThinkingConfigParamUnion interface { | |
| - implementsThinkingConfigParamUnion() | |
| +func (u *ThinkingConfigParamUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfThinkingConfigEnabled) { | |
| + return u.OfThinkingConfigEnabled | |
| + } else if !param.IsOmitted(u.OfThinkingConfigDisabled) { | |
| + return u.OfThinkingConfigDisabled | |
| + } | |
| + return nil | |
| } | |
| -type ThinkingConfigParamType string | |
| - | |
| -const ( | |
| - ThinkingConfigParamTypeEnabled ThinkingConfigParamType = "enabled" | |
| - ThinkingConfigParamTypeDisabled ThinkingConfigParamType = "disabled" | |
| -) | |
| - | |
| -func (r ThinkingConfigParamType) IsKnown() bool { | |
| - switch r { | |
| - case ThinkingConfigParamTypeEnabled, ThinkingConfigParamTypeDisabled: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ThinkingConfigParamUnion) GetBudgetTokens() *int64 { | |
| + if vt := u.OfThinkingConfigEnabled; vt != nil { | |
| + return &vt.BudgetTokens | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type ThinkingDelta struct { | |
| - Thinking string `json:"thinking,required"` | |
| - Type ThinkingDeltaType `json:"type,required"` | |
| - JSON thinkingDeltaJSON `json:"-"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ThinkingConfigParamUnion) GetType() *string { | |
| + if vt := u.OfThinkingConfigEnabled; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfThinkingConfigDisabled; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| -// thinkingDeltaJSON contains the JSON metadata for the struct [ThinkingDelta] | |
| -type thinkingDeltaJSON struct { | |
| - Thinking apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func init() { | |
| + apijson.RegisterUnion[ThinkingConfigParamUnion]( | |
| + "type", | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(ThinkingConfigEnabledParam{}), | |
| + DiscriminatorValue: "enabled", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(ThinkingConfigDisabledParam{}), | |
| + DiscriminatorValue: "disabled", | |
| + }, | |
| + ) | |
| } | |
| -func (r *ThinkingDelta) UnmarshalJSON(data []byte) (err error) { | |
| +type ThinkingDelta struct { | |
| + Thinking string `json:"thinking,required"` | |
| + Type constant.ThinkingDelta `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Thinking resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r ThinkingDelta) RawJSON() string { return r.JSON.raw } | |
| +func (r *ThinkingDelta) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r thinkingDeltaJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r ThinkingDelta) implementsContentBlockDeltaEventDelta() {} | |
| - | |
| -type ThinkingDeltaType string | |
| - | |
| -const ( | |
| - ThinkingDeltaTypeThinkingDelta ThinkingDeltaType = "thinking_delta" | |
| -) | |
| - | |
| -func (r ThinkingDeltaType) IsKnown() bool { | |
| - switch r { | |
| - case ThinkingDeltaTypeThinkingDelta: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| +// The properties InputSchema, Name are required. | |
| type ToolParam struct { | |
| // [JSON schema](https://json-schema.org/draft/2020-12) for this tool's input. | |
| // | |
| // This defines the shape of the `input` that your tool accepts and that the model | |
| // will produce. | |
| - InputSchema param.Field[interface{}] `json:"input_schema,required"` | |
| + InputSchema ToolInputSchemaParam `json:"input_schema,omitzero,required"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[string] `json:"name,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| + Name string `json:"name,required"` | |
| // Description of what this tool does. | |
| // | |
| // Tool descriptions should be as detailed as possible. The more information that | |
| // the model has about what the tool is and how to use it, the better it will | |
| // perform. You can use natural language descriptions to reinforce important | |
| // aspects of the tool input JSON schema. | |
| - Description param.Field[string] `json:"description"` | |
| + Description param.Opt[string] `json:"description,omitzero"` | |
| + CacheControl CacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ToolParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow ToolParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r ToolParam) implementsMessageCountTokensToolUnionParam() {} | |
| - | |
| -func (r ToolParam) implementsToolUnionUnionParam() {} | |
| - | |
| // [JSON schema](https://json-schema.org/draft/2020-12) for this tool's input. | |
| // | |
| // This defines the shape of the `input` that your tool accepts and that the model | |
| // will produce. | |
| +// | |
| +// The property Type is required. | |
| type ToolInputSchemaParam struct { | |
| - Type param.Field[ToolInputSchemaType] `json:"type,required"` | |
| - Properties param.Field[interface{}] `json:"properties"` | |
| - ExtraFields map[string]interface{} `json:"-,extras"` | |
| -} | |
| - | |
| -func (r ToolInputSchemaParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + Properties interface{} `json:"properties,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "object". | |
| + Type constant.Object `json:"type,required"` | |
| + ExtraFields map[string]interface{} `json:"-,extras"` | |
| + paramObj | |
| } | |
| -type ToolInputSchemaType string | |
| - | |
| -const ( | |
| - ToolInputSchemaTypeObject ToolInputSchemaType = "object" | |
| -) | |
| - | |
| -func (r ToolInputSchemaType) IsKnown() bool { | |
| - switch r { | |
| - case ToolInputSchemaTypeObject: | |
| - return true | |
| - } | |
| - return false | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolInputSchemaParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| +func (r ToolInputSchemaParam) MarshalJSON() (data []byte, err error) { | |
| + type shadow ToolInputSchemaParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties Name, Type are required. | |
| type ToolBash20250124Param struct { | |
| + CacheControl CacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[ToolBash20250124Name] `json:"name,required"` | |
| - Type param.Field[ToolBash20250124Type] `json:"type,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| + // | |
| + // This field can be elided, and will marshal its zero value as "bash". | |
| + Name constant.Bash `json:"name,required"` | |
| + // This field can be elided, and will marshal its zero value as "bash_20250124". | |
| + Type constant.Bash20250124 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolBash20250124Param) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ToolBash20250124Param) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow ToolBash20250124Param | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r ToolBash20250124Param) implementsMessageCountTokensToolUnionParam() {} | |
| - | |
| -func (r ToolBash20250124Param) implementsToolUnionUnionParam() {} | |
| +func ToolChoiceParamOfToolChoiceTool(name string) ToolChoiceUnionParam { | |
| + var variant ToolChoiceToolParam | |
| + variant.Name = name | |
| + return ToolChoiceUnionParam{OfToolChoiceTool: &variant} | |
| +} | |
| -// Name of the tool. | |
| +// Only one field can be non-zero. | |
| // | |
| -// This is how the tool will be called by the model and in tool_use blocks. | |
| -type ToolBash20250124Name string | |
| - | |
| -const ( | |
| - ToolBash20250124NameBash ToolBash20250124Name = "bash" | |
| -) | |
| - | |
| -func (r ToolBash20250124Name) IsKnown() bool { | |
| - switch r { | |
| - case ToolBash20250124NameBash: | |
| - return true | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type ToolChoiceUnionParam struct { | |
| + OfToolChoiceAuto *ToolChoiceAutoParam `json:",omitzero,inline"` | |
| + OfToolChoiceAny *ToolChoiceAnyParam `json:",omitzero,inline"` | |
| + OfToolChoiceTool *ToolChoiceToolParam `json:",omitzero,inline"` | |
| + OfToolChoiceNone *ToolChoiceNoneParam `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u ToolChoiceUnionParam) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u ToolChoiceUnionParam) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[ToolChoiceUnionParam](u.OfToolChoiceAuto, u.OfToolChoiceAny, u.OfToolChoiceTool, u.OfToolChoiceNone) | |
| +} | |
| + | |
| +func (u *ToolChoiceUnionParam) asAny() any { | |
| + if !param.IsOmitted(u.OfToolChoiceAuto) { | |
| + return u.OfToolChoiceAuto | |
| + } else if !param.IsOmitted(u.OfToolChoiceAny) { | |
| + return u.OfToolChoiceAny | |
| + } else if !param.IsOmitted(u.OfToolChoiceTool) { | |
| + return u.OfToolChoiceTool | |
| + } else if !param.IsOmitted(u.OfToolChoiceNone) { | |
| + return u.OfToolChoiceNone | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type ToolBash20250124Type string | |
| - | |
| -const ( | |
| - ToolBash20250124TypeBash20250124 ToolBash20250124Type = "bash_20250124" | |
| -) | |
| - | |
| -func (r ToolBash20250124Type) IsKnown() bool { | |
| - switch r { | |
| - case ToolBash20250124TypeBash20250124: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolChoiceUnionParam) GetName() *string { | |
| + if vt := u.OfToolChoiceTool; vt != nil { | |
| + return &vt.Name | |
| } | |
| - return false | |
| -} | |
| - | |
| -// 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. | |
| -type ToolChoiceParam struct { | |
| - Type param.Field[ToolChoiceType] `json:"type,required"` | |
| - // Whether to disable parallel tool use. | |
| - // | |
| - // Defaults to `false`. If set to `true`, the model will output at most one tool | |
| - // use. | |
| - DisableParallelToolUse param.Field[bool] `json:"disable_parallel_tool_use"` | |
| - // The name of the tool to use. | |
| - Name param.Field[string] `json:"name"` | |
| + return nil | |
| } | |
| -func (r ToolChoiceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolChoiceUnionParam) GetType() *string { | |
| + if vt := u.OfToolChoiceAuto; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfToolChoiceAny; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfToolChoiceTool; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfToolChoiceNone; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| -func (r ToolChoiceParam) implementsToolChoiceUnionParam() {} | |
| - | |
| -// 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. | |
| -// | |
| -// Satisfied by [ToolChoiceAutoParam], [ToolChoiceAnyParam], [ToolChoiceToolParam], | |
| -// [ToolChoiceNoneParam], [ToolChoiceParam]. | |
| -type ToolChoiceUnionParam interface { | |
| - implementsToolChoiceUnionParam() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolChoiceUnionParam) GetDisableParallelToolUse() *bool { | |
| + if vt := u.OfToolChoiceAuto; vt != nil && vt.DisableParallelToolUse.IsPresent() { | |
| + return &vt.DisableParallelToolUse.Value | |
| + } else if vt := u.OfToolChoiceAny; vt != nil && vt.DisableParallelToolUse.IsPresent() { | |
| + return &vt.DisableParallelToolUse.Value | |
| + } else if vt := u.OfToolChoiceTool; vt != nil && vt.DisableParallelToolUse.IsPresent() { | |
| + return &vt.DisableParallelToolUse.Value | |
| + } | |
| + return nil | |
| } | |
| -type ToolChoiceType string | |
| - | |
| -const ( | |
| - ToolChoiceTypeAuto ToolChoiceType = "auto" | |
| - ToolChoiceTypeAny ToolChoiceType = "any" | |
| - ToolChoiceTypeTool ToolChoiceType = "tool" | |
| - ToolChoiceTypeNone ToolChoiceType = "none" | |
| -) | |
| - | |
| -func (r ToolChoiceType) IsKnown() bool { | |
| - switch r { | |
| - case ToolChoiceTypeAuto, ToolChoiceTypeAny, ToolChoiceTypeTool, ToolChoiceTypeNone: | |
| - return true | |
| - } | |
| - return false | |
| +func init() { | |
| + apijson.RegisterUnion[ToolChoiceUnionParam]( | |
| + "type", | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(ToolChoiceAutoParam{}), | |
| + DiscriminatorValue: "auto", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(ToolChoiceAnyParam{}), | |
| + DiscriminatorValue: "any", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(ToolChoiceToolParam{}), | |
| + DiscriminatorValue: "tool", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(ToolChoiceNoneParam{}), | |
| + DiscriminatorValue: "none", | |
| + }, | |
| + ) | |
| } | |
| // The model will use any available tools. | |
| +// | |
| +// The property Type is required. | |
| type ToolChoiceAnyParam struct { | |
| - Type param.Field[ToolChoiceAnyType] `json:"type,required"` | |
| // Whether to disable parallel tool use. | |
| // | |
| // Defaults to `false`. If set to `true`, the model will output exactly one tool | |
| // use. | |
| - DisableParallelToolUse param.Field[bool] `json:"disable_parallel_tool_use"` | |
| + DisableParallelToolUse param.Opt[bool] `json:"disable_parallel_tool_use,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "any". | |
| + Type constant.Any `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolChoiceAnyParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ToolChoiceAnyParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ToolChoiceAnyParam) implementsToolChoiceUnionParam() {} | |
| - | |
| -type ToolChoiceAnyType string | |
| - | |
| -const ( | |
| - ToolChoiceAnyTypeAny ToolChoiceAnyType = "any" | |
| -) | |
| - | |
| -func (r ToolChoiceAnyType) IsKnown() bool { | |
| - switch r { | |
| - case ToolChoiceAnyTypeAny: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow ToolChoiceAnyParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| // The model will automatically decide whether to use tools. | |
| +// | |
| +// The property Type is required. | |
| type ToolChoiceAutoParam struct { | |
| - Type param.Field[ToolChoiceAutoType] `json:"type,required"` | |
| // Whether to disable parallel tool use. | |
| // | |
| // Defaults to `false`. If set to `true`, the model will output at most one tool | |
| // use. | |
| - DisableParallelToolUse param.Field[bool] `json:"disable_parallel_tool_use"` | |
| + DisableParallelToolUse param.Opt[bool] `json:"disable_parallel_tool_use,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "auto". | |
| + Type constant.Auto `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolChoiceAutoParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ToolChoiceAutoParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ToolChoiceAutoParam) implementsToolChoiceUnionParam() {} | |
| - | |
| -type ToolChoiceAutoType string | |
| - | |
| -const ( | |
| - ToolChoiceAutoTypeAuto ToolChoiceAutoType = "auto" | |
| -) | |
| - | |
| -func (r ToolChoiceAutoType) IsKnown() bool { | |
| - switch r { | |
| - case ToolChoiceAutoTypeAuto: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow ToolChoiceAutoParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| // The model will not be allowed to use tools. | |
| +// | |
| +// The property Type is required. | |
| type ToolChoiceNoneParam struct { | |
| - Type param.Field[ToolChoiceNoneType] `json:"type,required"` | |
| + // This field can be elided, and will marshal its zero value as "none". | |
| + Type constant.None `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolChoiceNoneParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ToolChoiceNoneParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ToolChoiceNoneParam) implementsToolChoiceUnionParam() {} | |
| - | |
| -type ToolChoiceNoneType string | |
| - | |
| -const ( | |
| - ToolChoiceNoneTypeNone ToolChoiceNoneType = "none" | |
| -) | |
| - | |
| -func (r ToolChoiceNoneType) IsKnown() bool { | |
| - switch r { | |
| - case ToolChoiceNoneTypeNone: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow ToolChoiceNoneParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| // The model will use the specified tool with `tool_choice.name`. | |
| +// | |
| +// The properties Name, Type are required. | |
| type ToolChoiceToolParam struct { | |
| // The name of the tool to use. | |
| - Name param.Field[string] `json:"name,required"` | |
| - Type param.Field[ToolChoiceToolType] `json:"type,required"` | |
| + Name string `json:"name,required"` | |
| // Whether to disable parallel tool use. | |
| // | |
| // Defaults to `false`. If set to `true`, the model will output exactly one tool | |
| // use. | |
| - DisableParallelToolUse param.Field[bool] `json:"disable_parallel_tool_use"` | |
| + DisableParallelToolUse param.Opt[bool] `json:"disable_parallel_tool_use,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "tool". | |
| + Type constant.Tool `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolChoiceToolParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ToolChoiceToolParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ToolChoiceToolParam) implementsToolChoiceUnionParam() {} | |
| - | |
| -type ToolChoiceToolType string | |
| - | |
| -const ( | |
| - ToolChoiceToolTypeTool ToolChoiceToolType = "tool" | |
| -) | |
| - | |
| -func (r ToolChoiceToolType) IsKnown() bool { | |
| - switch r { | |
| - case ToolChoiceToolTypeTool: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow ToolChoiceToolParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties ToolUseID, Type are required. | |
| type ToolResultBlockParam struct { | |
| - ToolUseID param.Field[string] `json:"tool_use_id,required"` | |
| - Type param.Field[ToolResultBlockParamType] `json:"type,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| - Content param.Field[[]ToolResultBlockParamContentUnion] `json:"content"` | |
| - IsError param.Field[bool] `json:"is_error"` | |
| + ToolUseID string `json:"tool_use_id,required"` | |
| + IsError param.Opt[bool] `json:"is_error,omitzero"` | |
| + CacheControl CacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + Content []ToolResultBlockParamContentUnion `json:"content,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "tool_result". | |
| + Type constant.ToolResult `json:"type,required"` | |
| + paramObj | |
| } | |
| -func NewToolResultBlock(toolUseID string, content string, isError bool) ToolResultBlockParam { | |
| - return ToolResultBlockParam{ | |
| - Type: F(ToolResultBlockParamTypeToolResult), | |
| - ToolUseID: F(toolUseID), | |
| - Content: F([]ToolResultBlockParamContentUnion{NewTextBlock(content)}), | |
| - IsError: F(isError), | |
| +func NewToolResultBlock(toolUseID string, content string, isError bool) ContentBlockParamUnion { | |
| + blockParam := ToolResultBlockParam{ | |
| + ToolUseID: toolUseID, | |
| + Content: []ToolResultBlockParamContentUnion{{OfRequestTextBlock: &TextBlockParam{ | |
| + Text: content, | |
| + }}}, | |
| + IsError: Bool(isError), | |
| } | |
| + return ContentBlockParamUnion{OfRequestToolResultBlock: &blockParam} | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolResultBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ToolResultBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow ToolResultBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r ToolResultBlockParam) implementsContentBlockParamUnion() {} | |
| - | |
| -type ToolResultBlockParamType string | |
| +// Only one field can be non-zero. | |
| +// | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type ToolResultBlockParamContentUnion struct { | |
| + OfRequestTextBlock *TextBlockParam `json:",omitzero,inline"` | |
| + OfRequestImageBlock *ImageBlockParam `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| -const ( | |
| - ToolResultBlockParamTypeToolResult ToolResultBlockParamType = "tool_result" | |
| -) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u ToolResultBlockParamContentUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u ToolResultBlockParamContentUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[ToolResultBlockParamContentUnion](u.OfRequestTextBlock, u.OfRequestImageBlock) | |
| +} | |
| -func (r ToolResultBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case ToolResultBlockParamTypeToolResult: | |
| - return true | |
| +func (u *ToolResultBlockParamContentUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfRequestTextBlock) { | |
| + return u.OfRequestTextBlock | |
| + } else if !param.IsOmitted(u.OfRequestImageBlock) { | |
| + return u.OfRequestImageBlock | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type ToolResultBlockParamContent struct { | |
| - Type param.Field[ToolResultBlockParamContentType] `json:"type,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| - Citations param.Field[interface{}] `json:"citations"` | |
| - Source param.Field[interface{}] `json:"source"` | |
| - Text param.Field[string] `json:"text"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolResultBlockParamContentUnion) GetText() *string { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return &vt.Text | |
| + } | |
| + return nil | |
| } | |
| -func (r ToolResultBlockParamContent) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolResultBlockParamContentUnion) GetCitations() []TextCitationParamUnion { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return vt.Citations | |
| + } | |
| + return nil | |
| } | |
| -func (r ToolResultBlockParamContent) implementsToolResultBlockParamContentUnion() {} | |
| - | |
| -// Satisfied by [TextBlockParam], [ImageBlockParam], [ToolResultBlockParamContent]. | |
| -type ToolResultBlockParamContentUnion interface { | |
| - implementsToolResultBlockParamContentUnion() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolResultBlockParamContentUnion) GetSource() *ImageBlockParamSourceUnion { | |
| + if vt := u.OfRequestImageBlock; vt != nil { | |
| + return &vt.Source | |
| + } | |
| + return nil | |
| } | |
| -type ToolResultBlockParamContentType string | |
| - | |
| -const ( | |
| - ToolResultBlockParamContentTypeText ToolResultBlockParamContentType = "text" | |
| - ToolResultBlockParamContentTypeImage ToolResultBlockParamContentType = "image" | |
| -) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolResultBlockParamContentUnion) GetType() *string { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfRequestImageBlock; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| +} | |
| -func (r ToolResultBlockParamContentType) IsKnown() bool { | |
| - switch r { | |
| - case ToolResultBlockParamContentTypeText, ToolResultBlockParamContentTypeImage: | |
| - return true | |
| +// Returns a pointer to the underlying variant's CacheControl property, if present. | |
| +func (u ToolResultBlockParamContentUnion) GetCacheControl() *CacheControlEphemeralParam { | |
| + if vt := u.OfRequestTextBlock; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfRequestImageBlock; vt != nil { | |
| + return &vt.CacheControl | |
| } | |
| - return false | |
| + return nil | |
| +} | |
| + | |
| +func init() { | |
| + apijson.RegisterUnion[ToolResultBlockParamContentUnion]( | |
| + "type", | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(TextBlockParam{}), | |
| + DiscriminatorValue: "text", | |
| + }, | |
| + apijson.UnionVariant{ | |
| + TypeFilter: gjson.JSON, | |
| + Type: reflect.TypeOf(ImageBlockParam{}), | |
| + DiscriminatorValue: "image", | |
| + }, | |
| + ) | |
| } | |
| +// The properties Name, Type are required. | |
| type ToolTextEditor20250124Param struct { | |
| + CacheControl CacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| // Name of the tool. | |
| // | |
| // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[ToolTextEditor20250124Name] `json:"name,required"` | |
| - Type param.Field[ToolTextEditor20250124Type] `json:"type,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| + // | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "str_replace_editor". | |
| + Name constant.StrReplaceEditor `json:"name,required"` | |
| + // This field can be elided, and will marshal its zero value as | |
| + // "text_editor_20250124". | |
| + Type constant.TextEditor20250124 `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolTextEditor20250124Param) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ToolTextEditor20250124Param) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow ToolTextEditor20250124Param | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -func (r ToolTextEditor20250124Param) implementsMessageCountTokensToolUnionParam() {} | |
| - | |
| -func (r ToolTextEditor20250124Param) implementsToolUnionUnionParam() {} | |
| +func ToolUnionParamOfTool(inputSchema ToolInputSchemaParam, name string) ToolUnionParam { | |
| + var variant ToolParam | |
| + variant.InputSchema = inputSchema | |
| + variant.Name = name | |
| + return ToolUnionParam{OfTool: &variant} | |
| +} | |
| -// Name of the tool. | |
| +// Only one field can be non-zero. | |
| // | |
| -// This is how the tool will be called by the model and in tool_use blocks. | |
| -type ToolTextEditor20250124Name string | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type ToolUnionParam struct { | |
| + OfTool *ToolParam `json:",omitzero,inline"` | |
| + OfBashTool20250124 *ToolBash20250124Param `json:",omitzero,inline"` | |
| + OfTextEditor20250124 *ToolTextEditor20250124Param `json:",omitzero,inline"` | |
| + paramUnion | |
| +} | |
| -const ( | |
| - ToolTextEditor20250124NameStrReplaceEditor ToolTextEditor20250124Name = "str_replace_editor" | |
| -) | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u ToolUnionParam) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() } | |
| +func (u ToolUnionParam) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[ToolUnionParam](u.OfTool, u.OfBashTool20250124, u.OfTextEditor20250124) | |
| +} | |
| -func (r ToolTextEditor20250124Name) IsKnown() bool { | |
| - switch r { | |
| - case ToolTextEditor20250124NameStrReplaceEditor: | |
| - return true | |
| +func (u *ToolUnionParam) asAny() any { | |
| + if !param.IsOmitted(u.OfTool) { | |
| + return u.OfTool | |
| + } else if !param.IsOmitted(u.OfBashTool20250124) { | |
| + return u.OfBashTool20250124 | |
| + } else if !param.IsOmitted(u.OfTextEditor20250124) { | |
| + return u.OfTextEditor20250124 | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type ToolTextEditor20250124Type string | |
| - | |
| -const ( | |
| - ToolTextEditor20250124TypeTextEditor20250124 ToolTextEditor20250124Type = "text_editor_20250124" | |
| -) | |
| - | |
| -func (r ToolTextEditor20250124Type) IsKnown() bool { | |
| - switch r { | |
| - case ToolTextEditor20250124TypeTextEditor20250124: | |
| - return true | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolUnionParam) GetInputSchema() *ToolInputSchemaParam { | |
| + if vt := u.OfTool; vt != nil { | |
| + return &vt.InputSchema | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type ToolUnionParam struct { | |
| - // Name of the tool. | |
| - // | |
| - // This is how the tool will be called by the model and in tool_use blocks. | |
| - Name param.Field[string] `json:"name,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| - // Description of what this tool does. | |
| - // | |
| - // Tool descriptions should be as detailed as possible. The more information that | |
| - // the model has about what the tool is and how to use it, the better it will | |
| - // perform. You can use natural language descriptions to reinforce important | |
| - // aspects of the tool input JSON schema. | |
| - Description param.Field[string] `json:"description"` | |
| - InputSchema param.Field[interface{}] `json:"input_schema"` | |
| - Type param.Field[ToolUnionType] `json:"type"` | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolUnionParam) GetDescription() *string { | |
| + if vt := u.OfTool; vt != nil && vt.Description.IsPresent() { | |
| + return &vt.Description.Value | |
| + } | |
| + return nil | |
| } | |
| -func (r ToolUnionParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolUnionParam) GetName() *string { | |
| + if vt := u.OfTool; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return (*string)(&vt.Name) | |
| + } | |
| + return nil | |
| } | |
| -func (r ToolUnionParam) implementsToolUnionUnionParam() {} | |
| - | |
| -// Satisfied by [ToolParam], [ToolBash20250124Param], | |
| -// [ToolTextEditor20250124Param], [ToolUnionParam]. | |
| -type ToolUnionUnionParam interface { | |
| - implementsToolUnionUnionParam() | |
| +// Returns a pointer to the underlying variant's property, if present. | |
| +func (u ToolUnionParam) GetType() *string { | |
| + if vt := u.OfBashTool20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return (*string)(&vt.Type) | |
| + } | |
| + return nil | |
| } | |
| -type ToolUnionType string | |
| - | |
| -const ( | |
| - ToolUnionTypeBash20250124 ToolUnionType = "bash_20250124" | |
| - ToolUnionTypeTextEditor20250124 ToolUnionType = "text_editor_20250124" | |
| -) | |
| - | |
| -func (r ToolUnionType) IsKnown() bool { | |
| - switch r { | |
| - case ToolUnionTypeBash20250124, ToolUnionTypeTextEditor20250124: | |
| - return true | |
| +// Returns a pointer to the underlying variant's CacheControl property, if present. | |
| +func (u ToolUnionParam) GetCacheControl() *CacheControlEphemeralParam { | |
| + if vt := u.OfTool; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfBashTool20250124; vt != nil { | |
| + return &vt.CacheControl | |
| + } else if vt := u.OfTextEditor20250124; vt != nil { | |
| + return &vt.CacheControl | |
| } | |
| - return false | |
| + return nil | |
| } | |
| type ToolUseBlock struct { | |
| ID string `json:"id,required"` | |
| Input json.RawMessage `json:"input,required"` | |
| Name string `json:"name,required"` | |
| - Type ToolUseBlockType `json:"type,required"` | |
| - JSON toolUseBlockJSON `json:"-"` | |
| -} | |
| - | |
| -// toolUseBlockJSON contains the JSON metadata for the struct [ToolUseBlock] | |
| -type toolUseBlockJSON struct { | |
| - ID apijson.Field | |
| - Input apijson.Field | |
| - Name apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *ToolUseBlock) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.ToolUse `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + Input resp.Field | |
| + Name resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r ToolUseBlock) RawJSON() string { return r.JSON.raw } | |
| +func (r *ToolUseBlock) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r toolUseBlockJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r ToolUseBlock) implementsContentBlock() {} | |
| - | |
| -func (r ToolUseBlock) implementsContentBlockStartEventContentBlock() {} | |
| - | |
| -type ToolUseBlockType string | |
| - | |
| -const ( | |
| - ToolUseBlockTypeToolUse ToolUseBlockType = "tool_use" | |
| -) | |
| - | |
| -func (r ToolUseBlockType) IsKnown() bool { | |
| - switch r { | |
| - case ToolUseBlockTypeToolUse: | |
| - return true | |
| - } | |
| - return false | |
| +func (r ToolUseBlock) ToParam() ToolUseBlockParam { | |
| + var toolUse ToolUseBlockParam | |
| + toolUse.Type = r.Type | |
| + toolUse.ID = r.ID | |
| + toolUse.Input = r.Input | |
| + toolUse.Name = r.Name | |
| + return toolUse | |
| } | |
| +// The properties ID, Input, Name, Type are required. | |
| type ToolUseBlockParam struct { | |
| - ID param.Field[string] `json:"id,required"` | |
| - Input param.Field[interface{}] `json:"input,required"` | |
| - Name param.Field[string] `json:"name,required"` | |
| - Type param.Field[ToolUseBlockParamType] `json:"type,required"` | |
| - CacheControl param.Field[CacheControlEphemeralParam] `json:"cache_control"` | |
| -} | |
| - | |
| -func NewToolUseBlockParam(id string, name string, input interface{}) ToolUseBlockParam { | |
| - return ToolUseBlockParam{ | |
| - ID: F(id), | |
| - Input: F(input), | |
| - Name: F(name), | |
| - Type: F(ToolUseBlockParamTypeToolUse), | |
| - } | |
| -} | |
| - | |
| + ID string `json:"id,required"` | |
| + Input interface{} `json:"input,omitzero,required"` | |
| + Name string `json:"name,required"` | |
| + CacheControl CacheControlEphemeralParam `json:"cache_control,omitzero"` | |
| + // This field can be elided, and will marshal its zero value as "tool_use". | |
| + Type constant.ToolUse `json:"type,required"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ToolUseBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r ToolUseBlockParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r ToolUseBlockParam) implementsContentBlockParamUnion() {} | |
| - | |
| -type ToolUseBlockParamType string | |
| - | |
| -const ( | |
| - ToolUseBlockParamTypeToolUse ToolUseBlockParamType = "tool_use" | |
| -) | |
| - | |
| -func (r ToolUseBlockParamType) IsKnown() bool { | |
| - switch r { | |
| - case ToolUseBlockParamTypeToolUse: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow ToolUseBlockParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties Type, URL are required. | |
| type URLImageSourceParam struct { | |
| - Type param.Field[URLImageSourceType] `json:"type,required"` | |
| - URL param.Field[string] `json:"url,required"` | |
| + URL string `json:"url,required"` | |
| + // This field can be elided, and will marshal its zero value as "url". | |
| + Type constant.URL `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f URLImageSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r URLImageSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r URLImageSourceParam) implementsImageBlockParamSourceUnion() {} | |
| - | |
| -type URLImageSourceType string | |
| - | |
| -const ( | |
| - URLImageSourceTypeURL URLImageSourceType = "url" | |
| -) | |
| - | |
| -func (r URLImageSourceType) IsKnown() bool { | |
| - switch r { | |
| - case URLImageSourceTypeURL: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow URLImageSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties Type, URL are required. | |
| type URLPDFSourceParam struct { | |
| - Type param.Field[URLPDFSourceType] `json:"type,required"` | |
| - URL param.Field[string] `json:"url,required"` | |
| + URL string `json:"url,required"` | |
| + // This field can be elided, and will marshal its zero value as "url". | |
| + Type constant.URL `json:"type,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f URLPDFSourceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r URLPDFSourceParam) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| -} | |
| - | |
| -func (r URLPDFSourceParam) implementsDocumentBlockParamSourceUnion() {} | |
| - | |
| -type URLPDFSourceType string | |
| - | |
| -const ( | |
| - URLPDFSourceTypeURL URLPDFSourceType = "url" | |
| -) | |
| - | |
| -func (r URLPDFSourceType) IsKnown() bool { | |
| - switch r { | |
| - case URLPDFSourceTypeURL: | |
| - return true | |
| - } | |
| - return false | |
| + type shadow URLPDFSourceParam | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type Usage struct { | |
| // The number of input tokens used to create the cache entry. | |
| - CacheCreationInputTokens int64 `json:"cache_creation_input_tokens,required,nullable"` | |
| + CacheCreationInputTokens int64 `json:"cache_creation_input_tokens,required"` | |
| // The number of input tokens read from the cache. | |
| - CacheReadInputTokens int64 `json:"cache_read_input_tokens,required,nullable"` | |
| + CacheReadInputTokens int64 `json:"cache_read_input_tokens,required"` | |
| // The number of input tokens which were used. | |
| InputTokens int64 `json:"input_tokens,required"` | |
| // The number of output tokens which were used. | |
| - OutputTokens int64 `json:"output_tokens,required"` | |
| - JSON usageJSON `json:"-"` | |
| -} | |
| - | |
| -// usageJSON contains the JSON metadata for the struct [Usage] | |
| -type usageJSON struct { | |
| - CacheCreationInputTokens apijson.Field | |
| - CacheReadInputTokens apijson.Field | |
| - InputTokens apijson.Field | |
| - OutputTokens apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *Usage) UnmarshalJSON(data []byte) (err error) { | |
| + OutputTokens int64 `json:"output_tokens,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CacheCreationInputTokens resp.Field | |
| + CacheReadInputTokens resp.Field | |
| + InputTokens resp.Field | |
| + OutputTokens resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r Usage) RawJSON() string { return r.JSON.raw } | |
| +func (r *Usage) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r usageJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| type MessageNewParams struct { | |
| // The maximum number of tokens to generate before stopping. | |
| // | |
| @@ -3348,7 +3315,7 @@ type MessageNewParams struct { | |
| // | |
| // Different models have different maximum values for this parameter. See | |
| // [models](https://docs.anthropic.com/en/docs/models-overview) for details. | |
| - MaxTokens param.Field[int64] `json:"max_tokens,required"` | |
| + MaxTokens int64 `json:"max_tokens,required"` | |
| // Input messages. | |
| // | |
| // Our models are trained to operate on alternating `user` and `assistant` | |
| @@ -3441,13 +3408,40 @@ type MessageNewParams struct { | |
| // [system prompt](https://docs.anthropic.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. | |
| - Messages param.Field[[]MessageParam] `json:"messages,required"` | |
| + Messages []MessageParam `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 param.Field[Model] `json:"model,required"` | |
| + Model Model `json:"model,omitzero,required"` | |
| + // 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"` | |
| // An object describing metadata about the request. | |
| - Metadata param.Field[MetadataParam] `json:"metadata"` | |
| + Metadata MetadataParam `json:"metadata,omitzero"` | |
| // Custom text sequences that will cause the model to stop generating. | |
| // | |
| // Our models will normally stop when they have naturally completed their turn, | |
| @@ -3457,22 +3451,13 @@ type MessageNewParams struct { | |
| // 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 param.Field[[]string] `json:"stop_sequences"` | |
| + 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.anthropic.com/en/docs/system-prompts). | |
| - System param.Field[[]TextBlockParam] `json:"system"` | |
| - // 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.Field[float64] `json:"temperature"` | |
| + System []TextBlockParam `json:"system,omitzero"` | |
| // Configuration for enabling Claude's extended thinking. | |
| // | |
| // When enabled, responses include `thinking` content blocks showing Claude's | |
| @@ -3482,10 +3467,10 @@ type MessageNewParams struct { | |
| // See | |
| // [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| // for details. | |
| - Thinking param.Field[ThinkingConfigParamUnion] `json:"thinking"` | |
| + Thinking ThinkingConfigParamUnion `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 param.Field[ToolChoiceUnionParam] `json:"tool_choice"` | |
| + ToolChoice ToolChoiceUnionParam `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` | |
| @@ -3561,29 +3546,17 @@ type MessageNewParams struct { | |
| // JSON structure of output. | |
| // | |
| // See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details. | |
| - Tools param.Field[[]ToolUnionUnionParam] `json:"tools"` | |
| - // 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.Field[int64] `json:"top_k"` | |
| - // 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.Field[float64] `json:"top_p"` | |
| + Tools []ToolUnionParam `json:"tools,omitzero"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f MessageNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| func (r MessageNewParams) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow MessageNewParams | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type MessageCountTokensParams struct { | |
| @@ -3679,17 +3652,17 @@ type MessageCountTokensParams struct { | |
| // [system prompt](https://docs.anthropic.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. | |
| - Messages param.Field[[]MessageParam] `json:"messages,required"` | |
| + Messages []MessageParam `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 param.Field[Model] `json:"model,required"` | |
| + Model Model `json:"model,omitzero,required"` | |
| // 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.anthropic.com/en/docs/system-prompts). | |
| - System param.Field[MessageCountTokensParamsSystemUnion] `json:"system"` | |
| + System MessageCountTokensParamsSystemUnion `json:"system,omitzero"` | |
| // Configuration for enabling Claude's extended thinking. | |
| // | |
| // When enabled, responses include `thinking` content blocks showing Claude's | |
| @@ -3699,10 +3672,10 @@ type MessageCountTokensParams struct { | |
| // See | |
| // [extended thinking](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| // for details. | |
| - Thinking param.Field[ThinkingConfigParamUnion] `json:"thinking"` | |
| + Thinking ThinkingConfigParamUnion `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 param.Field[ToolChoiceUnionParam] `json:"tool_choice"` | |
| + ToolChoice ToolChoiceUnionParam `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` | |
| @@ -3778,24 +3751,42 @@ type MessageCountTokensParams struct { | |
| // JSON structure of output. | |
| // | |
| // See our [guide](https://docs.anthropic.com/en/docs/tool-use) for more details. | |
| - Tools param.Field[[]MessageCountTokensToolUnionParam] `json:"tools"` | |
| + Tools []MessageCountTokensToolUnionParam `json:"tools,omitzero"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f MessageCountTokensParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| func (r MessageCountTokensParams) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow MessageCountTokensParams | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| -// System prompt. | |
| +// Only one field can be non-zero. | |
| // | |
| -// 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.anthropic.com/en/docs/system-prompts). | |
| -// | |
| -// Satisfied by [shared.UnionString], [MessageCountTokensParamsSystemArray]. | |
| -type MessageCountTokensParamsSystemUnion interface { | |
| - ImplementsMessageCountTokensParamsSystemUnion() | |
| +// Use [param.IsOmitted] to confirm if a field is set. | |
| +type MessageCountTokensParamsSystemUnion struct { | |
| + OfString param.Opt[string] `json:",omitzero,inline"` | |
| + OfMessageCountTokenssSystemArray []TextBlockParam `json:",omitzero,inline"` | |
| + paramUnion | |
| } | |
| -type MessageCountTokensParamsSystemArray []TextBlockParam | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (u MessageCountTokensParamsSystemUnion) IsPresent() bool { | |
| + return !param.IsOmitted(u) && !u.IsNull() | |
| +} | |
| +func (u MessageCountTokensParamsSystemUnion) MarshalJSON() ([]byte, error) { | |
| + return param.MarshalUnion[MessageCountTokensParamsSystemUnion](u.OfString, u.OfMessageCountTokenssSystemArray) | |
| +} | |
| -func (r MessageCountTokensParamsSystemArray) ImplementsMessageCountTokensParamsSystemUnion() {} | |
| +func (u *MessageCountTokensParamsSystemUnion) asAny() any { | |
| + if !param.IsOmitted(u.OfString) { | |
| + return &u.OfString.Value | |
| + } else if !param.IsOmitted(u.OfMessageCountTokenssSystemArray) { | |
| + return &u.OfMessageCountTokenssSystemArray | |
| + } | |
| + return nil | |
| +} | |
| diff --git a/message_test.go b/message_test.go | |
| index 2791ec3..2d8f749 100644 | |
| --- a/message_test.go | |
| +++ b/message_test.go | |
| @@ -6,9 +6,7 @@ import ( | |
| "context" | |
| "errors" | |
| "os" | |
| - "strings" | |
| "testing" | |
| - "time" | |
| "github.com/anthropics/anthropic-sdk-go" | |
| "github.com/anthropics/anthropic-sdk-go/internal/testutil" | |
| @@ -28,48 +26,55 @@ func TestMessageNewWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - Metadata: anthropic.F(anthropic.MetadataParam{ | |
| - UserID: anthropic.F("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| - }), | |
| - StopSequences: anthropic.F([]string{"string"}), | |
| - System: anthropic.F([]anthropic.TextBlockParam{{Text: anthropic.F("x"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - Temperature: anthropic.F(1.000000), | |
| - Thinking: anthropic.F[anthropic.ThinkingConfigParamUnion](anthropic.ThinkingConfigEnabledParam{ | |
| - BudgetTokens: anthropic.F(int64(1024)), | |
| - Type: anthropic.F(anthropic.ThinkingConfigEnabledTypeEnabled), | |
| - }), | |
| - ToolChoice: anthropic.F[anthropic.ToolChoiceUnionParam](anthropic.ToolChoiceAutoParam{ | |
| - Type: anthropic.F(anthropic.ToolChoiceAutoTypeAuto), | |
| - DisableParallelToolUse: anthropic.F(true), | |
| - }), | |
| - Tools: anthropic.F([]anthropic.ToolUnionUnionParam{anthropic.ToolParam{ | |
| - Description: anthropic.F("Get the current weather in a given location"), | |
| - Name: anthropic.F("x"), | |
| - InputSchema: anthropic.F[interface{}](map[string]interface{}{ | |
| - "type": "object", | |
| - "properties": map[string]interface{}{ | |
| - "location": map[string]interface{}{ | |
| - "description": "The city and state, e.g. San Francisco, CA", | |
| - "type": "string", | |
| - }, | |
| - "unit": map[string]interface{}{ | |
| - "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| - "type": "string", | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + Role: anthropic.MessageParamRoleUser, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + Metadata: anthropic.MetadataParam{ | |
| + UserID: anthropic.String("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| + }, | |
| + StopSequences: []string{"string"}, | |
| + System: []anthropic.TextBlockParam{{Text: "x", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}}, | |
| + Temperature: anthropic.Float(1), | |
| + Thinking: anthropic.ThinkingConfigParamUnion{ | |
| + OfThinkingConfigEnabled: &anthropic.ThinkingConfigEnabledParam{ | |
| + BudgetTokens: 1024, | |
| + }, | |
| + }, | |
| + ToolChoice: anthropic.ToolChoiceUnionParam{ | |
| + OfToolChoiceAuto: &anthropic.ToolChoiceAutoParam{ | |
| + DisableParallelToolUse: anthropic.Bool(true), | |
| + }, | |
| + }, | |
| + Tools: []anthropic.ToolUnionParam{{ | |
| + OfTool: &anthropic.ToolParam{ | |
| + InputSchema: anthropic.ToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| + "location": map[string]interface{}{ | |
| + "description": "The city and state, e.g. San Francisco, CA", | |
| + "type": "string", | |
| + }, | |
| + "unit": map[string]interface{}{ | |
| + "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| + "type": "string", | |
| + }, | |
| }, | |
| }, | |
| - }), | |
| - CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{ | |
| - Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral), | |
| - }), | |
| - }}), | |
| - TopK: anthropic.F(int64(5)), | |
| - TopP: anthropic.F(0.700000), | |
| + Name: "name", | |
| + CacheControl: anthropic.CacheControlEphemeralParam{}, | |
| + Description: anthropic.String("Get the current weather in a given location"), | |
| + }, | |
| + }}, | |
| + TopK: anthropic.Int(5), | |
| + TopP: anthropic.Float(0.7), | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| @@ -93,54 +98,59 @@ func TestMessageCountTokensWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Messages.CountTokens(context.TODO(), anthropic.MessageCountTokensParams{ | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - System: anthropic.F[anthropic.MessageCountTokensParamsSystemUnion](anthropic.MessageCountTokensParamsSystemArray([]anthropic.TextBlockParam{{ | |
| - Text: anthropic.F("Today's date is 2024-06-01."), | |
| - Type: anthropic.F(anthropic.TextBlockParamTypeText), | |
| - CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{ | |
| - Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral), | |
| - }), | |
| - Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{ | |
| - CitedText: anthropic.F("cited_text"), | |
| - DocumentIndex: anthropic.F(int64(0)), | |
| - DocumentTitle: anthropic.F("x"), | |
| - EndCharIndex: anthropic.F(int64(0)), | |
| - StartCharIndex: anthropic.F(int64(0)), | |
| - Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation), | |
| - }}), | |
| - }})), | |
| - Thinking: anthropic.F[anthropic.ThinkingConfigParamUnion](anthropic.ThinkingConfigEnabledParam{ | |
| - BudgetTokens: anthropic.F(int64(1024)), | |
| - Type: anthropic.F(anthropic.ThinkingConfigEnabledTypeEnabled), | |
| - }), | |
| - ToolChoice: anthropic.F[anthropic.ToolChoiceUnionParam](anthropic.ToolChoiceAutoParam{ | |
| - Type: anthropic.F(anthropic.ToolChoiceAutoTypeAuto), | |
| - DisableParallelToolUse: anthropic.F(true), | |
| - }), | |
| - Tools: anthropic.F([]anthropic.MessageCountTokensToolUnionParam{anthropic.ToolParam{ | |
| - InputSchema: anthropic.F[interface{}](map[string]interface{}{ | |
| - "type": "object", | |
| - "properties": map[string]interface{}{ | |
| - "location": map[string]interface{}{ | |
| - "description": "The city and state, e.g. San Francisco, CA", | |
| - "type": "string", | |
| + Messages: []anthropic.MessageParam{{ | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + Role: anthropic.MessageParamRoleUser, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + System: anthropic.MessageCountTokensParamsSystemUnion{ | |
| + OfMessageCountTokenssSystemArray: []anthropic.TextBlockParam{{ | |
| + Text: "Today's date is 2024-06-01.", | |
| + CacheControl: anthropic.CacheControlEphemeralParam{}, | |
| + Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{ | |
| + CitedText: "cited_text", | |
| + DocumentIndex: 0, | |
| + DocumentTitle: anthropic.String("x"), | |
| + EndCharIndex: 0, | |
| + StartCharIndex: 0, | |
| }, | |
| - "unit": map[string]interface{}{ | |
| - "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| - "type": "string", | |
| + }}, | |
| + }}, | |
| + }, | |
| + Thinking: anthropic.ThinkingConfigParamUnion{ | |
| + OfThinkingConfigEnabled: &anthropic.ThinkingConfigEnabledParam{ | |
| + BudgetTokens: 1024, | |
| + }, | |
| + }, | |
| + ToolChoice: anthropic.ToolChoiceUnionParam{ | |
| + OfToolChoiceAuto: &anthropic.ToolChoiceAutoParam{ | |
| + DisableParallelToolUse: anthropic.Bool(true), | |
| + }, | |
| + }, | |
| + Tools: []anthropic.MessageCountTokensToolUnionParam{{ | |
| + OfTool: &anthropic.ToolParam{ | |
| + InputSchema: anthropic.ToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| + "location": map[string]interface{}{ | |
| + "description": "The city and state, e.g. San Francisco, CA", | |
| + "type": "string", | |
| + }, | |
| + "unit": map[string]interface{}{ | |
| + "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| + "type": "string", | |
| + }, | |
| }, | |
| }, | |
| - }), | |
| - Name: anthropic.F("name"), | |
| - CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{ | |
| - Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral), | |
| - }), | |
| - Description: anthropic.F("Get the current weather in a given location"), | |
| - }}), | |
| + Name: "name", | |
| + CacheControl: anthropic.CacheControlEphemeralParam{}, | |
| + Description: anthropic.String("Get the current weather in a given location"), | |
| + }, | |
| + }}, | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| @@ -150,62 +160,3 @@ func TestMessageCountTokensWithOptionalParams(t *testing.T) { | |
| t.Fatalf("err should be nil: %s", err.Error()) | |
| } | |
| } | |
| - | |
| -func TestMessageNewWithLargeMaxTokens(t *testing.T) { | |
| - baseURL := "http://localhost:4010" | |
| - if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { | |
| - baseURL = envURL | |
| - } | |
| - if !testutil.CheckTestServer(t, baseURL) { | |
| - return | |
| - } | |
| - client := anthropic.NewClient( | |
| - option.WithBaseURL(baseURL), | |
| - option.WithAPIKey("my-anthropic-api-key"), | |
| - ) | |
| - _, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(23000)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{}}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - }) | |
| - if err == nil { | |
| - t.Fatalf("err should be set") | |
| - } | |
| - if !strings.Contains(err.Error(), "Streaming is strongly recommended") { | |
| - t.Log(err.Error()) | |
| - t.Fatalf("err should be our streaming warning") | |
| - } | |
| - | |
| - // with custom request timeout | |
| - _, err = client.Messages.New(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(23000)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{}}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - }, option.WithRequestTimeout(9999999999)) | |
| - if err != nil { | |
| - t.Fatalf("err should be nil") | |
| - } | |
| - | |
| - // with custom context timeout | |
| - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) | |
| - defer cancel() | |
| - _, err = client.Messages.New(ctx, anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(23000)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{}}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - }) | |
| - if err != nil { | |
| - t.Fatalf("err should be nil") | |
| - } | |
| - | |
| - // streaming does not error | |
| - stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(23000)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{}}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - }) | |
| - if stream.Err() != nil { | |
| - t.Log(stream.Err()) | |
| - t.Fatalf("err should be nil") | |
| - } | |
| -} | |
| diff --git a/messagebatch.go b/messagebatch.go | |
| index f691282..4be3fa3 100644 | |
| --- a/messagebatch.go | |
| +++ b/messagebatch.go | |
| @@ -4,22 +4,23 @@ package anthropic | |
| import ( | |
| "context" | |
| + "encoding/json" | |
| "errors" | |
| "fmt" | |
| "net/http" | |
| "net/url" | |
| - "reflect" | |
| "time" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apijson" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apiquery" | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| "github.com/anthropics/anthropic-sdk-go/internal/requestconfig" | |
| "github.com/anthropics/anthropic-sdk-go/option" | |
| "github.com/anthropics/anthropic-sdk-go/packages/jsonl" | |
| "github.com/anthropics/anthropic-sdk-go/packages/pagination" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| "github.com/anthropics/anthropic-sdk-go/shared" | |
| - "github.com/tidwall/gjson" | |
| + "github.com/anthropics/anthropic-sdk-go/shared/constant" | |
| ) | |
| // MessageBatchService contains methods and other services that help with | |
| @@ -35,8 +36,8 @@ type MessageBatchService struct { | |
| // NewMessageBatchService 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 NewMessageBatchService(opts ...option.RequestOption) (r *MessageBatchService) { | |
| - r = &MessageBatchService{} | |
| +func NewMessageBatchService(opts ...option.RequestOption) (r MessageBatchService) { | |
| + r = MessageBatchService{} | |
| r.Options = opts | |
| return | |
| } | |
| @@ -175,44 +176,23 @@ type DeletedMessageBatch struct { | |
| // Deleted object type. | |
| // | |
| // For Message Batches, this is always `"message_batch_deleted"`. | |
| - Type DeletedMessageBatchType `json:"type,required"` | |
| - JSON deletedMessageBatchJSON `json:"-"` | |
| -} | |
| - | |
| -// deletedMessageBatchJSON contains the JSON metadata for the struct | |
| -// [DeletedMessageBatch] | |
| -type deletedMessageBatchJSON struct { | |
| - ID apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *DeletedMessageBatch) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.MessageBatchDeleted `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r DeletedMessageBatch) RawJSON() string { return r.JSON.raw } | |
| +func (r *DeletedMessageBatch) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r deletedMessageBatchJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -// Deleted object type. | |
| -// | |
| -// For Message Batches, this is always `"message_batch_deleted"`. | |
| -type DeletedMessageBatchType string | |
| - | |
| -const ( | |
| - DeletedMessageBatchTypeMessageBatchDeleted DeletedMessageBatchType = "message_batch_deleted" | |
| -) | |
| - | |
| -func (r DeletedMessageBatchType) IsKnown() bool { | |
| - switch r { | |
| - case DeletedMessageBatchTypeMessageBatchDeleted: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type MessageBatch struct { | |
| // Unique object identifier. | |
| // | |
| @@ -220,10 +200,10 @@ type MessageBatch struct { | |
| 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,nullable" format:"date-time"` | |
| + 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,nullable" format:"date-time"` | |
| + 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"` | |
| @@ -232,11 +212,13 @@ type MessageBatch struct { | |
| // | |
| // Processing ends when every request in a Message Batch has either succeeded, | |
| // errored, canceled, or expired. | |
| - EndedAt time.Time `json:"ended_at,required,nullable" format:"date-time"` | |
| + 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 MessageBatchProcessingStatus `json:"processing_status,required"` | |
| // Tallies requests within the Message Batch, categorized by their status. | |
| // | |
| @@ -249,38 +231,35 @@ type MessageBatch struct { | |
| // | |
| // 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,nullable"` | |
| + ResultsURL string `json:"results_url,required"` | |
| // Object type. | |
| // | |
| // For Message Batches, this is always `"message_batch"`. | |
| - Type MessageBatchType `json:"type,required"` | |
| - JSON messageBatchJSON `json:"-"` | |
| -} | |
| - | |
| -// messageBatchJSON contains the JSON metadata for the struct [MessageBatch] | |
| -type messageBatchJSON struct { | |
| - ID apijson.Field | |
| - ArchivedAt apijson.Field | |
| - CancelInitiatedAt apijson.Field | |
| - CreatedAt apijson.Field | |
| - EndedAt apijson.Field | |
| - ExpiresAt apijson.Field | |
| - ProcessingStatus apijson.Field | |
| - RequestCounts apijson.Field | |
| - ResultsURL apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageBatch) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.MessageBatch `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + ArchivedAt resp.Field | |
| + CancelInitiatedAt resp.Field | |
| + CreatedAt resp.Field | |
| + EndedAt resp.Field | |
| + ExpiresAt resp.Field | |
| + ProcessingStatus resp.Field | |
| + RequestCounts resp.Field | |
| + ResultsURL resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageBatch) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageBatch) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageBatchJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| // Processing status of the Message Batch. | |
| type MessageBatchProcessingStatus string | |
| @@ -290,144 +269,59 @@ const ( | |
| MessageBatchProcessingStatusEnded MessageBatchProcessingStatus = "ended" | |
| ) | |
| -func (r MessageBatchProcessingStatus) IsKnown() bool { | |
| - switch r { | |
| - case MessageBatchProcessingStatusInProgress, MessageBatchProcessingStatusCanceling, MessageBatchProcessingStatusEnded: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| -// Object type. | |
| -// | |
| -// For Message Batches, this is always `"message_batch"`. | |
| -type MessageBatchType string | |
| - | |
| -const ( | |
| - MessageBatchTypeMessageBatch MessageBatchType = "message_batch" | |
| -) | |
| - | |
| -func (r MessageBatchType) IsKnown() bool { | |
| - switch r { | |
| - case MessageBatchTypeMessageBatch: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type MessageBatchCanceledResult struct { | |
| - Type MessageBatchCanceledResultType `json:"type,required"` | |
| - JSON messageBatchCanceledResultJSON `json:"-"` | |
| -} | |
| - | |
| -// messageBatchCanceledResultJSON contains the JSON metadata for the struct | |
| -// [MessageBatchCanceledResult] | |
| -type messageBatchCanceledResultJSON struct { | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageBatchCanceledResult) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.Canceled `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageBatchCanceledResult) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageBatchCanceledResult) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageBatchCanceledResultJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r MessageBatchCanceledResult) implementsMessageBatchResult() {} | |
| - | |
| -type MessageBatchCanceledResultType string | |
| - | |
| -const ( | |
| - MessageBatchCanceledResultTypeCanceled MessageBatchCanceledResultType = "canceled" | |
| -) | |
| - | |
| -func (r MessageBatchCanceledResultType) IsKnown() bool { | |
| - switch r { | |
| - case MessageBatchCanceledResultTypeCanceled: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type MessageBatchErroredResult struct { | |
| - Error shared.ErrorResponse `json:"error,required"` | |
| - Type MessageBatchErroredResultType `json:"type,required"` | |
| - JSON messageBatchErroredResultJSON `json:"-"` | |
| -} | |
| - | |
| -// messageBatchErroredResultJSON contains the JSON metadata for the struct | |
| -// [MessageBatchErroredResult] | |
| -type messageBatchErroredResultJSON struct { | |
| - Error apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageBatchErroredResult) UnmarshalJSON(data []byte) (err error) { | |
| + Error shared.ErrorResponse `json:"error,required"` | |
| + Type constant.Errored `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Error resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageBatchErroredResult) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageBatchErroredResult) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageBatchErroredResultJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r MessageBatchErroredResult) implementsMessageBatchResult() {} | |
| - | |
| -type MessageBatchErroredResultType string | |
| - | |
| -const ( | |
| - MessageBatchErroredResultTypeErrored MessageBatchErroredResultType = "errored" | |
| -) | |
| - | |
| -func (r MessageBatchErroredResultType) IsKnown() bool { | |
| - switch r { | |
| - case MessageBatchErroredResultTypeErrored: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type MessageBatchExpiredResult struct { | |
| - Type MessageBatchExpiredResultType `json:"type,required"` | |
| - JSON messageBatchExpiredResultJSON `json:"-"` | |
| -} | |
| - | |
| -// messageBatchExpiredResultJSON contains the JSON metadata for the struct | |
| -// [MessageBatchExpiredResult] | |
| -type messageBatchExpiredResultJSON struct { | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageBatchExpiredResult) UnmarshalJSON(data []byte) (err error) { | |
| + Type constant.Expired `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageBatchExpiredResult) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageBatchExpiredResult) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageBatchExpiredResultJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r MessageBatchExpiredResult) implementsMessageBatchResult() {} | |
| - | |
| -type MessageBatchExpiredResultType string | |
| - | |
| -const ( | |
| - MessageBatchExpiredResultTypeExpired MessageBatchExpiredResultType = "expired" | |
| -) | |
| - | |
| -func (r MessageBatchExpiredResultType) IsKnown() bool { | |
| - switch r { | |
| - case MessageBatchExpiredResultTypeExpired: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| // This is a single line in the response `.jsonl` file and does not represent the | |
| // response as a whole. | |
| type MessageBatchIndividualResponse struct { | |
| @@ -441,27 +335,23 @@ type MessageBatchIndividualResponse struct { | |
| // 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 MessageBatchResult `json:"result,required"` | |
| - JSON messageBatchIndividualResponseJSON `json:"-"` | |
| -} | |
| - | |
| -// messageBatchIndividualResponseJSON contains the JSON metadata for the struct | |
| -// [MessageBatchIndividualResponse] | |
| -type messageBatchIndividualResponseJSON struct { | |
| - CustomID apijson.Field | |
| - Result apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageBatchIndividualResponse) UnmarshalJSON(data []byte) (err error) { | |
| + Result MessageBatchResultUnion `json:"result,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + CustomID resp.Field | |
| + Result resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageBatchIndividualResponse) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageBatchIndividualResponse) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageBatchIndividualResponseJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| type MessageBatchRequestCounts struct { | |
| // Number of requests in the Message Batch that have been canceled. | |
| // | |
| @@ -480,211 +370,439 @@ type MessageBatchRequestCounts struct { | |
| // 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 messageBatchRequestCountsJSON `json:"-"` | |
| -} | |
| - | |
| -// messageBatchRequestCountsJSON contains the JSON metadata for the struct | |
| -// [MessageBatchRequestCounts] | |
| -type messageBatchRequestCountsJSON struct { | |
| - Canceled apijson.Field | |
| - Errored apijson.Field | |
| - Expired apijson.Field | |
| - Processing apijson.Field | |
| - Succeeded apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *MessageBatchRequestCounts) UnmarshalJSON(data []byte) (err error) { | |
| + Succeeded int64 `json:"succeeded,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Canceled resp.Field | |
| + Errored resp.Field | |
| + Expired resp.Field | |
| + Processing resp.Field | |
| + Succeeded resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageBatchRequestCounts) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageBatchRequestCounts) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r messageBatchRequestCountsJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -// 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. | |
| -type MessageBatchResult struct { | |
| - Type MessageBatchResultType `json:"type,required"` | |
| - Error shared.ErrorResponse `json:"error"` | |
| - Message Message `json:"message"` | |
| - JSON messageBatchResultJSON `json:"-"` | |
| - union MessageBatchResultUnion | |
| -} | |
| - | |
| -// messageBatchResultJSON contains the JSON metadata for the struct | |
| -// [MessageBatchResult] | |
| -type messageBatchResultJSON struct { | |
| - Type apijson.Field | |
| - Error apijson.Field | |
| - Message apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r messageBatchResultJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -func (r *MessageBatchResult) UnmarshalJSON(data []byte) (err error) { | |
| - *r = MessageBatchResult{} | |
| - err = apijson.UnmarshalRoot(data, &r.union) | |
| - if err != nil { | |
| - return err | |
| - } | |
| - return apijson.Port(r.union, &r) | |
| -} | |
| - | |
| -// AsUnion returns a [MessageBatchResultUnion] interface which you can cast to the | |
| -// specific types for more type safety. | |
| +// MessageBatchResultUnion contains all possible properties and values from | |
| +// [MessageBatchSucceededResult], [MessageBatchErroredResult], | |
| +// [MessageBatchCanceledResult], [MessageBatchExpiredResult]. | |
| // | |
| -// Possible runtime types of the union are [MessageBatchSucceededResult], | |
| -// [MessageBatchErroredResult], [MessageBatchCanceledResult], | |
| -// [MessageBatchExpiredResult]. | |
| -func (r MessageBatchResult) AsUnion() MessageBatchResultUnion { | |
| - return r.union | |
| -} | |
| - | |
| -// Processing result for this request. | |
| +// Use the [MessageBatchResultUnion.AsAny] method to switch on the variant. | |
| // | |
| -// 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. | |
| +// Use the methods beginning with 'As' to cast the union to one of its variants. | |
| +type MessageBatchResultUnion struct { | |
| + // This field is from variant [MessageBatchSucceededResult]. | |
| + Message Message `json:"message"` | |
| + // Any of "succeeded", "errored", "canceled", "expired". | |
| + Type string `json:"type"` | |
| + // This field is from variant [MessageBatchErroredResult]. | |
| + Error shared.ErrorResponse `json:"error"` | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + Error resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Use the following switch statement to find the correct variant | |
| // | |
| -// Union satisfied by [MessageBatchSucceededResult], [MessageBatchErroredResult], | |
| -// [MessageBatchCanceledResult] or [MessageBatchExpiredResult]. | |
| -type MessageBatchResultUnion interface { | |
| - implementsMessageBatchResult() | |
| -} | |
| - | |
| -func init() { | |
| - apijson.RegisterUnion( | |
| - reflect.TypeOf((*MessageBatchResultUnion)(nil)).Elem(), | |
| - "type", | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(MessageBatchSucceededResult{}), | |
| - DiscriminatorValue: "succeeded", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(MessageBatchErroredResult{}), | |
| - DiscriminatorValue: "errored", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(MessageBatchCanceledResult{}), | |
| - DiscriminatorValue: "canceled", | |
| - }, | |
| - apijson.UnionVariant{ | |
| - TypeFilter: gjson.JSON, | |
| - Type: reflect.TypeOf(MessageBatchExpiredResult{}), | |
| - DiscriminatorValue: "expired", | |
| - }, | |
| - ) | |
| -} | |
| - | |
| -type MessageBatchResultType string | |
| - | |
| -const ( | |
| - MessageBatchResultTypeSucceeded MessageBatchResultType = "succeeded" | |
| - MessageBatchResultTypeErrored MessageBatchResultType = "errored" | |
| - MessageBatchResultTypeCanceled MessageBatchResultType = "canceled" | |
| - MessageBatchResultTypeExpired MessageBatchResultType = "expired" | |
| -) | |
| - | |
| -func (r MessageBatchResultType) IsKnown() bool { | |
| - switch r { | |
| - case MessageBatchResultTypeSucceeded, MessageBatchResultTypeErrored, MessageBatchResultTypeCanceled, MessageBatchResultTypeExpired: | |
| - return true | |
| +// switch variant := MessageBatchResultUnion.AsAny().(type) { | |
| +// case MessageBatchSucceededResult: | |
| +// case MessageBatchErroredResult: | |
| +// case MessageBatchCanceledResult: | |
| +// case MessageBatchExpiredResult: | |
| +// default: | |
| +// fmt.Errorf("no variant present") | |
| +// } | |
| +func (u MessageBatchResultUnion) AsAny() any { | |
| + switch u.Type { | |
| + case "succeeded": | |
| + return u.AsSucceededResult() | |
| + case "errored": | |
| + return u.AsErroredResult() | |
| + case "canceled": | |
| + return u.AsCanceledResult() | |
| + case "expired": | |
| + return u.AsExpiredResult() | |
| } | |
| - return false | |
| + return nil | |
| } | |
| -type MessageBatchSucceededResult struct { | |
| - Message Message `json:"message,required"` | |
| - Type MessageBatchSucceededResultType `json:"type,required"` | |
| - JSON messageBatchSucceededResultJSON `json:"-"` | |
| +func (u MessageBatchResultUnion) AsSucceededResult() (v MessageBatchSucceededResult) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -// messageBatchSucceededResultJSON contains the JSON metadata for the struct | |
| -// [MessageBatchSucceededResult] | |
| -type messageBatchSucceededResultJSON struct { | |
| - Message apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| +func (u MessageBatchResultUnion) AsErroredResult() (v MessageBatchErroredResult) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r *MessageBatchSucceededResult) UnmarshalJSON(data []byte) (err error) { | |
| - return apijson.UnmarshalRoot(data, r) | |
| +func (u MessageBatchResultUnion) AsCanceledResult() (v MessageBatchCanceledResult) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r messageBatchSucceededResultJSON) RawJSON() string { | |
| - return r.raw | |
| +func (u MessageBatchResultUnion) AsExpiredResult() (v MessageBatchExpiredResult) { | |
| + apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v) | |
| + return | |
| } | |
| -func (r MessageBatchSucceededResult) implementsMessageBatchResult() {} | |
| - | |
| -type MessageBatchSucceededResultType string | |
| +// Returns the unmodified JSON received from the API | |
| +func (u MessageBatchResultUnion) RawJSON() string { return u.JSON.raw } | |
| -const ( | |
| - MessageBatchSucceededResultTypeSucceeded MessageBatchSucceededResultType = "succeeded" | |
| -) | |
| +func (r *MessageBatchResultUnion) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| +} | |
| -func (r MessageBatchSucceededResultType) IsKnown() bool { | |
| - switch r { | |
| - case MessageBatchSucceededResultTypeSucceeded: | |
| - return true | |
| - } | |
| - return false | |
| +type MessageBatchSucceededResult struct { | |
| + Message Message `json:"message,required"` | |
| + Type constant.Succeeded `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + Message resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| +} | |
| + | |
| +// Returns the unmodified JSON received from the API | |
| +func (r MessageBatchSucceededResult) RawJSON() string { return r.JSON.raw } | |
| +func (r *MessageBatchSucceededResult) UnmarshalJSON(data []byte) error { | |
| + return apijson.UnmarshalRoot(data, r) | |
| } | |
| type MessageBatchNewParams struct { | |
| // List of requests for prompt completion. Each is an individual request to create | |
| // a Message. | |
| - Requests param.Field[[]MessageBatchNewParamsRequest] `json:"requests,required"` | |
| + Requests []MessageBatchNewParamsRequest `json:"requests,omitzero,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f MessageBatchNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| func (r MessageBatchNewParams) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow MessageBatchNewParams | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| +// The properties CustomID, Params are required. | |
| type MessageBatchNewParamsRequest 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 param.Field[string] `json:"custom_id,required"` | |
| + CustomID string `json:"custom_id,required"` | |
| // Messages API creation parameters for the individual request. | |
| // | |
| // See the [Messages API reference](/en/api/messages) for full documentation on | |
| // available parameters. | |
| - Params param.Field[MessageNewParams] `json:"params,required"` | |
| + Params MessageBatchNewParamsRequestParams `json:"params,omitzero,required"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f MessageBatchNewParamsRequest) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| func (r MessageBatchNewParamsRequest) MarshalJSON() (data []byte, err error) { | |
| - return apijson.MarshalRoot(r) | |
| + type shadow MessageBatchNewParamsRequest | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| +} | |
| + | |
| +// Messages API creation parameters for the individual request. | |
| +// | |
| +// See the [Messages API reference](/en/api/messages) for full documentation on | |
| +// available parameters. | |
| +// | |
| +// The properties MaxTokens, Messages, Model are required. | |
| +type MessageBatchNewParamsRequestParams 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.anthropic.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" }] } | |
| + // ``` | |
| + // | |
| + // Starting with Claude 3 models, you can also send image content blocks: | |
| + // | |
| + // ```json | |
| + // | |
| + // { | |
| + // "role": "user", | |
| + // "content": [ | |
| + // { | |
| + // "type": "image", | |
| + // "source": { | |
| + // "type": "base64", | |
| + // "media_type": "image/jpeg", | |
| + // "data": "/9j/4AAQSkZJRg..." | |
| + // } | |
| + // }, | |
| + // { "type": "text", "text": "What is in this image?" } | |
| + // ] | |
| + // } | |
| + // | |
| + // ``` | |
| + // | |
| + // We currently support the `base64` source type for images, and the `image/jpeg`, | |
| + // `image/png`, `image/gif`, and `image/webp` media types. | |
| + // | |
| + // See [examples](https://docs.anthropic.com/en/api/messages-examples#vision) for | |
| + // more input examples. | |
| + // | |
| + // Note that if you want to include a | |
| + // [system prompt](https://docs.anthropic.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. | |
| + Messages []MessageParam `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"` | |
| + // Whether to incrementally stream the response using server-sent events. | |
| + // | |
| + // See [streaming](https://docs.anthropic.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"` | |
| + // An object describing metadata about the request. | |
| + Metadata MetadataParam `json:"metadata,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.anthropic.com/en/docs/system-prompts). | |
| + System []TextBlockParam `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.anthropic.com/en/docs/build-with-claude/extended-thinking) | |
| + // for details. | |
| + Thinking ThinkingConfigParamUnion `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 ToolChoiceUnionParam `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. | |
| + // | |
| + // 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.anthropic.com/en/docs/tool-use) for more details. | |
| + Tools []ToolUnionParam `json:"tools,omitzero"` | |
| + paramObj | |
| +} | |
| + | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f MessageBatchNewParamsRequestParams) IsPresent() bool { | |
| + return !param.IsOmitted(f) && !f.IsNull() | |
| +} | |
| +func (r MessageBatchNewParamsRequestParams) MarshalJSON() (data []byte, err error) { | |
| + type shadow MessageBatchNewParamsRequestParams | |
| + return param.MarshalObject(r, (*shadow)(&r)) | |
| } | |
| type MessageBatchListParams 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.Field[string] `query:"after_id"` | |
| + 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.Field[string] `query:"before_id"` | |
| + 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.Field[int64] `query:"limit"` | |
| + Limit param.Opt[int64] `query:"limit,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f MessageBatchListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| // URLQuery serializes [MessageBatchListParams]'s query parameters as `url.Values`. | |
| func (r MessageBatchListParams) URLQuery() (v url.Values) { | |
| return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ | |
| diff --git a/messagebatch_test.go b/messagebatch_test.go | |
| index 0fc6bf5..dc26d43 100644 | |
| --- a/messagebatch_test.go | |
| +++ b/messagebatch_test.go | |
| @@ -26,53 +26,61 @@ func TestMessageBatchNew(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Messages.Batches.New(context.TODO(), anthropic.MessageBatchNewParams{ | |
| - Requests: anthropic.F([]anthropic.MessageBatchNewParamsRequest{{ | |
| - CustomID: anthropic.F("my-custom-id-1"), | |
| - Params: anthropic.F(anthropic.MessageNewParams{ | |
| - MaxTokens: anthropic.F(int64(1024)), | |
| - Messages: anthropic.F([]anthropic.MessageParam{{ | |
| - Content: anthropic.F([]anthropic.ContentBlockParamUnion{anthropic.TextBlockParam{Text: anthropic.F("What is a quaternion?"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)}), Citations: anthropic.F([]anthropic.TextCitationParamUnion{anthropic.CitationCharLocationParam{CitedText: anthropic.F("cited_text"), DocumentIndex: anthropic.F(int64(0)), DocumentTitle: anthropic.F("x"), EndCharIndex: anthropic.F(int64(0)), StartCharIndex: anthropic.F(int64(0)), Type: anthropic.F(anthropic.CitationCharLocationParamTypeCharLocation)}})}}), | |
| - Role: anthropic.F(anthropic.MessageParamRoleUser), | |
| - }}), | |
| - Model: anthropic.F(anthropic.ModelClaude3_7SonnetLatest), | |
| - Metadata: anthropic.F(anthropic.MetadataParam{ | |
| - UserID: anthropic.F("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| - }), | |
| - StopSequences: anthropic.F([]string{"string"}), | |
| - System: anthropic.F([]anthropic.TextBlockParam{{Text: anthropic.F("x"), Type: anthropic.F(anthropic.TextBlockParamTypeText), CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral)})}}), | |
| - Temperature: anthropic.F(1.000000), | |
| - Thinking: anthropic.F[anthropic.ThinkingConfigParamUnion](anthropic.ThinkingConfigEnabledParam{ | |
| - BudgetTokens: anthropic.F(int64(1024)), | |
| - Type: anthropic.F(anthropic.ThinkingConfigEnabledTypeEnabled), | |
| - }), | |
| - ToolChoice: anthropic.F[anthropic.ToolChoiceUnionParam](anthropic.ToolChoiceAutoParam{ | |
| - Type: anthropic.F(anthropic.ToolChoiceAutoTypeAuto), | |
| - DisableParallelToolUse: anthropic.F(true), | |
| - }), | |
| - Tools: anthropic.F([]anthropic.ToolUnionUnionParam{anthropic.ToolParam{ | |
| - Description: anthropic.F("Get the current weather in a given location"), | |
| - Name: anthropic.F("x"), | |
| - InputSchema: anthropic.F[interface{}](map[string]interface{}{ | |
| - "type": "object", | |
| - "properties": map[string]interface{}{ | |
| - "location": map[string]interface{}{ | |
| - "description": "The city and state, e.g. San Francisco, CA", | |
| - "type": "string", | |
| - }, | |
| - "unit": map[string]interface{}{ | |
| - "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| - "type": "string", | |
| + Requests: []anthropic.MessageBatchNewParamsRequest{{ | |
| + CustomID: "my-custom-id-1", | |
| + Params: anthropic.MessageBatchNewParamsRequestParams{ | |
| + MaxTokens: 1024, | |
| + Messages: []anthropic.MessageParam{{ | |
| + Content: []anthropic.ContentBlockParamUnion{{ | |
| + OfRequestTextBlock: &anthropic.TextBlockParam{Text: "What is a quaternion?", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}, | |
| + }}, | |
| + Role: anthropic.MessageParamRoleUser, | |
| + }}, | |
| + Model: anthropic.ModelClaude3_7SonnetLatest, | |
| + Metadata: anthropic.MetadataParam{ | |
| + UserID: anthropic.String("13803d75-b4b5-4c3e-b2a2-6f21399b021b"), | |
| + }, | |
| + StopSequences: []string{"string"}, | |
| + Stream: anthropic.Bool(true), | |
| + System: []anthropic.TextBlockParam{{Text: "x", CacheControl: anthropic.CacheControlEphemeralParam{}, Citations: []anthropic.TextCitationParamUnion{{ | |
| + OfRequestCharLocationCitation: &anthropic.CitationCharLocationParam{CitedText: "cited_text", DocumentIndex: 0, DocumentTitle: anthropic.String("x"), EndCharIndex: 0, StartCharIndex: 0}, | |
| + }}}}, | |
| + Temperature: anthropic.Float(1), | |
| + Thinking: anthropic.ThinkingConfigParamUnion{ | |
| + OfThinkingConfigEnabled: &anthropic.ThinkingConfigEnabledParam{ | |
| + BudgetTokens: 1024, | |
| + }, | |
| + }, | |
| + ToolChoice: anthropic.ToolChoiceUnionParam{ | |
| + OfToolChoiceAuto: &anthropic.ToolChoiceAutoParam{ | |
| + DisableParallelToolUse: anthropic.Bool(true), | |
| + }, | |
| + }, | |
| + Tools: []anthropic.ToolUnionParam{{ | |
| + OfTool: &anthropic.ToolParam{ | |
| + InputSchema: anthropic.ToolInputSchemaParam{ | |
| + Properties: map[string]interface{}{ | |
| + "location": map[string]interface{}{ | |
| + "description": "The city and state, e.g. San Francisco, CA", | |
| + "type": "string", | |
| + }, | |
| + "unit": map[string]interface{}{ | |
| + "description": "Unit for the output - one of (celsius, fahrenheit)", | |
| + "type": "string", | |
| + }, | |
| }, | |
| }, | |
| - }), | |
| - CacheControl: anthropic.F(anthropic.CacheControlEphemeralParam{ | |
| - Type: anthropic.F(anthropic.CacheControlEphemeralTypeEphemeral), | |
| - }), | |
| - }}), | |
| - TopK: anthropic.F(int64(5)), | |
| - TopP: anthropic.F(0.700000), | |
| - }), | |
| - }}), | |
| + Name: "name", | |
| + CacheControl: anthropic.CacheControlEphemeralParam{}, | |
| + Description: anthropic.String("Get the current weather in a given location"), | |
| + }, | |
| + }}, | |
| + TopK: anthropic.Int(5), | |
| + TopP: anthropic.Float(0.7), | |
| + }, | |
| + }}, | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| @@ -118,9 +126,9 @@ func TestMessageBatchListWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Messages.Batches.List(context.TODO(), anthropic.MessageBatchListParams{ | |
| - AfterID: anthropic.F("after_id"), | |
| - BeforeID: anthropic.F("before_id"), | |
| - Limit: anthropic.F(int64(1)), | |
| + AfterID: anthropic.String("after_id"), | |
| + BeforeID: anthropic.String("before_id"), | |
| + Limit: anthropic.Int(1), | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| diff --git a/model.go b/model.go | |
| index 09e542d..ff06749 100644 | |
| --- a/model.go | |
| +++ b/model.go | |
| @@ -12,10 +12,12 @@ import ( | |
| "github.com/anthropics/anthropic-sdk-go/internal/apijson" | |
| "github.com/anthropics/anthropic-sdk-go/internal/apiquery" | |
| - "github.com/anthropics/anthropic-sdk-go/internal/param" | |
| "github.com/anthropics/anthropic-sdk-go/internal/requestconfig" | |
| "github.com/anthropics/anthropic-sdk-go/option" | |
| "github.com/anthropics/anthropic-sdk-go/packages/pagination" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/param" | |
| + "github.com/anthropics/anthropic-sdk-go/packages/resp" | |
| + "github.com/anthropics/anthropic-sdk-go/shared/constant" | |
| ) | |
| // ModelService contains methods and other services that help with interacting with | |
| @@ -31,8 +33,8 @@ type ModelService struct { | |
| // NewModelService 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 NewModelService(opts ...option.RequestOption) (r *ModelService) { | |
| - r = &ModelService{} | |
| +func NewModelService(opts ...option.RequestOption) (r ModelService) { | |
| + r = ModelService{} | |
| r.Options = opts | |
| return | |
| } | |
| @@ -92,58 +94,43 @@ type ModelInfo struct { | |
| // Object type. | |
| // | |
| // For Models, this is always `"model"`. | |
| - Type ModelInfoType `json:"type,required"` | |
| - JSON modelInfoJSON `json:"-"` | |
| + Type constant.Model `json:"type,required"` | |
| + // Metadata for the response, check the presence of optional fields with the | |
| + // [resp.Field.IsPresent] method. | |
| + JSON struct { | |
| + ID resp.Field | |
| + CreatedAt resp.Field | |
| + DisplayName resp.Field | |
| + Type resp.Field | |
| + ExtraFields map[string]resp.Field | |
| + raw string | |
| + } `json:"-"` | |
| } | |
| -// modelInfoJSON contains the JSON metadata for the struct [ModelInfo] | |
| -type modelInfoJSON struct { | |
| - ID apijson.Field | |
| - CreatedAt apijson.Field | |
| - DisplayName apijson.Field | |
| - Type apijson.Field | |
| - raw string | |
| - ExtraFields map[string]apijson.Field | |
| -} | |
| - | |
| -func (r *ModelInfo) UnmarshalJSON(data []byte) (err error) { | |
| +// Returns the unmodified JSON received from the API | |
| +func (r ModelInfo) RawJSON() string { return r.JSON.raw } | |
| +func (r *ModelInfo) UnmarshalJSON(data []byte) error { | |
| return apijson.UnmarshalRoot(data, r) | |
| } | |
| -func (r modelInfoJSON) RawJSON() string { | |
| - return r.raw | |
| -} | |
| - | |
| -// Object type. | |
| -// | |
| -// For Models, this is always `"model"`. | |
| -type ModelInfoType string | |
| - | |
| -const ( | |
| - ModelInfoTypeModel ModelInfoType = "model" | |
| -) | |
| - | |
| -func (r ModelInfoType) IsKnown() bool { | |
| - switch r { | |
| - case ModelInfoTypeModel: | |
| - return true | |
| - } | |
| - return false | |
| -} | |
| - | |
| type ModelListParams 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.Field[string] `query:"after_id"` | |
| + 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.Field[string] `query:"before_id"` | |
| + 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.Field[int64] `query:"limit"` | |
| + Limit param.Opt[int64] `query:"limit,omitzero" json:"-"` | |
| + paramObj | |
| } | |
| +// IsPresent returns true if the field's value is not omitted and not the JSON | |
| +// "null". To check if this field is omitted, use [param.IsOmitted]. | |
| +func (f ModelListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() } | |
| + | |
| // URLQuery serializes [ModelListParams]'s query parameters as `url.Values`. | |
| func (r ModelListParams) URLQuery() (v url.Values) { | |
| return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ | |
| diff --git a/model_test.go b/model_test.go | |
| index 5a53add..9cec548 100644 | |
| --- a/model_test.go | |
| +++ b/model_test.go | |
| @@ -48,9 +48,9 @@ func TestModelListWithOptionalParams(t *testing.T) { | |
| option.WithAPIKey("my-anthropic-api-key"), | |
| ) | |
| _, err := client.Models.List(context.TODO(), anthropic.ModelListParams{ | |
| - AfterID: anthropic.F("after_id"), | |
| - BeforeID: anthropic.F("before_id"), | |
| - Limit: anthropic.F(int64(1)), | |
| + AfterID: anthropic.String("after_id"), | |
| + BeforeID: anthropic.String("before_id"), | |
| + Limit: anthropic.Int(1), | |
| }) | |
| if err != nil { | |
| var apierr *anthropic.Error | |
| diff --git a/option/requestoption.go b/option/requestoption.go | |
| index 5594c6d..1a82a80 100644 | |
| --- a/option/requestoption.go | |
| +++ b/option/requestoption.go | |
| @@ -9,6 +9,7 @@ import ( | |
| "log" | |
| "net/http" | |
| "net/url" | |
| + "strings" | |
| "time" | |
| "github.com/anthropics/anthropic-sdk-go/internal/requestconfig" | |
| @@ -20,27 +21,32 @@ import ( | |
| // options pattern in our [README]. | |
| // | |
| // [README]: https://pkg.go.dev/github.com/anthropics/anthropic-sdk-go#readme-requestoptions | |
| -type RequestOption = func(*requestconfig.RequestConfig) error | |
| +type RequestOption = requestconfig.RequestOption | |
| // WithBaseURL returns a RequestOption that sets the BaseURL for the client. | |
| +// | |
| +// For security reasons, ensure that the base URL is trusted. | |
| func WithBaseURL(base string) RequestOption { | |
| u, err := url.Parse(base) | |
| if err != nil { | |
| log.Fatalf("failed to parse BaseURL: %s\n", err) | |
| } | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| + if u.Path != "" && !strings.HasSuffix(u.Path, "/") { | |
| + u.Path += "/" | |
| + } | |
| r.BaseURL = u | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithHTTPClient returns a RequestOption that changes the underlying [http.Client] used to make this | |
| // request, which by default is [http.DefaultClient]. | |
| func WithHTTPClient(client *http.Client) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| r.HTTPClient = client | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // MiddlewareNext is a function which is called by a middleware to pass an HTTP request | |
| @@ -55,10 +61,10 @@ type Middleware = func(*http.Request, MiddlewareNext) (*http.Response, error) | |
| // WithMiddleware returns a RequestOption that applies the given middleware | |
| // to the requests made. Each middleware will execute in the order they were given. | |
| func WithMiddleware(middlewares ...Middleware) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| r.Middlewares = append(r.Middlewares, middlewares...) | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithMaxRetries returns a RequestOption that sets the maximum number of retries that the client | |
| @@ -70,68 +76,68 @@ func WithMaxRetries(retries int) RequestOption { | |
| if retries < 0 { | |
| panic("option: cannot have fewer than 0 retries") | |
| } | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| r.MaxRetries = retries | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithHeader returns a RequestOption that sets the header value to the associated key. It overwrites | |
| // any value if there was one already present. | |
| func WithHeader(key, value string) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| r.Request.Header.Set(key, value) | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithHeaderAdd returns a RequestOption that adds the header value to the associated key. It appends | |
| // onto any existing values. | |
| func WithHeaderAdd(key, value string) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| r.Request.Header.Add(key, value) | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithHeaderDel returns a RequestOption that deletes the header value(s) associated with the given key. | |
| func WithHeaderDel(key string) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| r.Request.Header.Del(key) | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithQuery returns a RequestOption that sets the query value to the associated key. It overwrites | |
| // any value if there was one already present. | |
| func WithQuery(key, value string) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| query := r.Request.URL.Query() | |
| query.Set(key, value) | |
| r.Request.URL.RawQuery = query.Encode() | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithQueryAdd returns a RequestOption that adds the query value to the associated key. It appends | |
| // onto any existing values. | |
| func WithQueryAdd(key, value string) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| query := r.Request.URL.Query() | |
| query.Add(key, value) | |
| r.Request.URL.RawQuery = query.Encode() | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithQueryDel returns a RequestOption that deletes the query value(s) associated with the key. | |
| func WithQueryDel(key string) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| query := r.Request.URL.Query() | |
| query.Del(key) | |
| r.Request.URL.RawQuery = query.Encode() | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithJSONSet returns a RequestOption that sets the body's JSON value associated with the key. | |
| @@ -139,7 +145,7 @@ func WithQueryDel(key string) RequestOption { | |
| // | |
| // [sjson format]: https://github.com/tidwall/sjson | |
| func WithJSONSet(key string, value interface{}) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) (err error) { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) (err error) { | |
| if buffer, ok := r.Body.(*bytes.Buffer); ok { | |
| b := buffer.Bytes() | |
| b, err = sjson.SetBytes(b, key, value) | |
| @@ -151,7 +157,7 @@ func WithJSONSet(key string, value interface{}) RequestOption { | |
| } | |
| return fmt.Errorf("cannot use WithJSONSet on a body that is not serialized as *bytes.Buffer") | |
| - } | |
| + }) | |
| } | |
| // WithJSONDel returns a RequestOption that deletes the body's JSON value associated with the key. | |
| @@ -159,7 +165,7 @@ func WithJSONSet(key string, value interface{}) RequestOption { | |
| // | |
| // [sjson format]: https://github.com/tidwall/sjson | |
| func WithJSONDel(key string) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) (err error) { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) (err error) { | |
| if buffer, ok := r.Body.(*bytes.Buffer); ok { | |
| b := buffer.Bytes() | |
| b, err = sjson.DeleteBytes(b, key) | |
| @@ -171,24 +177,24 @@ func WithJSONDel(key string) RequestOption { | |
| } | |
| return fmt.Errorf("cannot use WithJSONDel on a body that is not serialized as *bytes.Buffer") | |
| - } | |
| + }) | |
| } | |
| // WithResponseBodyInto returns a RequestOption that overwrites the deserialization target with | |
| // the given destination. If provided, we don't deserialize into the default struct. | |
| func WithResponseBodyInto(dst any) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| r.ResponseBodyInto = dst | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithResponseInto returns a RequestOption that copies the [*http.Response] into the given address. | |
| func WithResponseInto(dst **http.Response) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| r.ResponseInto = dst | |
| return nil | |
| - } | |
| + }) | |
| } | |
| // WithRequestBody returns a RequestOption that provides a custom serialized body with the given | |
| @@ -196,7 +202,7 @@ func WithResponseInto(dst **http.Response) RequestOption { | |
| // | |
| // body accepts an io.Reader or raw []bytes. | |
| func WithRequestBody(contentType string, body any) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { | |
| + return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error { | |
| if reader, ok := body.(io.Reader); ok { | |
| r.Body = reader | |
| return r.Apply(WithHeader("Content-Type", contentType)) | |
| @@ -208,17 +214,17 @@ func WithRequestBody(contentType string, body any) RequestOption { | |
| } | |
| return fmt.Errorf("body must be a byte slice or implement io.Reader") | |
| - } | |
| + }) | |
| } | |
| // WithRequestTimeout returns a RequestOption that sets the timeout for | |
| // each request attempt. This should be smaller than the timeout defined in | |
| // the context, which spans all retries. | |
| func WithRequestTimeout(dur time.Duration) RequestOption { | |
| - return func(r *requestconfig.RequestConfig) error { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment