diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index 1ae9272b..803358ab 100644
--- a/.speakeasy/gen.lock
+++ b/.speakeasy/gen.lock
@@ -1,19 +1,19 @@
lockVersion: 2.0.0
id: c48cf606-fb42-4a45-9c23-8f0555307828
management:
- docChecksum: a4a66ca81e062a140820ff0a8797409f
+ docChecksum: ad7637a68c46f585f25b6a36b9dd0f64
docVersion: 1.0.0
speakeasyVersion: 1.787.0
generationVersion: 2.914.0
- releaseVersion: 0.11.16
- configChecksum: a4a1bd1b84fa14d397a7dfb0bb351efc
+ releaseVersion: 0.11.17
+ configChecksum: e1094fdca787104fc58b99c1a21f533d
repoURL: https://github.com/OpenRouterTeam/python-sdk.git
installationURL: https://github.com/OpenRouterTeam/python-sdk.git
published: true
persistentEdits:
- generation_id: c9801f2b-9850-4020-b390-d229911befbe
- pristine_commit_hash: 71dbc8aa473f514b093d15901e5f67dece278cb7
- pristine_tree_hash: 2769400e291cb8861d2736b7b3e036f7d043614e
+ generation_id: efe0a4c5-68bb-420f-acd6-9382a2e84419
+ pristine_commit_hash: 2c5b8d0d8b460f97ba19d673e012040cb8cceddc
+ pristine_tree_hash: d8087e47e225e199329a004d366ac4e933efff90
features:
python:
acceptHeaders: 3.0.0
@@ -702,8 +702,8 @@ trackedFiles:
pristine_git_object: 151dd8398dc818ff4d26d6859d25efd202d03917
docs/components/byokproviderslug.mdx:
id: 6ea70819f6d8
- last_write_checksum: sha1:5116cfa7ed1f8270dfc9d277d3cc0ee02b147c44
- pristine_git_object: 439563d0fe5440c4f0127337f39ddc403f63ae06
+ last_write_checksum: sha1:195859204474448ffacfda46106c4c529cc05a4e
+ pristine_git_object: 619d8a0909e742416ef893c01e0093ab5cc5c686
docs/components/caching.mdx:
id: edc8a0f8f37f
last_write_checksum: sha1:b4e6619f389c1440555ec567fbdcddbc9976e63e
@@ -712,6 +712,10 @@ trackedFiles:
id: 34ac0e581d79
last_write_checksum: sha1:62ee9ccab6cec4572383cef654997ab4106d4676
pristine_git_object: ace8f22b972273bdee620a9981abcb0cc46d994e
+ docs/components/category.mdx:
+ id: c952e528e6a0
+ last_write_checksum: sha1:8c57eac99923f3c4d343cd6dc3727c58d405c33c
+ pristine_git_object: e67ca2a02783050e89bed3f53bf59d2e8c805478
docs/components/chatassistantimages.mdx:
id: ffb19be9dace
last_write_checksum: sha1:cbcf9e1fb04e660786ad38a273b852cf84504f9f
@@ -2082,8 +2086,8 @@ trackedFiles:
pristine_git_object: 8501680bcfebabb3af52b518c01f732d18282120
docs/components/imagegenerationrequestoptions.mdx:
id: 2245ece0aaf8
- last_write_checksum: sha1:ef565300c4aaaacf991f0ecabb2dade678494423
- pristine_git_object: 26f3f1ecd8f4865034e81ce1eca81552d90d70b8
+ last_write_checksum: sha1:d6ca724147440eda6fe039b29ab5495824ae5c0a
+ pristine_git_object: b6426f4b8f4549a0e1e3e931b0cc467012c7d512
docs/components/imagegenerationrequestoutputformat.mdx:
id: 380f12bf77bd
last_write_checksum: sha1:afb479dc34118828e988888a8f49e7a5a50a45ab
@@ -3818,8 +3822,8 @@ trackedFiles:
pristine_git_object: f7cde44d7ed6638b63f3f5c3921096cd368c1b1e
docs/components/provideroptions.mdx:
id: 2697807524fe
- last_write_checksum: sha1:e1d6db7e6b3ed82bc19a6ece557566273f9a4b93
- pristine_git_object: b15b96fc074273c0d83e59b9b69c64ce8dfb48d8
+ last_write_checksum: sha1:f0ee004496e6067b61305a24191eecb3c7444dbb
+ pristine_git_object: c9df643ff81878c93f6d6f363f622be76442f13a
docs/components/provideroverloadedresponseerrordata.mdx:
id: dc500cd14889
last_write_checksum: sha1:6c1d551db4083f1d0bc429baa1ce472d2c085331
@@ -4460,6 +4464,18 @@ trackedFiles:
id: 36a519fbf209
last_write_checksum: sha1:14f4bf5f550f0dfddb8bd950e000ed431a5470e9
pristine_git_object: a93cd73684c2a51b27f8a1e13a09f980a676567e
+ docs/components/submitgenerationfeedbackrequest.mdx:
+ id: fba2401919b4
+ last_write_checksum: sha1:0c574d3011a3b5c9183697be0484a019188b5ec0
+ pristine_git_object: 9e56152e2335fe11da9245816c8d1e97cd86948f
+ docs/components/submitgenerationfeedbackresponse.mdx:
+ id: 965ad9f0e7d8
+ last_write_checksum: sha1:7451bf17e40384dd0c719af06afd429f305da84d
+ pristine_git_object: ba546e044aa0cacbde96b10562c4526a03cc0408
+ docs/components/submitgenerationfeedbackresponsedata.mdx:
+ id: 3dc9b2ef8c55
+ last_write_checksum: sha1:3bd23a1fe786aa76836d0990d51213c9ddd8fc36
+ pristine_git_object: 2b6ccfe5787d34259f7c5c89e9852d32afd6aef4
docs/components/supportedaspectratio.mdx:
id: 236a2016da06
last_write_checksum: sha1:638d1fbeb7e634fd924c4c1c92a0cc69f5291635
@@ -4926,8 +4942,8 @@ trackedFiles:
pristine_git_object: 67f56887bb4758559189e3e9e6123dff9a38df81
docs/components/videogenerationrequestoptions.mdx:
id: 1d67160e7e7a
- last_write_checksum: sha1:8f1c4b3b0a67cce0aad25ef560ca635a929f8784
- pristine_git_object: f3d6474edb250bfaecbdb3a1fa9c930e9587a46b
+ last_write_checksum: sha1:5212fca896119c2cbede7f2efbc0855d007e68d1
+ pristine_git_object: c1d338ae75a61869d4e8b5110b2a85d5e624da1e
docs/components/videogenerationrequestprovider.mdx:
id: d6424dd5de9d
last_write_checksum: sha1:72aa46a3335220b579db56574ea179d150dbe2b6
@@ -6178,8 +6194,8 @@ trackedFiles:
pristine_git_object: 0f0b54e43577a8a835cd971f82e48c3921e3d88e
docs/operations/provider.mdx:
id: c75b3bbeeaa0
- last_write_checksum: sha1:c55d7af5c40483430e2debde39643c564ea19838
- pristine_git_object: 1b6b620243fb2472e1bfe2acc7bbb646b8a82a79
+ last_write_checksum: sha1:050746e3c160daa03b108e45aed42aadf82d641f
+ pristine_git_object: 139a0786eebb659c9b410f430efac3115759d5ae
docs/operations/queryanalyticsdata1.mdx:
id: 0e41beea77d0
last_write_checksum: sha1:f9a349b4fee07f786180e94b45f92002bfae0e56
@@ -6244,6 +6260,14 @@ trackedFiles:
id: b3291e6c44b9
last_write_checksum: sha1:2594ecd2302b9515e5997f4fbaaebba4a9a0615c
pristine_git_object: af1d9e961714b356ae1a7cd86d64ff636215bae8
+ docs/operations/submitgenerationfeedbackglobals.mdx:
+ id: cdef4c621cb3
+ last_write_checksum: sha1:dc4e93ccccf8e97b25a5a64428a8bf8c679037bd
+ pristine_git_object: bbd731b6fa9990b637d7dad9fd5614619c83d0d9
+ docs/operations/submitgenerationfeedbackrequest.mdx:
+ id: f159f51b36f7
+ last_write_checksum: sha1:1d16f944195d66950cba4bfc2f96255286cf33c0
+ pristine_git_object: 18f5cc3e2fe30014037f8f68d5513a4981d513b9
docs/operations/tasktype.mdx:
id: d3da8106d2d1
last_write_checksum: sha1:06aede3448490e1fb77b5c1b758238a11ce1dceb
@@ -6418,8 +6442,8 @@ trackedFiles:
pristine_git_object: 8ed39ab511e8430389a8cb92bed10b088a586006
docs/sdks/generations/README.mdx:
id: a754fecc8514
- last_write_checksum: sha1:e4276fe2f85be0fbafaf573fe58d17b7236d0652
- pristine_git_object: b29ea120367f5944c6a71e31f6c3d5e07ab4b798
+ last_write_checksum: sha1:b5f8035c676b5eb050472ed9697b64718aed8f17
+ pristine_git_object: f262b34982a18293f5ae22bfbbf385010bfcdc9c
docs/sdks/guardrails/README.mdx:
id: a0cd4218b8fa
last_write_checksum: sha1:b6543c22a38aca53d7bfbc8d41ed482965fc3b3c
@@ -6482,8 +6506,8 @@ trackedFiles:
pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544
pyproject.toml:
id: 5d07e7d72637
- last_write_checksum: sha1:061a0de3204cab06837642e4c0785b6b93705db3
- pristine_git_object: 60e16427643f806b9ab68941ac30f77e162c0c64
+ last_write_checksum: sha1:8564217ec020db72f0e9fdbc4cc2a9741aef8da8
+ pristine_git_object: 1f53995948f1621cbe09a49eab44c5b08e538977
scripts/prepare_readme.py:
id: e0c5957a6035
last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54
@@ -6510,8 +6534,8 @@ trackedFiles:
pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137
src/openrouter/_version.py:
id: d8d15ad6c586
- last_write_checksum: sha1:24cd6e9d1cf6e73b5cdef8748fa0124728b83567
- pristine_git_object: 623fc3453b008b588e0be363ab8c42525c104cfb
+ last_write_checksum: sha1:24a6775af4e431ffa67c67f909015339440e6b0a
+ pristine_git_object: d07f58993aa7027d3e22432eeec9c887d991b7ea
src/openrouter/analytics.py:
id: cb406b5aaabb
last_write_checksum: sha1:9e709b71dd0611056dc0cec6150b578defe32841
@@ -6550,8 +6574,8 @@ trackedFiles:
pristine_git_object: ad3d247954547814054c01989a2dff3d12b3e4e1
src/openrouter/components/__init__.py:
id: 81754e97b3f4
- last_write_checksum: sha1:010555a6206e0d8eaf1215bab3ad9a3a86db071f
- pristine_git_object: d127e29e5b6be993e21770cb1d968397fda34e8f
+ last_write_checksum: sha1:f4f8b839a539a8885447d5bbdadcc985553d65c8
+ pristine_git_object: 25795f206171fcfa804e2e44c033713d99f52c21
src/openrouter/components/aabenchmarkentry.py:
id: e2e0f0b48c82
last_write_checksum: sha1:fab4d9a24d2cea937bb749d46c5f83941e99d65c
@@ -6878,8 +6902,8 @@ trackedFiles:
pristine_git_object: 47ef267b5e0f7b615b0cd66018728e3f47440a66
src/openrouter/components/byokproviderslug.py:
id: 6738a8516caf
- last_write_checksum: sha1:2b105bacb46fd7150af7f079241fab2ba6700322
- pristine_git_object: 38050fde0204f069cb2568fafc91338a7051c92f
+ last_write_checksum: sha1:a5a6e1a2e7709f0afb9d97347c5d76457fea7d3e
+ pristine_git_object: 044751122a1397e7624e0e3abd867286dc96c6fc
src/openrouter/components/capabilitydescriptor.py:
id: 368790a86f10
last_write_checksum: sha1:a167551924ee82b4b5876a0ab698a45fe8c87a95
@@ -7486,8 +7510,8 @@ trackedFiles:
pristine_git_object: 6b9a8990973466285f9b49b366bbc5fc1ae42e41
src/openrouter/components/imagegenerationrequest.py:
id: f8291a7be9a0
- last_write_checksum: sha1:179a0b7ea9363fa826749e8bb6fb21074433e43e
- pristine_git_object: fbb59ab7c3ea49aa774b4fc917eb9ed9d4484d32
+ last_write_checksum: sha1:8a1e549056b8ef856f89c75182b49e3386c410fd
+ pristine_git_object: d1937b9c35752d03b04098295ea5dadb1804dafb
src/openrouter/components/imagegenerationresponse.py:
id: 53354cd0cbfc
last_write_checksum: sha1:53f1cde7b8bfe4f9e786a76f6e57b0a1f76aced2
@@ -8146,8 +8170,8 @@ trackedFiles:
pristine_git_object: 009c1401a29123f18887b48c03f9c2a8b11ca2b5
src/openrouter/components/provideroptions.py:
id: 73dde6c8f359
- last_write_checksum: sha1:ddde99f94118559796f316a1f05de70060f3bee1
- pristine_git_object: d84b93dea4982ead0bd8a069cb0801a8e02447c0
+ last_write_checksum: sha1:72fe38a2faab604e52a16eec0b5d1273b3eda64d
+ pristine_git_object: 9ab53163a6884a4fbf41c87391903f013eead544
src/openrouter/components/provideroverloadedresponseerrordata.py:
id: 5b693682570e
last_write_checksum: sha1:1ebc4527736f1e174ab37c84bea8a169fda9f8b8
@@ -8484,6 +8508,14 @@ trackedFiles:
id: a8425c790cb6
last_write_checksum: sha1:f434a1ff30f069c379b1809edd62b0435998156a
pristine_git_object: eb9f276769106934801d88ce9d2c5c5c67fe1bc2
+ src/openrouter/components/submitgenerationfeedbackrequest.py:
+ id: ae68ea802a9c
+ last_write_checksum: sha1:3d0fb9415d218dfbe5b978791c95bc0f28abb131
+ pristine_git_object: c73cccc81298593ce3f4acbf2b25f02956528d8f
+ src/openrouter/components/submitgenerationfeedbackresponse.py:
+ id: 1e1463bcfd03
+ last_write_checksum: sha1:d7ba55af6eca473c91a3cd09a73068bb8a75ad22
+ pristine_git_object: 139b0fc5a600fee17eafff1d36df72754c90b2fe
src/openrouter/components/taskclassificationitem.py:
id: 86d4bab5ebf3
last_write_checksum: sha1:16176fda0ccd16b0be59bb5c4b74db78eae02f36
@@ -8614,8 +8646,8 @@ trackedFiles:
pristine_git_object: 572d04f457607099ae7e041922de146de10e2eae
src/openrouter/components/videogenerationrequest.py:
id: 70e3c9ff288c
- last_write_checksum: sha1:bb81c3a4684e20898148e1415980457732da28d2
- pristine_git_object: 1f383a973b0d3f20605db372c24c9e9204c95d85
+ last_write_checksum: sha1:ded4141016409c0ee6bdde4061c704f8b006c84c
+ pristine_git_object: d96af0892419695a7fe096e045490a9a4ff13b8f
src/openrouter/components/videogenerationresponse.py:
id: 541f1321b072
last_write_checksum: sha1:18c3aa7845f63a9614286b1a27b6098eae1c4951
@@ -8826,8 +8858,8 @@ trackedFiles:
pristine_git_object: 1c20e7d6a4837053dac23f3d7985ef6910217589
src/openrouter/generations.py:
id: 70e1c21042bc
- last_write_checksum: sha1:c513500d0aecefad46e4e791094672dd8a31e6f2
- pristine_git_object: cecdd21a8e07352f8fa8d44e9018e01dfd918a99
+ last_write_checksum: sha1:00b190db603c57571f77ccfe5d5612a3f42c62a0
+ pristine_git_object: f6dbf5440466ba6b1d92442cad1b91e2b3587c52
src/openrouter/guardrails.py:
id: 705839f34e66
last_write_checksum: sha1:e525be9e5746b7b1cb6d170ac74cce37f010004a
@@ -8866,8 +8898,8 @@ trackedFiles:
pristine_git_object: a1dea9b45650cc42a6f60447c032fa46b102839a
src/openrouter/operations/__init__.py:
id: 9afcea1e7161
- last_write_checksum: sha1:46a3dfac25ac1c3d774e37ec8df54f9ba9851e46
- pristine_git_object: ab9fa9e4793e73671cc752005123a482b51b506f
+ last_write_checksum: sha1:23cba14efcf42e3a94779c6c259362a6f8a97deb
+ pristine_git_object: 3ee6fd4deecd7fcc382a5256db8e43c6f7e719ca
src/openrouter/operations/bulkaddworkspacemembers.py:
id: e0ed56117619
last_write_checksum: sha1:5c44eb0d40fdece3ac084615f6c6082be4cf1d5a
@@ -9082,8 +9114,8 @@ trackedFiles:
pristine_git_object: cc90375e9aac23107e57e18e6adecc38f544e185
src/openrouter/operations/listbyokkeys.py:
id: b6dd42b3e05f
- last_write_checksum: sha1:ca0276ecb273e8b62e43937369d7b059ad73d9f1
- pristine_git_object: 2ec07724128bf2fb6152e84694f31b4234279e82
+ last_write_checksum: sha1:7f5d32c8e8d9dc55fe7c5e8bf8fd71ed6406e10a
+ pristine_git_object: c3080ca256a625e437d85da39c703d0c3b495049
src/openrouter/operations/listembeddingsmodels.py:
id: bf749a1f23d6
last_write_checksum: sha1:19ed80a098e6e1b43bedfcccb11b4c8d8794541c
@@ -9188,6 +9220,10 @@ trackedFiles:
id: d9fee71bb577
last_write_checksum: sha1:0cba4011b8e305270ac30f88cb7ab59b6aefe619
pristine_git_object: b065e38c8d449348c4d133004653607e4194da6e
+ src/openrouter/operations/submitgenerationfeedback.py:
+ id: a1f4458f5e75
+ last_write_checksum: sha1:634750972ca2bf7d76b1530f19f0d5401a44c3d8
+ pristine_git_object: 878e3ec2224f81c003c35efa326d2ba53ee595c0
src/openrouter/operations/updatebyokkey.py:
id: 486f4ea60120
last_write_checksum: sha1:a170382e38c66128bddbe8ea18c034d1350910da
@@ -10823,5 +10859,22 @@ examples:
application/json: {"error": {"code": 404, "message": "Resource not found"}}
"500":
application/json: {"error": {"code": 500, "message": "Internal Server Error"}}
+ submitGenerationFeedback:
+ speakeasy-default-submit-generation-feedback:
+ requestBody:
+ application/json: {"category": "incorrect_response", "generation_id": "gen-3bhGkxlo4XFrqiabUM7NDtwDzWwG"}
+ responses:
+ "200":
+ application/json: {"data": {"success": true}}
+ "400":
+ application/json: {"error": {"code": 400, "message": "Invalid request parameters"}}
+ "401":
+ application/json: {"error": {"code": 401, "message": "Missing Authentication header"}}
+ "404":
+ application/json: {"error": {"code": 404, "message": "Resource not found"}}
+ "429":
+ application/json: {"error": {"code": 429, "message": "Rate limit exceeded"}}
+ "500":
+ application/json: {"error": {"code": 500, "message": "Internal Server Error"}}
examplesVersion: 1.0.2
-releaseNotes: "## Python SDK Changes:\n* `open_router.beta.responses.send()`: \n * `request.tools[].union(image_generation)` **Changed** (Breaking ⚠️)\n * `response` **Changed** (Breaking ⚠️)\n* `open_router.presets.create_presets_responses()`: \n * `request.tools[].union(image_generation)` **Changed** (Breaking ⚠️)\n"
+releaseNotes: "## Python SDK Changes:\n* `open_router.tts.create_speech()`: \n * `request.provider.options` **Changed** (Breaking ⚠️)\n* `open_router.stt.create_transcription()`: \n * `request.provider.options` **Changed** (Breaking ⚠️)\n* `open_router.byok.list()`: \n * `request.provider` **Changed** (Breaking ⚠️)\n * `response.data[].provider` **Changed** (Breaking ⚠️)\n* `open_router.byok.create()`: \n * `request.provider` **Changed** (Breaking ⚠️)\n * `response.data.provider` **Changed** (Breaking ⚠️)\n* `open_router.byok.get()`: `response.data.provider` **Changed** (Breaking ⚠️)\n* `open_router.byok.update()`: `response.data.provider` **Changed** (Breaking ⚠️)\n* `open_router.images.generate()`: \n * `request.provider.options` **Changed** (Breaking ⚠️)\n* `open_router.video_generation.generate()`: \n * `request.provider.options` **Changed** (Breaking ⚠️)\n* `open_router.generations.submit_feedback()`: **Added**\n"
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index 76543dda..d85800f2 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -36,7 +36,7 @@ generation:
documentation: mintlify
preApplyUnionDiscriminators: true
python:
- version: 0.11.16
+ version: 0.11.17
additionalDependencies:
dev: {}
main: {}
diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml
index 198ee997..1a0c9ef1 100644
--- a/.speakeasy/out.openapi.yaml
+++ b/.speakeasy/out.openapi.yaml
@@ -4047,7 +4047,7 @@ components:
- recraft
- reka
- relace
- - sakana-ai
+ - sakana
- sambanova
- seed
- siliconflow
@@ -18440,7 +18440,7 @@ components:
additionalProperties:
nullable: true
type: object
- sakana-ai:
+ sakana:
additionalProperties:
nullable: true
type: object
@@ -21121,6 +21121,59 @@ components:
$ref: '#/components/schemas/SubagentNestedTool'
type: array
type: object
+ SubmitGenerationFeedbackRequest:
+ description: Structured feedback about a specific generation
+ example:
+ category: incorrect_response
+ comment: The model repeated the same paragraph three times.
+ generation_id: gen-3bhGkxlo4XFrqiabUM7NDtwDzWwG
+ properties:
+ category:
+ description: The category of feedback being reported
+ enum:
+ - latency
+ - incoherence
+ - incorrect_response
+ - formatting
+ - billing
+ - api_error
+ - other
+ example: incorrect_response
+ type: string
+ x-speakeasy-unknown-values: allow
+ comment:
+ description: An optional free-text comment describing the feedback
+ example: The model repeated the same paragraph three times.
+ maxLength: 1000
+ type: string
+ generation_id:
+ description: The generation to submit feedback on
+ example: gen-3bhGkxlo4XFrqiabUM7NDtwDzWwG
+ minLength: 1
+ type: string
+ required:
+ - generation_id
+ - category
+ type: object
+ SubmitGenerationFeedbackResponse:
+ description: Confirmation that the feedback was recorded
+ example:
+ data:
+ success: true
+ properties:
+ data:
+ properties:
+ success:
+ const: true
+ description: Whether the feedback was recorded
+ example: true
+ type: boolean
+ required:
+ - success
+ type: object
+ required:
+ - data
+ type: object
SupportedParameters:
additionalProperties:
$ref: '#/components/schemas/CapabilityDescriptor'
@@ -24710,7 +24763,7 @@ paths:
- recraft
- reka
- relace
- - sakana-ai
+ - sakana
- sambanova
- seed
- siliconflow
@@ -27262,6 +27315,89 @@ paths:
- $ref: "#/components/parameters/AppIdentifier"
- $ref: "#/components/parameters/AppDisplayName"
- $ref: "#/components/parameters/AppCategories"
+ /generation/feedback:
+ post:
+ description: >-
+ Submit structured feedback on a generation the authenticated user made. [Management key](/docs/guides/overview/auth/management-api-keys) required.
+ operationId: submitGenerationFeedback
+ requestBody:
+ content:
+ application/json:
+ example:
+ category: incorrect_response
+ comment: The model repeated the same paragraph three times.
+ generation_id: gen-3bhGkxlo4XFrqiabUM7NDtwDzWwG
+ schema:
+ $ref: '#/components/schemas/SubmitGenerationFeedbackRequest'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ example:
+ data:
+ success: true
+ schema:
+ $ref: '#/components/schemas/SubmitGenerationFeedbackResponse'
+ description: Feedback recorded successfully
+ '400':
+ content:
+ application/json:
+ example:
+ error:
+ code: 400
+ message: Invalid request parameters
+ schema:
+ $ref: '#/components/schemas/BadRequestResponse'
+ description: Bad Request - Invalid request parameters or malformed input
+ '401':
+ content:
+ application/json:
+ example:
+ error:
+ code: 401
+ message: Missing Authentication header
+ schema:
+ $ref: '#/components/schemas/UnauthorizedResponse'
+ description: Unauthorized - Authentication required or invalid credentials
+ '404':
+ content:
+ application/json:
+ example:
+ error:
+ code: 404
+ message: Resource not found
+ schema:
+ $ref: '#/components/schemas/NotFoundResponse'
+ description: Not Found - Resource does not exist
+ '429':
+ content:
+ application/json:
+ example:
+ error:
+ code: 429
+ message: Rate limit exceeded
+ schema:
+ $ref: '#/components/schemas/TooManyRequestsResponse'
+ description: Too Many Requests - Rate limit exceeded
+ '500':
+ content:
+ application/json:
+ example:
+ error:
+ code: 500
+ message: Internal Server Error
+ schema:
+ $ref: '#/components/schemas/InternalServerResponse'
+ description: Internal Server Error - Unexpected server error
+ summary: Submit feedback for a generation
+ tags:
+ - Generations
+ x-speakeasy-name-override: submitFeedback
+ parameters:
+ - $ref: "#/components/parameters/AppIdentifier"
+ - $ref: "#/components/parameters/AppDisplayName"
+ - $ref: "#/components/parameters/AppCategories"
/guardrails:
get:
description: >-
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index af61311a..4af3fa7d 100644
--- a/.speakeasy/workflow.lock
+++ b/.speakeasy/workflow.lock
@@ -2,8 +2,8 @@ speakeasyVersion: 1.787.0
sources:
OpenRouter API:
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:daca20db09d6cfb4b50c5e6bf7d8f5cbadae39021bd5cb9c856d71b4e6f9c192
- sourceBlobDigest: sha256:0834507d142ac7906f4ca76b874a2b49bd5709b782a420377f3cf4349552a445
+ sourceRevisionDigest: sha256:99649ad73bd44656a11c0f47bf5b52ff056911ce5543fdd487b1c7d835d4d01e
+ sourceBlobDigest: sha256:fb03e6ac1679e81970afc16a019748cc195bb2881a09f0e5dc0ae18934621701
tags:
- latest
- 1.0.0
@@ -11,10 +11,10 @@ targets:
open-router:
source: OpenRouter API
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:daca20db09d6cfb4b50c5e6bf7d8f5cbadae39021bd5cb9c856d71b4e6f9c192
- sourceBlobDigest: sha256:0834507d142ac7906f4ca76b874a2b49bd5709b782a420377f3cf4349552a445
+ sourceRevisionDigest: sha256:99649ad73bd44656a11c0f47bf5b52ff056911ce5543fdd487b1c7d835d4d01e
+ sourceBlobDigest: sha256:fb03e6ac1679e81970afc16a019748cc195bb2881a09f0e5dc0ae18934621701
codeSamplesNamespace: open-router-python-code-samples
- codeSamplesRevisionDigest: sha256:d7c4a0cd51e67e5c63e2540958b5a5df3406fbbe723c58338a51e48feb9ddae2
+ codeSamplesRevisionDigest: sha256:a6459b61a352d9d8512b16c634606461a35e4275e373904dec9cd85e245db64b
workflow:
workflowVersion: 1.0.0
speakeasyVersion: 1.787.0
diff --git a/RELEASES.md b/RELEASES.md
index 0076cf6e..bd0faa76 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -268,4 +268,14 @@ Based on:
### Generated
- [python v0.11.16] .
### Releases
-- [PyPI v0.11.16] https://pypi.org/project/openrouter/0.11.16 - .
\ No newline at end of file
+- [PyPI v0.11.16] https://pypi.org/project/openrouter/0.11.16 - .
+
+## 2026-07-09 21:34:56
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [python v0.11.17] .
+### Releases
+- [PyPI v0.11.17] https://pypi.org/project/openrouter/0.11.17 - .
\ No newline at end of file
diff --git a/docs/components/byokproviderslug.mdx b/docs/components/byokproviderslug.mdx
index 439563d0..619d8a09 100644
--- a/docs/components/byokproviderslug.mdx
+++ b/docs/components/byokproviderslug.mdx
@@ -89,7 +89,7 @@ This is an open enum. Unrecognized values will not fail type checks.
- `"recraft"`
- `"reka"`
- `"relace"`
-- `"sakana-ai"`
+- `"sakana"`
- `"sambanova"`
- `"seed"`
- `"siliconflow"`
diff --git a/docs/components/category.mdx b/docs/components/category.mdx
new file mode 100644
index 00000000..e67ca2a0
--- /dev/null
+++ b/docs/components/category.mdx
@@ -0,0 +1,27 @@
+---
+title: "Category"
+---
+
+The category of feedback being reported
+
+## Example Usage
+
+```python
+from openrouter.components import Category
+
+# Open enum: unrecognized values are captured as UnrecognizedStr
+value: Category = "latency"
+```
+
+
+## Values
+
+This is an open enum. Unrecognized values will not fail type checks.
+
+- `"latency"`
+- `"incoherence"`
+- `"incorrect_response"`
+- `"formatting"`
+- `"billing"`
+- `"api_error"`
+- `"other"`
diff --git a/docs/components/imagegenerationrequestoptions.mdx b/docs/components/imagegenerationrequestoptions.mdx
index 26f3f1ec..b6426f4b 100644
--- a/docs/components/imagegenerationrequestoptions.mdx
+++ b/docs/components/imagegenerationrequestoptions.mdx
@@ -106,7 +106,7 @@ Provider-specific options keyed by provider slug. Only options for the matched p
| `reka` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `relace` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `replicate` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
-| `sakana_ai` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
+| `sakana` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `sambanova` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `sambanova_cloaked` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `seed` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
diff --git a/docs/components/provideroptions.mdx b/docs/components/provideroptions.mdx
index b15b96fc..c9df643f 100644
--- a/docs/components/provideroptions.mdx
+++ b/docs/components/provideroptions.mdx
@@ -106,7 +106,7 @@ Provider-specific options keyed by provider slug. Only options for the matched p
| `reka` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `relace` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `replicate` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
-| `sakana_ai` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
+| `sakana` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `sambanova` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `sambanova_cloaked` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `seed` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
diff --git a/docs/components/submitgenerationfeedbackrequest.mdx b/docs/components/submitgenerationfeedbackrequest.mdx
new file mode 100644
index 00000000..9e56152e
--- /dev/null
+++ b/docs/components/submitgenerationfeedbackrequest.mdx
@@ -0,0 +1,14 @@
+---
+title: "SubmitGenerationFeedbackRequest"
+---
+
+Structured feedback about a specific generation
+
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| ----------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------- |
+| `category` | [components.Category](../components/category.mdx) | :heavy_check_mark: | The category of feedback being reported | incorrect_response |
+| `comment` | *Optional[str]* | :heavy_minus_sign: | An optional free-text comment describing the feedback | The model repeated the same paragraph three times. |
+| `generation_id` | *str* | :heavy_check_mark: | The generation to submit feedback on | gen-3bhGkxlo4XFrqiabUM7NDtwDzWwG |
\ No newline at end of file
diff --git a/docs/components/submitgenerationfeedbackresponse.mdx b/docs/components/submitgenerationfeedbackresponse.mdx
new file mode 100644
index 00000000..ba546e04
--- /dev/null
+++ b/docs/components/submitgenerationfeedbackresponse.mdx
@@ -0,0 +1,12 @@
+---
+title: "SubmitGenerationFeedbackResponse"
+---
+
+Confirmation that the feedback was recorded
+
+
+## Fields
+
+| Field | Type | Required | Description |
+| -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
+| `data` | [components.SubmitGenerationFeedbackResponseData](../components/submitgenerationfeedbackresponsedata.mdx) | :heavy_check_mark: | N/A |
\ No newline at end of file
diff --git a/docs/components/submitgenerationfeedbackresponsedata.mdx b/docs/components/submitgenerationfeedbackresponsedata.mdx
new file mode 100644
index 00000000..2b6ccfe5
--- /dev/null
+++ b/docs/components/submitgenerationfeedbackresponsedata.mdx
@@ -0,0 +1,9 @@
+---
+title: "SubmitGenerationFeedbackResponseData"
+---
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| --------------------------------- | --------------------------------- | --------------------------------- | --------------------------------- | --------------------------------- |
+| `success` | *Literal[True]* | :heavy_check_mark: | Whether the feedback was recorded | true |
\ No newline at end of file
diff --git a/docs/components/videogenerationrequestoptions.mdx b/docs/components/videogenerationrequestoptions.mdx
index f3d6474e..c1d338ae 100644
--- a/docs/components/videogenerationrequestoptions.mdx
+++ b/docs/components/videogenerationrequestoptions.mdx
@@ -106,7 +106,7 @@ Provider-specific options keyed by provider slug. Only options for the matched p
| `reka` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `relace` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `replicate` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
-| `sakana_ai` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
+| `sakana` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `sambanova` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `sambanova_cloaked` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
| `seed` | Dict[str, *Nullable[Any]*] | :heavy_minus_sign: | N/A |
diff --git a/docs/operations/provider.mdx b/docs/operations/provider.mdx
index 1b6b6202..139a0786 100644
--- a/docs/operations/provider.mdx
+++ b/docs/operations/provider.mdx
@@ -89,7 +89,7 @@ This is an open enum. Unrecognized values will not fail type checks.
- `"recraft"`
- `"reka"`
- `"relace"`
-- `"sakana-ai"`
+- `"sakana"`
- `"sambanova"`
- `"seed"`
- `"siliconflow"`
diff --git a/docs/operations/submitgenerationfeedbackglobals.mdx b/docs/operations/submitgenerationfeedbackglobals.mdx
new file mode 100644
index 00000000..bbd731b6
--- /dev/null
+++ b/docs/operations/submitgenerationfeedbackglobals.mdx
@@ -0,0 +1,11 @@
+---
+title: "SubmitGenerationFeedbackGlobals"
+---
+
+## Fields
+
+| Field | Type | Required | Description |
+| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `http_referer` | *Optional[str]* | :heavy_minus_sign: | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
|
+| `x_open_router_title` | *Optional[str]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
|
+| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
|
\ No newline at end of file
diff --git a/docs/operations/submitgenerationfeedbackrequest.mdx b/docs/operations/submitgenerationfeedbackrequest.mdx
new file mode 100644
index 00000000..18f5cc3e
--- /dev/null
+++ b/docs/operations/submitgenerationfeedbackrequest.mdx
@@ -0,0 +1,12 @@
+---
+title: "SubmitGenerationFeedbackRequest"
+---
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `http_referer` | *Optional[str]* | :heavy_minus_sign: | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
+| `x_open_router_title` | *Optional[str]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `submit_generation_feedback_request` | [components.SubmitGenerationFeedbackRequest](../components/submitgenerationfeedbackrequest.mdx) | :heavy_check_mark: | N/A | \{
"category": "incorrect_response",
"comment": "The model repeated the same paragraph three times.",
"generation_id": "gen-3bhGkxlo4XFrqiabUM7NDtwDzWwG"
} |
\ No newline at end of file
diff --git a/docs/sdks/generations/README.mdx b/docs/sdks/generations/README.mdx
index b29ea120..f262b349 100644
--- a/docs/sdks/generations/README.mdx
+++ b/docs/sdks/generations/README.mdx
@@ -11,6 +11,7 @@ Generation history endpoints
* [get_generation](#get_generation) - Get request & usage metadata for a generation
* [list_generation_content](#list_generation_content) - Get stored prompt and completion content for a generation
+* [submit_feedback](#submit_feedback) - Submit feedback for a generation
## get_generation
@@ -116,4 +117,56 @@ with OpenRouter(
| errors.BadGatewayResponseError | 502 | application/json |
| errors.EdgeNetworkTimeoutResponseError | 524 | application/json |
| errors.ProviderOverloadedResponseError | 529 | application/json |
-| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
\ No newline at end of file
+| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
+
+## submit_feedback
+
+Submit structured feedback on a generation the authenticated user made. [Management key](/docs/guides/overview/auth/management-api-keys) required.
+
+### Example Usage
+
+```python
+from openrouter import OpenRouter
+import os
+
+
+with OpenRouter(
+ http_referer="",
+ x_open_router_title="",
+ x_open_router_categories="",
+ api_key=os.getenv("OPENROUTER_API_KEY", ""),
+) as open_router:
+
+ res = open_router.generations.submit_feedback(category="incorrect_response", generation_id="gen-3bhGkxlo4XFrqiabUM7NDtwDzWwG", comment="The model repeated the same paragraph three times.")
+
+ # Handle response
+ print(res)
+
+```
+
+### Parameters
+
+| Parameter | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `category` | [components.Category](../../components/category.mdx) | :heavy_check_mark: | The category of feedback being reported | incorrect_response |
+| `generation_id` | *str* | :heavy_check_mark: | The generation to submit feedback on | gen-3bhGkxlo4XFrqiabUM7NDtwDzWwG |
+| `http_referer` | *Optional[str]* | :heavy_minus_sign: | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
+| `x_open_router_title` | *Optional[str]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `comment` | *Optional[str]* | :heavy_minus_sign: | An optional free-text comment describing the feedback | The model repeated the same paragraph three times. |
+| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | |
+
+### Response
+
+**[components.SubmitGenerationFeedbackResponse](../../components/submitgenerationfeedbackresponse.mdx)**
+
+### Errors
+
+| Error Type | Status Code | Content Type |
+| ----------------------------------- | ----------------------------------- | ----------------------------------- |
+| errors.BadRequestResponseError | 400 | application/json |
+| errors.UnauthorizedResponseError | 401 | application/json |
+| errors.NotFoundResponseError | 404 | application/json |
+| errors.TooManyRequestsResponseError | 429 | application/json |
+| errors.InternalServerResponseError | 500 | application/json |
+| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 60e16427..1f539959 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openrouter"
-version = "0.11.16"
+version = "0.11.17"
description = "Official Python Client SDK for OpenRouter."
authors = [{ name = "OpenRouter" },]
readme = "README-PYPI.md"
diff --git a/src/openrouter/_version.py b/src/openrouter/_version.py
index 623fc345..d07f5899 100644
--- a/src/openrouter/_version.py
+++ b/src/openrouter/_version.py
@@ -3,10 +3,10 @@
import importlib.metadata
__title__: str = "openrouter"
-__version__: str = "0.11.16"
+__version__: str = "0.11.17"
__openapi_doc_version__: str = "1.0.0"
__gen_version__: str = "2.914.0"
-__user_agent__: str = "speakeasy-sdk/python 0.11.16 2.914.0 1.0.0 openrouter"
+__user_agent__: str = "speakeasy-sdk/python 0.11.17 2.914.0 1.0.0 openrouter"
try:
if __package__ is not None:
diff --git a/src/openrouter/components/__init__.py b/src/openrouter/components/__init__.py
index d127e29e..25795f20 100644
--- a/src/openrouter/components/__init__.py
+++ b/src/openrouter/components/__init__.py
@@ -2488,6 +2488,17 @@
SubagentServerToolConfig,
SubagentServerToolConfigTypedDict,
)
+ from .submitgenerationfeedbackrequest import (
+ Category,
+ SubmitGenerationFeedbackRequest,
+ SubmitGenerationFeedbackRequestTypedDict,
+ )
+ from .submitgenerationfeedbackresponse import (
+ SubmitGenerationFeedbackResponse,
+ SubmitGenerationFeedbackResponseData,
+ SubmitGenerationFeedbackResponseDataTypedDict,
+ SubmitGenerationFeedbackResponseTypedDict,
+ )
from .taskclassificationitem import (
TaskClassificationItem,
TaskClassificationItemTypedDict,
@@ -2995,6 +3006,7 @@
"CachingTypedDict",
"CapabilityDescriptor",
"CapabilityDescriptorTypedDict",
+ "Category",
"ChatAssistantImages",
"ChatAssistantImagesImageURL",
"ChatAssistantImagesImageURLTypedDict",
@@ -4486,6 +4498,12 @@
"SubagentServerToolOpenRouter",
"SubagentServerToolOpenRouterType",
"SubagentServerToolOpenRouterTypedDict",
+ "SubmitGenerationFeedbackRequest",
+ "SubmitGenerationFeedbackRequestTypedDict",
+ "SubmitGenerationFeedbackResponse",
+ "SubmitGenerationFeedbackResponseData",
+ "SubmitGenerationFeedbackResponseDataTypedDict",
+ "SubmitGenerationFeedbackResponseTypedDict",
"SupportedAspectRatio",
"SupportedFrameImage",
"SupportedResolution",
@@ -6605,6 +6623,13 @@
"SubagentServerToolOpenRouterTypedDict": ".subagentservertool_openrouter",
"SubagentServerToolConfig": ".subagentservertoolconfig",
"SubagentServerToolConfigTypedDict": ".subagentservertoolconfig",
+ "Category": ".submitgenerationfeedbackrequest",
+ "SubmitGenerationFeedbackRequest": ".submitgenerationfeedbackrequest",
+ "SubmitGenerationFeedbackRequestTypedDict": ".submitgenerationfeedbackrequest",
+ "SubmitGenerationFeedbackResponse": ".submitgenerationfeedbackresponse",
+ "SubmitGenerationFeedbackResponseData": ".submitgenerationfeedbackresponse",
+ "SubmitGenerationFeedbackResponseDataTypedDict": ".submitgenerationfeedbackresponse",
+ "SubmitGenerationFeedbackResponseTypedDict": ".submitgenerationfeedbackresponse",
"TaskClassificationItem": ".taskclassificationitem",
"TaskClassificationItemTypedDict": ".taskclassificationitem",
"TaskClassificationMacroCategory": ".taskclassificationmacrocategory",
diff --git a/src/openrouter/components/byokproviderslug.py b/src/openrouter/components/byokproviderslug.py
index 38050fde..04475112 100644
--- a/src/openrouter/components/byokproviderslug.py
+++ b/src/openrouter/components/byokproviderslug.py
@@ -78,7 +78,7 @@
"recraft",
"reka",
"relace",
- "sakana-ai",
+ "sakana",
"sambanova",
"seed",
"siliconflow",
diff --git a/src/openrouter/components/imagegenerationrequest.py b/src/openrouter/components/imagegenerationrequest.py
index fbb59ab7..d1937b9c 100644
--- a/src/openrouter/components/imagegenerationrequest.py
+++ b/src/openrouter/components/imagegenerationrequest.py
@@ -162,7 +162,7 @@ class ImageGenerationRequestOptionsTypedDict(TypedDict):
reka: NotRequired[Dict[str, Nullable[Any]]]
relace: NotRequired[Dict[str, Nullable[Any]]]
replicate: NotRequired[Dict[str, Nullable[Any]]]
- sakana_ai: NotRequired[Dict[str, Nullable[Any]]]
+ sakana: NotRequired[Dict[str, Nullable[Any]]]
sambanova: NotRequired[Dict[str, Nullable[Any]]]
sambanova_cloaked: NotRequired[Dict[str, Nullable[Any]]]
seed: NotRequired[Dict[str, Nullable[Any]]]
@@ -422,9 +422,7 @@ class ImageGenerationRequestOptions(BaseModel):
replicate: Optional[Dict[str, Nullable[Any]]] = None
- sakana_ai: Annotated[
- Optional[Dict[str, Nullable[Any]]], pydantic.Field(alias="sakana-ai")
- ] = None
+ sakana: Optional[Dict[str, Nullable[Any]]] = None
sambanova: Optional[Dict[str, Nullable[Any]]] = None
@@ -579,7 +577,7 @@ def serialize_model(self, handler):
"reka",
"relace",
"replicate",
- "sakana-ai",
+ "sakana",
"sambanova",
"sambanova-cloaked",
"seed",
diff --git a/src/openrouter/components/provideroptions.py b/src/openrouter/components/provideroptions.py
index d84b93de..9ab53163 100644
--- a/src/openrouter/components/provideroptions.py
+++ b/src/openrouter/components/provideroptions.py
@@ -108,7 +108,7 @@ class ProviderOptionsTypedDict(TypedDict):
reka: NotRequired[Dict[str, Nullable[Any]]]
relace: NotRequired[Dict[str, Nullable[Any]]]
replicate: NotRequired[Dict[str, Nullable[Any]]]
- sakana_ai: NotRequired[Dict[str, Nullable[Any]]]
+ sakana: NotRequired[Dict[str, Nullable[Any]]]
sambanova: NotRequired[Dict[str, Nullable[Any]]]
sambanova_cloaked: NotRequired[Dict[str, Nullable[Any]]]
seed: NotRequired[Dict[str, Nullable[Any]]]
@@ -368,9 +368,7 @@ class ProviderOptions(BaseModel):
replicate: Optional[Dict[str, Nullable[Any]]] = None
- sakana_ai: Annotated[
- Optional[Dict[str, Nullable[Any]]], pydantic.Field(alias="sakana-ai")
- ] = None
+ sakana: Optional[Dict[str, Nullable[Any]]] = None
sambanova: Optional[Dict[str, Nullable[Any]]] = None
@@ -525,7 +523,7 @@ def serialize_model(self, handler):
"reka",
"relace",
"replicate",
- "sakana-ai",
+ "sakana",
"sambanova",
"sambanova-cloaked",
"seed",
diff --git a/src/openrouter/components/submitgenerationfeedbackrequest.py b/src/openrouter/components/submitgenerationfeedbackrequest.py
new file mode 100644
index 00000000..c73cccc8
--- /dev/null
+++ b/src/openrouter/components/submitgenerationfeedbackrequest.py
@@ -0,0 +1,62 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from openrouter.types import BaseModel, UNSET_SENTINEL, UnrecognizedStr
+from pydantic import model_serializer
+from typing import Literal, Optional, Union
+from typing_extensions import NotRequired, TypedDict
+
+
+Category = Union[
+ Literal[
+ "latency",
+ "incoherence",
+ "incorrect_response",
+ "formatting",
+ "billing",
+ "api_error",
+ "other",
+ ],
+ UnrecognizedStr,
+]
+r"""The category of feedback being reported"""
+
+
+class SubmitGenerationFeedbackRequestTypedDict(TypedDict):
+ r"""Structured feedback about a specific generation"""
+
+ category: Category
+ r"""The category of feedback being reported"""
+ generation_id: str
+ r"""The generation to submit feedback on"""
+ comment: NotRequired[str]
+ r"""An optional free-text comment describing the feedback"""
+
+
+class SubmitGenerationFeedbackRequest(BaseModel):
+ r"""Structured feedback about a specific generation"""
+
+ category: Category
+ r"""The category of feedback being reported"""
+
+ generation_id: str
+ r"""The generation to submit feedback on"""
+
+ comment: Optional[str] = None
+ r"""An optional free-text comment describing the feedback"""
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(["comment"])
+ serialized = handler(self)
+ m = {}
+
+ for n, f in type(self).model_fields.items():
+ k = f.alias or n
+ val = serialized.get(k, serialized.get(n))
+
+ if val != UNSET_SENTINEL:
+ if val is not None or k not in optional_fields:
+ m[k] = val
+
+ return m
diff --git a/src/openrouter/components/submitgenerationfeedbackresponse.py b/src/openrouter/components/submitgenerationfeedbackresponse.py
new file mode 100644
index 00000000..139b0fc5
--- /dev/null
+++ b/src/openrouter/components/submitgenerationfeedbackresponse.py
@@ -0,0 +1,40 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from openrouter.types import BaseModel
+from openrouter.utils import validate_const
+import pydantic
+from pydantic.functional_validators import AfterValidator
+from typing import Literal
+from typing_extensions import Annotated, TypedDict
+
+
+class SubmitGenerationFeedbackResponseDataTypedDict(TypedDict):
+ success: Literal[True]
+ r"""Whether the feedback was recorded"""
+
+
+class SubmitGenerationFeedbackResponseData(BaseModel):
+ SUCCESS: Annotated[
+ Annotated[Literal[True], AfterValidator(validate_const(True))],
+ pydantic.Field(alias="success"),
+ ] = True
+ r"""Whether the feedback was recorded"""
+
+
+class SubmitGenerationFeedbackResponseTypedDict(TypedDict):
+ r"""Confirmation that the feedback was recorded"""
+
+ data: SubmitGenerationFeedbackResponseDataTypedDict
+
+
+class SubmitGenerationFeedbackResponse(BaseModel):
+ r"""Confirmation that the feedback was recorded"""
+
+ data: SubmitGenerationFeedbackResponseData
+
+
+try:
+ SubmitGenerationFeedbackResponseData.model_rebuild()
+except NameError:
+ pass
diff --git a/src/openrouter/components/videogenerationrequest.py b/src/openrouter/components/videogenerationrequest.py
index 1f383a97..d96af089 100644
--- a/src/openrouter/components/videogenerationrequest.py
+++ b/src/openrouter/components/videogenerationrequest.py
@@ -127,7 +127,7 @@ class VideoGenerationRequestOptionsTypedDict(TypedDict):
reka: NotRequired[Dict[str, Nullable[Any]]]
relace: NotRequired[Dict[str, Nullable[Any]]]
replicate: NotRequired[Dict[str, Nullable[Any]]]
- sakana_ai: NotRequired[Dict[str, Nullable[Any]]]
+ sakana: NotRequired[Dict[str, Nullable[Any]]]
sambanova: NotRequired[Dict[str, Nullable[Any]]]
sambanova_cloaked: NotRequired[Dict[str, Nullable[Any]]]
seed: NotRequired[Dict[str, Nullable[Any]]]
@@ -387,9 +387,7 @@ class VideoGenerationRequestOptions(BaseModel):
replicate: Optional[Dict[str, Nullable[Any]]] = None
- sakana_ai: Annotated[
- Optional[Dict[str, Nullable[Any]]], pydantic.Field(alias="sakana-ai")
- ] = None
+ sakana: Optional[Dict[str, Nullable[Any]]] = None
sambanova: Optional[Dict[str, Nullable[Any]]] = None
@@ -544,7 +542,7 @@ def serialize_model(self, handler):
"reka",
"relace",
"replicate",
- "sakana-ai",
+ "sakana",
"sambanova",
"sambanova-cloaked",
"seed",
diff --git a/src/openrouter/generations.py b/src/openrouter/generations.py
index cecdd21a..f6dbf544 100644
--- a/src/openrouter/generations.py
+++ b/src/openrouter/generations.py
@@ -619,3 +619,313 @@ async def list_generation_content_async(
)
raise errors.OpenRouterDefaultError("Unexpected response received", http_res)
+
+ def submit_feedback(
+ self,
+ *,
+ category: components.Category,
+ generation_id: str,
+ http_referer: Optional[str] = None,
+ x_open_router_title: Optional[str] = None,
+ x_open_router_categories: Optional[str] = None,
+ comment: Optional[str] = None,
+ retries: OptionalNullable[utils.RetryConfig] = UNSET,
+ server_url: Optional[str] = None,
+ timeout_ms: Optional[int] = None,
+ http_headers: Optional[Mapping[str, str]] = None,
+ ) -> components.SubmitGenerationFeedbackResponse:
+ r"""Submit feedback for a generation
+
+ Submit structured feedback on a generation the authenticated user made. [Management key](/docs/guides/overview/auth/management-api-keys) required.
+
+ :param category: The category of feedback being reported
+ :param generation_id: The generation to submit feedback on
+ :param http_referer: The app identifier should be your app's URL and is used as the primary identifier for rankings.
+ This is used to track API usage per application.
+
+ :param x_open_router_title: The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ :param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ :param comment: An optional free-text comment describing the feedback
+ :param retries: Override the default retry configuration for this method
+ :param server_url: Override the default server URL for this method
+ :param timeout_ms: Override the default request timeout configuration for this method in milliseconds
+ :param http_headers: Additional headers to set or replace on requests.
+ """
+ base_url = None
+ url_variables = None
+ if timeout_ms is None:
+ timeout_ms = self.sdk_configuration.timeout_ms
+
+ if server_url is not None:
+ base_url = server_url
+ else:
+ base_url = self._get_url(base_url, url_variables)
+
+ request = operations.SubmitGenerationFeedbackRequest(
+ http_referer=http_referer,
+ x_open_router_title=x_open_router_title,
+ x_open_router_categories=x_open_router_categories,
+ submit_generation_feedback_request=components.SubmitGenerationFeedbackRequest(
+ category=category,
+ comment=comment,
+ generation_id=generation_id,
+ ),
+ )
+
+ req = self._build_request(
+ method="POST",
+ path="/generation/feedback",
+ base_url=base_url,
+ url_variables=url_variables,
+ request=request,
+ request_body_required=True,
+ request_has_path_params=False,
+ request_has_query_params=True,
+ user_agent_header="user-agent",
+ accept_header_value="application/json",
+ http_headers=http_headers,
+ _globals=operations.SubmitGenerationFeedbackGlobals(
+ http_referer=self.sdk_configuration.globals.http_referer,
+ x_open_router_title=self.sdk_configuration.globals.x_open_router_title,
+ x_open_router_categories=self.sdk_configuration.globals.x_open_router_categories,
+ ),
+ security=self.sdk_configuration.security,
+ get_serialized_body=lambda: utils.serialize_request_body(
+ request.submit_generation_feedback_request,
+ False,
+ False,
+ "json",
+ components.SubmitGenerationFeedbackRequest,
+ ),
+ allow_empty_value=None,
+ timeout_ms=timeout_ms,
+ )
+
+ if retries == UNSET:
+ if self.sdk_configuration.retry_config is not UNSET:
+ retries = self.sdk_configuration.retry_config
+ else:
+ retries = utils.RetryConfig(
+ "backoff", utils.BackoffStrategy(500, 60000, 1.5, 3600000), True
+ )
+
+ retry_config = None
+ if isinstance(retries, utils.RetryConfig):
+ retry_config = (retries, ["5XX"])
+
+ http_res = self.do_request(
+ hook_ctx=HookContext(
+ config=self.sdk_configuration,
+ base_url=base_url or "",
+ operation_id="submitGenerationFeedback",
+ oauth2_scopes=None,
+ security_source=get_security_from_env(
+ self.sdk_configuration.security, components.Security
+ ),
+ tags=["Generations"],
+ extensions=None,
+ ),
+ request=req,
+ is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c),
+ retry_config=retry_config,
+ )
+
+ response_data: Any = None
+ if utils.match_response(http_res, "200", "application/json"):
+ return unmarshal_json_response(
+ components.SubmitGenerationFeedbackResponse, http_res
+ )
+ if utils.match_response(http_res, "400", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.BadRequestResponseErrorData, http_res
+ )
+ raise errors.BadRequestResponseError(response_data, http_res)
+ if utils.match_response(http_res, "401", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.UnauthorizedResponseErrorData, http_res
+ )
+ raise errors.UnauthorizedResponseError(response_data, http_res)
+ if utils.match_response(http_res, "404", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.NotFoundResponseErrorData, http_res
+ )
+ raise errors.NotFoundResponseError(response_data, http_res)
+ if utils.match_response(http_res, "429", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.TooManyRequestsResponseErrorData, http_res
+ )
+ raise errors.TooManyRequestsResponseError(response_data, http_res)
+ if utils.match_response(http_res, "500", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternalServerResponseErrorData, http_res
+ )
+ raise errors.InternalServerResponseError(response_data, http_res)
+ if utils.match_response(http_res, "4XX", "*"):
+ http_res_text = utils.stream_to_text(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+ if utils.match_response(http_res, "5XX", "*"):
+ http_res_text = utils.stream_to_text(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+
+ raise errors.OpenRouterDefaultError("Unexpected response received", http_res)
+
+ async def submit_feedback_async(
+ self,
+ *,
+ category: components.Category,
+ generation_id: str,
+ http_referer: Optional[str] = None,
+ x_open_router_title: Optional[str] = None,
+ x_open_router_categories: Optional[str] = None,
+ comment: Optional[str] = None,
+ retries: OptionalNullable[utils.RetryConfig] = UNSET,
+ server_url: Optional[str] = None,
+ timeout_ms: Optional[int] = None,
+ http_headers: Optional[Mapping[str, str]] = None,
+ ) -> components.SubmitGenerationFeedbackResponse:
+ r"""Submit feedback for a generation
+
+ Submit structured feedback on a generation the authenticated user made. [Management key](/docs/guides/overview/auth/management-api-keys) required.
+
+ :param category: The category of feedback being reported
+ :param generation_id: The generation to submit feedback on
+ :param http_referer: The app identifier should be your app's URL and is used as the primary identifier for rankings.
+ This is used to track API usage per application.
+
+ :param x_open_router_title: The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ :param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ :param comment: An optional free-text comment describing the feedback
+ :param retries: Override the default retry configuration for this method
+ :param server_url: Override the default server URL for this method
+ :param timeout_ms: Override the default request timeout configuration for this method in milliseconds
+ :param http_headers: Additional headers to set or replace on requests.
+ """
+ base_url = None
+ url_variables = None
+ if timeout_ms is None:
+ timeout_ms = self.sdk_configuration.timeout_ms
+
+ if server_url is not None:
+ base_url = server_url
+ else:
+ base_url = self._get_url(base_url, url_variables)
+
+ request = operations.SubmitGenerationFeedbackRequest(
+ http_referer=http_referer,
+ x_open_router_title=x_open_router_title,
+ x_open_router_categories=x_open_router_categories,
+ submit_generation_feedback_request=components.SubmitGenerationFeedbackRequest(
+ category=category,
+ comment=comment,
+ generation_id=generation_id,
+ ),
+ )
+
+ req = self._build_request_async(
+ method="POST",
+ path="/generation/feedback",
+ base_url=base_url,
+ url_variables=url_variables,
+ request=request,
+ request_body_required=True,
+ request_has_path_params=False,
+ request_has_query_params=True,
+ user_agent_header="user-agent",
+ accept_header_value="application/json",
+ http_headers=http_headers,
+ _globals=operations.SubmitGenerationFeedbackGlobals(
+ http_referer=self.sdk_configuration.globals.http_referer,
+ x_open_router_title=self.sdk_configuration.globals.x_open_router_title,
+ x_open_router_categories=self.sdk_configuration.globals.x_open_router_categories,
+ ),
+ security=self.sdk_configuration.security,
+ get_serialized_body=lambda: utils.serialize_request_body(
+ request.submit_generation_feedback_request,
+ False,
+ False,
+ "json",
+ components.SubmitGenerationFeedbackRequest,
+ ),
+ allow_empty_value=None,
+ timeout_ms=timeout_ms,
+ )
+
+ if retries == UNSET:
+ if self.sdk_configuration.retry_config is not UNSET:
+ retries = self.sdk_configuration.retry_config
+ else:
+ retries = utils.RetryConfig(
+ "backoff", utils.BackoffStrategy(500, 60000, 1.5, 3600000), True
+ )
+
+ retry_config = None
+ if isinstance(retries, utils.RetryConfig):
+ retry_config = (retries, ["5XX"])
+
+ http_res = await self.do_request_async(
+ hook_ctx=HookContext(
+ config=self.sdk_configuration,
+ base_url=base_url or "",
+ operation_id="submitGenerationFeedback",
+ oauth2_scopes=None,
+ security_source=get_security_from_env(
+ self.sdk_configuration.security, components.Security
+ ),
+ tags=["Generations"],
+ extensions=None,
+ ),
+ request=req,
+ is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c),
+ retry_config=retry_config,
+ )
+
+ response_data: Any = None
+ if utils.match_response(http_res, "200", "application/json"):
+ return unmarshal_json_response(
+ components.SubmitGenerationFeedbackResponse, http_res
+ )
+ if utils.match_response(http_res, "400", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.BadRequestResponseErrorData, http_res
+ )
+ raise errors.BadRequestResponseError(response_data, http_res)
+ if utils.match_response(http_res, "401", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.UnauthorizedResponseErrorData, http_res
+ )
+ raise errors.UnauthorizedResponseError(response_data, http_res)
+ if utils.match_response(http_res, "404", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.NotFoundResponseErrorData, http_res
+ )
+ raise errors.NotFoundResponseError(response_data, http_res)
+ if utils.match_response(http_res, "429", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.TooManyRequestsResponseErrorData, http_res
+ )
+ raise errors.TooManyRequestsResponseError(response_data, http_res)
+ if utils.match_response(http_res, "500", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternalServerResponseErrorData, http_res
+ )
+ raise errors.InternalServerResponseError(response_data, http_res)
+ if utils.match_response(http_res, "4XX", "*"):
+ http_res_text = await utils.stream_to_text_async(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+ if utils.match_response(http_res, "5XX", "*"):
+ http_res_text = await utils.stream_to_text_async(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+
+ raise errors.OpenRouterDefaultError("Unexpected response received", http_res)
diff --git a/src/openrouter/operations/__init__.py b/src/openrouter/operations/__init__.py
index ab9fa9e4..3ee6fd4d 100644
--- a/src/openrouter/operations/__init__.py
+++ b/src/openrouter/operations/__init__.py
@@ -686,6 +686,12 @@
SendChatCompletionRequestResponse,
SendChatCompletionRequestResponseTypedDict,
)
+ from .submitgenerationfeedback import (
+ SubmitGenerationFeedbackGlobals,
+ SubmitGenerationFeedbackGlobalsTypedDict,
+ SubmitGenerationFeedbackRequest,
+ SubmitGenerationFeedbackRequestTypedDict,
+ )
from .updatebyokkey import (
UpdateBYOKKeyGlobals,
UpdateBYOKKeyGlobalsTypedDict,
@@ -1248,6 +1254,10 @@
"SendChatCompletionRequestResponseTypedDict",
"Source",
"Subcategory",
+ "SubmitGenerationFeedbackGlobals",
+ "SubmitGenerationFeedbackGlobalsTypedDict",
+ "SubmitGenerationFeedbackRequest",
+ "SubmitGenerationFeedbackRequestTypedDict",
"TaskType",
"TimeRange",
"TimeRangeTypedDict",
@@ -1825,6 +1835,10 @@
"SendChatCompletionRequestRequestTypedDict": ".sendchatcompletionrequest",
"SendChatCompletionRequestResponse": ".sendchatcompletionrequest",
"SendChatCompletionRequestResponseTypedDict": ".sendchatcompletionrequest",
+ "SubmitGenerationFeedbackGlobals": ".submitgenerationfeedback",
+ "SubmitGenerationFeedbackGlobalsTypedDict": ".submitgenerationfeedback",
+ "SubmitGenerationFeedbackRequest": ".submitgenerationfeedback",
+ "SubmitGenerationFeedbackRequestTypedDict": ".submitgenerationfeedback",
"UpdateBYOKKeyGlobals": ".updatebyokkey",
"UpdateBYOKKeyGlobalsTypedDict": ".updatebyokkey",
"UpdateBYOKKeyRequest": ".updatebyokkey",
diff --git a/src/openrouter/operations/listbyokkeys.py b/src/openrouter/operations/listbyokkeys.py
index 2ec07724..c3080ca2 100644
--- a/src/openrouter/operations/listbyokkeys.py
+++ b/src/openrouter/operations/listbyokkeys.py
@@ -149,7 +149,7 @@ def serialize_model(self, handler):
"recraft",
"reka",
"relace",
- "sakana-ai",
+ "sakana",
"sambanova",
"seed",
"siliconflow",
diff --git a/src/openrouter/operations/submitgenerationfeedback.py b/src/openrouter/operations/submitgenerationfeedback.py
new file mode 100644
index 00000000..878e3ec2
--- /dev/null
+++ b/src/openrouter/operations/submitgenerationfeedback.py
@@ -0,0 +1,146 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from openrouter.components import (
+ submitgenerationfeedbackrequest as components_submitgenerationfeedbackrequest,
+)
+from openrouter.types import BaseModel, UNSET_SENTINEL
+from openrouter.utils import FieldMetadata, HeaderMetadata, RequestMetadata
+import pydantic
+from pydantic import model_serializer
+from typing import Optional
+from typing_extensions import Annotated, NotRequired, TypedDict
+
+
+class SubmitGenerationFeedbackGlobalsTypedDict(TypedDict):
+ http_referer: NotRequired[str]
+ r"""The app identifier should be your app's URL and is used as the primary identifier for rankings.
+ This is used to track API usage per application.
+
+ """
+ x_open_router_title: NotRequired[str]
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+ x_open_router_categories: NotRequired[str]
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+
+class SubmitGenerationFeedbackGlobals(BaseModel):
+ http_referer: Annotated[
+ Optional[str],
+ pydantic.Field(alias="HTTP-Referer"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""The app identifier should be your app's URL and is used as the primary identifier for rankings.
+ This is used to track API usage per application.
+
+ """
+
+ x_open_router_title: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Title"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+
+ x_open_router_categories: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Categories"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(
+ ["HTTP-Referer", "X-OpenRouter-Title", "X-OpenRouter-Categories"]
+ )
+ serialized = handler(self)
+ m = {}
+
+ for n, f in type(self).model_fields.items():
+ k = f.alias or n
+ val = serialized.get(k, serialized.get(n))
+
+ if val != UNSET_SENTINEL:
+ if val is not None or k not in optional_fields:
+ m[k] = val
+
+ return m
+
+
+class SubmitGenerationFeedbackRequestTypedDict(TypedDict):
+ submit_generation_feedback_request: components_submitgenerationfeedbackrequest.SubmitGenerationFeedbackRequestTypedDict
+ http_referer: NotRequired[str]
+ r"""The app identifier should be your app's URL and is used as the primary identifier for rankings.
+ This is used to track API usage per application.
+
+ """
+ x_open_router_title: NotRequired[str]
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+ x_open_router_categories: NotRequired[str]
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+
+class SubmitGenerationFeedbackRequest(BaseModel):
+ submit_generation_feedback_request: Annotated[
+ components_submitgenerationfeedbackrequest.SubmitGenerationFeedbackRequest,
+ FieldMetadata(request=RequestMetadata(media_type="application/json")),
+ ]
+
+ http_referer: Annotated[
+ Optional[str],
+ pydantic.Field(alias="HTTP-Referer"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""The app identifier should be your app's URL and is used as the primary identifier for rankings.
+ This is used to track API usage per application.
+
+ """
+
+ x_open_router_title: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Title"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+
+ x_open_router_categories: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Categories"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(
+ ["HTTP-Referer", "X-OpenRouter-Title", "X-OpenRouter-Categories"]
+ )
+ serialized = handler(self)
+ m = {}
+
+ for n, f in type(self).model_fields.items():
+ k = f.alias or n
+ val = serialized.get(k, serialized.get(n))
+
+ if val != UNSET_SENTINEL:
+ if val is not None or k not in optional_fields:
+ m[k] = val
+
+ return m
diff --git a/uv.lock b/uv.lock
index 5722a13a..852a1d8c 100644
--- a/uv.lock
+++ b/uv.lock
@@ -213,7 +213,7 @@ wheels = [
[[package]]
name = "openrouter"
-version = "0.11.16"
+version = "0.11.17"
source = { editable = "." }
dependencies = [
{ name = "httpcore" },