From 316d4c9197417c83d4076037d09905a5390da06e Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Sat, 25 Oct 2025 22:04:49 -0500 Subject: [PATCH 001/609] wip --- packages/web/src/content/docs/acp.mdx | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 packages/web/src/content/docs/acp.mdx diff --git a/packages/web/src/content/docs/acp.mdx b/packages/web/src/content/docs/acp.mdx new file mode 100644 index 0000000000..379a6d84ba --- /dev/null +++ b/packages/web/src/content/docs/acp.mdx @@ -0,0 +1,4 @@ +--- +title: Agent Client Protocol (ACP) +description: use +--- From fdb5bae3c6578c41ffb5bf3140879f79a586d164 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 27 Oct 2025 00:56:00 -0500 Subject: [PATCH 002/609] docs: acp --- packages/web/astro.config.mjs | 1 + packages/web/src/content/docs/acp.mdx | 103 +++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/packages/web/astro.config.mjs b/packages/web/astro.config.mjs index 3bcd98cb7d..484807497b 100644 --- a/packages/web/astro.config.mjs +++ b/packages/web/astro.config.mjs @@ -86,6 +86,7 @@ export default defineConfig({ "lsp", "mcp-servers", "custom-tools", + "acp", ], }, diff --git a/packages/web/src/content/docs/acp.mdx b/packages/web/src/content/docs/acp.mdx index 379a6d84ba..ea741faca7 100644 --- a/packages/web/src/content/docs/acp.mdx +++ b/packages/web/src/content/docs/acp.mdx @@ -1,4 +1,103 @@ --- -title: Agent Client Protocol (ACP) -description: use +title: Agent Client Protocol +description: Use OpenCode in any ACP-compatible editor. --- + +OpenCode supports the [Agent Client Protocol (ACP)](https://agentclientprotocol.com), allowing you to use it directly in compatible editors and IDEs. + +ACP is an open protocol that standardizes communication between code editors and AI coding agents. Similar to LSP for language servers, ACP allows agents like OpenCode to work seamlessly across different development environments. + +:::tip +For a list of editors and tools that support ACP, see the [ACP progress report](https://zed.dev/blog/acp-progress-report#available-now). +::: + +--- + +## Configure + +To use OpenCode via ACP, configure your editor to run the `opencode acp` command. + +The command starts OpenCode as an ACP-compatible subprocess that communicates with your editor over JSON-RPC via stdio. + +Below are examples for popular editors that support ACP. + +--- + +### Zed + +Add to your Zed configuration (`~/.config/zed/settings.json`): + +```json +{ + "agent_servers": { + "OpenCode": { + "command": "opencode", + "args": ["acp"] + } + } +} +``` + +To open it, use the `agent: new thread` action in the Command Palette + +You can also bind a keyboard shortcut by editing your `keymap.json`: + +```json +[ + { + "bindings": { + "cmd-alt-o": ["agent::NewExternalAgentThread", { "agent": "OpenCode" }] + } + } +] +``` + +--- + +### Avante.nvim + +Add to your Avante configuration: + +```lua +{ + acp_providers = { + ["opencode"] = { + command = "opencode", + args = { "acp" } + } + } +} +``` + +If you need to pass environment variables: + +```lua +{ + acp_providers = { + ["opencode"] = { + command = "opencode", + args = { "acp" }, + env = { + OPENCODE_API_KEY = os.getenv("OPENCODE_API_KEY") + } + } + } +} +``` + +--- + +## Capabilities + +OpenCode works the same via ACP as it does in the terminal. All features are supported: + +- Built-in tools (file operations, terminal commands, etc.) +- Custom tools and slash commands +- MCP servers configured in your OpenCode config +- Project-specific rules from `AGENTS.md` +- Custom formatters and linters +- Agents and permissions system + +:::note +Some built-in slash commands like `/undo` and `/redo` are currently unsupported in ACP mode. +::: From db85f01effc3b395b734e8b36c9a8f4c912c4edd Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 27 Oct 2025 12:04:50 +0000 Subject: [PATCH 003/609] ignore: update download stats 2025-10-27 --- STATS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/STATS.md b/STATS.md index fd1a154466..cd00e57e03 100644 --- a/STATS.md +++ b/STATS.md @@ -120,3 +120,4 @@ | 2025-10-24 | 572,692 (+7,976) | 506,905 (+8,169) | 1,079,597 (+16,145) | | 2025-10-25 | 578,927 (+6,235) | 516,129 (+9,224) | 1,095,056 (+15,459) | | 2025-10-26 | 584,409 (+5,482) | 521,179 (+5,050) | 1,105,588 (+10,532) | +| 2025-10-27 | 589,999 (+5,590) | 526,001 (+4,822) | 1,116,000 (+10,412) | From b562863fcc7ff760130fa487d2f00054a9e8d93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernat=20Peric=C3=A0s?= Date: Mon, 27 Oct 2025 13:18:23 +0100 Subject: [PATCH 004/609] feat: add `session.started` event that triggers when a new session is created (#3413) --- packages/opencode/src/session/index.ts | 9 +++ .../opencode/test/session/session.test.ts | 71 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 packages/opencode/test/session/session.test.ts diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index ee4cc704f8..b4785c5364 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -78,6 +78,12 @@ export namespace Session { export type ShareInfo = z.output export const Event = { + Started: Bus.event( + "session.started", + z.object({ + info: Info, + }), + ), Updated: Bus.event( "session.updated", z.object({ @@ -167,6 +173,9 @@ export namespace Session { } log.info("created", result) await Storage.write(["session", Instance.project.id, result.id], result) + Bus.publish(Event.Started, { + info: result, + }) const cfg = await Config.get() if (!result.parentID && (Flag.OPENCODE_AUTO_SHARE || cfg.share === "auto")) share(result.id) diff --git a/packages/opencode/test/session/session.test.ts b/packages/opencode/test/session/session.test.ts new file mode 100644 index 0000000000..573c9e59e8 --- /dev/null +++ b/packages/opencode/test/session/session.test.ts @@ -0,0 +1,71 @@ +import { describe, expect, test } from "bun:test" +import path from "path" +import { Session } from "../../src/session" +import { Bus } from "../../src/bus" +import { Log } from "../../src/util/log" +import { Instance } from "../../src/project/instance" + +const projectRoot = path.join(__dirname, "../..") +Log.init({ print: false }) + +describe("session.started event", () => { + test("should emit session.started event when session is created", async () => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + let eventReceived = false + let receivedInfo: Session.Info | undefined + + const unsub = Bus.subscribe(Session.Event.Started, (event) => { + eventReceived = true + receivedInfo = event.properties.info as Session.Info + }) + + const session = await Session.create({}) + + await new Promise((resolve) => setTimeout(resolve, 100)) + + unsub() + + expect(eventReceived).toBe(true) + expect(receivedInfo).toBeDefined() + expect(receivedInfo?.id).toBe(session.id) + expect(receivedInfo?.projectID).toBe(session.projectID) + expect(receivedInfo?.directory).toBe(session.directory) + expect(receivedInfo?.title).toBe(session.title) + + await Session.remove(session.id) + }, + }) + }) + + test("session.started event should be emitted before session.updated", async () => { + await Instance.provide({ + directory: projectRoot, + fn: async () => { + const events: string[] = [] + + const unsubStarted = Bus.subscribe(Session.Event.Started, () => { + events.push("started") + }) + + const unsubUpdated = Bus.subscribe(Session.Event.Updated, () => { + events.push("updated") + }) + + const session = await Session.create({}) + + await new Promise((resolve) => setTimeout(resolve, 100)) + + unsubStarted() + unsubUpdated() + + expect(events).toContain("started") + expect(events).toContain("updated") + expect(events.indexOf("started")).toBeLessThan(events.indexOf("updated")) + + await Session.remove(session.id) + }, + }) + }) +}) From e6301ca5d514d81010564a0c46f00b1ce441bbcb Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 27 Oct 2025 10:42:47 -0500 Subject: [PATCH 005/609] tweak: rename event --- packages/opencode/src/session/index.ts | 6 +++--- packages/opencode/test/session/session.test.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index b4785c5364..ff9f436e2f 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -78,8 +78,8 @@ export namespace Session { export type ShareInfo = z.output export const Event = { - Started: Bus.event( - "session.started", + Created: Bus.event( + "session.created", z.object({ info: Info, }), @@ -173,7 +173,7 @@ export namespace Session { } log.info("created", result) await Storage.write(["session", Instance.project.id, result.id], result) - Bus.publish(Event.Started, { + Bus.publish(Event.Created, { info: result, }) const cfg = await Config.get() diff --git a/packages/opencode/test/session/session.test.ts b/packages/opencode/test/session/session.test.ts index 573c9e59e8..219cef1271 100644 --- a/packages/opencode/test/session/session.test.ts +++ b/packages/opencode/test/session/session.test.ts @@ -16,7 +16,7 @@ describe("session.started event", () => { let eventReceived = false let receivedInfo: Session.Info | undefined - const unsub = Bus.subscribe(Session.Event.Started, (event) => { + const unsub = Bus.subscribe(Session.Event.Created, (event) => { eventReceived = true receivedInfo = event.properties.info as Session.Info }) @@ -45,7 +45,7 @@ describe("session.started event", () => { fn: async () => { const events: string[] = [] - const unsubStarted = Bus.subscribe(Session.Event.Started, () => { + const unsubStarted = Bus.subscribe(Session.Event.Created, () => { events.push("started") }) From 0e65700183c6ed6b008112ee9638ce7621d6347a Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 27 Oct 2025 10:47:04 -0500 Subject: [PATCH 006/609] update sdk --- packages/sdk/js/src/gen/types.gen.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 47bb20972c..0b55cc5b45 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -1197,6 +1197,13 @@ export type EventSessionIdle = { } } +export type EventSessionCreated = { + type: "session.created" + properties: { + info: Session + } +} + export type EventSessionUpdated = { type: "session.updated" properties: { @@ -1247,6 +1254,7 @@ export type Event = | EventFileWatcherUpdated | EventTodoUpdated | EventSessionIdle + | EventSessionCreated | EventSessionUpdated | EventSessionDeleted | EventSessionError From a606e1d2ec9d634f9b8468e2f6c0ce4259d5afa0 Mon Sep 17 00:00:00 2001 From: Aurelien Ribon Date: Mon, 27 Oct 2025 16:50:57 +0100 Subject: [PATCH 007/609] fix: dont set reasoning effort to `medium` for `gpt-5-pro` (#3474) --- packages/opencode/src/provider/transform.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 73ff442abe..dda02cc4ec 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -92,7 +92,9 @@ export namespace ProviderTransform { } if (modelID.includes("gpt-5") && !modelID.includes("gpt-5-chat")) { - if (!modelID.includes("codex")) result["reasoningEffort"] = "medium" + if (!modelID.includes("codex") && !modelID.includes("gpt-5-pro")) { + result["reasoningEffort"] = "medium" + } if (providerID !== "azure") { result["textVerbosity"] = modelID.includes("codex") ? "medium" : "low" From 0af450575647fc906f017b0065fe3aca227c369f Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 27 Oct 2025 14:03:30 -0500 Subject: [PATCH 008/609] fix: litellm error tool= param must be specified --- packages/opencode/src/session/compaction.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index d9ead57916..76313453f3 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -155,6 +155,7 @@ export namespace SessionCompaction { error, }) }, + tools: model.info.tool_call ? {} : undefined, messages: [ ...system.map( (x): ModelMessage => ({ From 0acae8211afb1194035a1801a7cd9d9ed1d66eae Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Mon, 27 Oct 2025 06:48:03 -0500 Subject: [PATCH 009/609] wip: desktop work --- bun.lock | 6 +++--- package.json | 6 +++--- packages/desktop/src/components/diff.tsx | 27 +++++++++++++++++++----- packages/ui/package.json | 2 +- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/bun.lock b/bun.lock index 8dcbb2b272..d2959d4c5d 100644 --- a/bun.lock +++ b/bun.lock @@ -276,7 +276,7 @@ "version": "0.15.18", "dependencies": { "@kobalte/core": "catalog:", - "@pierre/precision-diffs": "0.0.2-alpha.1-1", + "@pierre/precision-diffs": "catalog:", "@solidjs/meta": "catalog:", "fuzzysort": "catalog:", "luxon": "catalog:", @@ -343,7 +343,7 @@ "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.0.2-alpha.1-1", + "@pierre/precision-diffs": "0.3.2", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "@tsconfig/bun": "1.0.9", @@ -937,7 +937,7 @@ "@petamoriken/float16": ["@petamoriken/float16@3.9.2", "", {}, "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog=="], - "@pierre/precision-diffs": ["@pierre/precision-diffs@0.0.2-alpha.1-1", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" } }, "sha512-T43cwB7gMnbM+tp9p73NptUm4uUOfmrP5ihMOAHWQPpzBa/oeTjqZlmEmSQLpT8WKKnWG0lbKZPtlw7l0gW0Vw=="], + "@pierre/precision-diffs": ["@pierre/precision-diffs@0.3.2", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-HE+wFB0TV+wmjur/J+qI5PsRQl5RN6tCEFTusW0S5FDfZJUIpkxJCacqUxyEI0DriXMKhgGQ+oCQShfaFELdrQ=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], diff --git a/package.json b/package.json index 48afdc7c0b..a5e5217977 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@tsconfig/bun": "1.0.9", "@cloudflare/workers-types": "4.20251008.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.0.2-alpha.1-1", + "@pierre/precision-diffs": "0.3.2", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "diff": "8.0.2", @@ -53,8 +53,8 @@ "turbo": "2.5.6" }, "dependencies": { - "@opencode-ai/sdk": "workspace:*", - "@opencode-ai/script": "workspace:*" + "@opencode-ai/script": "workspace:*", + "@opencode-ai/sdk": "workspace:*" }, "repository": { "type": "git", diff --git a/packages/desktop/src/components/diff.tsx b/packages/desktop/src/components/diff.tsx index d8457b5284..b3d6d7e259 100644 --- a/packages/desktop/src/components/diff.tsx +++ b/packages/desktop/src/components/diff.tsx @@ -2,8 +2,9 @@ import { type FileContents, FileDiff, type DiffLineAnnotation, + type HunkData, DiffFileRendererOptions, - registerCustomTheme, + // registerCustomTheme, } from "@pierre/precision-diffs" import { ComponentProps, createEffect, splitProps } from "solid-js" @@ -15,8 +16,7 @@ export type DiffProps = Omit, "themes"> & { classList?: ComponentProps<"div">["classList"] } -// @ts-expect-error -registerCustomTheme("opencode", () => import("./theme.json")) +// registerCustomTheme("opencode", () => import("./theme.json")) // interface ThreadMetadata { // threadId: string @@ -49,7 +49,7 @@ export function Diff(props: DiffProps) { // annotations and a container element to hold the diff createEffect(() => { const instance = new FileDiff({ - theme: "opencode", + theme: "pierre-light", // Or can also provide a 'themes' prop, which allows the code to adapt // to your OS light or dark theme // themes: { dark: 'pierre-night', light: 'pierre-light' }, @@ -97,7 +97,24 @@ export function Diff(props: DiffProps) { // // 'simple': // Just a subtle bar separator between each hunk - hunkSeparators: "line-info", + // hunkSeparators: "line-info", + hunkSeparators(hunkData: HunkData) { + const fragment = document.createDocumentFragment() + const numCol = document.createElement("div") + numCol.textContent = `${hunkData.lines}` + numCol.style.position = "sticky" + numCol.style.left = "0" + numCol.style.backgroundColor = "var(--pjs-bg)" + numCol.style.zIndex = "2" + fragment.appendChild(numCol) + const contentCol = document.createElement("div") + contentCol.textContent = "unmodified lines" + contentCol.style.position = "sticky" + contentCol.style.width = "var(--pjs-column-content-width)" + contentCol.style.left = "var(--pjs-column-number-width)" + fragment.appendChild(contentCol) + return fragment + }, // On lines that have both additions and deletions, we can run a // separate diff check to mark parts of the lines that change. // 'none': diff --git a/packages/ui/package.json b/packages/ui/package.json index bf75293aa1..cdb9eee1c8 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@kobalte/core": "catalog:", - "@pierre/precision-diffs": "0.0.2-alpha.1-1", + "@pierre/precision-diffs": "catalog:", "@solidjs/meta": "catalog:", "fuzzysort": "catalog:", "luxon": "catalog:", From d03b79e61eef0be1cca669e5e6a13df78cc4be85 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Mon, 27 Oct 2025 06:53:09 -0500 Subject: [PATCH 010/609] wip: desktop work --- packages/desktop/src/components/diff.tsx | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/desktop/src/components/diff.tsx b/packages/desktop/src/components/diff.tsx index b3d6d7e259..c39ad852e5 100644 --- a/packages/desktop/src/components/diff.tsx +++ b/packages/desktop/src/components/diff.tsx @@ -97,24 +97,24 @@ export function Diff(props: DiffProps) { // // 'simple': // Just a subtle bar separator between each hunk - // hunkSeparators: "line-info", - hunkSeparators(hunkData: HunkData) { - const fragment = document.createDocumentFragment() - const numCol = document.createElement("div") - numCol.textContent = `${hunkData.lines}` - numCol.style.position = "sticky" - numCol.style.left = "0" - numCol.style.backgroundColor = "var(--pjs-bg)" - numCol.style.zIndex = "2" - fragment.appendChild(numCol) - const contentCol = document.createElement("div") - contentCol.textContent = "unmodified lines" - contentCol.style.position = "sticky" - contentCol.style.width = "var(--pjs-column-content-width)" - contentCol.style.left = "var(--pjs-column-number-width)" - fragment.appendChild(contentCol) - return fragment - }, + hunkSeparators: "line-info", + // hunkSeparators(hunkData: HunkData) { + // const fragment = document.createDocumentFragment() + // const numCol = document.createElement("div") + // numCol.textContent = `${hunkData.lines}` + // numCol.style.position = "sticky" + // numCol.style.left = "0" + // numCol.style.backgroundColor = "var(--pjs-bg)" + // numCol.style.zIndex = "2" + // fragment.appendChild(numCol) + // const contentCol = document.createElement("div") + // contentCol.textContent = "unmodified lines" + // contentCol.style.position = "sticky" + // contentCol.style.width = "var(--pjs-column-content-width)" + // contentCol.style.left = "var(--pjs-column-number-width)" + // fragment.appendChild(contentCol) + // return fragment + // }, // On lines that have both additions and deletions, we can run a // separate diff check to mark parts of the lines that change. // 'none': From fc115ea367dd034c7b989819d4f547c5d7519253 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:35:47 -0500 Subject: [PATCH 011/609] wip: desktop work --- bun.lock | 1 + packages/desktop/package.json | 3 +- .../src/components/assistant-message.tsx | 362 +++++++++++++++ .../desktop/src/components/diff-changes.tsx | 20 + packages/desktop/src/context/local.tsx | 8 - packages/desktop/src/pages/index.tsx | 180 +++++-- packages/opencode/src/tool/tool.ts | 3 + packages/ui/script/colors.txt | 438 +++++++++--------- packages/ui/src/components/collapsible.css | 46 +- packages/ui/src/components/collapsible.tsx | 14 +- packages/ui/src/components/icon.tsx | 10 + packages/ui/src/styles/tailwind/colors.css | 16 +- packages/ui/src/styles/theme.css | 50 +- 13 files changed, 854 insertions(+), 297 deletions(-) create mode 100644 packages/desktop/src/components/assistant-message.tsx create mode 100644 packages/desktop/src/components/diff-changes.tsx diff --git a/bun.lock b/bun.lock index d2959d4c5d..42d0881097 100644 --- a/bun.lock +++ b/bun.lock @@ -141,6 +141,7 @@ "@types/luxon": "3.7.1", "@types/node": "catalog:", "@typescript/native-preview": "catalog:", + "opencode": "workspace:*", "typescript": "catalog:", "vite": "catalog:", "vite-plugin-icons-spritesheet": "3.0.1", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 135ee9bb1b..c4af384f40 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -12,12 +12,13 @@ }, "license": "MIT", "devDependencies": { + "opencode": "workspace:*", "@tailwindcss/vite": "catalog:", "@tsconfig/bun": "1.0.9", "@types/luxon": "3.7.1", "@types/node": "catalog:", - "typescript": "catalog:", "@typescript/native-preview": "catalog:", + "typescript": "catalog:", "vite": "catalog:", "vite-plugin-icons-spritesheet": "3.0.1", "vite-plugin-solid": "catalog:" diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx new file mode 100644 index 0000000000..2e3d659aa9 --- /dev/null +++ b/packages/desktop/src/components/assistant-message.tsx @@ -0,0 +1,362 @@ +import type { Part, AssistantMessage, ReasoningPart, TextPart, ToolPart } from "@opencode-ai/sdk" +import type { Tool } from "opencode/tool/tool" +import type { ReadTool } from "opencode/tool/read" +import { children, Component, createMemo, For, Match, Show, Switch, type JSX } from "solid-js" +import { Dynamic } from "solid-js/web" +import { Markdown } from "./markdown" +import { Collapsible, Icon, IconProps } from "@opencode-ai/ui" +import { getDirectory, getFilename } from "@/utils" +import { ListTool } from "opencode/tool/ls" +import { GlobTool } from "opencode/tool/glob" +import { GrepTool } from "opencode/tool/grep" +import { WebFetchTool } from "opencode/tool/webfetch" +import { TaskTool } from "opencode/tool/task" +import { BashTool } from "opencode/tool/bash" +import { EditTool } from "opencode/tool/edit" +import { DiffChanges } from "./diff-changes" +import { WriteTool } from "opencode/tool/write" + +export function AssistantMessage(props: { message: AssistantMessage; parts: Part[] }) { + return ( +
+ + {(part) => { + const component = createMemo(() => PART_MAPPING[part.type as keyof typeof PART_MAPPING]) + return ( + + + + ) + }} + +
+ ) +} + +const PART_MAPPING = { + text: TextPart, + tool: ToolPart, + reasoning: ReasoningPart, +} + +function ReasoningPart(props: { part: ReasoningPart; message: AssistantMessage }) { + return null + // return ( + // + //
{props.part.text}
+ //
+ // ) +} + +function TextPart(props: { part: TextPart; message: AssistantMessage }) { + return ( + + + + ) +} + +function ToolPart(props: { part: ToolPart; message: AssistantMessage }) { + // const sync = useSync() + + const component = createMemo(() => { + const render = ToolRegistry.render(props.part.tool) ?? GenericTool + + const metadata = props.part.state.status === "pending" ? {} : (props.part.state.metadata ?? {}) + const input = props.part.state.status === "completed" ? props.part.state.input : {} + // const permissions = sync.data.permission[props.message.sessionID] ?? [] + // const permissionIndex = permissions.findIndex((x) => x.callID === props.part.callID) + // const permission = permissions[permissionIndex] + + return ( + <> + + {/* {props.part.state.error.replace("Error: ", "")} */} + + ) + }) + + return {component()} +} + +type TriggerTitle = { + title: string + subtitle?: string + args?: string[] + action?: JSX.Element +} + +const isTriggerTitle = (val: any): val is TriggerTitle => { + return typeof val === "object" && val !== null && "title" in val && !(val instanceof Node) +} + +function BasicTool(props: { icon: IconProps["name"]; trigger: TriggerTitle | JSX.Element; children?: JSX.Element }) { + const resolved = children(() => props.children) + + return ( + + +
+
+ + + +
+
+ + {(props.trigger as TriggerTitle).title} + + + {(props.trigger as TriggerTitle).subtitle} + + + + {(arg) => {arg}} + + +
+ {(props.trigger as TriggerTitle).action} +
+
+ {props.trigger as JSX.Element} +
+
+ + + +
+
+ + {props.children} + +
+ ) +} + +function GenericTool(props: ToolProps) { + return +} + +type ToolProps = { + input: Partial> + metadata: Partial> + // permission: Record + tool: string + output?: string +} + +const ToolRegistry = (() => { + const state: Record< + string, + { + name: string + render?: Component> + } + > = {} + function register(input: { name: string; render?: Component> }) { + state[input.name] = input + return input + } + return { + register, + render(name: string) { + return state[name]?.render + }, + } +})() + +ToolRegistry.register({ + name: "read", + render(props) { + return ( + + ) + }, +}) + +ToolRegistry.register({ + name: "list", + render(props) { + return ( + + +
{props.output}
+
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "glob", + render(props) { + return ( + {props.output} + + + ) + }, +}) + +ToolRegistry.register({ + name: "grep", + render(props) { + const args = [] + if (props.input.pattern) args.push("pattern=" + props.input.pattern) + if (props.input.include) args.push("include=" + props.input.include) + return ( + + +
{props.output}
+
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "webfetch", + render(props) { + return ( + + + + ), + }} + > + +
{props.output}
+
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "task", + render(props) { + return ( + + +
{props.output}
+
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "bash", + render(props) { + return ( + + +
{props.output}
+
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "edit", + render(props) { + return ( + +
+
Edit
+
+ + {getDirectory(props.input.filePath!)}/ + + {getFilename(props.input.filePath ?? "")} +
+
+
{/* */}
+ + } + > + +
{props.output}
+
+
+ ) + }, +}) + +ToolRegistry.register({ + name: "write", + render(props) { + return ( + +
+
Write
+
+ + {getDirectory(props.input.filePath!)}/ + + {getFilename(props.input.filePath ?? "")} +
+
+
{/* */}
+ + } + > + +
{props.output}
+
+
+ ) + }, +}) diff --git a/packages/desktop/src/components/diff-changes.tsx b/packages/desktop/src/components/diff-changes.tsx new file mode 100644 index 0000000000..3b633f70f7 --- /dev/null +++ b/packages/desktop/src/components/diff-changes.tsx @@ -0,0 +1,20 @@ +import { FileDiff } from "@opencode-ai/sdk" +import { createMemo, Show } from "solid-js" + +export function DiffChanges(props: { diff: FileDiff | FileDiff[] }) { + const additions = createMemo(() => + Array.isArray(props.diff) ? props.diff.reduce((acc, diff) => acc + (diff.additions ?? 0), 0) : props.diff.additions, + ) + const deletions = createMemo(() => + Array.isArray(props.diff) ? props.diff.reduce((acc, diff) => acc + (diff.deletions ?? 0), 0) : props.diff.deletions, + ) + const total = createMemo(() => additions() + deletions()) + return ( + 0}> +
+ {`+${additions()}`} + {`-${deletions()}`} +
+
+ ) +} diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx index 6ed8ec17b9..978dbfbc68 100644 --- a/packages/desktop/src/context/local.tsx +++ b/packages/desktop/src/context/local.tsx @@ -460,13 +460,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ return sync.data.message[store.active]?.find((m) => m.id === store.activeMessage) }) - const activeAssistantMessages = createMemo(() => { - if (!store.active || !activeMessage()) return [] - return sync.data.message[store.active]?.filter( - (m) => m.role === "assistant" && m.parentID == activeMessage()?.id, - ) - }) - const model = createMemo(() => { if (!last()) return const model = sync.data.provider.find((x) => x.id === last().providerID)?.models[last().modelID] @@ -504,7 +497,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ return { active, activeMessage, - activeAssistantMessages, lastUserMessage, cost, last, diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx index 6702284b20..15da87bd67 100644 --- a/packages/desktop/src/pages/index.tsx +++ b/packages/desktop/src/pages/index.tsx @@ -22,6 +22,10 @@ import { Code } from "@/components/code" import { useSync } from "@/context/sync" import { useSDK } from "@/context/sdk" import { Diff } from "@/components/diff" +import { ProgressCircle } from "@/components/progress-circle" +import { AssistantMessage } from "@/components/assistant-message" +import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk" +import { DiffChanges } from "@/components/diff-changes" export default function Page() { const local = useLocal() @@ -92,7 +96,7 @@ export default function Page() { } } - if (event.key.length === 1 && event.key !== "Unidentified") { + if (event.key.length === 1 && event.key !== "Unidentified" && !(event.ctrlKey || event.metaKey)) { inputRef?.focus() } } @@ -392,9 +396,6 @@ export default function Page() { {(session) => { const diffs = createMemo(() => session.summary?.diffs ?? []) const filesChanged = createMemo(() => diffs().length) - const additions = createMemo(() => diffs().reduce((acc, diff) => (acc ?? 0) + (diff.additions ?? 0), 0)) - const deletions = createMemo(() => diffs().reduce((acc, diff) => (acc ?? 0) + (diff.deletions ?? 0), 0)) - return (
@@ -408,12 +409,7 @@ export default function Page() {
{`${filesChanged() || "No"} file${filesChanged() !== 1 ? "s" : ""} changed`} - -
- {`+${additions()}`} - {`-${deletions()}`} -
-
+
@@ -434,13 +430,12 @@ export default function Page() {
- +
Chat
- -
- {local.session.context()}% -
-
+ + +
{local.session.context() ?? 0}%
+
{/* Review */} file.path)}> @@ -548,33 +543,114 @@ export default function Page() { 1}>
    - {(message) => ( -
  • local.session.setActiveMessage(message.id)} - > -
    - - - - - - - - - -
    -
    { + const countLines = (text: string) => { + if (!text) return 0 + return text.split("\n").length + } + + const additions = createMemo( + () => + message.summary?.diffs.reduce((acc, diff) => acc + (diff.additions ?? 0), 0) ?? 0, + ) + + const deletions = createMemo( + () => + message.summary?.diffs.reduce((acc, diff) => acc + (diff.deletions ?? 0), 0) ?? 0, + ) + + const totalBeforeLines = createMemo( + () => + message.summary?.diffs.reduce((acc, diff) => acc + countLines(diff.before), 0) ?? + 0, + ) + + const blockCounts = createMemo(() => { + const TOTAL_BLOCKS = 5 + + const adds = additions() + const dels = deletions() + const unchanged = Math.max(0, totalBeforeLines() - dels) + + const totalActivity = unchanged + adds + dels + + if (totalActivity === 0) { + return { added: 0, deleted: 0, neutral: TOTAL_BLOCKS } + } + + const percentAdded = adds / totalActivity + const percentDeleted = dels / totalActivity + const added_raw = percentAdded * TOTAL_BLOCKS + const deleted_raw = percentDeleted * TOTAL_BLOCKS + + let added = adds > 0 ? Math.ceil(added_raw) : 0 + let deleted = dels > 0 ? Math.ceil(deleted_raw) : 0 + + let total_allocated = added + deleted + if (total_allocated > TOTAL_BLOCKS) { + if (added_raw < deleted_raw) { + added = Math.floor(added_raw) + } else { + deleted = Math.floor(deleted_raw) + } + + total_allocated = added + deleted + if (total_allocated > TOTAL_BLOCKS) { + if (added_raw < deleted_raw) { + deleted = Math.floor(deleted_raw) + } else { + added = Math.floor(added_raw) + } + } + } + + const neutral = Math.max(0, TOTAL_BLOCKS - added - deleted) + + return { added, deleted, neutral } + }) + + const ADD_COLOR = "var(--icon-diff-add-base)" + const DELETE_COLOR = "var(--icon-diff-delete-base)" + const NEUTRAL_COLOR = "var(--icon-weak-base)" + + const visibleBlocks = createMemo(() => { + const counts = blockCounts() + const blocks = [ + ...Array(counts.added).fill(ADD_COLOR), + ...Array(counts.deleted).fill(DELETE_COLOR), + ...Array(counts.neutral).fill(NEUTRAL_COLOR), + ] + return blocks.slice(0, 5) + }) + + return ( +
  • local.session.setActiveMessage(message.id)} > - {message.summary?.title ?? local.session.getMessageText(message)} -
- - )} +
+ + + + {(color, i) => ( + + )} + + + +
+
+ {message.summary?.title ?? local.session.getMessageText(message)} +
+ + ) + }} @@ -585,6 +661,11 @@ export default function Page() { const title = createMemo(() => message.summary?.title) const prompt = createMemo(() => local.session.getMessageText(message)) const summary = createMemo(() => message.summary?.body) + const assistantMessages = createMemo(() => { + return sync.data.message[activeSession().id]?.filter( + (m) => m.role === "assistant" && m.parentID == message.id, + ) as AssistantMessageType[] + }) return (
-
- {`+${diff.additions}`} - {`-${diff.deletions}`} -
+
@@ -661,10 +739,18 @@ export default function Page() { {/* Response */} -
+

Response

+
+ + {(assistantMessage) => { + const parts = createMemo(() => sync.data.part[assistantMessage.id]) + return + }} + +
) diff --git a/packages/opencode/src/tool/tool.ts b/packages/opencode/src/tool/tool.ts index 978c9c072b..c7a28c516b 100644 --- a/packages/opencode/src/tool/tool.ts +++ b/packages/opencode/src/tool/tool.ts @@ -32,6 +32,9 @@ export namespace Tool { }> } + export type InferParameters = T extends Info ? z.infer

: never + export type InferMetadata = T extends Info ? M : never + export function define( id: string, init: Info["init"] | Awaited["init"]>>, diff --git a/packages/ui/script/colors.txt b/packages/ui/script/colors.txt index 15f8bb3d11..b022e8a115 100644 --- a/packages/ui/script/colors.txt +++ b/packages/ui/script/colors.txt @@ -1,214 +1,224 @@ - --background-base: #f8f7f7; - --background-weak: var(--smoke-light-3); - --background-strong: var(--smoke-light-1); - --background-stronger: #fcfcfc; - --base: var(--smoke-light-alpha-2); - --surface-base: var(--smoke-light-alpha-2); - --base2: var(--smoke-light-alpha-2); - --base3: var(--smoke-light-alpha-2); - --surface-inset-base: var(--smoke-light-alpha-3); - --surface-inset-base-hover: var(--smoke-light-alpha-3); - --surface-inset-strong: #1f000017; - --surface-inset-strong-hover: #1f000017; - --surface-raised-base: var(--smoke-light-alpha-1); - --surface-float-base: var(--smoke-dark-1); - --surface-float-base-hover: var(--smoke-dark-2); - --surface-raised-base-hover: var(--smoke-light-alpha-2); - --surface-raised-strong: var(--smoke-light-1); - --surface-raised-strong-hover: var(--white); - --surface-raised-stronger: var(--white); - --surface-raised-stronger-hover: var(--white); - --surface-weak: var(--smoke-light-alpha-3); - --surface-weaker: var(--smoke-light-alpha-4); - --surface-strong: #ffffff; - --surface-raised-stronger-non-alpha: var(--white); - --surface-brand-base: var(--yuzu-light-9); - --surface-brand-hover: var(--yuzu-light-10); - --surface-interactive-base: var(--cobalt-light-3); - --surface-interactive-hover: var(--cobalt-light-4); - --surface-interactive-weak: var(--cobalt-light-2); - --surface-interactive-weak-hover: var(--cobalt-light-3); - --surface-success-base: var(--apple-light-3); - --surface-success-weak: var(--apple-light-2); - --surface-success-strong: var(--apple-light-9); - --surface-warning-base: var(--solaris-light-3); - --surface-warning-weak: var(--solaris-light-2); - --surface-warning-strong: var(--solaris-light-9); - --surface-critical-base: var(--ember-light-3); - --surface-critical-weak: var(--ember-light-2); - --surface-critical-strong: var(--ember-light-9); - --surface-info-base: var(--lilac-light-3); - --surface-info-weak: var(--lilac-light-2); - --surface-info-strong: var(--lilac-light-9); - --surface-diff-skip-base: var(--smoke-light-3); - --surface-diff-unchanged-base: #ffffff00; - --surface-diff-hidden-base: var(--blue-light-3); - --surface-diff-hidden-weak: var(--blue-light-2); - --surface-diff-hidden-weaker: var(--blue-light-1); - --surface-diff-hidden-strong: var(--blue-light-5); - --surface-diff-hidden-stronger: var(--blue-light-9); - --surface-diff-add-base: var(--mint-light-3); - --surface-diff-add-weak: var(--mint-light-2); - --surface-diff-add-weaker: var(--mint-light-1); - --surface-diff-add-strong: var(--mint-light-5); - --surface-diff-add-stronger: var(--mint-light-9); - --surface-diff-delete-base: var(--ember-light-3); - --surface-diff-delete-weak: var(--ember-light-2); - --surface-diff-delete-weaker: var(--ember-light-1); - --surface-diff-delete-strong: var(--ember-light-6); - --surface-diff-delete-stronger: var(--ember-light-9); - --text-base: var(--smoke-light-11); - --input-base: var(--smoke-light-1); - --input-hover: var(--smoke-light-2); - --input-active: var(--cobalt-light-1); - --input-selected: var(--cobalt-light-4); - --input-focus: var(--cobalt-light-1); - --input-disabled: var(--smoke-light-4); - --text-weak: var(--smoke-light-9); - --text-weaker: var(--smoke-light-8); - --text-strong: var(--smoke-light-12); - --text-on-brand-base: var(--smoke-light-alpha-11); - --text-on-interactive-base: var(--smoke-light-1); - --text-on-success-base: var(--smoke-dark-alpha-11); - --text-on-warning-base: var(--smoke-dark-alpha-11); - --text-on-info-base: var(--smoke-dark-alpha-11); - --text-diff-add-base: var(--mint-light-11); - --text-diff-delete-base: var(--ember-light-11); - --text-diff-delete-strong: var(--ember-light-12); - --text-diff-add-strong: var(--mint-light-12); - --text-on-info-weak: var(--smoke-dark-alpha-9); - --text-on-info-strong: var(--smoke-dark-alpha-12); - --text-on-warning-weak: var(--smoke-dark-alpha-9); - --text-on-warning-strong: var(--smoke-dark-alpha-12); - --text-on-success-weak: var(--smoke-dark-alpha-9); - --text-on-success-strong: var(--smoke-dark-alpha-12); - --text-on-brand-weak: var(--smoke-light-alpha-9); - --text-on-brand-weaker: var(--smoke-light-alpha-8); - --text-on-brand-strong: var(--smoke-light-alpha-12); - --button-secondary-base: #fdfcfc; - --border-base: var(--smoke-light-alpha-7); - --border-hover: var(--smoke-light-alpha-8); - --border-active: var(--smoke-light-alpha-9); - --border-selected: var(--cobalt-light-alpha-9); - --border-disabled: var(--smoke-light-alpha-8); - --border-focus: var(--smoke-light-alpha-9); - --border-weak-base: var(--smoke-light-alpha-5); - --border-strong-base: var(--smoke-light-alpha-7); - --border-strong-hover: var(--smoke-light-alpha-8); - --border-strong-active: var(--smoke-light-alpha-7); - --border-strong-selected: var(--cobalt-light-alpha-6); - --border-strong-disabled: var(--smoke-light-alpha-6); - --border-strong-focus: var(--smoke-light-alpha-7); - --border-weak-hover: var(--smoke-light-alpha-6); - --border-weak-active: var(--smoke-light-alpha-7); - --border-weak-selected: var(--cobalt-light-alpha-6); - --border-weak-disabled: var(--smoke-light-alpha-6); - --border-weak-focus: var(--smoke-light-alpha-7); - --border-interactive-base: var(--cobalt-light-7); - --border-interactive-hover: var(--cobalt-light-8); - --border-interactive-active: var(--cobalt-light-9); - --border-interactive-selected: var(--cobalt-light-9); - --border-interactive-disabled: var(--smoke-light-8); - --border-interactive-focus: var(--cobalt-light-9); - --border-success-base: var(--apple-light-6); - --border-success-hover: var(--apple-light-7); - --border-success-selected: var(--apple-light-9); - --border-warning-base: var(--solaris-light-6); - --border-warning-hover: var(--solaris-light-7); - --border-warning-selected: var(--solaris-light-9); - --border-critical-base: var(--ember-light-6); - --border-critical-hover: var(--ember-light-7); - --border-critical-selected: var(--ember-light-9); - --border-info-base: var(--lilac-light-6); - --border-info-hover: var(--lilac-light-7); - --border-info-selected: var(--lilac-light-9); - --icon-base: var(--smoke-light-9); - --icon-hover: var(--smoke-light-11); - --icon-active: var(--smoke-light-12); - --icon-selected: var(--smoke-light-12); - --icon-disabled: var(--smoke-light-8); - --icon-focus: var(--smoke-light-12); - --icon-weak-base: var(--smoke-light-7); - --icon-invert-base: #ffffff; - --icon-weak-hover: var(--smoke-light-8); - --icon-weak-active: var(--smoke-light-9); - --icon-weak-selected: var(--smoke-light-10); - --icon-weak-disabled: var(--smoke-light-6); - --icon-weak-focus: var(--smoke-light-9); - --icon-strong-base: var(--smoke-light-12); - --icon-strong-hover: var(--smoke-light-12); - --icon-strong-active: var(--smoke-light-12); - --icon-strong-selected: var(--smoke-light-12); - --icon-strong-disabled: var(--smoke-light-8); - --icon-strong-focus: var(--smoke-light-12); - --icon-brand-base: var(--smoke-light-12); - --icon-interactive-base: var(--cobalt-light-9); - --icon-success-base: var(--apple-light-7); - --icon-success-hover: var(--apple-light-8); - --icon-success-active: var(--apple-light-11); - --icon-warning-base: var(--amber-light-7); - --icon-warning-hover: var(--amber-light-8); - --icon-warning-active: var(--amber-light-11); - --icon-critical-base: var(--ember-light-7); - --icon-critical-hover: var(--ember-light-8); - --icon-critical-active: var(--ember-light-11); - --icon-info-base: var(--lilac-light-7); - --icon-info-hover: var(--lilac-light-8); - --icon-info-active: var(--lilac-light-11); - --icon-on-brand-base: var(--smoke-light-alpha-11); - --icon-on-brand-hover: var(--smoke-light-alpha-12); - --icon-on-brand-selected: var(--smoke-light-alpha-12); - --icon-on-interactive-base: var(--smoke-light-alpha-9); - --icon-on-interactive-hover: var(--smoke-light-alpha-10); - --icon-on-interactive-selected: var(--smoke-light-alpha-11); - --icon-agent-plan-base: var(--purple-light-9); - --icon-agent-docs-base: var(--amber-light-9); - --icon-agent-ask-base: var(--cyan-light-9); - --icon-agent-build-base: var(--blue-light-9); - --icon-on-success-base: var(--apple-light-alpha-9); - --icon-on-success-hover: var(--apple-light-alpha-10); - --icon-on-success-selected: var(--apple-light-alpha-11); - --icon-on-warning-base: var(--amber-lightalpha-9); - --icon-on-warning-hover: var(--amber-lightalpha-10); - --icon-on-warning-selected: var(--amber-lightalpha-11); - --icon-on-critical-base: var(--ember-light-alpha-9); - --icon-on-critical-hover: var(--ember-light-alpha-10); - --icon-on-critical-selected: var(--ember-light-alpha-11); - --icon-on-info-base: var(--lilac-light-9); - --icon-on-info-hover: var(--lilac-light-alpha-10); - --icon-on-info-selected: var(--lilac-light-alpha-11); - --icon-diff-add-base: var(--mint-light-11); - --icon-diff-add-hover: var(--mint-light-12); - --icon-diff-add-active: var(--mint-light-12); - --icon-diff-delete-base: var(--ember-light-9); - --icon-diff-delete-hover: var(--ember-light-10); - --icon-diff-delete-active: var(--ember-light-11); - --syntax-comment: #ffffff; - --syntax-string: #ffffff; - --syntax-keyword: #ffffff; - --syntax-function: #ffffff; - --syntax-number: #ffffff; - --syntax-operator: #ffffff; - --syntax-variable: #ffffff; - --syntax-type: #ffffff; - --syntax-constant: #ffffff; - --syntax-punctuation: #ffffff; - --syntax-success: #ffffff; - --syntax-warning: #ffffff; - --syntax-critical: #ffffff; - --syntax-info: #ffffff; - --markdown-heading: #ffffff; - --markdown-text: #ffffff; - --markdown-link: #ffffff; - --markdown-link-text: #ffffff; - --markdown-code: #ffffff; - --markdown-block-quote: #ffffff; - --markdown-emph: #ffffff; - --markdown-strong: #ffffff; - --markdown-horizontal-rule: #ffffff; - --markdown-list-item: #ffffff; - --markdown-list-enumeration: #ffffff; - --markdown-image: #ffffff; - --markdown-image-text: #ffffff; - --markdown-code-block: #ffffff; - --border-color: #ffffff; +--background-base: #F8F7F7; +--background-weak: var(--smoke-light-3); +--background-strong: var(--smoke-light-1); +--background-stronger: #FCFCFC; +--base: var(--smoke-light-alpha-2); +--surface-base: var(--smoke-light-alpha-2); +--surface-base-hover: #0500000F; +--surface-base-active: var(--smoke-light-alpha-3); +--surface-base-interactive-active: var(--cobalt-light-alpha-3); +--base2: var(--smoke-light-alpha-2); +--base3: var(--smoke-light-alpha-2); +--surface-inset-base: var(--smoke-light-alpha-2); +--surface-inset-base-hover: var(--smoke-light-alpha-3); +--surface-inset-strong: #1F000017; +--surface-inset-strong-hover: #1F000017; +--surface-raised-base: var(--smoke-light-alpha-1); +--surface-float-base: var(--smoke-dark-1); +--surface-float-base-hover: var(--smoke-dark-2); +--surface-raised-base-hover: var(--smoke-light-alpha-2); +--surface-raised-strong: var(--smoke-light-1); +--surface-raised-strong-hover: var(--white); +--surface-raised-stronger: var(--white); +--surface-raised-stronger-hover: var(--white); +--surface-weak: var(--smoke-light-alpha-3); +--surface-weaker: var(--smoke-light-alpha-4); +--surface-strong: #FFFFFF; +--surface-raised-stronger-non-alpha: var(--white); +--surface-brand-base: var(--yuzu-light-9); +--surface-brand-hover: var(--yuzu-light-10); +--surface-interactive-base: var(--cobalt-light-3); +--surface-interactive-hover: var(--cobalt-light-4); +--surface-interactive-weak: var(--cobalt-light-2); +--surface-interactive-weak-hover: var(--cobalt-light-3); +--surface-success-base: var(--apple-light-3); +--surface-success-weak: var(--apple-light-2); +--surface-success-strong: var(--apple-light-9); +--surface-warning-base: var(--solaris-light-3); +--surface-warning-weak: var(--solaris-light-2); +--surface-warning-strong: var(--solaris-light-9); +--surface-critical-base: var(--ember-light-3); +--surface-critical-weak: var(--ember-light-2); +--surface-critical-strong: var(--ember-light-9); +--surface-info-base: var(--lilac-light-3); +--surface-info-weak: var(--lilac-light-2); +--surface-info-strong: var(--lilac-light-9); +--surface-diff-hidden-base: var(--blue-light-3); +--surface-diff-skip-base: var(--smoke-light-2); +--surface-diff-unchanged-base: #FFFFFF00; +--surface-diff-hidden-weak: var(--blue-light-2); +--surface-diff-hidden-weaker: var(--blue-light-1); +--surface-diff-hidden-strong: var(--blue-light-5); +--surface-diff-hidden-stronger: var(--blue-light-9); +--surface-diff-add-base: var(--mint-light-3); +--surface-diff-add-weak: var(--mint-light-2); +--surface-diff-add-weaker: var(--mint-light-1); +--surface-diff-add-strong: var(--mint-light-5); +--surface-diff-add-stronger: var(--mint-light-9); +--surface-diff-delete-base: var(--ember-light-3); +--surface-diff-delete-weak: var(--ember-light-2); +--surface-diff-delete-weaker: var(--ember-light-1); +--surface-diff-delete-strong: var(--ember-light-6); +--surface-diff-delete-stronger: var(--ember-light-9); +--text-base: var(--smoke-light-11); +--input-base: var(--smoke-light-1); +--input-hover: var(--smoke-light-2); +--input-active: var(--cobalt-light-1); +--input-selected: var(--cobalt-light-4); +--input-focus: var(--cobalt-light-1); +--input-disabled: var(--smoke-light-4); +--text-weak: var(--smoke-light-9); +--text-weaker: var(--smoke-light-8); +--text-strong: var(--smoke-light-12); +--text-interactive-base: var(--cobalt-light-9); +--text-on-brand-base: var(--smoke-light-alpha-11); +--text-on-interactive-base: var(--smoke-light-1); +--text-on-interactive-weak: var(--smoke-dark-alpha-11); +--text-on-success-base: var(--smoke-dark-alpha-11); +--text-on-warning-base: var(--smoke-dark-alpha-11); +--text-on-info-base: var(--smoke-dark-alpha-11); +--text-diff-add-base: var(--mint-light-11); +--text-diff-delete-base: var(--ember-light-11); +--text-diff-delete-strong: var(--ember-light-12); +--text-diff-add-strong: var(--mint-light-12); +--text-on-info-weak: var(--smoke-dark-alpha-9); +--text-on-info-strong: var(--smoke-dark-alpha-12); +--text-on-warning-weak: var(--smoke-dark-alpha-9); +--text-on-warning-strong: var(--smoke-dark-alpha-12); +--text-on-success-weak: var(--smoke-dark-alpha-9); +--text-on-success-strong: var(--smoke-dark-alpha-12); +--text-on-brand-weak: var(--smoke-light-alpha-9); +--text-on-brand-weaker: var(--smoke-light-alpha-8); +--text-on-brand-strong: var(--smoke-light-alpha-12); +--button-secondary-base: #FDFCFC; +--button-secondary-base-hover: #FAF9F9; +--border-base: var(--smoke-light-alpha-7); +--border-hover: var(--smoke-light-alpha-8); +--border-active: var(--smoke-light-alpha-9); +--border-selected: var(--cobalt-light-alpha-9); +--border-disabled: var(--smoke-light-alpha-8); +--border-focus: var(--smoke-light-alpha-9); +--border-weak-base: var(--smoke-light-alpha-5); +--border-strong-base: var(--smoke-light-alpha-7); +--border-strong-hover: var(--smoke-light-alpha-8); +--border-strong-active: var(--smoke-light-alpha-7); +--border-strong-selected: var(--cobalt-light-alpha-6); +--border-strong-disabled: var(--smoke-light-alpha-6); +--border-strong-focus: var(--smoke-light-alpha-7); +--border-weak-hover: var(--smoke-light-alpha-6); +--border-weak-active: var(--smoke-light-alpha-7); +--border-weak-selected: var(--cobalt-light-alpha-5); +--border-weak-disabled: var(--smoke-light-alpha-6); +--border-weak-focus: var(--smoke-light-alpha-7); +--border-interactive-base: var(--cobalt-light-7); +--border-interactive-hover: var(--cobalt-light-8); +--border-interactive-active: var(--cobalt-light-9); +--border-interactive-selected: var(--cobalt-light-9); +--border-interactive-disabled: var(--smoke-light-8); +--border-interactive-focus: var(--cobalt-light-9); +--border-success-base: var(--apple-light-6); +--border-success-hover: var(--apple-light-7); +--border-success-selected: var(--apple-light-9); +--border-warning-base: var(--solaris-light-6); +--border-warning-hover: var(--solaris-light-7); +--border-warning-selected: var(--solaris-light-9); +--border-critical-base: var(--ember-light-6); +--border-critical-hover: var(--ember-light-7); +--border-critical-selected: var(--ember-light-9); +--border-info-base: var(--lilac-light-6); +--border-info-hover: var(--lilac-light-7); +--border-info-selected: var(--lilac-light-9); +--icon-base: var(--smoke-light-9); +--icon-hover: var(--smoke-light-11); +--icon-active: var(--smoke-light-12); +--icon-selected: var(--smoke-light-12); +--icon-disabled: var(--smoke-light-8); +--icon-focus: var(--smoke-light-12); +--icon-weak-base: var(--smoke-light-7); +--icon-invert-base: #FFFFFF; +--icon-weak-hover: var(--smoke-light-8); +--icon-weak-active: var(--smoke-light-9); +--icon-weak-selected: var(--smoke-light-10); +--icon-weak-disabled: var(--smoke-light-6); +--icon-weak-focus: var(--smoke-light-9); +--icon-strong-base: var(--smoke-light-12); +--icon-strong-hover: var(--smoke-light-12); +--icon-strong-active: var(--smoke-light-12); +--icon-strong-selected: var(--smoke-light-12); +--icon-strong-disabled: var(--smoke-light-8); +--icon-strong-focus: var(--smoke-light-12); +--icon-brand-base: var(--smoke-light-12); +--icon-interactive-base: var(--cobalt-light-9); +--icon-success-base: var(--apple-light-7); +--icon-success-hover: var(--apple-light-8); +--icon-success-active: var(--apple-light-11); +--icon-warning-base: var(--amber-light-7); +--icon-warning-hover: var(--amber-light-8); +--icon-warning-active: var(--amber-light-11); +--icon-critical-base: var(--ember-light-7); +--icon-critical-hover: var(--ember-light-8); +--icon-critical-active: var(--ember-light-11); +--icon-info-base: var(--lilac-light-7); +--icon-info-hover: var(--lilac-light-8); +--icon-info-active: var(--lilac-light-11); +--icon-on-brand-base: var(--smoke-light-alpha-11); +--icon-on-brand-hover: var(--smoke-light-alpha-12); +--icon-on-brand-selected: var(--smoke-light-alpha-12); +--icon-on-interactive-base: var(--smoke-light-1); +--icon-agent-plan-base: var(--purple-light-9); +--icon-agent-docs-base: var(--amber-light-9); +--icon-agent-ask-base: var(--cyan-light-9); +--icon-agent-build-base: var(--cobalt-light-9); +--icon-on-success-base: var(--apple-light-alpha-9); +--icon-on-success-hover: var(--apple-light-alpha-10); +--icon-on-success-selected: var(--apple-light-alpha-11); +--icon-on-warning-base: var(--amber-lightalpha-9); +--icon-on-warning-hover: var(--amber-lightalpha-10); +--icon-on-warning-selected: var(--amber-lightalpha-11); +--icon-on-critical-base: var(--ember-light-alpha-9); +--icon-on-critical-hover: var(--ember-light-alpha-10); +--icon-on-critical-selected: var(--ember-light-alpha-11); +--icon-on-info-base: var(--lilac-light-9); +--icon-on-info-hover: var(--lilac-light-alpha-10); +--icon-on-info-selected: var(--lilac-light-alpha-11); +--icon-diff-add-base: var(--mint-light-11); +--icon-diff-add-hover: var(--mint-light-12); +--icon-diff-add-active: var(--mint-light-12); +--icon-diff-delete-base: var(--ember-light-9); +--icon-diff-delete-hover: var(--ember-light-10); +--icon-diff-delete-active: var(--ember-light-11); +--syntax-comment: #8A8A8A; +--syntax-string: #D68C27; +--syntax-keyword: #3B7DD8; +--syntax-function: #D1383D; +--syntax-number: #3D9A57; +--syntax-operator: #D68C27; +--syntax-variable: #B0851F; +--syntax-type: #318795; +--syntax-constant: #953170; +--syntax-punctuation: #1A1A1A; +--syntax-success: var(--apple-dark-10); +--syntax-warning: var(--amber-light-10); +--syntax-critical: var(--ember-dark-9); +--syntax-info: var(--lilac-dark-11); +--markdown-heading: #D68C27; +--markdown-text: #1A1A1A; +--markdown-link: #3B7DD8; +--markdown-link-text: #318795; +--markdown-code: #3D9A57; +--markdown-block-quote: #B0851F; +--markdown-emph: #B0851F; +--markdown-strong: #D68C27; +--markdown-horizontal-rule: #8A8A8A; +--markdown-list-item: #3B7DD8; +--markdown-list-enumeration: #318795; +--markdown-image: #3B7DD8; +--markdown-image-text: #318795; +--markdown-code-block: #1A1A1A; +--border-color: #FFFFFF; +--border-weaker-base: var(--smoke-light-alpha-3); +--border-weaker-hover: var(--smoke-light-alpha-4); +--border-weaker-active: var(--smoke-light-alpha-6); +--border-weaker-selected: var(--cobalt-light-alpha-4); +--border-weaker-disabled: var(--smoke-light-alpha-2); +--border-weaker-focus: var(--smoke-light-alpha-6); diff --git a/packages/ui/src/components/collapsible.css b/packages/ui/src/components/collapsible.css index 441d0083f1..34699fc205 100644 --- a/packages/ui/src/components/collapsible.css +++ b/packages/ui/src/components/collapsible.css @@ -1,23 +1,55 @@ [data-component="collapsible"] { + width: 100%; display: flex; flex-direction: column; + background-color: var(--surface-inset-base); + border: 1px solid var(--border-weaker-base); + transition: background-color 0.15s ease; + border-radius: 8px; + overflow: clip; - [data-slot="trigger"] { - cursor: pointer; + [data-slot="collapsible-trigger"] { + width: 100%; + display: flex; + height: 40px; + padding: 6px 8px 6px 12px; + align-items: center; + align-self: stretch; + cursor: default; user-select: none; + color: var(--text-base); + /* text-12-medium */ + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-style: normal; + font-weight: var(--font-weight-medium); + line-height: var(--line-height-large); /* 166.667% */ + letter-spacing: var(--letter-spacing-normal); + + /* &:hover { */ + /* background-color: var(--surface-base); */ + /* } */ &:focus-visible { - outline: 2px solid var(--border-focus); - outline-offset: 2px; + outline: none; } - &[data-disabled] { cursor: not-allowed; - opacity: 0.5; + } + + [data-slot="collapsible-arrow"] { + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + + /* [data-slot="collapsible-arrow-icon"] { */ + /* } */ } } - [data-slot="content"] { + [data-slot="collapsible-content"] { overflow: hidden; /* animation: slideUp 250ms ease-out; */ diff --git a/packages/ui/src/components/collapsible.tsx b/packages/ui/src/components/collapsible.tsx index f926192e85..d2e4a139b4 100644 --- a/packages/ui/src/components/collapsible.tsx +++ b/packages/ui/src/components/collapsible.tsx @@ -1,5 +1,6 @@ import { Collapsible as Kobalte, CollapsibleRootProps } from "@kobalte/core/collapsible" import { ComponentProps, ParentProps, splitProps } from "solid-js" +import { Icon } from "./icon" export interface CollapsibleProps extends ParentProps { class?: string @@ -21,14 +22,23 @@ function CollapsibleRoot(props: CollapsibleProps) { } function CollapsibleTrigger(props: ComponentProps) { - return + return } function CollapsibleContent(props: ComponentProps) { - return + return +} + +function CollapsibleArrow(props?: ComponentProps<"div">) { + return ( +

+ +
+ ) } export const Collapsible = Object.assign(CollapsibleRoot, { + Arrow: CollapsibleArrow, Trigger: CollapsibleTrigger, Content: CollapsibleContent, }) diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 0011a96769..5736146e5d 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -139,6 +139,16 @@ const newIcons = { folder: ``, "pencil-line": ``, "chevron-grabber-vertical": ``, + mcp: ``, + glasses: ``, + "bullet-list": ``, + "magnifying-glass-menu": ``, + "window-cursor": ``, + task: ``, + checklist: ``, + console: ``, + "code-lines": ``, + "square-arrow-top-right": ``, } export interface IconProps extends ComponentProps<"svg"> { diff --git a/packages/ui/src/styles/tailwind/colors.css b/packages/ui/src/styles/tailwind/colors.css index 2bf3fd7721..e2f6788ab2 100644 --- a/packages/ui/src/styles/tailwind/colors.css +++ b/packages/ui/src/styles/tailwind/colors.css @@ -9,6 +9,9 @@ --color-background-stronger: var(--background-stronger); --color-base: var(--base); --color-surface-base: var(--surface-base); + --color-surface-base-hover: var(--surface-base-hover); + --color-surface-base-active: var(--surface-base-active); + --color-surface-base-interactive-active: var(--surface-base-interactive-active); --color-base2: var(--base2); --color-base3: var(--base3); --color-surface-inset-base: var(--surface-inset-base); @@ -45,9 +48,9 @@ --color-surface-info-base: var(--surface-info-base); --color-surface-info-weak: var(--surface-info-weak); --color-surface-info-strong: var(--surface-info-strong); + --color-surface-diff-hidden-base: var(--surface-diff-hidden-base); --color-surface-diff-skip-base: var(--surface-diff-skip-base); --color-surface-diff-unchanged-base: var(--surface-diff-unchanged-base); - --color-surface-diff-hidden-base: var(--surface-diff-hidden-base); --color-surface-diff-hidden-weak: var(--surface-diff-hidden-weak); --color-surface-diff-hidden-weaker: var(--surface-diff-hidden-weaker); --color-surface-diff-hidden-strong: var(--surface-diff-hidden-strong); @@ -72,8 +75,10 @@ --color-text-weak: var(--text-weak); --color-text-weaker: var(--text-weaker); --color-text-strong: var(--text-strong); + --color-text-interactive-base: var(--text-interactive-base); --color-text-on-brand-base: var(--text-on-brand-base); --color-text-on-interactive-base: var(--text-on-interactive-base); + --color-text-on-interactive-weak: var(--text-on-interactive-weak); --color-text-on-success-base: var(--text-on-success-base); --color-text-on-warning-base: var(--text-on-warning-base); --color-text-on-info-base: var(--text-on-info-base); @@ -91,6 +96,7 @@ --color-text-on-brand-weaker: var(--text-on-brand-weaker); --color-text-on-brand-strong: var(--text-on-brand-strong); --color-button-secondary-base: var(--button-secondary-base); + --color-button-secondary-base-hover: var(--button-secondary-base-hover); --color-border-base: var(--border-base); --color-border-hover: var(--border-hover); --color-border-active: var(--border-active); @@ -164,8 +170,6 @@ --color-icon-on-brand-hover: var(--icon-on-brand-hover); --color-icon-on-brand-selected: var(--icon-on-brand-selected); --color-icon-on-interactive-base: var(--icon-on-interactive-base); - --color-icon-on-interactive-hover: var(--icon-on-interactive-hover); - --color-icon-on-interactive-selected: var(--icon-on-interactive-selected); --color-icon-agent-plan-base: var(--icon-agent-plan-base); --color-icon-agent-docs-base: var(--icon-agent-docs-base); --color-icon-agent-ask-base: var(--icon-agent-ask-base); @@ -217,4 +221,10 @@ --color-markdown-image-text: var(--markdown-image-text); --color-markdown-code-block: var(--markdown-code-block); --color-border-color: var(--border-color); + --color-border-weaker-base: var(--border-weaker-base); + --color-border-weaker-hover: var(--border-weaker-hover); + --color-border-weaker-active: var(--border-weaker-active); + --color-border-weaker-selected: var(--border-weaker-selected); + --color-border-weaker-disabled: var(--border-weaker-disabled); + --color-border-weaker-focus: var(--border-weaker-focus); } \ No newline at end of file diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css index 5358f380d9..0c22bae5a4 100644 --- a/packages/ui/src/styles/theme.css +++ b/packages/ui/src/styles/theme.css @@ -66,11 +66,14 @@ --background-weak: var(--smoke-light-3); --background-strong: var(--smoke-light-1); --background-stronger: #fcfcfc; - --surface-base: var(--smoke-light-alpha-2); --base: var(--smoke-light-alpha-2); + --surface-base: var(--smoke-light-alpha-2); + --surface-base-hover: #0500000f; + --surface-base-active: var(--smoke-light-alpha-3); + --surface-base-interactive-active: var(--cobalt-light-alpha-3); --base2: var(--smoke-light-alpha-2); --base3: var(--smoke-light-alpha-2); - --surface-inset-base: var(--smoke-light-alpha-3); + --surface-inset-base: var(--smoke-light-alpha-2); --surface-inset-base-hover: var(--smoke-light-alpha-3); --surface-inset-strong: #1f000017; --surface-inset-strong-hover: #1f000017; @@ -105,7 +108,7 @@ --surface-info-weak: var(--lilac-light-2); --surface-info-strong: var(--lilac-light-9); --surface-diff-hidden-base: var(--blue-light-3); - --surface-diff-skip-base: var(--smoke-light-3); + --surface-diff-skip-base: var(--smoke-light-2); --surface-diff-unchanged-base: #ffffff00; --surface-diff-hidden-weak: var(--blue-light-2); --surface-diff-hidden-weaker: var(--blue-light-1); @@ -131,6 +134,7 @@ --text-weak: var(--smoke-light-9); --text-weaker: var(--smoke-light-8); --text-strong: var(--smoke-light-12); + --text-interactive-base: var(--cobalt-light-9); --text-on-brand-base: var(--smoke-light-alpha-11); --text-on-interactive-base: var(--smoke-light-1); --text-on-interactive-weak: var(--smoke-dark-alpha-11); @@ -151,7 +155,7 @@ --text-on-brand-weaker: var(--smoke-light-alpha-8); --text-on-brand-strong: var(--smoke-light-alpha-12); --button-secondary-base: #fdfcfc; - --button-secondary-base-hover: var(--smoke-light-2); + --button-secondary-base-hover: #faf9f9; --border-base: var(--smoke-light-alpha-7); --border-hover: var(--smoke-light-alpha-8); --border-active: var(--smoke-light-alpha-9); @@ -167,7 +171,7 @@ --border-strong-focus: var(--smoke-light-alpha-7); --border-weak-hover: var(--smoke-light-alpha-6); --border-weak-active: var(--smoke-light-alpha-7); - --border-weak-selected: var(--cobalt-light-alpha-4); + --border-weak-selected: var(--cobalt-light-alpha-5); --border-weak-disabled: var(--smoke-light-alpha-6); --border-weak-focus: var(--smoke-light-alpha-7); --border-interactive-base: var(--cobalt-light-7); @@ -228,7 +232,7 @@ --icon-agent-plan-base: var(--purple-light-9); --icon-agent-docs-base: var(--amber-light-9); --icon-agent-ask-base: var(--cyan-light-9); - --icon-agent-build-base: var(--blue-light-9); + --icon-agent-build-base: var(--cobalt-light-9); --icon-on-success-base: var(--apple-light-alpha-9); --icon-on-success-hover: var(--apple-light-alpha-10); --icon-on-success-selected: var(--apple-light-alpha-11); @@ -276,6 +280,12 @@ --markdown-image-text: #318795; --markdown-code-block: #1a1a1a; --border-color: #ffffff; + --border-weaker-base: var(--smoke-light-alpha-3); + --border-weaker-hover: var(--smoke-light-alpha-4); + --border-weaker-active: var(--smoke-light-alpha-6); + --border-weaker-selected: var(--cobalt-light-alpha-4); + --border-weaker-disabled: var(--smoke-light-alpha-2); + --border-weaker-focus: var(--smoke-light-alpha-6); @media (prefers-color-scheme: dark) { /* OC-1-Dark */ @@ -284,8 +294,11 @@ --background-weak: #201d1d; --background-strong: #151313; --background-stronger: #201c1c; - --surface-base: var(--smoke-dark-alpha-3); --base: var(--smoke-dark-alpha-2); + --surface-base: var(--smoke-dark-alpha-2); + --surface-base-hover: #e0b7b716; + --surface-base-active: var(--smoke-dark-alpha-3); + --surface-base-interactive-active: var(--cobalt-dark-alpha-2); --base2: var(--smoke-dark-alpha-2); --base3: var(--smoke-dark-alpha-2); --surface-inset-base: #0e0b0b7f; @@ -300,8 +313,8 @@ --surface-raised-strong-hover: var(--smoke-dark-alpha-6); --surface-raised-stronger: var(--smoke-dark-alpha-6); --surface-raised-stronger-hover: var(--smoke-dark-alpha-7); - --surface-weak: var(--smoke-dark-alpha-5); - --surface-weaker: var(--smoke-dark-alpha-6); + --surface-weak: var(--smoke-dark-alpha-4); + --surface-weaker: var(--smoke-dark-alpha-5); --surface-strong: var(--smoke-dark-alpha-7); --surface-raised-stronger-non-alpha: var(--smoke-dark-4); --surface-brand-base: var(--yuzu-light-9); @@ -323,7 +336,7 @@ --surface-info-weak: var(--lilac-light-2); --surface-info-strong: var(--lilac-light-9); --surface-diff-hidden-base: var(--blue-dark-2); - --surface-diff-skip-base: var(--smoke-dark-alpha-2); + --surface-diff-skip-base: var(--smoke-dark-alpha-1); --surface-diff-unchanged-base: var(--smoke-dark-1); --surface-diff-hidden-weak: var(--blue-dark-1); --surface-diff-hidden-weaker: var(--blue-dark-3); @@ -349,6 +362,7 @@ --text-weak: var(--smoke-dark-alpha-9); --text-weaker: var(--smoke-dark-alpha-8); --text-strong: var(--smoke-dark-alpha-12); + --text-interactive-base: var(--cobalt-dark-11); --text-on-brand-base: var(--smoke-dark-alpha-11); --text-on-interactive-base: var(--smoke-dark-12); --text-on-interactive-weak: var(--smoke-dark-alpha-11); @@ -368,12 +382,12 @@ --text-on-brand-weak: var(--smoke-dark-alpha-9); --text-on-brand-weaker: var(--smoke-dark-alpha-8); --text-on-brand-strong: var(--smoke-dark-alpha-12); - --button-secondary-base: var(--smoke-dark-6); - --button-secondary-base-hover: var(--smoke-dark-5); + --button-secondary-base: var(--smoke-dark-4); + --button-secondary-base-hover: #2a2727; --border-base: var(--smoke-dark-alpha-7); --border-hover: var(--smoke-dark-alpha-8); --border-active: var(--smoke-dark-alpha-9); - --border-selected: var(--cobalt-dark-alpha-9); + --border-selected: var(--cobalt-dark-alpha-11); --border-disabled: var(--smoke-dark-alpha-8); --border-focus: var(--smoke-dark-alpha-9); --border-weak-base: var(--smoke-dark-alpha-6); @@ -385,7 +399,7 @@ --border-strong-focus: var(--smoke-dark-alpha-8); --border-weak-hover: var(--smoke-dark-alpha-7); --border-weak-active: var(--smoke-dark-alpha-8); - --border-weak-selected: var(--cobalt-dark-alpha-3); + --border-weak-selected: var(--cobalt-dark-alpha-6); --border-weak-disabled: var(--smoke-dark-alpha-6); --border-weak-focus: var(--smoke-dark-alpha-8); --border-interactive-base: var(--cobalt-light-7); @@ -446,7 +460,7 @@ --icon-agent-plan-base: var(--purple-dark-9); --icon-agent-docs-base: var(--amber-dark-9); --icon-agent-ask-base: var(--cyan-dark-9); - --icon-agent-build-base: var(--blue-dark-9); + --icon-agent-build-base: var(--cobalt-dark-11); --icon-on-success-base: var(--apple-dark-alpha-9); --icon-on-success-hover: var(--apple-dark-alpha-10); --icon-on-success-selected: var(--apple-dark-alpha-11); @@ -494,5 +508,11 @@ --markdown-image-text: #56b6c2; --markdown-code-block: #eeeeee; --border-color: #ffffff; + --border-weaker-base: var(--smoke-dark-alpha-3); + --border-weaker-hover: var(--smoke-dark-alpha-4); + --border-weaker-active: var(--smoke-dark-alpha-6); + --border-weaker-selected: var(--cobalt-dark-alpha-3); + --border-weaker-disabled: var(--smoke-dark-alpha-2); + --border-weaker-focus: var(--smoke-dark-alpha-6); } } From 485e4520e7a1292176373068f37fb91356b68948 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:37:03 -0500 Subject: [PATCH 012/609] wip: desktop work --- .../desktop/src/components/assistant-message.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx index 2e3d659aa9..38c06bbe55 100644 --- a/packages/desktop/src/components/assistant-message.tsx +++ b/packages/desktop/src/components/assistant-message.tsx @@ -6,15 +6,15 @@ import { Dynamic } from "solid-js/web" import { Markdown } from "./markdown" import { Collapsible, Icon, IconProps } from "@opencode-ai/ui" import { getDirectory, getFilename } from "@/utils" -import { ListTool } from "opencode/tool/ls" -import { GlobTool } from "opencode/tool/glob" -import { GrepTool } from "opencode/tool/grep" -import { WebFetchTool } from "opencode/tool/webfetch" -import { TaskTool } from "opencode/tool/task" -import { BashTool } from "opencode/tool/bash" -import { EditTool } from "opencode/tool/edit" +import type { ListTool } from "opencode/tool/ls" +import type { GlobTool } from "opencode/tool/glob" +import type { GrepTool } from "opencode/tool/grep" +import type { WebFetchTool } from "opencode/tool/webfetch" +import type { TaskTool } from "opencode/tool/task" +import type { BashTool } from "opencode/tool/bash" +import type { EditTool } from "opencode/tool/edit" +import type { WriteTool } from "opencode/tool/write" import { DiffChanges } from "./diff-changes" -import { WriteTool } from "opencode/tool/write" export function AssistantMessage(props: { message: AssistantMessage; parts: Part[] }) { return ( From ee07ed2dc41d6f2e19b11b71bfcaa9892df780d1 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 27 Oct 2025 15:44:12 -0500 Subject: [PATCH 013/609] chore: delete unused file --- packages/opencode/src/auth/github-copilot.ts | 147 ------------------- 1 file changed, 147 deletions(-) delete mode 100644 packages/opencode/src/auth/github-copilot.ts diff --git a/packages/opencode/src/auth/github-copilot.ts b/packages/opencode/src/auth/github-copilot.ts deleted file mode 100644 index bd5740c9b2..0000000000 --- a/packages/opencode/src/auth/github-copilot.ts +++ /dev/null @@ -1,147 +0,0 @@ -import z from "zod" -import { Auth } from "./index" -import { NamedError } from "../util/error" - -export namespace AuthGithubCopilot { - const CLIENT_ID = "Iv1.b507a08c87ecfe98" - const DEVICE_CODE_URL = "https://github.com/login/device/code" - const ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token" - const COPILOT_API_KEY_URL = "https://api.github.com/copilot_internal/v2/token" - - interface DeviceCodeResponse { - device_code: string - user_code: string - verification_uri: string - expires_in: number - interval: number - } - - interface AccessTokenResponse { - access_token?: string - error?: string - error_description?: string - } - - interface CopilotTokenResponse { - token: string - expires_at: number - refresh_in: number - endpoints: { - api: string - } - } - - export async function authorize() { - const deviceResponse = await fetch(DEVICE_CODE_URL, { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/json", - "User-Agent": "GitHubCopilotChat/0.26.7", - }, - body: JSON.stringify({ - client_id: CLIENT_ID, - scope: "read:user", - }), - }) - const deviceData: DeviceCodeResponse = await deviceResponse.json() - return { - device: deviceData.device_code, - user: deviceData.user_code, - verification: deviceData.verification_uri, - interval: deviceData.interval || 5, - expiry: deviceData.expires_in, - } - } - - export async function poll(device_code: string) { - const response = await fetch(ACCESS_TOKEN_URL, { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/json", - "User-Agent": "GitHubCopilotChat/0.26.7", - }, - body: JSON.stringify({ - client_id: CLIENT_ID, - device_code, - grant_type: "urn:ietf:params:oauth:grant-type:device_code", - }), - }) - - if (!response.ok) return "failed" - - const data: AccessTokenResponse = await response.json() - - if (data.access_token) { - // Store the GitHub OAuth token - await Auth.set("github-copilot", { - type: "oauth", - refresh: data.access_token, - access: "", - expires: 0, - }) - return "complete" - } - - if (data.error === "authorization_pending") return "pending" - - if (data.error) return "failed" - - return "pending" - } - - export async function access() { - const info = await Auth.get("github-copilot") - if (!info || info.type !== "oauth") return - if (info.access && info.expires > Date.now()) return info.access - - // Get new Copilot API token - const response = await fetch(COPILOT_API_KEY_URL, { - headers: { - Accept: "application/json", - Authorization: `Bearer ${info.refresh}`, - "User-Agent": "GitHubCopilotChat/0.26.7", - "Editor-Version": "vscode/1.99.3", - "Editor-Plugin-Version": "copilot-chat/0.26.7", - }, - }) - - if (!response.ok) return - - const tokenData: CopilotTokenResponse = await response.json() - - // Store the Copilot API token - await Auth.set("github-copilot", { - type: "oauth", - refresh: info.refresh, - access: tokenData.token, - expires: tokenData.expires_at * 1000, - }) - - return tokenData.token - } - - export const DeviceCodeError = NamedError.create("DeviceCodeError", z.object({})) - - export const TokenExchangeError = NamedError.create( - "TokenExchangeError", - z.object({ - message: z.string(), - }), - ) - - export const AuthenticationError = NamedError.create( - "AuthenticationError", - z.object({ - message: z.string(), - }), - ) - - export const CopilotTokenError = NamedError.create( - "CopilotTokenError", - z.object({ - message: z.string(), - }), - ) -} From 3c56dbcf5840e540eb8970805a6c725cce8e4f85 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Mon, 27 Oct 2025 16:15:13 -0500 Subject: [PATCH 014/609] chore: rm comment --- packages/opencode/src/session/prompt.ts | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 7018978e2e..26a04cb8e8 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -191,28 +191,6 @@ export namespace SessionPrompt { processor, }) - // const permUnsub = (() => { - // const handled = new Set() - // const options = [ - // { optionId: "allow_once", kind: "allow_once", name: "Allow once" }, - // { optionId: "allow_always", kind: "allow_always", name: "Always allow" }, - // { optionId: "reject_once", kind: "reject_once", name: "Reject" }, - // ] - // return Bus.subscribe(Permission.Event.Updated, async (event) => { - // const info = event.properties - // if (info.sessionID !== input.sessionID) return - // if (handled.has(info.id)) return - // handled.add(info.id) - // const toolCallId = info.callID ?? info.id - // const metadata = info.metadata ?? {} - // // TODO: emit permission event to bus for ACP to handle - // Permission.respond({ sessionID: info.sessionID, permissionID: info.id, response: "reject" }) - // }) - // })() - // await using _permSub = defer(() => { - // permUnsub?.() - // }) - const params = await Plugin.trigger( "chat.params", { From e3e9fd7aa8fbf5a7d7b21d721d014b15e16c41bb Mon Sep 17 00:00:00 2001 From: Jay V Date: Mon, 27 Oct 2025 17:48:17 -0400 Subject: [PATCH 015/609] docs: edit --- packages/web/astro.config.mjs | 2 +- packages/web/src/content/docs/acp.mdx | 32 +++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/web/astro.config.mjs b/packages/web/astro.config.mjs index 484807497b..7d509cabcc 100644 --- a/packages/web/astro.config.mjs +++ b/packages/web/astro.config.mjs @@ -85,8 +85,8 @@ export default defineConfig({ "permissions", "lsp", "mcp-servers", - "custom-tools", "acp", + "custom-tools", ], }, diff --git a/packages/web/src/content/docs/acp.mdx b/packages/web/src/content/docs/acp.mdx index ea741faca7..15ec1a1f07 100644 --- a/packages/web/src/content/docs/acp.mdx +++ b/packages/web/src/content/docs/acp.mdx @@ -1,16 +1,16 @@ --- -title: Agent Client Protocol +title: ACP Support description: Use OpenCode in any ACP-compatible editor. --- -OpenCode supports the [Agent Client Protocol (ACP)](https://agentclientprotocol.com), allowing you to use it directly in compatible editors and IDEs. - -ACP is an open protocol that standardizes communication between code editors and AI coding agents. Similar to LSP for language servers, ACP allows agents like OpenCode to work seamlessly across different development environments. +OpenCode supports the [Agent Client Protocol](https://agentclientprotocol.com) or (ACP), allowing you to use it directly in compatible editors and IDEs. :::tip -For a list of editors and tools that support ACP, see the [ACP progress report](https://zed.dev/blog/acp-progress-report#available-now). +For a list of editors and tools that support ACP, check out the [ACP progress report](https://zed.dev/blog/acp-progress-report#available-now). ::: +ACP is an open protocol that standardizes communication between code editors and AI coding agents. + --- ## Configure @@ -25,9 +25,9 @@ Below are examples for popular editors that support ACP. ### Zed -Add to your Zed configuration (`~/.config/zed/settings.json`): +Add to your [Zed](https://zed.dev) configuration (`~/.config/zed/settings.json`): -```json +```json title="~/.config/zed/settings.json" { "agent_servers": { "OpenCode": { @@ -38,11 +38,11 @@ Add to your Zed configuration (`~/.config/zed/settings.json`): } ``` -To open it, use the `agent: new thread` action in the Command Palette +To open it, use the `agent: new thread` action in the **Command Palette**. You can also bind a keyboard shortcut by editing your `keymap.json`: -```json +```json title="keymap.json" [ { "bindings": { @@ -56,7 +56,7 @@ You can also bind a keyboard shortcut by editing your `keymap.json`: ### Avante.nvim -Add to your Avante configuration: +Add to your [Avante.nvim](https://github.com/yetone/avante.nvim) configuration: ```lua { @@ -71,7 +71,7 @@ Add to your Avante configuration: If you need to pass environment variables: -```lua +```lua {6-8} { acp_providers = { ["opencode"] = { @@ -87,17 +87,17 @@ If you need to pass environment variables: --- -## Capabilities +## Support OpenCode works the same via ACP as it does in the terminal. All features are supported: +:::note +Some built-in slash commands like `/undo` and `/redo` are currently unsupported. +::: + - Built-in tools (file operations, terminal commands, etc.) - Custom tools and slash commands - MCP servers configured in your OpenCode config - Project-specific rules from `AGENTS.md` - Custom formatters and linters - Agents and permissions system - -:::note -Some built-in slash commands like `/undo` and `/redo` are currently unsupported in ACP mode. -::: From 55453dc606d4225a5b4908b082c6e1fb08df69ff Mon Sep 17 00:00:00 2001 From: Jay V Date: Mon, 27 Oct 2025 17:49:31 -0400 Subject: [PATCH 016/609] Add missing dependencies for desktop package --- bun.lock | 40 +++++++++++++++++++++++++++++++++-- packages/desktop/package.json | 2 +- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/bun.lock b/bun.lock index 42d0881097..012afac4e6 100644 --- a/bun.lock +++ b/bun.lock @@ -114,7 +114,7 @@ "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", "@opencode-ai/ui": "workspace:*", - "@pierre/precision-diffs": "catalog:", + "@pierre/precision-diffs": "0.3.5", "@shikijs/transformers": "3.9.2", "@solid-primitives/active-element": "2.1.3", "@solid-primitives/event-bus": "1.1.2", @@ -938,7 +938,7 @@ "@petamoriken/float16": ["@petamoriken/float16@3.9.2", "", {}, "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog=="], - "@pierre/precision-diffs": ["@pierre/precision-diffs@0.3.2", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-HE+wFB0TV+wmjur/J+qI5PsRQl5RN6tCEFTusW0S5FDfZJUIpkxJCacqUxyEI0DriXMKhgGQ+oCQShfaFELdrQ=="], + "@pierre/precision-diffs": ["@pierre/precision-diffs@0.3.5", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-qbotIS8CahO/7guljDzU3RVpDfg6WViWe0EB0/SZQi3xHD+nzxxlC+pGoyIFSn+47GG0EKxTnvkfaYANm19FCA=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], @@ -3498,6 +3498,8 @@ "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], + "@opencode-ai/ui/@pierre/precision-diffs": ["@pierre/precision-diffs@0.3.2", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-HE+wFB0TV+wmjur/J+qI5PsRQl5RN6tCEFTusW0S5FDfZJUIpkxJCacqUxyEI0DriXMKhgGQ+oCQShfaFELdrQ=="], + "@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/types": "3.4.2" } }, "sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg=="], "@opencode-ai/web/@types/luxon": ["@types/luxon@3.6.2", "", {}, "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw=="], @@ -3734,6 +3736,8 @@ "nypm/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "opencode/@pierre/precision-diffs": ["@pierre/precision-diffs@0.3.2", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-HE+wFB0TV+wmjur/J+qI5PsRQl5RN6tCEFTusW0S5FDfZJUIpkxJCacqUxyEI0DriXMKhgGQ+oCQShfaFELdrQ=="], + "opencode/ulid": ["ulid@3.0.1", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-dPJyqPzx8preQhqq24bBG1YNkvigm87K8kVEHCD+ruZg24t6IFEFv00xMWfxcC4djmFtiTLdFuADn4+DOz6R7Q=="], "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], @@ -4068,6 +4072,10 @@ "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], + "@opencode-ai/ui/@pierre/precision-diffs/@shikijs/transformers": ["@shikijs/transformers@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/types": "3.13.0" } }, "sha512-833lcuVzcRiG+fXvgslWsM2f4gHpjEgui1ipIknSizRuTgMkNZupiXE5/TVJ6eSYfhNBFhBZKkReKWO2GgYmqA=="], + + "@opencode-ai/ui/@pierre/precision-diffs/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="], + "@opencode-ai/web/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="], "@opencode-ai/web/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.4.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg=="], @@ -4234,6 +4242,10 @@ "nypm/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + "opencode/@pierre/precision-diffs/@shikijs/transformers": ["@shikijs/transformers@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/types": "3.13.0" } }, "sha512-833lcuVzcRiG+fXvgslWsM2f4gHpjEgui1ipIknSizRuTgMkNZupiXE5/TVJ6eSYfhNBFhBZKkReKWO2GgYmqA=="], + + "opencode/@pierre/precision-diffs/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="], + "opencontrol/@modelcontextprotocol/sdk/express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], "opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="], @@ -4414,6 +4426,18 @@ "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + "@opencode-ai/ui/@pierre/precision-diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], + + "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="], + + "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="], + + "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="], + + "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="], + + "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], + "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], "@vercel/nft/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -4436,6 +4460,18 @@ "nitropack/serve-static/send/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + "opencode/@pierre/precision-diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], + + "opencode/@pierre/precision-diffs/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="], + + "opencode/@pierre/precision-diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="], + + "opencode/@pierre/precision-diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="], + + "opencode/@pierre/precision-diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="], + + "opencode/@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], + "opencontrol/@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "opencontrol/@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], diff --git a/packages/desktop/package.json b/packages/desktop/package.json index c4af384f40..77ace500da 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -27,7 +27,7 @@ "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", "@opencode-ai/ui": "workspace:*", - "@pierre/precision-diffs": "catalog:", + "@pierre/precision-diffs": "0.3.5", "@shikijs/transformers": "3.9.2", "@solid-primitives/active-element": "2.1.3", "@solid-primitives/event-bus": "1.1.2", From a2951a2702d2f9d71f26a15d59be748038409bad Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Mon, 27 Oct 2025 18:03:32 -0400 Subject: [PATCH 017/609] Remove typecheck script from desktop package --- packages/desktop/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 77ace500da..a14b019434 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -7,8 +7,7 @@ "start": "vite", "dev": "vite", "build": "vite build", - "serve": "vite preview", - "typecheck": "tsgo --noEmit" + "serve": "vite preview" }, "license": "MIT", "devDependencies": { From e3e16e58c580a57dd109bf4d4d416af789a21874 Mon Sep 17 00:00:00 2001 From: Jay V Date: Mon, 27 Oct 2025 18:16:25 -0400 Subject: [PATCH 018/609] docs: edit --- packages/web/src/content/docs/providers.mdx | 72 ++++++++++----------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/web/src/content/docs/providers.mdx b/packages/web/src/content/docs/providers.mdx index dbf4b62def..9a5818f701 100644 --- a/packages/web/src/content/docs/providers.mdx +++ b/packages/web/src/content/docs/providers.mdx @@ -374,42 +374,6 @@ Some models need to be manually enabled in your [GitHub Copilot settings](https: --- -### Groq - -1. Head over to the [Groq console](https://console.groq.com/), click **Create API Key**, and copy the key. - -2. Run `opencode auth login` and select Groq. - - ```bash - $ opencode auth login - - ┌ Add credential - │ - ◆ Select provider - │ ● Groq - │ ... - └ - ``` - -3. Enter the API key for the provider. - - ```bash - $ opencode auth login - - ┌ Add credential - │ - ◇ Select provider - │ Groq - │ - ◇ Enter your API key - │ _ - └ - ``` - -4. Run the `/models` command to select the one you want. - ---- - ### Google Vertex AI To use Google Vertex AI with OpenCode: @@ -446,6 +410,42 @@ To use Google Vertex AI with OpenCode: --- +### Groq + +1. Head over to the [Groq console](https://console.groq.com/), click **Create API Key**, and copy the key. + +2. Run `opencode auth login` and select Groq. + + ```bash + $ opencode auth login + + ┌ Add credential + │ + ◆ Select provider + │ ● Groq + │ ... + └ + ``` + +3. Enter the API key for the provider. + + ```bash + $ opencode auth login + + ┌ Add credential + │ + ◇ Select provider + │ Groq + │ + ◇ Enter your API key + │ _ + └ + ``` + +4. Run the `/models` command to select the one you want. + +--- + ### LM Studio You can configure opencode to use local models through LM Studio. From 7216a8c86d964207083784f2d3d595a5affb9518 Mon Sep 17 00:00:00 2001 From: kcrommett <523952+kcrommett@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:51:33 -0700 Subject: [PATCH 019/609] fix: editor paste functionality for text attachments (#3489) --- packages/tui/internal/components/chat/editor.go | 7 +++++-- packages/tui/internal/tui/tui.go | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/tui/internal/components/chat/editor.go b/packages/tui/internal/components/chat/editor.go index 2841e2cc85..d3c8138409 100644 --- a/packages/tui/internal/components/chat/editor.go +++ b/packages/tui/internal/components/chat/editor.go @@ -48,6 +48,7 @@ type EditorComponent interface { SetInterruptKeyInDebounce(inDebounce bool) SetExitKeyInDebounce(inDebounce bool) RestoreFromHistory(index int) + GetAttachments() []*attachment.Attachment } type editorComponent struct { @@ -471,6 +472,10 @@ func (m *editorComponent) Length() int { return m.textarea.Length() } +func (m *editorComponent) GetAttachments() []*attachment.Attachment { + return m.textarea.GetAttachments() +} + func (m *editorComponent) Submit() (tea.Model, tea.Cmd) { value := strings.TrimSpace(m.Value()) if value == "" { @@ -628,9 +633,7 @@ func (m *editorComponent) SetValueWithAttachments(value string) { } if end > start { filePath := value[start:end] - slog.Debug("test", "filePath", filePath) if _, err := os.Stat(filepath.Join(util.CwdPath, filePath)); err == nil { - slog.Debug("test", "found", true) attachment := m.createAttachmentFromFile(filePath) if attachment != nil { m.textarea.InsertAttachment(attachment) diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go index 69fa7bdb85..279443674b 100644 --- a/packages/tui/internal/tui/tui.go +++ b/packages/tui/internal/tui/tui.go @@ -1164,6 +1164,14 @@ func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) { } value := a.editor.Value() + + // Expand text attachments before opening editor + for _, att := range a.editor.GetAttachments() { + if textSource, ok := att.GetTextSource(); ok { + value = strings.Replace(value, att.Display, textSource.Value, 1) + } + } + updated, cmd := a.editor.Clear() a.editor = updated.(chat.EditorComponent) cmds = append(cmds, cmd) From 71abca9571b74830908bf5d2aff0c9864b1c5191 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 27 Oct 2025 17:00:49 -0400 Subject: [PATCH 020/609] wip: zen --- .../console/app/src/routes/zen/util/error.ts | 5 + .../console/app/src/routes/zen/util/format.ts | 1 + .../app/src/routes/zen/{ => util}/handler.ts | 115 ++-- .../console/app/src/routes/zen/util/logger.ts | 12 + .../src/routes/zen/util/provider/anthropic.ts | 618 ++++++++++++++++++ .../zen/util/provider/openai-compatible.ts | 541 +++++++++++++++ .../src/routes/zen/util/provider/openai.ts | 600 +++++++++++++++++ .../src/routes/zen/util/provider/provider.ts | 207 ++++++ .../app/src/routes/zen/v1/chat/completions.ts | 58 +- .../console/app/src/routes/zen/v1/messages.ts | 59 +- .../console/app/src/routes/zen/v1/models.ts | 60 ++ .../app/src/routes/zen/v1/responses.ts | 47 +- 12 files changed, 2108 insertions(+), 215 deletions(-) create mode 100644 packages/console/app/src/routes/zen/util/error.ts create mode 100644 packages/console/app/src/routes/zen/util/format.ts rename packages/console/app/src/routes/zen/{ => util}/handler.ts (86%) create mode 100644 packages/console/app/src/routes/zen/util/logger.ts create mode 100644 packages/console/app/src/routes/zen/util/provider/anthropic.ts create mode 100644 packages/console/app/src/routes/zen/util/provider/openai-compatible.ts create mode 100644 packages/console/app/src/routes/zen/util/provider/openai.ts create mode 100644 packages/console/app/src/routes/zen/util/provider/provider.ts create mode 100644 packages/console/app/src/routes/zen/v1/models.ts diff --git a/packages/console/app/src/routes/zen/util/error.ts b/packages/console/app/src/routes/zen/util/error.ts new file mode 100644 index 0000000000..dfc7e9fcdb --- /dev/null +++ b/packages/console/app/src/routes/zen/util/error.ts @@ -0,0 +1,5 @@ +export class AuthError extends Error {} +export class CreditsError extends Error {} +export class MonthlyLimitError extends Error {} +export class UserLimitError extends Error {} +export class ModelError extends Error {} diff --git a/packages/console/app/src/routes/zen/util/format.ts b/packages/console/app/src/routes/zen/util/format.ts new file mode 100644 index 0000000000..53a0749691 --- /dev/null +++ b/packages/console/app/src/routes/zen/util/format.ts @@ -0,0 +1 @@ +export type Format = "anthropic" | "openai" | "oa-compat" diff --git a/packages/console/app/src/routes/zen/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts similarity index 86% rename from packages/console/app/src/routes/zen/handler.ts rename to packages/console/app/src/routes/zen/util/handler.ts index 67b03ab002..7fbb518a08 100644 --- a/packages/console/app/src/routes/zen/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -1,67 +1,41 @@ -import { z } from "zod" import type { APIEvent } from "@solidjs/start/server" -import path from "node:path" import { and, Database, eq, isNull, lt, or, sql } from "@opencode-ai/console-core/drizzle/index.js" import { KeyTable } from "@opencode-ai/console-core/schema/key.sql.js" import { BillingTable, UsageTable } from "@opencode-ai/console-core/schema/billing.sql.js" import { centsToMicroCents } from "@opencode-ai/console-core/util/price.js" import { Identifier } from "@opencode-ai/console-core/identifier.js" -import { Resource } from "@opencode-ai/console-resource" -import { Billing } from "../../../../core/src/billing" +import { Billing } from "@opencode-ai/console-core/billing.js" import { Actor } from "@opencode-ai/console-core/actor.js" import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js" import { ZenData } from "@opencode-ai/console-core/model.js" import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js" import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js" import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js" +import { logger } from "./logger" +import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError } from "./error" +import { createBodyConverter, createStreamPartConverter, createResponseConverter } from "./provider/provider" +import { Format } from "./format" +import { anthropicHelper } from "./provider/anthropic" +import { openaiHelper } from "./provider/openai" +import { oaCompatHelper } from "./provider/openai-compatible" + +type ZenData = Awaited> +type Model = ZenData["models"][string] export async function handler( input: APIEvent, opts: { - modifyBody?: (body: any) => any - setAuthHeader: (headers: Headers, apiKey: string) => void + format: Format parseApiKey: (headers: Headers) => string | undefined - onStreamPart: (chunk: string) => void - getStreamUsage: () => any - normalizeUsage: (body: any) => { - inputTokens: number - outputTokens: number - reasoningTokens?: number - cacheReadTokens?: number - cacheWrite5mTokens?: number - cacheWrite1hTokens?: number - } }, ) { - class AuthError extends Error {} - class CreditsError extends Error {} - class MonthlyLimitError extends Error {} - class UserLimitError extends Error {} - class ModelError extends Error {} - - type ZenData = Awaited> - type Model = ZenData["models"][string] - const FREE_WORKSPACES = [ "wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank "wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench ] - const logger = { - metric: (values: Record) => { - console.log(`_metric:${JSON.stringify(values)}`) - }, - log: console.log, - debug: (message: string) => { - if (Resource.App.stage === "production") return - console.debug(message) - }, - } - try { - const url = new URL(input.request.url) const body = await input.request.json() - logger.debug(JSON.stringify(body)) logger.metric({ is_tream: !!body.stream, session: input.request.headers.get("x-opencode-session"), @@ -78,22 +52,28 @@ export async function handler( // Request to model provider const startTimestamp = Date.now() - const res = await fetch(path.posix.join(providerInfo.api, url.pathname.replace(/^\/zen\/v1/, "") + url.search), { + const reqUrl = providerInfo.modifyUrl(providerInfo.api) + const reqBody = JSON.stringify( + providerInfo.modifyBody({ + ...createBodyConverter(opts.format, providerInfo.format)(body), + model: providerInfo.model, + }), + ) + logger.debug("REQUEST URL: " + reqUrl) + logger.debug("REQUEST: " + reqBody) + const res = await fetch(reqUrl, { method: "POST", headers: (() => { const headers = input.request.headers headers.delete("host") headers.delete("content-length") - opts.setAuthHeader(headers, providerInfo.apiKey) + providerInfo.modifyHeaders(headers, providerInfo.apiKey) Object.entries(providerInfo.headerMappings ?? {}).forEach(([k, v]) => { headers.set(k, headers.get(v)!) }) return headers })(), - body: JSON.stringify({ - ...(opts.modifyBody?.(body) ?? body), - model: providerInfo.model, - }), + body: reqBody, }) // Scrub response headers @@ -104,14 +84,19 @@ export async function handler( resHeaders.set(k, v) } } + logger.debug("STATUS: " + res.status + " " + res.statusText) + if (res.status === 400 || res.status === 503) { + logger.debug("RESPONSE: " + (await res.text())) + } // Handle non-streaming response if (!body.stream) { + const responseConverter = createResponseConverter(providerInfo.format, opts.format) const json = await res.json() - const body = JSON.stringify(json) + const body = JSON.stringify(responseConverter(json)) logger.metric({ response_length: body.length }) - logger.debug(body) - await trackUsage(authInfo, modelInfo, providerInfo.id, json.usage) + logger.debug("RESPONSE: " + body) + await trackUsage(authInfo, modelInfo, providerInfo, json.usage) await reload(authInfo) return new Response(body, { status: res.status, @@ -121,10 +106,13 @@ export async function handler( } // Handle streaming response + const streamConverter = createStreamPartConverter(providerInfo.format, opts.format) + const usageParser = providerInfo.createUsageParser() const stream = new ReadableStream({ start(c) { const reader = res.body?.getReader() const decoder = new TextDecoder() + const encoder = new TextEncoder() let buffer = "" let responseLength = 0 @@ -136,9 +124,9 @@ export async function handler( response_length: responseLength, "timestamp.last_byte": Date.now(), }) - const usage = opts.getStreamUsage() + const usage = usageParser.retrieve() if (usage) { - await trackUsage(authInfo, modelInfo, providerInfo.id, usage) + await trackUsage(authInfo, modelInfo, providerInfo, usage) await reload(authInfo) } c.close() @@ -158,12 +146,21 @@ export async function handler( const parts = buffer.split("\n\n") buffer = parts.pop() ?? "" - for (const part of parts) { - logger.debug(part) - opts.onStreamPart(part.trim()) + for (let part of parts) { + logger.debug("PART: " + part) + + part = part.trim() + usageParser.parse(part) + + if (providerInfo.format !== opts.format) { + part = streamConverter(part) + c.enqueue(encoder.encode(part + "\n\n")) + } } - c.enqueue(value) + if (providerInfo.format === opts.format) { + c.enqueue(value) + } return pump() }) || Promise.resolve() @@ -235,7 +232,11 @@ export async function handler( throw new ModelError(`Provider ${provider.id} not supported`) } - return { ...provider, ...zenData.providers[provider.id] } + return { + ...provider, + ...zenData.providers[provider.id], + ...(provider.id === "anthropic" ? anthropicHelper : provider.id === "openai" ? openaiHelper : oaCompatHelper), + } } async function authenticate( @@ -356,11 +357,11 @@ export async function handler( async function trackUsage( authInfo: Awaited>, modelInfo: ReturnType, - providerId: string, + providerInfo: Awaited>, usage: any, ) { const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } = - opts.normalizeUsage(usage) + providerInfo.normalizeUsage(usage) const modelCost = modelInfo.cost200K && @@ -421,7 +422,7 @@ export async function handler( workspaceID: authInfo.workspaceID, id: Identifier.create("usage"), model: modelInfo.id, - provider: providerId, + provider: providerInfo.id, inputTokens, outputTokens, reasoningTokens, diff --git a/packages/console/app/src/routes/zen/util/logger.ts b/packages/console/app/src/routes/zen/util/logger.ts new file mode 100644 index 0000000000..aef46ddd0e --- /dev/null +++ b/packages/console/app/src/routes/zen/util/logger.ts @@ -0,0 +1,12 @@ +import { Resource } from "@opencode-ai/console-resource" + +export const logger = { + metric: (values: Record) => { + console.log(`_metric:${JSON.stringify(values)}`) + }, + log: console.log, + debug: (message: string) => { + if (Resource.App.stage === "production") return + console.debug(message) + }, +} diff --git a/packages/console/app/src/routes/zen/util/provider/anthropic.ts b/packages/console/app/src/routes/zen/util/provider/anthropic.ts new file mode 100644 index 0000000000..64b040a533 --- /dev/null +++ b/packages/console/app/src/routes/zen/util/provider/anthropic.ts @@ -0,0 +1,618 @@ +import { ProviderHelper, CommonRequest, CommonResponse, CommonChunk } from "./provider" + +type Usage = { + cache_creation?: { + ephemeral_5m_input_tokens?: number + ephemeral_1h_input_tokens?: number + } + cache_creation_input_tokens?: number + cache_read_input_tokens?: number + input_tokens?: number + output_tokens?: number + server_tool_use?: { + web_search_requests?: number + } +} + +export const anthropicHelper = { + format: "anthropic", + modifyUrl: (providerApi: string) => providerApi + "/messages", + modifyHeaders: (headers: Headers, apiKey: string) => { + headers.set("x-api-key", apiKey) + headers.set("anthropic-version", headers.get("anthropic-version") ?? "2023-06-01") + }, + modifyBody: (body: Record) => { + return { + ...body, + service_tier: "standard_only", + } + }, + createUsageParser: () => { + let usage: Usage + + return { + parse: (chunk: string) => { + const data = chunk.split("\n")[1] + if (!data.startsWith("data: ")) return + + let json + try { + json = JSON.parse(data.slice(6)) + } catch (e) { + return + } + + const usageUpdate = json.usage ?? json.message?.usage + if (!usageUpdate) return + usage = { + ...usage, + ...usageUpdate, + cache_creation: { + ...usage?.cache_creation, + ...usageUpdate.cache_creation, + }, + server_tool_use: { + ...usage?.server_tool_use, + ...usageUpdate.server_tool_use, + }, + } + }, + retrieve: () => usage, + } + }, + normalizeUsage: (usage: Usage) => ({ + inputTokens: usage.input_tokens ?? 0, + outputTokens: usage.output_tokens ?? 0, + reasoningTokens: undefined, + cacheReadTokens: usage.cache_read_input_tokens ?? undefined, + cacheWrite5mTokens: usage.cache_creation?.ephemeral_5m_input_tokens ?? undefined, + cacheWrite1hTokens: usage.cache_creation?.ephemeral_1h_input_tokens ?? undefined, + }), +} satisfies ProviderHelper + +export function fromAnthropicRequest(body: any): CommonRequest { + if (!body || typeof body !== "object") return body + + const msgs: any[] = [] + + const sys = Array.isArray(body.system) ? body.system : undefined + if (sys && sys.length > 0) { + for (const s of sys) { + if (!s) continue + if ((s as any).type !== "text") continue + if (typeof (s as any).text !== "string") continue + if ((s as any).text.length === 0) continue + msgs.push({ role: "system", content: (s as any).text }) + } + } + + const toImg = (src: any) => { + if (!src || typeof src !== "object") return undefined + if ((src as any).type === "url" && typeof (src as any).url === "string") + return { type: "image_url", image_url: { url: (src as any).url } } + if ( + (src as any).type === "base64" && + typeof (src as any).media_type === "string" && + typeof (src as any).data === "string" + ) + return { type: "image_url", image_url: { url: `data:${(src as any).media_type};base64,${(src as any).data}` } } + return undefined + } + + const inMsgs = Array.isArray(body.messages) ? body.messages : [] + for (const m of inMsgs) { + if (!m || !(m as any).role) continue + + if ((m as any).role === "user") { + const partsIn = Array.isArray((m as any).content) ? (m as any).content : [] + const partsOut: any[] = [] + for (const p of partsIn) { + if (!p || !(p as any).type) continue + if ((p as any).type === "text" && typeof (p as any).text === "string") + partsOut.push({ type: "text", text: (p as any).text }) + if ((p as any).type === "image") { + const ip = toImg((p as any).source) + if (ip) partsOut.push(ip) + } + if ((p as any).type === "tool_result") { + const id = (p as any).tool_use_id + const content = + typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content) + msgs.push({ role: "tool", tool_call_id: id, content }) + } + } + if (partsOut.length > 0) { + if (partsOut.length === 1 && partsOut[0].type === "text") msgs.push({ role: "user", content: partsOut[0].text }) + else msgs.push({ role: "user", content: partsOut }) + } + continue + } + + if ((m as any).role === "assistant") { + const partsIn = Array.isArray((m as any).content) ? (m as any).content : [] + const texts: string[] = [] + const tcs: any[] = [] + for (const p of partsIn) { + if (!p || !(p as any).type) continue + if ((p as any).type === "text" && typeof (p as any).text === "string") texts.push((p as any).text) + if ((p as any).type === "tool_use") { + const name = (p as any).name + const id = (p as any).id + const inp = (p as any).input + const input = (() => { + if (typeof inp === "string") return inp + try { + return JSON.stringify(inp ?? {}) + } catch { + return String(inp ?? "") + } + })() + tcs.push({ id, type: "function", function: { name, arguments: input } }) + } + } + const out: any = { role: "assistant", content: texts.join("") } + if (tcs.length > 0) out.tool_calls = tcs + msgs.push(out) + continue + } + } + + const tools = Array.isArray(body.tools) + ? body.tools + .filter((t: any) => t && typeof t === "object" && "input_schema" in t) + .map((t: any) => ({ + type: "function", + function: { name: (t as any).name, description: (t as any).description, parameters: (t as any).input_schema }, + })) + : undefined + + const tcin = body.tool_choice + const tc = (() => { + if (!tcin) return undefined + if ((tcin as any).type === "auto") return "auto" + if ((tcin as any).type === "any") return "required" + if ((tcin as any).type === "tool" && typeof (tcin as any).name === "string") + return { type: "function" as const, function: { name: (tcin as any).name } } + return undefined + })() + + const stop = (() => { + const v = body.stop_sequences + if (!v) return undefined + if (Array.isArray(v)) return v.length === 1 ? v[0] : v + if (typeof v === "string") return v + return undefined + })() + + return { + max_tokens: body.max_tokens, + temperature: body.temperature, + top_p: body.top_p, + stop, + messages: msgs, + stream: !!body.stream, + tools, + tool_choice: tc, + } +} + +export function toAnthropicRequest(body: CommonRequest) { + if (!body || typeof body !== "object") return body + + const sysIn = Array.isArray(body.messages) ? body.messages.filter((m: any) => m && m.role === "system") : [] + let ccCount = 0 + const cc = () => { + ccCount++ + return ccCount <= 4 ? { cache_control: { type: "ephemeral" } } : {} + } + const system = sysIn + .filter((m: any) => typeof m.content === "string" && m.content.length > 0) + .map((m: any) => ({ type: "text", text: m.content, ...cc() })) + + const msgsIn = Array.isArray(body.messages) ? body.messages : [] + const msgsOut: any[] = [] + + const toSrc = (p: any) => { + if (!p || typeof p !== "object") return undefined + if ((p as any).type === "image_url" && (p as any).image_url) { + const u = (p as any).image_url.url ?? (p as any).image_url + if (typeof u === "string" && u.startsWith("data:")) { + const m = u.match(/^data:([^;]+);base64,(.*)$/) + if (m) return { type: "base64", media_type: m[1], data: m[2] } + } + if (typeof u === "string") return { type: "url", url: u } + } + return undefined + } + + for (const m of msgsIn) { + if (!m || !(m as any).role) continue + + if ((m as any).role === "user") { + if (typeof (m as any).content === "string") { + msgsOut.push({ + role: "user", + content: [{ type: "text", text: (m as any).content, ...cc() }], + }) + } else if (Array.isArray((m as any).content)) { + const parts: any[] = [] + for (const p of (m as any).content) { + if (!p || !(p as any).type) continue + if ((p as any).type === "text" && typeof (p as any).text === "string") + parts.push({ type: "text", text: (p as any).text, ...cc() }) + if ((p as any).type === "image_url") { + const s = toSrc(p) + if (s) parts.push({ type: "image", source: s, ...cc() }) + } + } + if (parts.length > 0) msgsOut.push({ role: "user", content: parts }) + } + continue + } + + if ((m as any).role === "assistant") { + const out: any = { role: "assistant", content: [] as any[] } + if (typeof (m as any).content === "string" && (m as any).content.length > 0) { + ;(out.content as any[]).push({ type: "text", text: (m as any).content, ...cc() }) + } + if (Array.isArray((m as any).tool_calls)) { + for (const tc of (m as any).tool_calls) { + if ((tc as any).type === "function" && (tc as any).function) { + let input: any + const a = (tc as any).function.arguments + if (typeof a === "string") { + try { + input = JSON.parse(a) + } catch { + input = a + } + } else input = a + const id = (tc as any).id || `toolu_${Math.random().toString(36).slice(2)}` + ;(out.content as any[]).push({ + type: "tool_use", + id, + name: (tc as any).function.name, + input, + ...cc(), + }) + } + } + } + if ((out.content as any[]).length > 0) msgsOut.push(out) + continue + } + + if ((m as any).role === "tool") { + msgsOut.push({ + role: "user", + content: [ + { + type: "tool_result", + tool_use_id: (m as any).tool_call_id, + content: (m as any).content, + ...cc(), + }, + ], + }) + continue + } + } + + const tools = Array.isArray(body.tools) + ? body.tools + .filter((t: any) => t && typeof t === "object" && (t as any).type === "function") + .map((t: any) => ({ + name: (t as any).function.name, + description: (t as any).function.description, + input_schema: (t as any).function.parameters, + ...cc(), + })) + : undefined + + const tcIn = body.tool_choice + const tool_choice = (() => { + if (!tcIn) return undefined + if (tcIn === "auto") return { type: "auto" } + if (tcIn === "required") return { type: "any" } + if ((tcIn as any).type === "function" && (tcIn as any).function?.name) + return { type: "tool", name: (tcIn as any).function.name } + return undefined + })() + + const stop_sequences = (() => { + const v = body.stop + if (!v) return undefined + if (Array.isArray(v)) return v + if (typeof v === "string") return [v] + return undefined + })() + + return { + max_tokens: body.max_tokens ?? 32_000, + temperature: body.temperature, + top_p: body.top_p, + system: system.length > 0 ? system : undefined, + messages: msgsOut, + stream: !!body.stream, + tools, + tool_choice, + stop_sequences, + } +} + +export function fromAnthropicResponse(resp: any): CommonResponse { + if (!resp || typeof resp !== "object") return resp + + if (Array.isArray((resp as any).choices)) return resp + + const isAnthropic = typeof (resp as any).type === "string" && (resp as any).type === "message" + if (!isAnthropic) return resp + + const idIn = (resp as any).id + const id = + typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` + const model = (resp as any).model + + const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : [] + const text = blocks + .filter((b) => b && b.type === "text" && typeof (b as any).text === "string") + .map((b: any) => b.text) + .join("") + const tcs = blocks + .filter((b) => b && b.type === "tool_use") + .map((b: any) => { + const name = (b as any).name + const args = (() => { + const inp = (b as any).input + if (typeof inp === "string") return inp + try { + return JSON.stringify(inp ?? {}) + } catch { + return String(inp ?? "") + } + })() + const tid = + typeof (b as any).id === "string" && (b as any).id.length > 0 + ? (b as any).id + : `toolu_${Math.random().toString(36).slice(2)}` + return { id: tid, type: "function" as const, function: { name, arguments: args } } + }) + + const finish = (r: string | null) => { + if (r === "end_turn") return "stop" + if (r === "tool_use") return "tool_calls" + if (r === "max_tokens") return "length" + if (r === "content_filter") return "content_filter" + return null + } + + const u = (resp as any).usage + const usage = (() => { + if (!u) return undefined as any + const pt = typeof (u as any).input_tokens === "number" ? (u as any).input_tokens : undefined + const ct = typeof (u as any).output_tokens === "number" ? (u as any).output_tokens : undefined + const total = pt != null && ct != null ? pt + ct : undefined + const cached = + typeof (u as any).cache_read_input_tokens === "number" ? (u as any).cache_read_input_tokens : undefined + const details = cached != null ? { cached_tokens: cached } : undefined + return { + prompt_tokens: pt, + completion_tokens: ct, + total_tokens: total, + ...(details ? { prompt_tokens_details: details } : {}), + } + })() + + return { + id, + object: "chat.completion", + created: Math.floor(Date.now() / 1000), + model, + choices: [ + { + index: 0, + message: { + role: "assistant", + ...(text && text.length > 0 ? { content: text } : {}), + ...(tcs.length > 0 ? { tool_calls: tcs } : {}), + }, + finish_reason: finish((resp as any).stop_reason ?? null), + }, + ], + ...(usage ? { usage } : {}), + } +} + +export function toAnthropicResponse(resp: CommonResponse) { + if (!resp || typeof resp !== "object") return resp + + if (!Array.isArray((resp as any).choices)) return resp + + const choice = (resp as any).choices[0] + if (!choice) return resp + + const message = choice.message + if (!message) return resp + + const content: any[] = [] + + if (typeof message.content === "string" && message.content.length > 0) + content.push({ type: "text", text: message.content }) + + if (Array.isArray(message.tool_calls)) { + for (const tc of message.tool_calls) { + if ((tc as any).type === "function" && (tc as any).function) { + let input: any + try { + input = JSON.parse((tc as any).function.arguments) + } catch { + input = (tc as any).function.arguments + } + content.push({ type: "tool_use", id: (tc as any).id, name: (tc as any).function.name, input }) + } + } + } + + const stop_reason = (() => { + const r = choice.finish_reason + if (r === "stop") return "end_turn" + if (r === "tool_calls") return "tool_use" + if (r === "length") return "max_tokens" + if (r === "content_filter") return "content_filter" + return null + })() + + const usage = (() => { + const u = (resp as any).usage + if (!u) return undefined + return { + input_tokens: u.prompt_tokens, + output_tokens: u.completion_tokens, + cache_read_input_tokens: u.prompt_tokens_details?.cached_tokens, + } + })() + + return { + id: (resp as any).id, + type: "message", + role: "assistant", + content: content.length > 0 ? content : [{ type: "text", text: "" }], + model: (resp as any).model, + stop_reason, + usage, + } +} + +export function fromAnthropicChunk(chunk: string): CommonChunk | string { + // Anthropic sends two lines per part: "event: \n" + "data: " + const lines = chunk.split("\n") + const dataLine = lines.find((l) => l.startsWith("data: ")) + if (!dataLine) return chunk + + let json + try { + json = JSON.parse(dataLine.slice(6)) + } catch { + return chunk + } + + const out: CommonChunk = { + id: json.id ?? json.message?.id ?? "", + object: "chat.completion.chunk", + created: Math.floor(Date.now() / 1000), + model: json.model ?? json.message?.model ?? "", + choices: [], + } + + if (json.type === "content_block_start") { + const cb = json.content_block + if (cb?.type === "text") { + out.choices.push({ index: json.index ?? 0, delta: { role: "assistant", content: "" }, finish_reason: null }) + } else if (cb?.type === "tool_use") { + out.choices.push({ + index: json.index ?? 0, + delta: { + tool_calls: [ + { index: json.index ?? 0, id: cb.id, type: "function", function: { name: cb.name, arguments: "" } }, + ], + }, + finish_reason: null, + }) + } + } + + if (json.type === "content_block_delta") { + const d = json.delta + if (d?.type === "text_delta") { + out.choices.push({ index: json.index ?? 0, delta: { content: d.text }, finish_reason: null }) + } else if (d?.type === "input_json_delta") { + out.choices.push({ + index: json.index ?? 0, + delta: { tool_calls: [{ index: json.index ?? 0, function: { arguments: d.partial_json } }] }, + finish_reason: null, + }) + } + } + + if (json.type === "message_delta") { + const d = json.delta + const finish_reason = (() => { + const r = d?.stop_reason + if (r === "end_turn") return "stop" + if (r === "tool_use") return "tool_calls" + if (r === "max_tokens") return "length" + if (r === "content_filter") return "content_filter" + return null + })() + + out.choices.push({ index: 0, delta: {}, finish_reason }) + } + + if (json.usage) { + const u = json.usage + out.usage = { + prompt_tokens: u.input_tokens, + completion_tokens: u.output_tokens, + total_tokens: (u.input_tokens || 0) + (u.output_tokens || 0), + ...(u.cache_read_input_tokens ? { prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens } } : {}), + } + } + + return out +} + +export function toAnthropicChunk(chunk: CommonChunk): string { + if (!chunk.choices || !Array.isArray(chunk.choices) || chunk.choices.length === 0) { + return JSON.stringify({}) + } + + const choice = chunk.choices[0] + const delta = choice.delta + if (!delta) return JSON.stringify({}) + + const result: any = {} + + if (delta.content) { + result.type = "content_block_delta" + result.index = 0 + result.delta = { type: "text_delta", text: delta.content } + } + + if (delta.tool_calls) { + for (const tc of delta.tool_calls) { + if (tc.function?.name) { + result.type = "content_block_start" + result.index = tc.index ?? 0 + result.content_block = { type: "tool_use", id: tc.id, name: tc.function.name, input: {} } + } else if (tc.function?.arguments) { + result.type = "content_block_delta" + result.index = tc.index ?? 0 + result.delta = { type: "input_json_delta", partial_json: tc.function.arguments } + } + } + } + + if (choice.finish_reason) { + const stop_reason = (() => { + const r = choice.finish_reason + if (r === "stop") return "end_turn" + if (r === "tool_calls") return "tool_use" + if (r === "length") return "max_tokens" + if (r === "content_filter") return "content_filter" + return null + })() + result.type = "message_delta" + result.delta = { stop_reason, stop_sequence: null } + } + + if (chunk.usage) { + const u = chunk.usage + result.usage = { + input_tokens: u.prompt_tokens, + output_tokens: u.completion_tokens, + cache_read_input_tokens: u.prompt_tokens_details?.cached_tokens, + } + } + + return JSON.stringify(result) +} diff --git a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts new file mode 100644 index 0000000000..aae6bed57e --- /dev/null +++ b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts @@ -0,0 +1,541 @@ +import { ProviderHelper, CommonRequest, CommonResponse, CommonChunk } from "./provider" + +type Usage = { + prompt_tokens?: number + completion_tokens?: number + total_tokens?: number + // used by moonshot + cached_tokens?: number + // used by xai + prompt_tokens_details?: { + text_tokens?: number + audio_tokens?: number + image_tokens?: number + cached_tokens?: number + } + completion_tokens_details?: { + reasoning_tokens?: number + audio_tokens?: number + accepted_prediction_tokens?: number + rejected_prediction_tokens?: number + } +} + +export const oaCompatHelper = { + format: "oa-compat", + modifyUrl: (providerApi: string) => providerApi + "/chat/completions", + modifyHeaders: (headers: Headers, apiKey: string) => { + headers.set("authorization", `Bearer ${apiKey}`) + }, + modifyBody: (body: Record) => { + return { + ...body, + ...(body.stream ? { stream_options: { include_usage: true } } : {}), + } + }, + createUsageParser: () => { + let usage: Usage + + return { + parse: (chunk: string) => { + if (!chunk.startsWith("data: ")) return + + let json + try { + json = JSON.parse(chunk.slice(6)) as { usage?: Usage } + } catch (e) { + return + } + + if (!json.usage) return + usage = json.usage + }, + retrieve: () => usage, + } + }, + normalizeUsage: (usage: Usage) => { + const inputTokens = usage.prompt_tokens ?? 0 + const outputTokens = usage.completion_tokens ?? 0 + const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? undefined + const cacheReadTokens = usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined + return { + inputTokens: inputTokens - (cacheReadTokens ?? 0), + outputTokens, + reasoningTokens, + cacheReadTokens, + cacheWrite5mTokens: undefined, + cacheWrite1hTokens: undefined, + } + }, +} satisfies ProviderHelper + +export function fromOaCompatibleRequest(body: any): CommonRequest { + if (!body || typeof body !== "object") return body + + const msgsIn = Array.isArray(body.messages) ? body.messages : [] + const msgsOut: any[] = [] + + for (const m of msgsIn) { + if (!m || !m.role) continue + + if (m.role === "system") { + if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content }) + continue + } + + if (m.role === "user") { + if (typeof m.content === "string") { + msgsOut.push({ role: "user", content: m.content }) + } else if (Array.isArray(m.content)) { + const parts: any[] = [] + for (const p of m.content) { + if (!p || !p.type) continue + if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text }) + if (p.type === "image_url") parts.push({ type: "image_url", image_url: p.image_url }) + } + if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text }) + else if (parts.length > 0) msgsOut.push({ role: "user", content: parts }) + } + continue + } + + if (m.role === "assistant") { + const out: any = { role: "assistant" } + if (typeof m.content === "string") out.content = m.content + if (Array.isArray(m.tool_calls)) out.tool_calls = m.tool_calls + msgsOut.push(out) + continue + } + + if (m.role === "tool") { + msgsOut.push({ role: "tool", tool_call_id: m.tool_call_id, content: m.content }) + continue + } + } + + return { + max_tokens: body.max_tokens, + temperature: body.temperature, + top_p: body.top_p, + stop: body.stop, + messages: msgsOut, + stream: !!body.stream, + tools: Array.isArray(body.tools) ? body.tools : undefined, + tool_choice: body.tool_choice, + } +} + +export function toOaCompatibleRequest(body: CommonRequest) { + if (!body || typeof body !== "object") return body + + const msgsIn = Array.isArray(body.messages) ? body.messages : [] + const msgsOut: any[] = [] + + const toImg = (p: any) => { + if (!p || typeof p !== "object") return undefined + if (p.type === "image_url" && p.image_url) return { type: "image_url", image_url: p.image_url } + const s = (p as any).source + if (!s || typeof s !== "object") return undefined + if (s.type === "url" && typeof s.url === "string") return { type: "image_url", image_url: { url: s.url } } + if (s.type === "base64" && typeof s.media_type === "string" && typeof s.data === "string") + return { type: "image_url", image_url: { url: `data:${s.media_type};base64,${s.data}` } } + return undefined + } + + for (const m of msgsIn) { + if (!m || !m.role) continue + + if (m.role === "system") { + if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content }) + continue + } + + if (m.role === "user") { + if (typeof m.content === "string") { + msgsOut.push({ role: "user", content: m.content }) + continue + } + if (Array.isArray(m.content)) { + const parts: any[] = [] + for (const p of m.content) { + if (!p || !p.type) continue + if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text }) + const ip = toImg(p) + if (ip) parts.push(ip) + } + if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text }) + else if (parts.length > 0) msgsOut.push({ role: "user", content: parts }) + } + continue + } + + if (m.role === "assistant") { + const out: any = { role: "assistant" } + if (typeof m.content === "string") out.content = m.content + if (Array.isArray(m.tool_calls)) out.tool_calls = m.tool_calls + msgsOut.push(out) + continue + } + + if (m.role === "tool") { + msgsOut.push({ role: "tool", tool_call_id: m.tool_call_id, content: m.content }) + continue + } + } + + const tools = Array.isArray(body.tools) + ? body.tools.map((tool: any) => ({ + type: "function", + function: { + name: tool.name, + description: tool.description, + parameters: tool.parameters, + }, + })) + : undefined + + return { + model: body.model, + max_tokens: body.max_tokens, + temperature: body.temperature, + top_p: body.top_p, + stop: body.stop, + messages: msgsOut, + stream: !!body.stream, + tools, + tool_choice: body.tool_choice, + response_format: (body as any).response_format, + } +} + +export function fromOaCompatibleResponse(resp: any): CommonResponse { + if (!resp || typeof resp !== "object") return resp + + if (!Array.isArray((resp as any).choices)) return resp + + const choice = (resp as any).choices[0] + if (!choice) return resp + + const message = choice.message + if (!message) return resp + + const content: any[] = [] + + if (typeof message.content === "string" && message.content.length > 0) { + content.push({ type: "text", text: message.content }) + } + + if (Array.isArray(message.tool_calls)) { + for (const toolCall of message.tool_calls) { + if (toolCall.type === "function" && toolCall.function) { + let input + try { + input = JSON.parse(toolCall.function.arguments) + } catch { + input = toolCall.function.arguments + } + content.push({ + type: "tool_use", + id: toolCall.id, + name: toolCall.function.name, + input, + }) + } + } + } + + const stopReason = (() => { + const reason = choice.finish_reason + if (reason === "stop") return "stop" + if (reason === "tool_calls") return "tool_calls" + if (reason === "length") return "length" + if (reason === "content_filter") return "content_filter" + return null + })() + + const usage = (() => { + const u = (resp as any).usage + if (!u) return undefined + return { + prompt_tokens: u.prompt_tokens, + completion_tokens: u.completion_tokens, + total_tokens: u.total_tokens, + ...(u.prompt_tokens_details?.cached_tokens + ? { prompt_tokens_details: { cached_tokens: u.prompt_tokens_details.cached_tokens } } + : {}), + } + })() + + return { + id: (resp as any).id, + object: "chat.completion" as const, + created: Math.floor(Date.now() / 1000), + model: (resp as any).model, + choices: [ + { + index: 0, + message: { + role: "assistant" as const, + ...(content.length > 0 && content.some((c) => c.type === "text") + ? { + content: content + .filter((c) => c.type === "text") + .map((c: any) => c.text) + .join(""), + } + : {}), + ...(content.length > 0 && content.some((c) => c.type === "tool_use") + ? { + tool_calls: content + .filter((c) => c.type === "tool_use") + .map((c: any) => ({ + id: c.id, + type: "function" as const, + function: { + name: c.name, + arguments: typeof c.input === "string" ? c.input : JSON.stringify(c.input), + }, + })), + } + : {}), + }, + finish_reason: stopReason, + }, + ], + ...(usage ? { usage } : {}), + } +} + +export function toOaCompatibleResponse(resp: CommonResponse) { + if (!resp || typeof resp !== "object") return resp + + if (Array.isArray((resp as any).choices)) return resp + + const isAnthropic = typeof (resp as any).type === "string" && (resp as any).type === "message" + if (!isAnthropic) return resp + + const idIn = (resp as any).id + const id = + typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` + const model = (resp as any).model + + const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : [] + const text = blocks + .filter((b) => b && b.type === "text" && typeof b.text === "string") + .map((b) => b.text) + .join("") + const tcs = blocks + .filter((b) => b && b.type === "tool_use") + .map((b) => { + const name = (b as any).name + const args = (() => { + const inp = (b as any).input + if (typeof inp === "string") return inp + try { + return JSON.stringify(inp ?? {}) + } catch { + return String(inp ?? "") + } + })() + const tid = + typeof (b as any).id === "string" && (b as any).id.length > 0 + ? (b as any).id + : `toolu_${Math.random().toString(36).slice(2)}` + return { id: tid, type: "function" as const, function: { name, arguments: args } } + }) + + const finish = (r: string | null) => { + if (r === "end_turn") return "stop" + if (r === "tool_use") return "tool_calls" + if (r === "max_tokens") return "length" + if (r === "content_filter") return "content_filter" + return null + } + + const u = (resp as any).usage + const usage = (() => { + if (!u) return undefined as any + const pt = typeof u.input_tokens === "number" ? u.input_tokens : undefined + const ct = typeof u.output_tokens === "number" ? u.output_tokens : undefined + const total = pt != null && ct != null ? pt + ct : undefined + const cached = typeof u.cache_read_input_tokens === "number" ? u.cache_read_input_tokens : undefined + const details = cached != null ? { cached_tokens: cached } : undefined + return { + prompt_tokens: pt, + completion_tokens: ct, + total_tokens: total, + ...(details ? { prompt_tokens_details: details } : {}), + } + })() + + return { + id, + object: "chat.completion", + created: Math.floor(Date.now() / 1000), + model, + choices: [ + { + index: 0, + message: { + role: "assistant", + ...(text && text.length > 0 ? { content: text } : {}), + ...(tcs.length > 0 ? { tool_calls: tcs } : {}), + }, + finish_reason: finish((resp as any).stop_reason ?? null), + }, + ], + ...(usage ? { usage } : {}), + } +} + +export function fromOaCompatibleChunk(chunk: string): CommonChunk | string { + if (!chunk.startsWith("data: ")) return chunk + + let json + try { + json = JSON.parse(chunk.slice(6)) + } catch { + return chunk + } + + if (!json.choices || !Array.isArray(json.choices) || json.choices.length === 0) { + return chunk + } + + const choice = json.choices[0] + const delta = choice.delta + + if (!delta) return chunk + + const result: CommonChunk = { + id: json.id ?? "", + object: "chat.completion.chunk", + created: json.created ?? Math.floor(Date.now() / 1000), + model: json.model ?? "", + choices: [], + } + + if (delta.content) { + result.choices.push({ + index: choice.index ?? 0, + delta: { content: delta.content }, + finish_reason: null, + }) + } + + if (delta.tool_calls) { + for (const toolCall of delta.tool_calls) { + result.choices.push({ + index: choice.index ?? 0, + delta: { + tool_calls: [ + { + index: toolCall.index ?? 0, + id: toolCall.id, + type: toolCall.type ?? "function", + function: toolCall.function, + }, + ], + }, + finish_reason: null, + }) + } + } + + if (choice.finish_reason) { + result.choices.push({ + index: choice.index ?? 0, + delta: {}, + finish_reason: choice.finish_reason, + }) + } + + if (json.usage) { + const usage = json.usage + result.usage = { + prompt_tokens: usage.prompt_tokens, + completion_tokens: usage.completion_tokens, + total_tokens: usage.total_tokens, + ...(usage.prompt_tokens_details?.cached_tokens + ? { prompt_tokens_details: { cached_tokens: usage.prompt_tokens_details.cached_tokens } } + : {}), + } + } + + return result +} + +export function toOaCompatibleChunk(chunk: CommonChunk): string { + const result: any = { + id: chunk.id, + object: "chat.completion.chunk", + created: chunk.created, + model: chunk.model, + choices: [], + } + + if (!chunk.choices || chunk.choices.length === 0) { + return `data: ${JSON.stringify(result)}` + } + + const choice = chunk.choices[0] + const delta = choice.delta + + if (delta?.role) { + result.choices.push({ + index: choice.index, + delta: { role: delta.role }, + finish_reason: null, + }) + } + + if (delta?.content) { + result.choices.push({ + index: choice.index, + delta: { content: delta.content }, + finish_reason: null, + }) + } + + if (delta?.tool_calls) { + for (const tc of delta.tool_calls) { + result.choices.push({ + index: choice.index, + delta: { + tool_calls: [ + { + index: tc.index, + id: tc.id, + type: tc.type, + function: tc.function, + }, + ], + }, + finish_reason: null, + }) + } + } + + if (choice.finish_reason) { + result.choices.push({ + index: choice.index, + delta: {}, + finish_reason: choice.finish_reason, + }) + } + + if (chunk.usage) { + result.usage = { + prompt_tokens: chunk.usage.prompt_tokens, + completion_tokens: chunk.usage.completion_tokens, + total_tokens: chunk.usage.total_tokens, + ...(chunk.usage.prompt_tokens_details?.cached_tokens + ? { + prompt_tokens_details: { cached_tokens: chunk.usage.prompt_tokens_details.cached_tokens }, + } + : {}), + } + } + + return `data: ${JSON.stringify(result)}` +} diff --git a/packages/console/app/src/routes/zen/util/provider/openai.ts b/packages/console/app/src/routes/zen/util/provider/openai.ts new file mode 100644 index 0000000000..9781d821de --- /dev/null +++ b/packages/console/app/src/routes/zen/util/provider/openai.ts @@ -0,0 +1,600 @@ +import { ProviderHelper, CommonRequest, CommonResponse, CommonChunk } from "./provider" + +type Usage = { + input_tokens?: number + input_tokens_details?: { + cached_tokens?: number + } + output_tokens?: number + output_tokens_details?: { + reasoning_tokens?: number + } + total_tokens?: number +} + +export const openaiHelper = { + format: "openai", + modifyUrl: (providerApi: string) => providerApi + "/responses", + modifyHeaders: (headers: Headers, apiKey: string) => { + headers.set("authorization", `Bearer ${apiKey}`) + }, + modifyBody: (body: Record) => { + return body + }, + createUsageParser: () => { + let usage: Usage + + return { + parse: (chunk: string) => { + const [event, data] = chunk.split("\n") + if (event !== "event: response.completed") return + if (!data.startsWith("data: ")) return + + let json + try { + json = JSON.parse(data.slice(6)) as { response?: { usage?: Usage } } + } catch (e) { + return + } + + if (!json.response?.usage) return + usage = json.response.usage + }, + retrieve: () => usage, + } + }, + normalizeUsage: (usage: Usage) => { + const inputTokens = usage.input_tokens ?? 0 + const outputTokens = usage.output_tokens ?? 0 + const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? undefined + const cacheReadTokens = usage.input_tokens_details?.cached_tokens ?? undefined + return { + inputTokens: inputTokens - (cacheReadTokens ?? 0), + outputTokens: outputTokens - (reasoningTokens ?? 0), + reasoningTokens, + cacheReadTokens, + cacheWrite5mTokens: undefined, + cacheWrite1hTokens: undefined, + } + }, +} satisfies ProviderHelper + +export function fromOpenaiRequest(body: any): CommonRequest { + if (!body || typeof body !== "object") return body + + const toImg = (p: any) => { + if (!p || typeof p !== "object") return undefined + if ((p as any).type === "image_url" && (p as any).image_url) + return { type: "image_url", image_url: (p as any).image_url } + if ((p as any).type === "input_image" && (p as any).image_url) + return { type: "image_url", image_url: (p as any).image_url } + const s = (p as any).source + if (!s || typeof s !== "object") return undefined + if ((s as any).type === "url" && typeof (s as any).url === "string") + return { type: "image_url", image_url: { url: (s as any).url } } + if ( + (s as any).type === "base64" && + typeof (s as any).media_type === "string" && + typeof (s as any).data === "string" + ) + return { type: "image_url", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } } + return undefined + } + + const msgs: any[] = [] + + const inMsgs = Array.isArray(body.input) ? body.input : Array.isArray(body.messages) ? body.messages : [] + + for (const m of inMsgs) { + if (!m) continue + + // Responses API items without role: + if (!(m as any).role && (m as any).type) { + if ((m as any).type === "function_call") { + const name = (m as any).name + const a = (m as any).arguments + const args = typeof a === "string" ? a : JSON.stringify(a ?? {}) + msgs.push({ + role: "assistant", + tool_calls: [{ id: (m as any).id, type: "function", function: { name, arguments: args } }], + }) + } + if ((m as any).type === "function_call_output") { + const id = (m as any).call_id + const out = (m as any).output + const content = typeof out === "string" ? out : JSON.stringify(out) + msgs.push({ role: "tool", tool_call_id: id, content }) + } + continue + } + + if ((m as any).role === "system" || (m as any).role === "developer") { + const c = (m as any).content + if (typeof c === "string" && c.length > 0) msgs.push({ role: "system", content: c }) + if (Array.isArray(c)) { + const t = c.find((p: any) => p && typeof p.text === "string") + if (t && typeof t.text === "string" && t.text.length > 0) msgs.push({ role: "system", content: t.text }) + } + continue + } + + if ((m as any).role === "user") { + const c = (m as any).content + if (typeof c === "string") { + msgs.push({ role: "user", content: c }) + } else if (Array.isArray(c)) { + const parts: any[] = [] + for (const p of c) { + if (!p || !(p as any).type) continue + if (((p as any).type === "text" || (p as any).type === "input_text") && typeof (p as any).text === "string") + parts.push({ type: "text", text: (p as any).text }) + const ip = toImg(p) + if (ip) parts.push(ip) + if ((p as any).type === "tool_result") { + const id = (p as any).tool_call_id + const content = + typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content) + msgs.push({ role: "tool", tool_call_id: id, content }) + } + } + if (parts.length === 1 && parts[0].type === "text") msgs.push({ role: "user", content: parts[0].text }) + else if (parts.length > 0) msgs.push({ role: "user", content: parts }) + } + continue + } + + if ((m as any).role === "assistant") { + const c = (m as any).content + const out: any = { role: "assistant" } + if (typeof c === "string" && c.length > 0) out.content = c + if (Array.isArray((m as any).tool_calls)) out.tool_calls = (m as any).tool_calls + msgs.push(out) + continue + } + + if ((m as any).role === "tool") { + msgs.push({ role: "tool", tool_call_id: (m as any).tool_call_id, content: (m as any).content }) + continue + } + } + + const tcIn = body.tool_choice + const tc = (() => { + if (!tcIn) return undefined + if (tcIn === "auto") return "auto" + if (tcIn === "required") return "required" + if ((tcIn as any).type === "function" && (tcIn as any).function?.name) + return { type: "function" as const, function: { name: (tcIn as any).function.name } } + return undefined + })() + + const stop = (() => { + const v = body.stop_sequences ?? body.stop + if (!v) return undefined + if (Array.isArray(v)) return v.length === 1 ? v[0] : v + if (typeof v === "string") return v + return undefined + })() + + return { + max_tokens: body.max_output_tokens ?? body.max_tokens, + temperature: body.temperature, + top_p: body.top_p, + stop, + messages: msgs, + stream: !!body.stream, + tools: Array.isArray(body.tools) ? body.tools : undefined, + tool_choice: tc, + } +} + +export function toOpenaiRequest(body: CommonRequest) { + if (!body || typeof body !== "object") return body + + const msgsIn = Array.isArray(body.messages) ? body.messages : [] + const input: any[] = [] + + const toPart = (p: any) => { + if (!p || typeof p !== "object") return undefined + if ((p as any).type === "text" && typeof (p as any).text === "string") + return { type: "input_text", text: (p as any).text } + if ((p as any).type === "image_url" && (p as any).image_url) + return { type: "input_image", image_url: (p as any).image_url } + const s = (p as any).source + if (!s || typeof s !== "object") return undefined + if ((s as any).type === "url" && typeof (s as any).url === "string") + return { type: "input_image", image_url: { url: (s as any).url } } + if ( + (s as any).type === "base64" && + typeof (s as any).media_type === "string" && + typeof (s as any).data === "string" + ) + return { type: "input_image", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } } + return undefined + } + + for (const m of msgsIn) { + if (!m || !(m as any).role) continue + + if ((m as any).role === "system") { + const c = (m as any).content + if (typeof c === "string") input.push({ role: "system", content: c }) + continue + } + + if ((m as any).role === "user") { + const c = (m as any).content + if (typeof c === "string") { + input.push({ role: "user", content: [{ type: "input_text", text: c }] }) + } else if (Array.isArray(c)) { + const parts: any[] = [] + for (const p of c) { + const op = toPart(p) + if (op) parts.push(op) + } + if (parts.length > 0) input.push({ role: "user", content: parts }) + } + continue + } + + if ((m as any).role === "assistant") { + const c = (m as any).content + if (typeof c === "string" && c.length > 0) { + input.push({ role: "assistant", content: [{ type: "output_text", text: c }] }) + } + if (Array.isArray((m as any).tool_calls)) { + for (const tc of (m as any).tool_calls) { + if ((tc as any).type === "function" && (tc as any).function) { + const name = (tc as any).function.name + const a = (tc as any).function.arguments + const args = typeof a === "string" ? a : JSON.stringify(a) + input.push({ type: "function_call", call_id: (tc as any).id, name, arguments: args }) + } + } + } + continue + } + + if ((m as any).role === "tool") { + const out = typeof (m as any).content === "string" ? (m as any).content : JSON.stringify((m as any).content) + input.push({ type: "function_call_output", call_id: (m as any).tool_call_id, output: out }) + continue + } + } + + const stop_sequences = (() => { + const v = body.stop + if (!v) return undefined + if (Array.isArray(v)) return v + if (typeof v === "string") return [v] + return undefined + })() + + const tcIn = body.tool_choice + const tool_choice = (() => { + if (!tcIn) return undefined + if (tcIn === "auto") return "auto" + if (tcIn === "required") return "required" + if ((tcIn as any).type === "function" && (tcIn as any).function?.name) + return { type: "function", function: { name: (tcIn as any).function.name } } + return undefined + })() + + const tools = (() => { + if (!Array.isArray(body.tools)) return undefined + return body.tools.map((tool: any) => { + if (tool.type === "function") { + return { + type: "function", + name: tool.function?.name, + description: tool.function?.description, + parameters: tool.function?.parameters, + strict: tool.function?.strict, + } + } + return tool + }) + })() + + return { + model: body.model, + input, + max_output_tokens: body.max_tokens, + top_p: body.top_p, + stop_sequences, + stream: !!body.stream, + tools, + tool_choice, + include: Array.isArray((body as any).include) ? (body as any).include : undefined, + truncation: (body as any).truncation, + metadata: (body as any).metadata, + store: (body as any).store, + user: (body as any).user, + text: { verbosity: "low" }, + reasoning: { effort: "medium" }, + } +} + +export function fromOpenaiResponse(resp: any): CommonResponse { + if (!resp || typeof resp !== "object") return resp + if (Array.isArray((resp as any).choices)) return resp + + const r = (resp as any).response ?? resp + if (!r || typeof r !== "object") return resp + + const idIn = (r as any).id + const id = + typeof idIn === "string" ? idIn.replace(/^resp_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` + const model = (r as any).model ?? (resp as any).model + + const out = Array.isArray((r as any).output) ? (r as any).output : [] + const text = out + .filter((o: any) => o && o.type === "message" && Array.isArray((o as any).content)) + .flatMap((o: any) => (o as any).content) + .filter((p: any) => p && p.type === "output_text" && typeof p.text === "string") + .map((p: any) => p.text) + .join("") + + const tcs = out + .filter((o: any) => o && o.type === "function_call") + .map((o: any) => { + const name = (o as any).name + const a = (o as any).arguments + const args = typeof a === "string" ? a : JSON.stringify(a ?? {}) + const tid = + typeof (o as any).id === "string" && (o as any).id.length > 0 + ? (o as any).id + : `toolu_${Math.random().toString(36).slice(2)}` + return { id: tid, type: "function" as const, function: { name, arguments: args } } + }) + + const finish = (r: string | null) => { + if (r === "stop") return "stop" + if (r === "tool_call" || r === "tool_calls") return "tool_calls" + if (r === "length" || r === "max_output_tokens") return "length" + if (r === "content_filter") return "content_filter" + return null + } + + const u = (r as any).usage ?? (resp as any).usage + const usage = (() => { + if (!u) return undefined as any + const pt = typeof (u as any).input_tokens === "number" ? (u as any).input_tokens : undefined + const ct = typeof (u as any).output_tokens === "number" ? (u as any).output_tokens : undefined + const total = pt != null && ct != null ? pt + ct : undefined + const cached = (u as any).input_tokens_details?.cached_tokens + const details = typeof cached === "number" ? { cached_tokens: cached } : undefined + return { + prompt_tokens: pt, + completion_tokens: ct, + total_tokens: total, + ...(details ? { prompt_tokens_details: details } : {}), + } + })() + + return { + id, + object: "chat.completion", + created: Math.floor(Date.now() / 1000), + model, + choices: [ + { + index: 0, + message: { + role: "assistant", + ...(text && text.length > 0 ? { content: text } : {}), + ...(tcs.length > 0 ? { tool_calls: tcs } : {}), + }, + finish_reason: finish((r as any).stop_reason ?? null), + }, + ], + ...(usage ? { usage } : {}), + } +} + +export function toOpenaiResponse(resp: CommonResponse) { + if (!resp || typeof resp !== "object") return resp + if (!Array.isArray((resp as any).choices)) return resp + + const choice = (resp as any).choices[0] + if (!choice) return resp + + const msg = choice.message + if (!msg) return resp + + const outputItems: any[] = [] + + if (typeof msg.content === "string" && msg.content.length > 0) { + outputItems.push({ + id: `msg_${Math.random().toString(36).slice(2)}`, + type: "message", + status: "completed", + role: "assistant", + content: [{ type: "output_text", text: msg.content, annotations: [], logprobs: [] }], + }) + } + + if (Array.isArray(msg.tool_calls)) { + for (const tc of msg.tool_calls) { + if ((tc as any).type === "function" && (tc as any).function) { + outputItems.push({ + id: (tc as any).id, + type: "function_call", + name: (tc as any).function.name, + call_id: (tc as any).id, + arguments: (tc as any).function.arguments, + }) + } + } + } + + const stop_reason = (() => { + const r = choice.finish_reason + if (r === "stop") return "stop" + if (r === "tool_calls") return "tool_call" + if (r === "length") return "max_output_tokens" + if (r === "content_filter") return "content_filter" + return null + })() + + const usage = (() => { + const u = (resp as any).usage + if (!u) return undefined + return { + input_tokens: u.prompt_tokens, + output_tokens: u.completion_tokens, + total_tokens: u.total_tokens, + ...(u.prompt_tokens_details?.cached_tokens + ? { input_tokens_details: { cached_tokens: u.prompt_tokens_details.cached_tokens } } + : {}), + } + })() + + return { + id: (resp as any).id?.replace(/^chatcmpl_/, "resp_") ?? `resp_${Math.random().toString(36).slice(2)}`, + object: "response", + model: (resp as any).model, + output: outputItems, + stop_reason, + usage, + } +} + +export function fromOpenaiChunk(chunk: string): CommonChunk | string { + const lines = chunk.split("\n") + const ev = lines[0] + const dl = lines[1] + if (!ev || !dl || !dl.startsWith("data: ")) return chunk + + let json: any + try { + json = JSON.parse(dl.slice(6)) + } catch { + return chunk + } + + const respObj = json.response ?? {} + + const out: CommonChunk = { + id: respObj.id ?? json.id ?? "", + object: "chat.completion.chunk", + created: Math.floor(Date.now() / 1000), + model: respObj.model ?? json.model ?? "", + choices: [], + } + + const e = ev.replace("event: ", "").trim() + + if (e === "response.output_text.delta") { + const d = (json as any).delta ?? (json as any).text ?? (json as any).output_text_delta + if (typeof d === "string" && d.length > 0) + out.choices.push({ index: 0, delta: { content: d }, finish_reason: null }) + } + + if (e === "response.output_item.added" && (json as any).item?.type === "function_call") { + const name = (json as any).item?.name + const id = (json as any).item?.id + if (typeof name === "string" && name.length > 0) { + out.choices.push({ + index: 0, + delta: { tool_calls: [{ index: 0, id, type: "function", function: { name, arguments: "" } }] }, + finish_reason: null, + }) + } + } + + if (e === "response.function_call_arguments.delta") { + const a = (json as any).delta ?? (json as any).arguments_delta + if (typeof a === "string" && a.length > 0) { + out.choices.push({ + index: 0, + delta: { tool_calls: [{ index: 0, function: { arguments: a } }] }, + finish_reason: null, + }) + } + } + + if (e === "response.completed") { + const fr = (() => { + const sr = (respObj as any).stop_reason ?? (json as any).stop_reason + if (sr === "stop") return "stop" + if (sr === "tool_call" || sr === "tool_calls") return "tool_calls" + if (sr === "length" || sr === "max_output_tokens") return "length" + if (sr === "content_filter") return "content_filter" + return null + })() + out.choices.push({ index: 0, delta: {}, finish_reason: fr }) + + const u = (respObj as any).usage ?? (json as any).response?.usage + if (u) { + out.usage = { + prompt_tokens: u.input_tokens, + completion_tokens: u.output_tokens, + total_tokens: (u.input_tokens || 0) + (u.output_tokens || 0), + ...(u.input_tokens_details?.cached_tokens + ? { prompt_tokens_details: { cached_tokens: u.input_tokens_details.cached_tokens } } + : {}), + } + } + } + + return out +} + +export function toOpenaiChunk(chunk: CommonChunk): string { + if (!chunk.choices || !Array.isArray(chunk.choices) || chunk.choices.length === 0) { + return "" + } + + const choice = chunk.choices[0] + const d = choice.delta + if (!d) return "" + + const id = chunk.id + const model = chunk.model + + if (d.content) { + const data = { id, type: "response.output_text.delta", delta: d.content, response: { id, model } } + return `event: response.output_text.delta\ndata: ${JSON.stringify(data)}` + } + + if (d.tool_calls) { + for (const tc of d.tool_calls) { + if (tc.function?.name) { + const data = { + type: "response.output_item.added", + output_index: 0, + item: { id: tc.id, type: "function_call", name: tc.function.name, call_id: tc.id, arguments: "" }, + } + return `event: response.output_item.added\ndata: ${JSON.stringify(data)}` + } + if (tc.function?.arguments) { + const data = { + type: "response.function_call_arguments.delta", + output_index: 0, + delta: tc.function.arguments, + } + return `event: response.function_call_arguments.delta\ndata: ${JSON.stringify(data)}` + } + } + } + + if (choice.finish_reason) { + const u = chunk.usage + const usage = u + ? { + input_tokens: u.prompt_tokens, + output_tokens: u.completion_tokens, + total_tokens: u.total_tokens, + ...(u.prompt_tokens_details?.cached_tokens + ? { input_tokens_details: { cached_tokens: u.prompt_tokens_details.cached_tokens } } + : {}), + } + : undefined + + const data: any = { id, type: "response.completed", response: { id, model, ...(usage ? { usage } : {}) } } + return `event: response.completed\ndata: ${JSON.stringify(data)}` + } + + return "" +} diff --git a/packages/console/app/src/routes/zen/util/provider/provider.ts b/packages/console/app/src/routes/zen/util/provider/provider.ts new file mode 100644 index 0000000000..5beb460e9a --- /dev/null +++ b/packages/console/app/src/routes/zen/util/provider/provider.ts @@ -0,0 +1,207 @@ +import { Format } from "../format" + +import { + fromAnthropicChunk, + fromAnthropicRequest, + fromAnthropicResponse, + toAnthropicChunk, + toAnthropicRequest, + toAnthropicResponse, +} from "./anthropic" +import { + fromOpenaiChunk, + fromOpenaiRequest, + fromOpenaiResponse, + toOpenaiChunk, + toOpenaiRequest, + toOpenaiResponse, +} from "./openai" +import { + fromOaCompatibleChunk, + fromOaCompatibleRequest, + fromOaCompatibleResponse, + toOaCompatibleChunk, + toOaCompatibleRequest, + toOaCompatibleResponse, +} from "./openai-compatible" + +export type ProviderHelper = { + format: Format + modifyUrl: (providerApi: string) => string + modifyHeaders: (headers: Headers, apiKey: string) => void + modifyBody: (body: Record) => Record + createUsageParser: () => { + parse: (chunk: string) => void + retrieve: () => any + } + normalizeUsage: (usage: any) => { + inputTokens: number + outputTokens: number + reasoningTokens?: number + cacheReadTokens?: number + cacheWrite5mTokens?: number + cacheWrite1hTokens?: number + } +} + +export interface CommonMessage { + role: "system" | "user" | "assistant" | "tool" + content?: string | Array + tool_call_id?: string + tool_calls?: CommonToolCall[] +} + +export interface CommonContentPart { + type: "text" | "image_url" + text?: string + image_url?: { url: string } +} + +export interface CommonToolCall { + id: string + type: "function" + function: { + name: string + arguments: string + } +} + +export interface CommonTool { + type: "function" + function: { + name: string + description?: string + parameters?: Record + } +} + +export interface CommonUsage { + input_tokens?: number + output_tokens?: number + total_tokens?: number + prompt_tokens?: number + completion_tokens?: number + cache_read_input_tokens?: number + cache_creation?: { + ephemeral_5m_input_tokens?: number + ephemeral_1h_input_tokens?: number + } + input_tokens_details?: { + cached_tokens?: number + } + output_tokens_details?: { + reasoning_tokens?: number + } +} + +export interface CommonRequest { + model?: string + max_tokens?: number + temperature?: number + top_p?: number + stop?: string | string[] + messages: CommonMessage[] + stream?: boolean + tools?: CommonTool[] + tool_choice?: "auto" | "required" | { type: "function"; function: { name: string } } +} + +export interface CommonResponse { + id: string + object: "chat.completion" + created: number + model: string + choices: Array<{ + index: number + message: { + role: "assistant" + content?: string + tool_calls?: CommonToolCall[] + } + finish_reason: "stop" | "tool_calls" | "length" | "content_filter" | null + }> + usage?: { + prompt_tokens?: number + completion_tokens?: number + total_tokens?: number + prompt_tokens_details?: { cached_tokens?: number } + } +} + +export interface CommonChunk { + id: string + object: "chat.completion.chunk" + created: number + model: string + choices: Array<{ + index: number + delta: { + role?: "assistant" + content?: string + tool_calls?: Array<{ + index: number + id?: string + type?: "function" + function?: { + name?: string + arguments?: string + } + }> + } + finish_reason: "stop" | "tool_calls" | "length" | "content_filter" | null + }> + usage?: { + prompt_tokens?: number + completion_tokens?: number + total_tokens?: number + prompt_tokens_details?: { cached_tokens?: number } + } +} + +export function createBodyConverter(from: Format, to: Format) { + return (body: any): any => { + if (from === to) return body + + let raw: CommonRequest + if (from === "anthropic") raw = fromAnthropicRequest(body) + else if (from === "openai") raw = fromOpenaiRequest(body) + else raw = fromOaCompatibleRequest(body) + + if (to === "anthropic") return toAnthropicRequest(raw) + if (to === "openai") return toOpenaiRequest(raw) + if (to === "oa-compat") return toOaCompatibleRequest(raw) + } +} + +export function createStreamPartConverter(from: Format, to: Format) { + return (part: any): any => { + if (from === to) return part + + let raw: CommonChunk | string + if (from === "anthropic") raw = fromAnthropicChunk(part) + else if (from === "openai") raw = fromOpenaiChunk(part) + else raw = fromOaCompatibleChunk(part) + + // If result is a string (error case), pass it through + if (typeof raw === "string") return raw + + if (to === "anthropic") return toAnthropicChunk(raw) + if (to === "openai") return toOpenaiChunk(raw) + if (to === "oa-compat") return toOaCompatibleChunk(raw) + } +} + +export function createResponseConverter(from: Format, to: Format) { + return (response: any): any => { + if (from === to) return response + + let raw: CommonResponse + if (from === "anthropic") raw = fromAnthropicResponse(response) + else if (from === "openai") raw = fromOpenaiResponse(response) + else raw = fromOaCompatibleResponse(response) + + if (to === "anthropic") return toAnthropicResponse(raw) + if (to === "openai") return toOpenaiResponse(raw) + if (to === "oa-compat") return toOaCompatibleResponse(raw) + } +} diff --git a/packages/console/app/src/routes/zen/v1/chat/completions.ts b/packages/console/app/src/routes/zen/v1/chat/completions.ts index 33c16247e1..44326e79eb 100644 --- a/packages/console/app/src/routes/zen/v1/chat/completions.ts +++ b/packages/console/app/src/routes/zen/v1/chat/completions.ts @@ -1,63 +1,9 @@ import type { APIEvent } from "@solidjs/start/server" -import { handler } from "~/routes/zen/handler" - -type Usage = { - prompt_tokens?: number - completion_tokens?: number - total_tokens?: number - // used by moonshot - cached_tokens?: number - // used by xai - prompt_tokens_details?: { - text_tokens?: number - audio_tokens?: number - image_tokens?: number - cached_tokens?: number - } - completion_tokens_details?: { - reasoning_tokens?: number - audio_tokens?: number - accepted_prediction_tokens?: number - rejected_prediction_tokens?: number - } -} +import { handler } from "~/routes/zen/util/handler" export function POST(input: APIEvent) { - let usage: Usage return handler(input, { - modifyBody: (body: any) => ({ - ...body, - ...(body.stream ? { stream_options: { include_usage: true } } : {}), - }), - setAuthHeader: (headers: Headers, apiKey: string) => { - headers.set("authorization", `Bearer ${apiKey}`) - }, + format: "oa-compat", parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1], - onStreamPart: (chunk: string) => { - if (!chunk.startsWith("data: ")) return - - let json - try { - json = JSON.parse(chunk.slice(6)) as { usage?: Usage } - } catch (e) { - return - } - - if (!json.usage) return - usage = json.usage - }, - getStreamUsage: () => usage, - normalizeUsage: (usage: Usage) => { - const inputTokens = usage.prompt_tokens ?? 0 - const outputTokens = usage.completion_tokens ?? 0 - const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? undefined - const cacheReadTokens = usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined - return { - inputTokens: inputTokens - (cacheReadTokens ?? 0), - outputTokens: outputTokens - (reasoningTokens ?? 0), - reasoningTokens, - cacheReadTokens, - } - }, }) } diff --git a/packages/console/app/src/routes/zen/v1/messages.ts b/packages/console/app/src/routes/zen/v1/messages.ts index 4a7dda5f70..4478b64447 100644 --- a/packages/console/app/src/routes/zen/v1/messages.ts +++ b/packages/console/app/src/routes/zen/v1/messages.ts @@ -1,64 +1,9 @@ import type { APIEvent } from "@solidjs/start/server" -import { handler } from "~/routes/zen/handler" - -type Usage = { - cache_creation?: { - ephemeral_5m_input_tokens?: number - ephemeral_1h_input_tokens?: number - } - cache_creation_input_tokens?: number - cache_read_input_tokens?: number - input_tokens?: number - output_tokens?: number - server_tool_use?: { - web_search_requests?: number - } -} +import { handler } from "~/routes/zen/util/handler" export function POST(input: APIEvent) { - let usage: Usage return handler(input, { - modifyBody: (body: any) => ({ - ...body, - service_tier: "standard_only", - }), - setAuthHeader: (headers: Headers, apiKey: string) => headers.set("x-api-key", apiKey), + format: "anthropic", parseApiKey: (headers: Headers) => headers.get("x-api-key") ?? undefined, - onStreamPart: (chunk: string) => { - const data = chunk.split("\n")[1] - if (!data.startsWith("data: ")) return - - let json - try { - json = JSON.parse(data.slice(6)) - } catch (e) { - return - } - - // ie. { type: "message_start"; message: { usage: Usage } } - // ie. { type: "message_delta"; usage: Usage } - const usageUpdate = json.usage ?? json.message?.usage - if (!usageUpdate) return - usage = { - ...usage, - ...usageUpdate, - cache_creation: { - ...usage?.cache_creation, - ...usageUpdate.cache_creation, - }, - server_tool_use: { - ...usage?.server_tool_use, - ...usageUpdate.server_tool_use, - }, - } - }, - getStreamUsage: () => usage, - normalizeUsage: (usage: Usage) => ({ - inputTokens: usage.input_tokens ?? 0, - outputTokens: usage.output_tokens ?? 0, - cacheReadTokens: usage.cache_read_input_tokens ?? undefined, - cacheWrite5mTokens: usage.cache_creation?.ephemeral_5m_input_tokens ?? undefined, - cacheWrite1hTokens: usage.cache_creation?.ephemeral_1h_input_tokens ?? undefined, - }), }) } diff --git a/packages/console/app/src/routes/zen/v1/models.ts b/packages/console/app/src/routes/zen/v1/models.ts new file mode 100644 index 0000000000..ad5769bb6b --- /dev/null +++ b/packages/console/app/src/routes/zen/v1/models.ts @@ -0,0 +1,60 @@ +import type { APIEvent } from "@solidjs/start/server" +import { and, Database, eq, isNull } from "@opencode-ai/console-core/drizzle/index.js" +import { KeyTable } from "@opencode-ai/console-core/schema/key.sql.js" +import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js" +import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js" +import { ZenData } from "@opencode-ai/console-core/model.js" + +export async function OPTIONS(input: APIEvent) { + return new Response(null, { + status: 200, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, Authorization", + }, + }) +} + +export async function GET(input: APIEvent) { + const zenData = ZenData.list() + const disabledModels = await authenticate() + + return new Response( + JSON.stringify({ + object: "list", + data: Object.entries(zenData.models) + .filter(([id]) => !disabledModels.includes(id)) + .map(([id, model]) => ({ + id: `opencode/${id}`, + object: "model", + created: Math.floor(Date.now() / 1000), + owned_by: "opencode", + })), + }), + { + headers: { + "Content-Type": "application/json", + }, + }, + ) + + async function authenticate() { + const apiKey = input.request.headers.get("authorization")?.split(" ")[1] + if (!apiKey) return [] + + const disabledModels = await Database.use((tx) => + tx + .select({ + model: ModelTable.model, + }) + .from(KeyTable) + .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) + .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted))) + .where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted))) + .then((rows) => rows.map((row) => row.model)), + ) + + return disabledModels + } +} diff --git a/packages/console/app/src/routes/zen/v1/responses.ts b/packages/console/app/src/routes/zen/v1/responses.ts index 486c129b90..eadc5bc8ea 100644 --- a/packages/console/app/src/routes/zen/v1/responses.ts +++ b/packages/console/app/src/routes/zen/v1/responses.ts @@ -1,52 +1,9 @@ import type { APIEvent } from "@solidjs/start/server" -import { handler } from "~/routes/zen/handler" - -type Usage = { - input_tokens?: number - input_tokens_details?: { - cached_tokens?: number - } - output_tokens?: number - output_tokens_details?: { - reasoning_tokens?: number - } - total_tokens?: number -} +import { handler } from "~/routes/zen/util/handler" export function POST(input: APIEvent) { - let usage: Usage return handler(input, { - setAuthHeader: (headers: Headers, apiKey: string) => { - headers.set("authorization", `Bearer ${apiKey}`) - }, + format: "openai", parseApiKey: (headers: Headers) => headers.get("authorization")?.split(" ")[1], - onStreamPart: (chunk: string) => { - const [event, data] = chunk.split("\n") - if (event !== "event: response.completed") return - if (!data.startsWith("data: ")) return - - let json - try { - json = JSON.parse(data.slice(6)) as { response?: { usage?: Usage } } - } catch (e) { - return - } - - if (!json.response?.usage) return - usage = json.response.usage - }, - getStreamUsage: () => usage, - normalizeUsage: (usage: Usage) => { - const inputTokens = usage.input_tokens ?? 0 - const outputTokens = usage.output_tokens ?? 0 - const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? undefined - const cacheReadTokens = usage.input_tokens_details?.cached_tokens ?? undefined - return { - inputTokens: inputTokens - (cacheReadTokens ?? 0), - outputTokens: outputTokens - (reasoningTokens ?? 0), - reasoningTokens, - cacheReadTokens, - } - }, }) } From 78169017136048fc65fb6cb9d13095a0c6c50af3 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 27 Oct 2025 21:25:56 -0400 Subject: [PATCH 021/609] wip: zen doc --- packages/web/src/content/docs/zen.mdx | 32 +++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index ab48c2c142..a53ad31315 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -71,9 +71,10 @@ You can also access our models through the following API endpoints. | Claude Haiku 4.5 | claude-haiku-4-5 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Haiku 3.5 | claude-3-5-haiku | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | | Claude Opus 4.1 | claude-opus-4-1 | `https://opencode.ai/zen/v1/messages` | `@ai-sdk/anthropic` | +| GLM 4.6 | glm-4.6 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | +| Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Qwen3 Coder 480B | qwen3-coder | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | | Grok Code Fast 1 | grok-code | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | -| Kimi K2 | kimi-k2 | `https://opencode.ai/zen/v1/chat/completions` | `@ai-sdk/openai-compatible` | The [model id](/docs/config/#models) in your OpenCode config uses the format `opencode/`. For example, for GPT 5 Codex, you would @@ -81,14 +82,41 @@ use `opencode/gpt-5-codex` in your config. --- +### Unified + +All models in Zen can also be accessed through a single unified endpoint: + +``` +https://opencode.ai/zen/v1/chat/completions +``` + +This endpoint is OpenAI-compatible, so it works seamlessly with the `@ai-sdk/openai-compatible` package and any OpenAI-compatible SDKs or tools. + +Use this if you want to simplify integration across multiple models without changing endpoints or SDKs. + +This feature is currently in beta. + +--- + +### Models + +You can fetch the full list of available models and their metadata from: + +``` +https://opencode.ai/zen/v1/models +``` + +--- + ## Pricing We support a pay-as-you-go model. Below are the prices **per 1M tokens**. | Model | Input | Output | Cached Read | Cached Write | | --------------------------------- | ------ | ------ | ----------- | ------------ | -| Qwen3 Coder 480B | $0.45 | $1.50 | - | - | +| GLM 4.6 | $0.60 | $1.90 | $0.11 | - | | Kimi K2 | $0.60 | $2.50 | $0.36 | - | +| Qwen3 Coder 480B | $0.45 | $1.50 | - | - | | Grok Code Fast 1 | Free | Free | - | - | | Code Supernova | Free | Free | - | - | | Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 | From 6fe8e3973cdcb623a39df0760a68cb49705789a0 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 27 Oct 2025 21:36:10 -0400 Subject: [PATCH 022/609] zen: support 1M claude context --- packages/console/app/src/routes/zen/util/handler.ts | 2 +- .../console/app/src/routes/zen/util/provider/anthropic.ts | 5 ++++- .../app/src/routes/zen/util/provider/openai-compatible.ts | 2 +- packages/console/app/src/routes/zen/util/provider/openai.ts | 2 +- .../console/app/src/routes/zen/util/provider/provider.ts | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 7fbb518a08..85ba5eea1e 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -67,7 +67,7 @@ export async function handler( const headers = input.request.headers headers.delete("host") headers.delete("content-length") - providerInfo.modifyHeaders(headers, providerInfo.apiKey) + providerInfo.modifyHeaders(headers, body, providerInfo.apiKey) Object.entries(providerInfo.headerMappings ?? {}).forEach(([k, v]) => { headers.set(k, headers.get(v)!) }) diff --git a/packages/console/app/src/routes/zen/util/provider/anthropic.ts b/packages/console/app/src/routes/zen/util/provider/anthropic.ts index 64b040a533..807f427afa 100644 --- a/packages/console/app/src/routes/zen/util/provider/anthropic.ts +++ b/packages/console/app/src/routes/zen/util/provider/anthropic.ts @@ -17,9 +17,12 @@ type Usage = { export const anthropicHelper = { format: "anthropic", modifyUrl: (providerApi: string) => providerApi + "/messages", - modifyHeaders: (headers: Headers, apiKey: string) => { + modifyHeaders: (headers: Headers, body: Record, apiKey: string) => { headers.set("x-api-key", apiKey) headers.set("anthropic-version", headers.get("anthropic-version") ?? "2023-06-01") + if (body.model.startsWith("claude-sonnet-")) { + headers.set("anthropic-beta", "context-1m-2025-08-07") + } }, modifyBody: (body: Record) => { return { diff --git a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts index aae6bed57e..cad6bd6862 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts @@ -24,7 +24,7 @@ type Usage = { export const oaCompatHelper = { format: "oa-compat", modifyUrl: (providerApi: string) => providerApi + "/chat/completions", - modifyHeaders: (headers: Headers, apiKey: string) => { + modifyHeaders: (headers: Headers, body: Record, apiKey: string) => { headers.set("authorization", `Bearer ${apiKey}`) }, modifyBody: (body: Record) => { diff --git a/packages/console/app/src/routes/zen/util/provider/openai.ts b/packages/console/app/src/routes/zen/util/provider/openai.ts index 9781d821de..21c15f3559 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai.ts @@ -15,7 +15,7 @@ type Usage = { export const openaiHelper = { format: "openai", modifyUrl: (providerApi: string) => providerApi + "/responses", - modifyHeaders: (headers: Headers, apiKey: string) => { + modifyHeaders: (headers: Headers, body: Record, apiKey: string) => { headers.set("authorization", `Bearer ${apiKey}`) }, modifyBody: (body: Record) => { diff --git a/packages/console/app/src/routes/zen/util/provider/provider.ts b/packages/console/app/src/routes/zen/util/provider/provider.ts index 5beb460e9a..c8ba644bac 100644 --- a/packages/console/app/src/routes/zen/util/provider/provider.ts +++ b/packages/console/app/src/routes/zen/util/provider/provider.ts @@ -28,7 +28,7 @@ import { export type ProviderHelper = { format: Format modifyUrl: (providerApi: string) => string - modifyHeaders: (headers: Headers, apiKey: string) => void + modifyHeaders: (headers: Headers, body: Record, apiKey: string) => void modifyBody: (body: Record) => Record createUsageParser: () => { parse: (chunk: string) => void From 4caa458232797564622d96a641438a9a9ec48b82 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 27 Oct 2025 21:40:08 -0400 Subject: [PATCH 023/609] acp: fix type error --- packages/opencode/src/cli/cmd/acp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/acp.ts b/packages/opencode/src/cli/cmd/acp.ts index 6628137f43..4f119d0124 100644 --- a/packages/opencode/src/cli/cmd/acp.ts +++ b/packages/opencode/src/cli/cmd/acp.ts @@ -29,7 +29,7 @@ export const AcpCommand = cmd({ const input = new WritableStream({ write(chunk) { return new Promise((resolve, reject) => { - process.stdout.write(Buffer.from(chunk), (err) => { + process.stdout.write(chunk, (err) => { if (err) { reject(err) } else { From 982954cc1b4b471be019ca012c18f9451c2fcfd8 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 28 Oct 2025 00:08:30 -0500 Subject: [PATCH 024/609] feat (acp): mcp server support, file diffs, some default slash commands (/init, /compact), show todos properly (#3490) The mcp server support does not mean acp didn't allow u to use mcp servers previously, it means that now you can connect new servers via ACP instead of relying on the opencode defined ones --- packages/opencode/src/acp/agent.ts | 238 ++++++++++++++----- packages/opencode/src/mcp/index.ts | 245 +++++++++++--------- packages/opencode/src/session/compaction.ts | 6 +- 3 files changed, 319 insertions(+), 170 deletions(-) diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 03bc4d5dd6..0fa2509d64 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -1,16 +1,20 @@ -import type { - Agent as ACPAgent, - AgentSideConnection, - AuthenticateRequest, - CancelNotification, - InitializeRequest, - LoadSessionRequest, - NewSessionRequest, - PermissionOption, - PromptRequest, - SetSessionModelRequest, - SetSessionModeRequest, - SetSessionModeResponse, +import { + sessionModeSchema, + type Agent as ACPAgent, + type AgentSideConnection, + type AuthenticateRequest, + type CancelNotification, + type InitializeRequest, + type LoadSessionRequest, + type NewSessionRequest, + type PermissionOption, + type PlanEntry, + type PromptRequest, + type SetSessionModelRequest, + type SetSessionModeRequest, + type SetSessionModeResponse, + type ToolCallContent, + type ToolKind, } from "@agentclientprotocol/sdk" import { Log } from "../util/log" import { ACPSessionManager } from "./session" @@ -25,24 +29,17 @@ import { Storage } from "@/storage/storage" import { Command } from "@/command" import { Agent as Agents } from "@/agent/agent" import { Permission } from "@/permission" +import { Session } from "@/session" +import { Identifier } from "@/id/id" +import { SessionCompaction } from "@/session/compaction" +import type { Config } from "@/config/config" +import { MCP } from "@/mcp" +import { Todo } from "@/session/todo" +import { z } from "zod" export namespace ACP { const log = Log.create({ service: "acp-agent" }) - // TODO: mcp servers? - - type ToolKind = - | "read" - | "edit" - | "delete" - | "move" - | "search" - | "execute" - | "think" - | "fetch" - | "switch_mode" - | "other" - export class Agent implements ACPAgent { private sessionManager = new ACPSessionManager() private connection: AgentSideConnection @@ -157,6 +154,62 @@ export namespace ACP { }) break case "completed": + const kind = toToolKind(part.tool) + const content: ToolCallContent[] = [ + { + type: "content", + content: { + type: "text", + text: part.state.output, + }, + }, + ] + + if (kind === "edit") { + const input = part.state.input + const filePath = typeof input["filePath"] === "string" ? input["filePath"] : "" + const oldText = typeof input["oldString"] === "string" ? input["oldString"] : "" + const newText = + typeof input["newString"] === "string" + ? input["newString"] + : typeof input["content"] === "string" + ? input["content"] + : "" + content.push({ + type: "diff", + path: filePath, + oldText, + newText, + }) + } + + if (part.tool === "todowrite") { + const parsedTodos = z.array(Todo.Info).safeParse(JSON.parse(part.state.output)) + if (parsedTodos.success) { + await this.connection + .sessionUpdate({ + sessionId: acpSession.id, + update: { + sessionUpdate: "plan", + entries: parsedTodos.data.map((todo) => { + const status: PlanEntry["status"] = + todo.status === "cancelled" ? "completed" : (todo.status as PlanEntry["status"]) + return { + priority: "medium", + status, + content: todo.content, + } + }), + }, + }) + .catch((err) => { + log.error("failed to send session update for todo", { error: err }) + }) + } else { + log.error("failed to parse todo output", { error: parsedTodos.error }) + } + } + await this.connection .sessionUpdate({ sessionId: acpSession.id, @@ -164,15 +217,8 @@ export namespace ACP { sessionUpdate: "tool_call_update", toolCallId: part.callID, status: "completed", - content: [ - { - type: "content", - content: { - type: "text", - text: part.state.output, - }, - }, - ], + kind, + content, title: part.state.title, rawOutput: { output: part.state.output, @@ -258,11 +304,14 @@ export namespace ACP { protocolVersion: 1, agentCapabilities: { loadSession: true, - // TODO: map acp mcp - // mcpCapabilities: { - // http: true, - // sse: true, - // }, + mcpCapabilities: { + http: true, + sse: true, + }, + promptCapabilities: { + embeddedContext: true, + image: true, + }, }, authMethods: [ { @@ -287,6 +336,7 @@ export namespace ACP { const model = await defaultModel(this.config) const session = await this.sessionManager.create(params.cwd, params.mcpServers, model) + log.info("creating_session", { mcpServers: params.mcpServers.length }) const load = await this.loadSession({ cwd: params.cwd, mcpServers: params.mcpServers, @@ -325,6 +375,17 @@ export namespace ACP { name: command.name, description: command.description ?? "", })) + const names = new Set(availableCommands.map((c) => c.name)) + if (!names.has("init")) + availableCommands.push({ + name: "init", + description: "create/update a AGENTS.md", + }) + if (!names.has("compact")) + availableCommands.push({ + name: "compact", + description: "compact the session", + }) setTimeout(() => { this.connection.sessionUpdate({ @@ -346,6 +407,35 @@ export namespace ACP { const currentModeId = availableModes.find((m) => m.name === "build")?.id ?? availableModes[0].id + const mcpServers: Record = {} + for (const server of params.mcpServers) { + if ("type" in server) { + mcpServers[server.name] = { + url: server.url, + headers: server.headers.reduce>((acc, { name, value }) => { + acc[name] = value + return acc + }, {}), + type: "remote", + } + } else { + mcpServers[server.name] = { + type: "local", + command: [server.command, ...server.args], + environment: server.env.reduce>((acc, { name, value }) => { + acc[name] = value + return acc + }, {}), + } + } + } + + await Promise.all( + Object.entries(mcpServers).map(async ([key, mcp]) => { + await MCP.add(key, mcp) + }), + ) + return { sessionId, models: { @@ -452,25 +542,25 @@ export namespace ACP { log.info("parts", { parts }) - const cmd = await (async () => { - const text = parts.filter((part) => part.type === "text").join("") - const match = text.match(/^\/(\w+)\s*(.*)$/) - if (!match) return + const cmd = (() => { + const text = parts + .filter((p) => p.type === "text") + .map((p) => p.text) + .join("") + .trim() - const [c, args] = match.slice(1) - const command = await Command.get(c) - if (!command) return - return { command, args } + if (!text.startsWith("/")) return + + const [name, ...rest] = text.slice(1).split(/\s+/) + return { name, args: rest.join(" ").trim() } })() - if (cmd) { - await SessionPrompt.command({ - sessionID, - command: cmd.command.name, - arguments: cmd.args, - agent, - }) - } else { + const done = { + stopReason: "end_turn" as const, + _meta: {}, + } + + if (!cmd) { await SessionPrompt.prompt({ sessionID, model: { @@ -480,12 +570,40 @@ export namespace ACP { parts, agent, }) + return done } - return { - stopReason: "end_turn" as const, - _meta: {}, + const command = await Command.get(cmd.name) + if (command) { + await SessionPrompt.command({ + sessionID, + command: command.name, + arguments: cmd.args, + model: model.providerID + "/" + model.modelID, + agent, + }) + return done } + + switch (cmd.name) { + case "init": + await Session.initialize({ + sessionID, + messageID: Identifier.ascending("message"), + providerID: model.providerID, + modelID: model.modelID, + }) + break + case "compact": + await SessionCompaction.run({ + sessionID, + providerID: model.providerID, + modelID: model.modelID, + }) + break + } + + return done } async cancel(params: CancelNotification) { diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index fa3513bb7d..1c3b843696 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -26,122 +26,22 @@ export namespace MCP { const state = Instance.state( async () => { const cfg = await Config.get() + const config = cfg.mcp ?? {} const clients: { [name: string]: MCPClient } = {} - for (const [key, mcp] of Object.entries(cfg.mcp ?? {})) { - if (mcp.enabled === false) { - log.info("mcp server disabled", { key }) - continue - } - log.info("found", { key, type: mcp.type }) - if (mcp.type === "remote") { - const transports = [ - { - name: "StreamableHTTP", - transport: new StreamableHTTPClientTransport(new URL(mcp.url), { - requestInit: { - headers: mcp.headers, - }, - }), - }, - { - name: "SSE", - transport: new SSEClientTransport(new URL(mcp.url), { - requestInit: { - headers: mcp.headers, - }, - }), - }, - ] - let lastError: Error | undefined - for (const { name, transport } of transports) { - const client = await experimental_createMCPClient({ - name: "opencode", - transport, - }).catch((error) => { - lastError = error instanceof Error ? error : new Error(String(error)) - log.debug("transport connection failed", { - key, - transport: name, - url: mcp.url, - error: lastError.message, - }) - return null - }) - if (client) { - log.debug("transport connection succeeded", { key, transport: name }) - clients[key] = client - break - } - } - if (!clients[key]) { - const errorMessage = lastError - ? `MCP server ${key} failed to connect: ${lastError.message}` - : `MCP server ${key} failed to connect to ${mcp.url}` - log.error("remote mcp connection failed", { key, url: mcp.url, error: lastError?.message }) - Bus.publish(Session.Event.Error, { - error: { - name: "UnknownError", - data: { - message: errorMessage, - }, - }, - }) - } - } - if (mcp.type === "local") { - const [cmd, ...args] = mcp.command - const client = await experimental_createMCPClient({ - name: "opencode", - transport: new StdioClientTransport({ - stderr: "ignore", - command: cmd, - args, - env: { - ...process.env, - ...(cmd === "opencode" ? { BUN_BE_BUN: "1" } : {}), - ...mcp.environment, - }, - }), - }).catch((error) => { - const errorMessage = - error instanceof Error - ? `MCP server ${key} failed to start: ${error.message}` - : `MCP server ${key} failed to start` - log.error("local mcp startup failed", { - key, - command: mcp.command, - error: error instanceof Error ? error.message : String(error), - }) - Bus.publish(Session.Event.Error, { - error: { - name: "UnknownError", - data: { - message: errorMessage, - }, - }, - }) - return null - }) - if (client) { - clients[key] = client - } - } - } - - for (const [key, client] of Object.entries(clients)) { - const result = await withTimeout(client.tools(), 5000).catch(() => {}) - if (!result) { - log.warn("mcp client verification failed, removing client", { key }) - delete clients[key] - } - } + await Promise.all( + Object.entries(config).map(async ([key, mcp]) => { + const result = await create(key, mcp).catch(() => undefined) + if (!result) return + clients[key] = result.client + }), + ) return { clients, - config: cfg.mcp ?? {}, + config, } }, async (state) => { @@ -151,6 +51,133 @@ export namespace MCP { }, ) + export async function add(name: string, mcp: Config.Mcp) { + const s = await state() + const result = await create(name, mcp) + if (!result) return + s.clients[name] = result.client + } + + async function create(name: string, mcp: Config.Mcp) { + if (mcp.enabled === false) { + log.info("mcp server disabled", { name }) + return + } + log.info("found", { name, type: mcp.type }) + + let mcpClient: MCPClient | undefined + + if (mcp.type === "remote") { + const transports = [ + { + name: "StreamableHTTP", + transport: new StreamableHTTPClientTransport(new URL(mcp.url), { + requestInit: { + headers: mcp.headers, + }, + }), + }, + { + name: "SSE", + transport: new SSEClientTransport(new URL(mcp.url), { + requestInit: { + headers: mcp.headers, + }, + }), + }, + ] + let lastError: Error | undefined + for (const { name, transport } of transports) { + const client = await experimental_createMCPClient({ + name: "opencode", + transport, + }).catch((error) => { + lastError = error instanceof Error ? error : new Error(String(error)) + log.debug("transport connection failed", { + name, + transport: name, + url: mcp.url, + error: lastError.message, + }) + return null + }) + if (client) { + log.debug("transport connection succeeded", { name, transport: name }) + mcpClient = client + break + } + } + if (!mcpClient) { + const errorMessage = lastError + ? `MCP server ${name} failed to connect: ${lastError.message}` + : `MCP server ${name} failed to connect to ${mcp.url}` + log.error("remote mcp connection failed", { name, url: mcp.url, error: lastError?.message }) + Bus.publish(Session.Event.Error, { + error: { + name: "UnknownError", + data: { + message: errorMessage, + }, + }, + }) + } + } + + if (mcp.type === "local") { + const [cmd, ...args] = mcp.command + const client = await experimental_createMCPClient({ + name: "opencode", + transport: new StdioClientTransport({ + stderr: "ignore", + command: cmd, + args, + env: { + ...process.env, + ...(cmd === "opencode" ? { BUN_BE_BUN: "1" } : {}), + ...mcp.environment, + }, + }), + }).catch((error) => { + const errorMessage = + error instanceof Error + ? `MCP server ${name} failed to start: ${error.message}` + : `MCP server ${name} failed to start` + log.error("local mcp startup failed", { + name, + command: mcp.command, + error: error instanceof Error ? error.message : String(error), + }) + Bus.publish(Session.Event.Error, { + error: { + name: "UnknownError", + data: { + message: errorMessage, + }, + }, + }) + return null + }) + if (client) { + mcpClient = client + } + } + + if (!mcpClient) { + log.warn("mcp client not initialized", { name }) + return + } + + const result = await withTimeout(mcpClient.tools(), 5000).catch(() => {}) + if (!result) { + log.warn("mcp client verification failed, dropping client", { name }) + return + } + + return { + client: mcpClient, + } + } + export async function status() { return state().then((state) => { const result: Record = {} diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 76313453f3..657ac4475c 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -189,7 +189,11 @@ export namespace SessionCompaction { case "text-delta": part.text += value.text if (value.providerMetadata) part.metadata = value.providerMetadata - if (part.text) await Session.updatePart(part) + if (part.text) + await Session.updatePart({ + part, + delta: value.text, + }) continue case "text-end": { part.text = part.text.trimEnd() From d8249f32a83b84d49ae0391975b305fc7de3fdcb Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 28 Oct 2025 01:14:13 -0400 Subject: [PATCH 025/609] do not set temperature for claude models --- packages/opencode/src/provider/transform.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index dda02cc4ec..6212edff80 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -75,7 +75,7 @@ export namespace ProviderTransform { export function temperature(_providerID: string, modelID: string) { if (modelID.toLowerCase().includes("qwen")) return 0.55 - if (modelID.toLowerCase().includes("claude")) return 1 + if (modelID.toLowerCase().includes("claude")) return undefined return 0 } From 872c9467b2b078019ad5a5e01906a67bdc6ce953 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 28 Oct 2025 00:43:29 -0500 Subject: [PATCH 026/609] chore: rm unused import --- packages/opencode/src/acp/agent.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 0fa2509d64..ae9a74a666 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -1,5 +1,4 @@ import { - sessionModeSchema, type Agent as ACPAgent, type AgentSideConnection, type AuthenticateRequest, From 22821744ef54ea9f8a4b27f62b55e74569ef8913 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 28 Oct 2025 02:54:23 -0400 Subject: [PATCH 027/609] feat: add OPENCODE_FAKE_VCS flag for VCS testing and update todo tracking instructions --- packages/opencode/src/flag/flag.ts | 1 + packages/opencode/src/project/project.ts | 2 ++ packages/opencode/src/session/prompt/anthropic.txt | 2 ++ 3 files changed, 5 insertions(+) diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts index fff271cd20..879aa758a7 100644 --- a/packages/opencode/src/flag/flag.ts +++ b/packages/opencode/src/flag/flag.ts @@ -9,6 +9,7 @@ export namespace Flag { export const OPENCODE_DISABLE_LSP_DOWNLOAD = truthy("OPENCODE_DISABLE_LSP_DOWNLOAD") export const OPENCODE_ENABLE_EXPERIMENTAL_MODELS = truthy("OPENCODE_ENABLE_EXPERIMENTAL_MODELS") export const OPENCODE_DISABLE_AUTOCOMPACT = truthy("OPENCODE_DISABLE_AUTOCOMPACT") + export const OPENCODE_FAKE_VCS = process.env["OPENCODE_FAKE_VCS"] // Experimental export const OPENCODE_EXPERIMENTAL_WATCHER = truthy("OPENCODE_EXPERIMENTAL_WATCHER") diff --git a/packages/opencode/src/project/project.ts b/packages/opencode/src/project/project.ts index 34bd4aea7b..339efc2cb1 100644 --- a/packages/opencode/src/project/project.ts +++ b/packages/opencode/src/project/project.ts @@ -4,6 +4,7 @@ import path from "path" import { $ } from "bun" import { Storage } from "../storage/storage" import { Log } from "../util/log" +import { Flag } from "@/flag/flag" export namespace Project { const log = Log.create({ service: "project" }) @@ -31,6 +32,7 @@ export namespace Project { const project: Info = { id: "global", worktree: "/", + vcs: Info.shape.vcs.parse(Flag.OPENCODE_FAKE_VCS), time: { created: Date.now(), }, diff --git a/packages/opencode/src/session/prompt/anthropic.txt b/packages/opencode/src/session/prompt/anthropic.txt index 4f377beb92..43b11250ac 100644 --- a/packages/opencode/src/session/prompt/anthropic.txt +++ b/packages/opencode/src/session/prompt/anthropic.txt @@ -93,6 +93,8 @@ user: What is the codebase structure? assistant: [Uses the Task tool] +IMPORTANT: Always use the TodoWrite tool to plan and track tasks throughout the conversation. + # Code References When referencing specific functions or pieces of code include the pattern `file_path:line_number` to allow the user to easily navigate to the source code location. From 6af6a1295f530c095a9f9699bd238993d8219a29 Mon Sep 17 00:00:00 2001 From: opencode Date: Tue, 28 Oct 2025 08:12:32 +0000 Subject: [PATCH 028/609] release: v0.15.19 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index 012afac4e6..eec72e6c65 100644 --- a/bun.lock +++ b/bun.lock @@ -37,7 +37,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -64,7 +64,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -88,7 +88,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -109,7 +109,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -150,7 +150,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -166,7 +166,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "0.15.18", + "version": "0.15.19", "bin": { "opencode": "./bin/opencode", }, @@ -230,7 +230,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -250,7 +250,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "0.15.18", + "version": "0.15.19", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -261,7 +261,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -274,7 +274,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@kobalte/core": "catalog:", "@pierre/precision-diffs": "catalog:", @@ -297,7 +297,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index b8dea62bc4..868aa18991 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "0.15.18" + "version": "0.15.19" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index f9a4909ff7..948e4af274 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "0.15.18", + "version": "0.15.19", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 2aa5608150..4be5f460a4 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "0.15.18", + "version": "0.15.19", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index accc76b42b..bf62733e71 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "0.15.18", + "version": "0.15.19", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index a14b019434..e401c22427 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "0.15.18", + "version": "0.15.19", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index 1557eecfc0..db56da8de8 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "0.15.18", + "version": "0.15.19", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index ca588b485f..93a69fbed3 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "0.15.18", + "version": "0.15.19", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 52efc93817..4395fb3e07 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "0.15.18", + "version": "0.15.19", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 15a4111182..042e35080d 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "0.15.18", + "version": "0.15.19", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 2f9e4cb556..5fc872c12d 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "0.15.18", + "version": "0.15.19", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index cdb9eee1c8..a6d6a0125f 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "0.15.18", + "version": "0.15.19", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index e24eeb042a..5337a44467 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "0.15.18", + "version": "0.15.19", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index b3220f8179..918cde1361 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "0.15.18", + "version": "0.15.19", "publisher": "sst-dev", "repository": { "type": "git", From dfebf40471bc1dd9b58d062382156878cf95a17e Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 28 Oct 2025 12:04:31 +0000 Subject: [PATCH 029/609] ignore: update download stats 2025-10-28 --- STATS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/STATS.md b/STATS.md index cd00e57e03..71fda16842 100644 --- a/STATS.md +++ b/STATS.md @@ -121,3 +121,4 @@ | 2025-10-25 | 578,927 (+6,235) | 516,129 (+9,224) | 1,095,056 (+15,459) | | 2025-10-26 | 584,409 (+5,482) | 521,179 (+5,050) | 1,105,588 (+10,532) | | 2025-10-27 | 589,999 (+5,590) | 526,001 (+4,822) | 1,116,000 (+10,412) | +| 2025-10-28 | 595,776 (+5,777) | 532,438 (+6,437) | 1,128,214 (+12,214) | From ee1af0fe80662b6c7c233ae3fe70ada19008bf23 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 28 Oct 2025 10:03:53 -0500 Subject: [PATCH 030/609] fix: blank version issue --- packages/sdk/go/.release-please-manifest.json | 2 +- packages/sdk/go/.stats.yml | 4 +- packages/sdk/go/CHANGELOG.md | 16 + packages/sdk/go/README.md | 2 +- packages/sdk/go/app.go | 77 ++++ packages/sdk/go/config.go | 104 ++++- packages/sdk/go/event.go | 177 +++++++- packages/sdk/go/file.go | 42 +- packages/sdk/go/internal/version.go | 2 +- packages/sdk/go/session.go | 421 ++++++++++++++++-- packages/sdk/go/session_test.go | 3 +- 11 files changed, 776 insertions(+), 74 deletions(-) diff --git a/packages/sdk/go/.release-please-manifest.json b/packages/sdk/go/.release-please-manifest.json index 6f2b40185d..4ad3fef33e 100644 --- a/packages/sdk/go/.release-please-manifest.json +++ b/packages/sdk/go/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.16.2" + ".": "0.18.0" } \ No newline at end of file diff --git a/packages/sdk/go/.stats.yml b/packages/sdk/go/.stats.yml index 911073ed45..5383f794ac 100644 --- a/packages/sdk/go/.stats.yml +++ b/packages/sdk/go/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 43 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-273fc9fea965af661dfed0902d00f10d6ed844f0681ca861a58821c4902eac2f.yml -openapi_spec_hash: c6144f23a1bac75f79be86edd405552b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-92f9d0f8daee2ea7458f8b9f1d7a7f941ff932442ad944bc7576254d5978b6d5.yml +openapi_spec_hash: 5b785c4ff6fb69039915f0e746abdaf9 config_hash: 026ef000d34bf2f930e7b41e77d2d3ff diff --git a/packages/sdk/go/CHANGELOG.md b/packages/sdk/go/CHANGELOG.md index 27affc4f0e..498a780295 100644 --- a/packages/sdk/go/CHANGELOG.md +++ b/packages/sdk/go/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 0.18.0 (2025-10-10) + +Full Changelog: [v0.17.0...v0.18.0](https://github.com/sst/opencode-sdk-go/compare/v0.17.0...v0.18.0) + +### Features + +* **api:** api update ([0a7f5e7](https://github.com/sst/opencode-sdk-go/commit/0a7f5e710911506512a132ba39e0593c412beb77)) + +## 0.17.0 (2025-10-07) + +Full Changelog: [v0.16.2...v0.17.0](https://github.com/sst/opencode-sdk-go/compare/v0.16.2...v0.17.0) + +### Features + +* **api:** api update ([84a3df5](https://github.com/sst/opencode-sdk-go/commit/84a3df50a7ff3d87e5593e4f29dfb5d561f71cc3)) + ## 0.16.2 (2025-09-26) Full Changelog: [v0.16.1...v0.16.2](https://github.com/sst/opencode-sdk-go/compare/v0.16.1...v0.16.2) diff --git a/packages/sdk/go/README.md b/packages/sdk/go/README.md index 2de28f6cef..f4c02d1259 100644 --- a/packages/sdk/go/README.md +++ b/packages/sdk/go/README.md @@ -24,7 +24,7 @@ Or to pin the version: ```sh -go get -u 'github.com/sst/opencode-sdk-go@v0.16.2' +go get -u 'github.com/sst/opencode-sdk-go@v0.18.0' ``` diff --git a/packages/sdk/go/app.go b/packages/sdk/go/app.go index 19662f1005..4ba42332a8 100644 --- a/packages/sdk/go/app.go +++ b/packages/sdk/go/app.go @@ -62,7 +62,9 @@ type Model struct { Temperature bool `json:"temperature,required"` ToolCall bool `json:"tool_call,required"` Experimental bool `json:"experimental"` + Modalities ModelModalities `json:"modalities"` Provider ModelProvider `json:"provider"` + Status ModelStatus `json:"status"` JSON modelJSON `json:"-"` } @@ -79,7 +81,9 @@ type modelJSON struct { Temperature apijson.Field ToolCall apijson.Field Experimental apijson.Field + Modalities apijson.Field Provider apijson.Field + Status apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -140,6 +144,64 @@ func (r modelLimitJSON) RawJSON() string { return r.raw } +type ModelModalities struct { + Input []ModelModalitiesInput `json:"input,required"` + Output []ModelModalitiesOutput `json:"output,required"` + JSON modelModalitiesJSON `json:"-"` +} + +// modelModalitiesJSON contains the JSON metadata for the struct [ModelModalities] +type modelModalitiesJSON struct { + Input apijson.Field + Output apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ModelModalities) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r modelModalitiesJSON) RawJSON() string { + return r.raw +} + +type ModelModalitiesInput string + +const ( + ModelModalitiesInputText ModelModalitiesInput = "text" + ModelModalitiesInputAudio ModelModalitiesInput = "audio" + ModelModalitiesInputImage ModelModalitiesInput = "image" + ModelModalitiesInputVideo ModelModalitiesInput = "video" + ModelModalitiesInputPdf ModelModalitiesInput = "pdf" +) + +func (r ModelModalitiesInput) IsKnown() bool { + switch r { + case ModelModalitiesInputText, ModelModalitiesInputAudio, ModelModalitiesInputImage, ModelModalitiesInputVideo, ModelModalitiesInputPdf: + return true + } + return false +} + +type ModelModalitiesOutput string + +const ( + ModelModalitiesOutputText ModelModalitiesOutput = "text" + ModelModalitiesOutputAudio ModelModalitiesOutput = "audio" + ModelModalitiesOutputImage ModelModalitiesOutput = "image" + ModelModalitiesOutputVideo ModelModalitiesOutput = "video" + ModelModalitiesOutputPdf ModelModalitiesOutput = "pdf" +) + +func (r ModelModalitiesOutput) IsKnown() bool { + switch r { + case ModelModalitiesOutputText, ModelModalitiesOutputAudio, ModelModalitiesOutputImage, ModelModalitiesOutputVideo, ModelModalitiesOutputPdf: + return true + } + return false +} + type ModelProvider struct { Npm string `json:"npm,required"` JSON modelProviderJSON `json:"-"` @@ -160,6 +222,21 @@ func (r modelProviderJSON) RawJSON() string { return r.raw } +type ModelStatus string + +const ( + ModelStatusAlpha ModelStatus = "alpha" + ModelStatusBeta ModelStatus = "beta" +) + +func (r ModelStatus) IsKnown() bool { + switch r { + case ModelStatusAlpha, ModelStatusBeta: + return true + } + return false +} + type Provider struct { ID string `json:"id,required"` Env []string `json:"env,required"` diff --git a/packages/sdk/go/config.go b/packages/sdk/go/config.go index 561a35a0f8..02460fb5df 100644 --- a/packages/sdk/go/config.go +++ b/packages/sdk/go/config.go @@ -1567,19 +1567,21 @@ func (r configProviderJSON) RawJSON() string { } type ConfigProviderModel struct { - ID string `json:"id"` - Attachment bool `json:"attachment"` - Cost ConfigProviderModelsCost `json:"cost"` - Experimental bool `json:"experimental"` - Limit ConfigProviderModelsLimit `json:"limit"` - Name string `json:"name"` - Options map[string]interface{} `json:"options"` - Provider ConfigProviderModelsProvider `json:"provider"` - Reasoning bool `json:"reasoning"` - ReleaseDate string `json:"release_date"` - Temperature bool `json:"temperature"` - ToolCall bool `json:"tool_call"` - JSON configProviderModelJSON `json:"-"` + ID string `json:"id"` + Attachment bool `json:"attachment"` + Cost ConfigProviderModelsCost `json:"cost"` + Experimental bool `json:"experimental"` + Limit ConfigProviderModelsLimit `json:"limit"` + Modalities ConfigProviderModelsModalities `json:"modalities"` + Name string `json:"name"` + Options map[string]interface{} `json:"options"` + Provider ConfigProviderModelsProvider `json:"provider"` + Reasoning bool `json:"reasoning"` + ReleaseDate string `json:"release_date"` + Status ConfigProviderModelsStatus `json:"status"` + Temperature bool `json:"temperature"` + ToolCall bool `json:"tool_call"` + JSON configProviderModelJSON `json:"-"` } // configProviderModelJSON contains the JSON metadata for the struct @@ -1590,11 +1592,13 @@ type configProviderModelJSON struct { Cost apijson.Field Experimental apijson.Field Limit apijson.Field + Modalities apijson.Field Name apijson.Field Options apijson.Field Provider apijson.Field Reasoning apijson.Field ReleaseDate apijson.Field + Status apijson.Field Temperature apijson.Field ToolCall apijson.Field raw string @@ -1659,6 +1663,65 @@ func (r configProviderModelsLimitJSON) RawJSON() string { return r.raw } +type ConfigProviderModelsModalities struct { + Input []ConfigProviderModelsModalitiesInput `json:"input,required"` + Output []ConfigProviderModelsModalitiesOutput `json:"output,required"` + JSON configProviderModelsModalitiesJSON `json:"-"` +} + +// configProviderModelsModalitiesJSON contains the JSON metadata for the struct +// [ConfigProviderModelsModalities] +type configProviderModelsModalitiesJSON struct { + Input apijson.Field + Output apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ConfigProviderModelsModalities) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r configProviderModelsModalitiesJSON) RawJSON() string { + return r.raw +} + +type ConfigProviderModelsModalitiesInput string + +const ( + ConfigProviderModelsModalitiesInputText ConfigProviderModelsModalitiesInput = "text" + ConfigProviderModelsModalitiesInputAudio ConfigProviderModelsModalitiesInput = "audio" + ConfigProviderModelsModalitiesInputImage ConfigProviderModelsModalitiesInput = "image" + ConfigProviderModelsModalitiesInputVideo ConfigProviderModelsModalitiesInput = "video" + ConfigProviderModelsModalitiesInputPdf ConfigProviderModelsModalitiesInput = "pdf" +) + +func (r ConfigProviderModelsModalitiesInput) IsKnown() bool { + switch r { + case ConfigProviderModelsModalitiesInputText, ConfigProviderModelsModalitiesInputAudio, ConfigProviderModelsModalitiesInputImage, ConfigProviderModelsModalitiesInputVideo, ConfigProviderModelsModalitiesInputPdf: + return true + } + return false +} + +type ConfigProviderModelsModalitiesOutput string + +const ( + ConfigProviderModelsModalitiesOutputText ConfigProviderModelsModalitiesOutput = "text" + ConfigProviderModelsModalitiesOutputAudio ConfigProviderModelsModalitiesOutput = "audio" + ConfigProviderModelsModalitiesOutputImage ConfigProviderModelsModalitiesOutput = "image" + ConfigProviderModelsModalitiesOutputVideo ConfigProviderModelsModalitiesOutput = "video" + ConfigProviderModelsModalitiesOutputPdf ConfigProviderModelsModalitiesOutput = "pdf" +) + +func (r ConfigProviderModelsModalitiesOutput) IsKnown() bool { + switch r { + case ConfigProviderModelsModalitiesOutputText, ConfigProviderModelsModalitiesOutputAudio, ConfigProviderModelsModalitiesOutputImage, ConfigProviderModelsModalitiesOutputVideo, ConfigProviderModelsModalitiesOutputPdf: + return true + } + return false +} + type ConfigProviderModelsProvider struct { Npm string `json:"npm,required"` JSON configProviderModelsProviderJSON `json:"-"` @@ -1680,6 +1743,21 @@ func (r configProviderModelsProviderJSON) RawJSON() string { return r.raw } +type ConfigProviderModelsStatus string + +const ( + ConfigProviderModelsStatusAlpha ConfigProviderModelsStatus = "alpha" + ConfigProviderModelsStatusBeta ConfigProviderModelsStatus = "beta" +) + +func (r ConfigProviderModelsStatus) IsKnown() bool { + switch r { + case ConfigProviderModelsStatusAlpha, ConfigProviderModelsStatusBeta: + return true + } + return false +} + type ConfigProviderOptions struct { APIKey string `json:"apiKey"` BaseURL string `json:"baseURL"` diff --git a/packages/sdk/go/event.go b/packages/sdk/go/event.go index ac5231c7fa..41a37951c5 100644 --- a/packages/sdk/go/event.go +++ b/packages/sdk/go/event.go @@ -65,6 +65,7 @@ type EventListResponse struct { // [EventListResponseEventFileWatcherUpdatedProperties], // [EventListResponseEventTodoUpdatedProperties], // [EventListResponseEventSessionIdleProperties], + // [EventListResponseEventSessionCreatedProperties], // [EventListResponseEventSessionUpdatedProperties], // [EventListResponseEventSessionDeletedProperties], // [EventListResponseEventSessionErrorProperties], [interface{}], @@ -110,9 +111,10 @@ func (r *EventListResponse) UnmarshalJSON(data []byte) (err error) { // [EventListResponseEventPermissionUpdated], // [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited], // [EventListResponseEventFileWatcherUpdated], [EventListResponseEventTodoUpdated], -// [EventListResponseEventSessionIdle], [EventListResponseEventSessionUpdated], -// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionError], -// [EventListResponseEventServerConnected], [EventListResponseEventIdeInstalled]. +// [EventListResponseEventSessionIdle], [EventListResponseEventSessionCreated], +// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted], +// [EventListResponseEventSessionError], [EventListResponseEventServerConnected], +// [EventListResponseEventIdeInstalled]. func (r EventListResponse) AsUnion() EventListResponseUnion { return r.union } @@ -126,9 +128,10 @@ func (r EventListResponse) AsUnion() EventListResponseUnion { // [EventListResponseEventPermissionUpdated], // [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited], // [EventListResponseEventFileWatcherUpdated], [EventListResponseEventTodoUpdated], -// [EventListResponseEventSessionIdle], [EventListResponseEventSessionUpdated], -// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionError], -// [EventListResponseEventServerConnected] or [EventListResponseEventIdeInstalled]. +// [EventListResponseEventSessionIdle], [EventListResponseEventSessionCreated], +// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted], +// [EventListResponseEventSessionError], [EventListResponseEventServerConnected] or +// [EventListResponseEventIdeInstalled]. type EventListResponseUnion interface { implementsEventListResponse() } @@ -189,6 +192,10 @@ func init() { TypeFilter: gjson.JSON, Type: reflect.TypeOf(EventListResponseEventSessionIdle{}), }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(EventListResponseEventSessionCreated{}), + }, apijson.UnionVariant{ TypeFilter: gjson.JSON, Type: reflect.TypeOf(EventListResponseEventSessionUpdated{}), @@ -482,14 +489,16 @@ func (r eventListResponseEventMessagePartUpdatedJSON) RawJSON() string { func (r EventListResponseEventMessagePartUpdated) implementsEventListResponse() {} type EventListResponseEventMessagePartUpdatedProperties struct { - Part Part `json:"part,required"` - JSON eventListResponseEventMessagePartUpdatedPropertiesJSON `json:"-"` + Part Part `json:"part,required"` + Delta string `json:"delta"` + JSON eventListResponseEventMessagePartUpdatedPropertiesJSON `json:"-"` } // eventListResponseEventMessagePartUpdatedPropertiesJSON contains the JSON // metadata for the struct [EventListResponseEventMessagePartUpdatedProperties] type eventListResponseEventMessagePartUpdatedPropertiesJSON struct { Part apijson.Field + Delta apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -1034,6 +1043,66 @@ func (r EventListResponseEventSessionIdleType) IsKnown() bool { return false } +type EventListResponseEventSessionCreated struct { + Properties EventListResponseEventSessionCreatedProperties `json:"properties,required"` + Type EventListResponseEventSessionCreatedType `json:"type,required"` + JSON eventListResponseEventSessionCreatedJSON `json:"-"` +} + +// eventListResponseEventSessionCreatedJSON contains the JSON metadata for the +// struct [EventListResponseEventSessionCreated] +type eventListResponseEventSessionCreatedJSON struct { + Properties apijson.Field + Type apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *EventListResponseEventSessionCreated) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r eventListResponseEventSessionCreatedJSON) RawJSON() string { + return r.raw +} + +func (r EventListResponseEventSessionCreated) implementsEventListResponse() {} + +type EventListResponseEventSessionCreatedProperties struct { + Info Session `json:"info,required"` + JSON eventListResponseEventSessionCreatedPropertiesJSON `json:"-"` +} + +// eventListResponseEventSessionCreatedPropertiesJSON contains the JSON metadata +// for the struct [EventListResponseEventSessionCreatedProperties] +type eventListResponseEventSessionCreatedPropertiesJSON struct { + Info apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *EventListResponseEventSessionCreatedProperties) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r eventListResponseEventSessionCreatedPropertiesJSON) RawJSON() string { + return r.raw +} + +type EventListResponseEventSessionCreatedType string + +const ( + EventListResponseEventSessionCreatedTypeSessionCreated EventListResponseEventSessionCreatedType = "session.created" +) + +func (r EventListResponseEventSessionCreatedType) IsKnown() bool { + switch r { + case EventListResponseEventSessionCreatedTypeSessionCreated: + return true + } + return false +} + type EventListResponseEventSessionUpdated struct { Properties EventListResponseEventSessionUpdatedProperties `json:"properties,required"` Type EventListResponseEventSessionUpdatedType `json:"type,required"` @@ -1204,7 +1273,8 @@ func (r eventListResponseEventSessionErrorPropertiesJSON) RawJSON() string { type EventListResponseEventSessionErrorPropertiesError struct { // This field can have the runtime type of [shared.ProviderAuthErrorData], - // [shared.UnknownErrorData], [interface{}], [shared.MessageAbortedErrorData]. + // [shared.UnknownErrorData], [interface{}], [shared.MessageAbortedErrorData], + // [EventListResponseEventSessionErrorPropertiesErrorAPIErrorData]. Data interface{} `json:"data,required"` Name EventListResponseEventSessionErrorPropertiesErrorName `json:"name,required"` JSON eventListResponseEventSessionErrorPropertiesErrorJSON `json:"-"` @@ -1239,14 +1309,16 @@ func (r *EventListResponseEventSessionErrorPropertiesError) UnmarshalJSON(data [ // Possible runtime types of the union are [shared.ProviderAuthError], // [shared.UnknownError], // [EventListResponseEventSessionErrorPropertiesErrorMessageOutputLengthError], -// [shared.MessageAbortedError]. +// [shared.MessageAbortedError], +// [EventListResponseEventSessionErrorPropertiesErrorAPIError]. func (r EventListResponseEventSessionErrorPropertiesError) AsUnion() EventListResponseEventSessionErrorPropertiesErrorUnion { return r.union } // Union satisfied by [shared.ProviderAuthError], [shared.UnknownError], -// [EventListResponseEventSessionErrorPropertiesErrorMessageOutputLengthError] or -// [shared.MessageAbortedError]. +// [EventListResponseEventSessionErrorPropertiesErrorMessageOutputLengthError], +// [shared.MessageAbortedError] or +// [EventListResponseEventSessionErrorPropertiesErrorAPIError]. type EventListResponseEventSessionErrorPropertiesErrorUnion interface { ImplementsEventListResponseEventSessionErrorPropertiesError() } @@ -1271,6 +1343,10 @@ func init() { TypeFilter: gjson.JSON, Type: reflect.TypeOf(shared.MessageAbortedError{}), }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(EventListResponseEventSessionErrorPropertiesErrorAPIError{}), + }, ) } @@ -1315,6 +1391,77 @@ func (r EventListResponseEventSessionErrorPropertiesErrorMessageOutputLengthErro return false } +type EventListResponseEventSessionErrorPropertiesErrorAPIError struct { + Data EventListResponseEventSessionErrorPropertiesErrorAPIErrorData `json:"data,required"` + Name EventListResponseEventSessionErrorPropertiesErrorAPIErrorName `json:"name,required"` + JSON eventListResponseEventSessionErrorPropertiesErrorAPIErrorJSON `json:"-"` +} + +// eventListResponseEventSessionErrorPropertiesErrorAPIErrorJSON contains the JSON +// metadata for the struct +// [EventListResponseEventSessionErrorPropertiesErrorAPIError] +type eventListResponseEventSessionErrorPropertiesErrorAPIErrorJSON struct { + Data apijson.Field + Name apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *EventListResponseEventSessionErrorPropertiesErrorAPIError) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r eventListResponseEventSessionErrorPropertiesErrorAPIErrorJSON) RawJSON() string { + return r.raw +} + +func (r EventListResponseEventSessionErrorPropertiesErrorAPIError) ImplementsEventListResponseEventSessionErrorPropertiesError() { +} + +type EventListResponseEventSessionErrorPropertiesErrorAPIErrorData struct { + IsRetryable bool `json:"isRetryable,required"` + Message string `json:"message,required"` + ResponseBody string `json:"responseBody"` + ResponseHeaders map[string]string `json:"responseHeaders"` + StatusCode float64 `json:"statusCode"` + JSON eventListResponseEventSessionErrorPropertiesErrorAPIErrorDataJSON `json:"-"` +} + +// eventListResponseEventSessionErrorPropertiesErrorAPIErrorDataJSON contains the +// JSON metadata for the struct +// [EventListResponseEventSessionErrorPropertiesErrorAPIErrorData] +type eventListResponseEventSessionErrorPropertiesErrorAPIErrorDataJSON struct { + IsRetryable apijson.Field + Message apijson.Field + ResponseBody apijson.Field + ResponseHeaders apijson.Field + StatusCode apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *EventListResponseEventSessionErrorPropertiesErrorAPIErrorData) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r eventListResponseEventSessionErrorPropertiesErrorAPIErrorDataJSON) RawJSON() string { + return r.raw +} + +type EventListResponseEventSessionErrorPropertiesErrorAPIErrorName string + +const ( + EventListResponseEventSessionErrorPropertiesErrorAPIErrorNameAPIError EventListResponseEventSessionErrorPropertiesErrorAPIErrorName = "APIError" +) + +func (r EventListResponseEventSessionErrorPropertiesErrorAPIErrorName) IsKnown() bool { + switch r { + case EventListResponseEventSessionErrorPropertiesErrorAPIErrorNameAPIError: + return true + } + return false +} + type EventListResponseEventSessionErrorPropertiesErrorName string const ( @@ -1322,11 +1469,12 @@ const ( EventListResponseEventSessionErrorPropertiesErrorNameUnknownError EventListResponseEventSessionErrorPropertiesErrorName = "UnknownError" EventListResponseEventSessionErrorPropertiesErrorNameMessageOutputLengthError EventListResponseEventSessionErrorPropertiesErrorName = "MessageOutputLengthError" EventListResponseEventSessionErrorPropertiesErrorNameMessageAbortedError EventListResponseEventSessionErrorPropertiesErrorName = "MessageAbortedError" + EventListResponseEventSessionErrorPropertiesErrorNameAPIError EventListResponseEventSessionErrorPropertiesErrorName = "APIError" ) func (r EventListResponseEventSessionErrorPropertiesErrorName) IsKnown() bool { switch r { - case EventListResponseEventSessionErrorPropertiesErrorNameProviderAuthError, EventListResponseEventSessionErrorPropertiesErrorNameUnknownError, EventListResponseEventSessionErrorPropertiesErrorNameMessageOutputLengthError, EventListResponseEventSessionErrorPropertiesErrorNameMessageAbortedError: + case EventListResponseEventSessionErrorPropertiesErrorNameProviderAuthError, EventListResponseEventSessionErrorPropertiesErrorNameUnknownError, EventListResponseEventSessionErrorPropertiesErrorNameMessageOutputLengthError, EventListResponseEventSessionErrorPropertiesErrorNameMessageAbortedError, EventListResponseEventSessionErrorPropertiesErrorNameAPIError: return true } return false @@ -1461,6 +1609,7 @@ const ( EventListResponseTypeFileWatcherUpdated EventListResponseType = "file.watcher.updated" EventListResponseTypeTodoUpdated EventListResponseType = "todo.updated" EventListResponseTypeSessionIdle EventListResponseType = "session.idle" + EventListResponseTypeSessionCreated EventListResponseType = "session.created" EventListResponseTypeSessionUpdated EventListResponseType = "session.updated" EventListResponseTypeSessionDeleted EventListResponseType = "session.deleted" EventListResponseTypeSessionError EventListResponseType = "session.error" @@ -1470,7 +1619,7 @@ const ( func (r EventListResponseType) IsKnown() bool { switch r { - case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeSessionCompacted, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeTodoUpdated, EventListResponseTypeSessionIdle, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionError, EventListResponseTypeServerConnected, EventListResponseTypeIdeInstalled: + case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeSessionCompacted, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeTodoUpdated, EventListResponseTypeSessionIdle, EventListResponseTypeSessionCreated, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionError, EventListResponseTypeServerConnected, EventListResponseTypeIdeInstalled: return true } return false diff --git a/packages/sdk/go/file.go b/packages/sdk/go/file.go index 8833f425b6..34a9c57d4a 100644 --- a/packages/sdk/go/file.go +++ b/packages/sdk/go/file.go @@ -144,17 +144,23 @@ func (r FileNodeType) IsKnown() bool { } type FileReadResponse struct { - Content string `json:"content,required"` - Diff string `json:"diff"` - Patch FileReadResponsePatch `json:"patch"` - JSON fileReadResponseJSON `json:"-"` + Content string `json:"content,required"` + Type FileReadResponseType `json:"type,required"` + Diff string `json:"diff"` + Encoding FileReadResponseEncoding `json:"encoding"` + MimeType string `json:"mimeType"` + Patch FileReadResponsePatch `json:"patch"` + JSON fileReadResponseJSON `json:"-"` } // fileReadResponseJSON contains the JSON metadata for the struct // [FileReadResponse] type fileReadResponseJSON struct { Content apijson.Field + Type apijson.Field Diff apijson.Field + Encoding apijson.Field + MimeType apijson.Field Patch apijson.Field raw string ExtraFields map[string]apijson.Field @@ -168,6 +174,34 @@ func (r fileReadResponseJSON) RawJSON() string { return r.raw } +type FileReadResponseType string + +const ( + FileReadResponseTypeText FileReadResponseType = "text" +) + +func (r FileReadResponseType) IsKnown() bool { + switch r { + case FileReadResponseTypeText: + return true + } + return false +} + +type FileReadResponseEncoding string + +const ( + FileReadResponseEncodingBase64 FileReadResponseEncoding = "base64" +) + +func (r FileReadResponseEncoding) IsKnown() bool { + switch r { + case FileReadResponseEncodingBase64: + return true + } + return false +} + type FileReadResponsePatch struct { Hunks []FileReadResponsePatchHunk `json:"hunks,required"` NewFileName string `json:"newFileName,required"` diff --git a/packages/sdk/go/internal/version.go b/packages/sdk/go/internal/version.go index 93a271b9ea..8dc40e7478 100644 --- a/packages/sdk/go/internal/version.go +++ b/packages/sdk/go/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.16.2" // x-release-please-version +const PackageVersion = "0.18.0" // x-release-please-version diff --git a/packages/sdk/go/session.go b/packages/sdk/go/session.go index 0ee81faad9..afd64cb9e3 100644 --- a/packages/sdk/go/session.go +++ b/packages/sdk/go/session.go @@ -365,6 +365,7 @@ type AssistantMessage struct { Cost float64 `json:"cost,required"` Mode string `json:"mode,required"` ModelID string `json:"modelID,required"` + ParentID string `json:"parentID,required"` Path AssistantMessagePath `json:"path,required"` ProviderID string `json:"providerID,required"` Role AssistantMessageRole `json:"role,required"` @@ -384,6 +385,7 @@ type assistantMessageJSON struct { Cost apijson.Field Mode apijson.Field ModelID apijson.Field + ParentID apijson.Field Path apijson.Field ProviderID apijson.Field Role apijson.Field @@ -519,7 +521,8 @@ func (r assistantMessageTokensCacheJSON) RawJSON() string { type AssistantMessageError struct { // This field can have the runtime type of [shared.ProviderAuthErrorData], - // [shared.UnknownErrorData], [interface{}], [shared.MessageAbortedErrorData]. + // [shared.UnknownErrorData], [interface{}], [shared.MessageAbortedErrorData], + // [AssistantMessageErrorAPIErrorData]. Data interface{} `json:"data,required"` Name AssistantMessageErrorName `json:"name,required"` JSON assistantMessageErrorJSON `json:"-"` @@ -553,13 +556,14 @@ func (r *AssistantMessageError) UnmarshalJSON(data []byte) (err error) { // // Possible runtime types of the union are [shared.ProviderAuthError], // [shared.UnknownError], [AssistantMessageErrorMessageOutputLengthError], -// [shared.MessageAbortedError]. +// [shared.MessageAbortedError], [AssistantMessageErrorAPIError]. func (r AssistantMessageError) AsUnion() AssistantMessageErrorUnion { return r.union } // Union satisfied by [shared.ProviderAuthError], [shared.UnknownError], -// [AssistantMessageErrorMessageOutputLengthError] or [shared.MessageAbortedError]. +// [AssistantMessageErrorMessageOutputLengthError], [shared.MessageAbortedError] or +// [AssistantMessageErrorAPIError]. type AssistantMessageErrorUnion interface { ImplementsAssistantMessageError() } @@ -584,6 +588,10 @@ func init() { TypeFilter: gjson.JSON, Type: reflect.TypeOf(shared.MessageAbortedError{}), }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(AssistantMessageErrorAPIError{}), + }, ) } @@ -626,6 +634,74 @@ func (r AssistantMessageErrorMessageOutputLengthErrorName) IsKnown() bool { return false } +type AssistantMessageErrorAPIError struct { + Data AssistantMessageErrorAPIErrorData `json:"data,required"` + Name AssistantMessageErrorAPIErrorName `json:"name,required"` + JSON assistantMessageErrorAPIErrorJSON `json:"-"` +} + +// assistantMessageErrorAPIErrorJSON contains the JSON metadata for the struct +// [AssistantMessageErrorAPIError] +type assistantMessageErrorAPIErrorJSON struct { + Data apijson.Field + Name apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AssistantMessageErrorAPIError) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r assistantMessageErrorAPIErrorJSON) RawJSON() string { + return r.raw +} + +func (r AssistantMessageErrorAPIError) ImplementsAssistantMessageError() {} + +type AssistantMessageErrorAPIErrorData struct { + IsRetryable bool `json:"isRetryable,required"` + Message string `json:"message,required"` + ResponseBody string `json:"responseBody"` + ResponseHeaders map[string]string `json:"responseHeaders"` + StatusCode float64 `json:"statusCode"` + JSON assistantMessageErrorAPIErrorDataJSON `json:"-"` +} + +// assistantMessageErrorAPIErrorDataJSON contains the JSON metadata for the struct +// [AssistantMessageErrorAPIErrorData] +type assistantMessageErrorAPIErrorDataJSON struct { + IsRetryable apijson.Field + Message apijson.Field + ResponseBody apijson.Field + ResponseHeaders apijson.Field + StatusCode apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *AssistantMessageErrorAPIErrorData) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r assistantMessageErrorAPIErrorDataJSON) RawJSON() string { + return r.raw +} + +type AssistantMessageErrorAPIErrorName string + +const ( + AssistantMessageErrorAPIErrorNameAPIError AssistantMessageErrorAPIErrorName = "APIError" +) + +func (r AssistantMessageErrorAPIErrorName) IsKnown() bool { + switch r { + case AssistantMessageErrorAPIErrorNameAPIError: + return true + } + return false +} + type AssistantMessageErrorName string const ( @@ -633,11 +709,12 @@ const ( AssistantMessageErrorNameUnknownError AssistantMessageErrorName = "UnknownError" AssistantMessageErrorNameMessageOutputLengthError AssistantMessageErrorName = "MessageOutputLengthError" AssistantMessageErrorNameMessageAbortedError AssistantMessageErrorName = "MessageAbortedError" + AssistantMessageErrorNameAPIError AssistantMessageErrorName = "APIError" ) func (r AssistantMessageErrorName) IsKnown() bool { switch r { - case AssistantMessageErrorNameProviderAuthError, AssistantMessageErrorNameUnknownError, AssistantMessageErrorNameMessageOutputLengthError, AssistantMessageErrorNameMessageAbortedError: + case AssistantMessageErrorNameProviderAuthError, AssistantMessageErrorNameUnknownError, AssistantMessageErrorNameMessageOutputLengthError, AssistantMessageErrorNameMessageAbortedError, AssistantMessageErrorNameAPIError: return true } return false @@ -918,13 +995,15 @@ type Message struct { Time interface{} `json:"time,required"` Cost float64 `json:"cost"` // This field can have the runtime type of [AssistantMessageError]. - Error interface{} `json:"error"` - Mode string `json:"mode"` - ModelID string `json:"modelID"` + Error interface{} `json:"error"` + Mode string `json:"mode"` + ModelID string `json:"modelID"` + ParentID string `json:"parentID"` // This field can have the runtime type of [AssistantMessagePath]. Path interface{} `json:"path"` ProviderID string `json:"providerID"` - Summary bool `json:"summary"` + // This field can have the runtime type of [UserMessageSummary], [bool]. + Summary interface{} `json:"summary"` // This field can have the runtime type of [[]string]. System interface{} `json:"system"` // This field can have the runtime type of [AssistantMessageTokens]. @@ -943,6 +1022,7 @@ type messageJSON struct { Error apijson.Field Mode apijson.Field ModelID apijson.Field + ParentID apijson.Field Path apijson.Field ProviderID apijson.Field Summary apijson.Field @@ -1013,9 +1093,12 @@ type Part struct { MessageID string `json:"messageID,required"` SessionID string `json:"sessionID,required"` Type PartType `json:"type,required"` + Attempt float64 `json:"attempt"` CallID string `json:"callID"` Cost float64 `json:"cost"` - Filename string `json:"filename"` + // This field can have the runtime type of [PartRetryPartError]. + Error interface{} `json:"error"` + Filename string `json:"filename"` // This field can have the runtime type of [[]string]. Files interface{} `json:"files"` Hash string `json:"hash"` @@ -1023,6 +1106,7 @@ type Part struct { Metadata interface{} `json:"metadata"` Mime string `json:"mime"` Name string `json:"name"` + Reason string `json:"reason"` Snapshot string `json:"snapshot"` // This field can have the runtime type of [FilePartSource], [AgentPartSource]. Source interface{} `json:"source"` @@ -1030,7 +1114,8 @@ type Part struct { State interface{} `json:"state"` Synthetic bool `json:"synthetic"` Text string `json:"text"` - // This field can have the runtime type of [TextPartTime], [ReasoningPartTime]. + // This field can have the runtime type of [TextPartTime], [ReasoningPartTime], + // [PartRetryPartTime]. Time interface{} `json:"time"` // This field can have the runtime type of [StepFinishPartTokens]. Tokens interface{} `json:"tokens"` @@ -1046,14 +1131,17 @@ type partJSON struct { MessageID apijson.Field SessionID apijson.Field Type apijson.Field + Attempt apijson.Field CallID apijson.Field Cost apijson.Field + Error apijson.Field Filename apijson.Field Files apijson.Field Hash apijson.Field Metadata apijson.Field Mime apijson.Field Name apijson.Field + Reason apijson.Field Snapshot apijson.Field Source apijson.Field State apijson.Field @@ -1085,14 +1173,14 @@ func (r *Part) UnmarshalJSON(data []byte) (err error) { // // Possible runtime types of the union are [TextPart], [ReasoningPart], [FilePart], // [ToolPart], [StepStartPart], [StepFinishPart], [SnapshotPart], [PartPatchPart], -// [AgentPart]. +// [AgentPart], [PartRetryPart]. func (r Part) AsUnion() PartUnion { return r.union } // Union satisfied by [TextPart], [ReasoningPart], [FilePart], [ToolPart], -// [StepStartPart], [StepFinishPart], [SnapshotPart], [PartPatchPart] or -// [AgentPart]. +// [StepStartPart], [StepFinishPart], [SnapshotPart], [PartPatchPart], [AgentPart] +// or [PartRetryPart]. type PartUnion interface { implementsPart() } @@ -1137,6 +1225,10 @@ func init() { TypeFilter: gjson.JSON, Type: reflect.TypeOf(AgentPart{}), }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(PartRetryPart{}), + }, ) } @@ -1186,6 +1278,141 @@ func (r PartPatchPartType) IsKnown() bool { return false } +type PartRetryPart struct { + ID string `json:"id,required"` + Attempt float64 `json:"attempt,required"` + Error PartRetryPartError `json:"error,required"` + MessageID string `json:"messageID,required"` + SessionID string `json:"sessionID,required"` + Time PartRetryPartTime `json:"time,required"` + Type PartRetryPartType `json:"type,required"` + JSON partRetryPartJSON `json:"-"` +} + +// partRetryPartJSON contains the JSON metadata for the struct [PartRetryPart] +type partRetryPartJSON struct { + ID apijson.Field + Attempt apijson.Field + Error apijson.Field + MessageID apijson.Field + SessionID apijson.Field + Time apijson.Field + Type apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *PartRetryPart) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r partRetryPartJSON) RawJSON() string { + return r.raw +} + +func (r PartRetryPart) implementsPart() {} + +type PartRetryPartError struct { + Data PartRetryPartErrorData `json:"data,required"` + Name PartRetryPartErrorName `json:"name,required"` + JSON partRetryPartErrorJSON `json:"-"` +} + +// partRetryPartErrorJSON contains the JSON metadata for the struct +// [PartRetryPartError] +type partRetryPartErrorJSON struct { + Data apijson.Field + Name apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *PartRetryPartError) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r partRetryPartErrorJSON) RawJSON() string { + return r.raw +} + +type PartRetryPartErrorData struct { + IsRetryable bool `json:"isRetryable,required"` + Message string `json:"message,required"` + ResponseBody string `json:"responseBody"` + ResponseHeaders map[string]string `json:"responseHeaders"` + StatusCode float64 `json:"statusCode"` + JSON partRetryPartErrorDataJSON `json:"-"` +} + +// partRetryPartErrorDataJSON contains the JSON metadata for the struct +// [PartRetryPartErrorData] +type partRetryPartErrorDataJSON struct { + IsRetryable apijson.Field + Message apijson.Field + ResponseBody apijson.Field + ResponseHeaders apijson.Field + StatusCode apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *PartRetryPartErrorData) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r partRetryPartErrorDataJSON) RawJSON() string { + return r.raw +} + +type PartRetryPartErrorName string + +const ( + PartRetryPartErrorNameAPIError PartRetryPartErrorName = "APIError" +) + +func (r PartRetryPartErrorName) IsKnown() bool { + switch r { + case PartRetryPartErrorNameAPIError: + return true + } + return false +} + +type PartRetryPartTime struct { + Created float64 `json:"created,required"` + JSON partRetryPartTimeJSON `json:"-"` +} + +// partRetryPartTimeJSON contains the JSON metadata for the struct +// [PartRetryPartTime] +type partRetryPartTimeJSON struct { + Created apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *PartRetryPartTime) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r partRetryPartTimeJSON) RawJSON() string { + return r.raw +} + +type PartRetryPartType string + +const ( + PartRetryPartTypeRetry PartRetryPartType = "retry" +) + +func (r PartRetryPartType) IsKnown() bool { + switch r { + case PartRetryPartTypeRetry: + return true + } + return false +} + type PartType string const ( @@ -1198,11 +1425,12 @@ const ( PartTypeSnapshot PartType = "snapshot" PartTypePatch PartType = "patch" PartTypeAgent PartType = "agent" + PartTypeRetry PartType = "retry" ) func (r PartType) IsKnown() bool { switch r { - case PartTypeText, PartTypeReasoning, PartTypeFile, PartTypeTool, PartTypeStepStart, PartTypeStepFinish, PartTypeSnapshot, PartTypePatch, PartTypeAgent: + case PartTypeText, PartTypeReasoning, PartTypeFile, PartTypeTool, PartTypeStepStart, PartTypeStepFinish, PartTypeSnapshot, PartTypePatch, PartTypeAgent, PartTypeRetry: return true } return false @@ -1280,16 +1508,17 @@ func (r ReasoningPartType) IsKnown() bool { } type Session struct { - ID string `json:"id,required"` - Directory string `json:"directory,required"` - ProjectID string `json:"projectID,required"` - Time SessionTime `json:"time,required"` - Title string `json:"title,required"` - Version string `json:"version,required"` - ParentID string `json:"parentID"` - Revert SessionRevert `json:"revert"` - Share SessionShare `json:"share"` - JSON sessionJSON `json:"-"` + ID string `json:"id,required"` + Directory string `json:"directory,required"` + ProjectID string `json:"projectID,required"` + Time SessionTime `json:"time,required"` + Title string `json:"title,required"` + Version string `json:"version,required"` + ParentID string `json:"parentID"` + Revert SessionRevert `json:"revert"` + Share SessionShare `json:"share"` + Summary SessionSummary `json:"summary"` + JSON sessionJSON `json:"-"` } // sessionJSON contains the JSON metadata for the struct [Session] @@ -1303,6 +1532,7 @@ type sessionJSON struct { ParentID apijson.Field Revert apijson.Field Share apijson.Field + Summary apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -1385,6 +1615,55 @@ func (r sessionShareJSON) RawJSON() string { return r.raw } +type SessionSummary struct { + Diffs []SessionSummaryDiff `json:"diffs,required"` + JSON sessionSummaryJSON `json:"-"` +} + +// sessionSummaryJSON contains the JSON metadata for the struct [SessionSummary] +type sessionSummaryJSON struct { + Diffs apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *SessionSummary) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r sessionSummaryJSON) RawJSON() string { + return r.raw +} + +type SessionSummaryDiff struct { + Additions float64 `json:"additions,required"` + After string `json:"after,required"` + Before string `json:"before,required"` + Deletions float64 `json:"deletions,required"` + File string `json:"file,required"` + JSON sessionSummaryDiffJSON `json:"-"` +} + +// sessionSummaryDiffJSON contains the JSON metadata for the struct +// [SessionSummaryDiff] +type sessionSummaryDiffJSON struct { + Additions apijson.Field + After apijson.Field + Before apijson.Field + Deletions apijson.Field + File apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *SessionSummaryDiff) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r sessionSummaryDiffJSON) RawJSON() string { + return r.raw +} + type SnapshotPart struct { ID string `json:"id,required"` MessageID string `json:"messageID,required"` @@ -1433,9 +1712,11 @@ type StepFinishPart struct { ID string `json:"id,required"` Cost float64 `json:"cost,required"` MessageID string `json:"messageID,required"` + Reason string `json:"reason,required"` SessionID string `json:"sessionID,required"` Tokens StepFinishPartTokens `json:"tokens,required"` Type StepFinishPartType `json:"type,required"` + Snapshot string `json:"snapshot"` JSON stepFinishPartJSON `json:"-"` } @@ -1444,9 +1725,11 @@ type stepFinishPartJSON struct { ID apijson.Field Cost apijson.Field MessageID apijson.Field + Reason apijson.Field SessionID apijson.Field Tokens apijson.Field Type apijson.Field + Snapshot apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -1530,6 +1813,7 @@ type StepStartPart struct { MessageID string `json:"messageID,required"` SessionID string `json:"sessionID,required"` Type StepStartPartType `json:"type,required"` + Snapshot string `json:"snapshot"` JSON stepStartPartJSON `json:"-"` } @@ -1539,6 +1823,7 @@ type stepStartPartJSON struct { MessageID apijson.Field SessionID apijson.Field Type apijson.Field + Snapshot apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -1872,7 +2157,9 @@ func (r ToolPart) implementsPart() {} type ToolPartState struct { Status ToolPartStateStatus `json:"status,required"` - Error string `json:"error"` + // This field can have the runtime type of [[]FilePart]. + Attachments interface{} `json:"attachments"` + Error string `json:"error"` // This field can have the runtime type of [interface{}], [map[string]interface{}]. Input interface{} `json:"input"` // This field can have the runtime type of [map[string]interface{}]. @@ -1889,6 +2176,7 @@ type ToolPartState struct { // toolPartStateJSON contains the JSON metadata for the struct [ToolPartState] type toolPartStateJSON struct { Status apijson.Field + Attachments apijson.Field Error apijson.Field Input apijson.Field Metadata apijson.Field @@ -1982,13 +2270,14 @@ func (r ToolPartType) IsKnown() bool { } type ToolStateCompleted struct { - Input map[string]interface{} `json:"input,required"` - Metadata map[string]interface{} `json:"metadata,required"` - Output string `json:"output,required"` - Status ToolStateCompletedStatus `json:"status,required"` - Time ToolStateCompletedTime `json:"time,required"` - Title string `json:"title,required"` - JSON toolStateCompletedJSON `json:"-"` + Input map[string]interface{} `json:"input,required"` + Metadata map[string]interface{} `json:"metadata,required"` + Output string `json:"output,required"` + Status ToolStateCompletedStatus `json:"status,required"` + Time ToolStateCompletedTime `json:"time,required"` + Title string `json:"title,required"` + Attachments []FilePart `json:"attachments"` + JSON toolStateCompletedJSON `json:"-"` } // toolStateCompletedJSON contains the JSON metadata for the struct @@ -2000,6 +2289,7 @@ type toolStateCompletedJSON struct { Status apijson.Field Time apijson.Field Title apijson.Field + Attachments apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -2224,11 +2514,12 @@ func (r toolStateRunningTimeJSON) RawJSON() string { } type UserMessage struct { - ID string `json:"id,required"` - Role UserMessageRole `json:"role,required"` - SessionID string `json:"sessionID,required"` - Time UserMessageTime `json:"time,required"` - JSON userMessageJSON `json:"-"` + ID string `json:"id,required"` + Role UserMessageRole `json:"role,required"` + SessionID string `json:"sessionID,required"` + Time UserMessageTime `json:"time,required"` + Summary UserMessageSummary `json:"summary"` + JSON userMessageJSON `json:"-"` } // userMessageJSON contains the JSON metadata for the struct [UserMessage] @@ -2237,6 +2528,7 @@ type userMessageJSON struct { Role apijson.Field SessionID apijson.Field Time apijson.Field + Summary apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -2285,6 +2577,60 @@ func (r userMessageTimeJSON) RawJSON() string { return r.raw } +type UserMessageSummary struct { + Diffs []UserMessageSummaryDiff `json:"diffs,required"` + Body string `json:"body"` + Title string `json:"title"` + JSON userMessageSummaryJSON `json:"-"` +} + +// userMessageSummaryJSON contains the JSON metadata for the struct +// [UserMessageSummary] +type userMessageSummaryJSON struct { + Diffs apijson.Field + Body apijson.Field + Title apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *UserMessageSummary) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r userMessageSummaryJSON) RawJSON() string { + return r.raw +} + +type UserMessageSummaryDiff struct { + Additions float64 `json:"additions,required"` + After string `json:"after,required"` + Before string `json:"before,required"` + Deletions float64 `json:"deletions,required"` + File string `json:"file,required"` + JSON userMessageSummaryDiffJSON `json:"-"` +} + +// userMessageSummaryDiffJSON contains the JSON metadata for the struct +// [UserMessageSummaryDiff] +type userMessageSummaryDiffJSON struct { + Additions apijson.Field + After apijson.Field + Before apijson.Field + Deletions apijson.Field + File apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *UserMessageSummaryDiff) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r userMessageSummaryDiffJSON) RawJSON() string { + return r.raw +} + type SessionCommandResponse struct { Info AssistantMessage `json:"info,required"` Parts []Part `json:"parts,required"` @@ -2542,6 +2888,7 @@ type SessionPromptParams struct { Agent param.Field[string] `json:"agent"` MessageID param.Field[string] `json:"messageID"` Model param.Field[SessionPromptParamsModel] `json:"model"` + NoReply param.Field[bool] `json:"noReply"` System param.Field[string] `json:"system"` Tools param.Field[map[string]bool] `json:"tools"` } diff --git a/packages/sdk/go/session_test.go b/packages/sdk/go/session_test.go index f2263c7bc6..6f910caf2d 100644 --- a/packages/sdk/go/session_test.go +++ b/packages/sdk/go/session_test.go @@ -361,7 +361,8 @@ func TestSessionPromptWithOptionalParams(t *testing.T) { ModelID: opencode.F("modelID"), ProviderID: opencode.F("providerID"), }), - System: opencode.F("system"), + NoReply: opencode.F(true), + System: opencode.F("system"), Tools: opencode.F(map[string]bool{ "foo": true, }), From 49ea5aa2ada1aed3ed5c9fc8debad5a28348d6e8 Mon Sep 17 00:00:00 2001 From: opencode Date: Tue, 28 Oct 2025 15:12:37 +0000 Subject: [PATCH 031/609] release: v0.15.20 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index eec72e6c65..7e1fceab33 100644 --- a/bun.lock +++ b/bun.lock @@ -37,7 +37,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -64,7 +64,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -88,7 +88,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -109,7 +109,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -150,7 +150,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -166,7 +166,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "0.15.19", + "version": "0.15.20", "bin": { "opencode": "./bin/opencode", }, @@ -230,7 +230,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -250,7 +250,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "0.15.19", + "version": "0.15.20", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -261,7 +261,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -274,7 +274,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@kobalte/core": "catalog:", "@pierre/precision-diffs": "catalog:", @@ -297,7 +297,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 868aa18991..0f36562b4e 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "0.15.19" + "version": "0.15.20" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 948e4af274..16de536d60 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "0.15.19", + "version": "0.15.20", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 4be5f460a4..f2cb56d29b 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "0.15.19", + "version": "0.15.20", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index bf62733e71..f93660af7d 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "0.15.19", + "version": "0.15.20", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index e401c22427..a2184a75a0 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "0.15.19", + "version": "0.15.20", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index db56da8de8..b1dd969e26 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "0.15.19", + "version": "0.15.20", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 93a69fbed3..c50d4eae0e 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "0.15.19", + "version": "0.15.20", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 4395fb3e07..27736e2a1c 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "0.15.19", + "version": "0.15.20", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 042e35080d..dbb890f607 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "0.15.19", + "version": "0.15.20", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 5fc872c12d..16756f5a1b 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "0.15.19", + "version": "0.15.20", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index a6d6a0125f..d85dbee58a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "0.15.19", + "version": "0.15.20", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 5337a44467..6cacf9bd05 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "0.15.19", + "version": "0.15.20", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 918cde1361..854797b6e8 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "0.15.19", + "version": "0.15.20", "publisher": "sst-dev", "repository": { "type": "git", From 74acd08eadf4d6078ad0b8aa2da3fd42eed5cb49 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 28 Oct 2025 10:21:32 -0500 Subject: [PATCH 032/609] add catch for mcp tool execution --- packages/opencode/src/session/prompt.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 26a04cb8e8..d27dc24bc0 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -582,7 +582,17 @@ export namespace SessionPrompt { args, }, ) - const result = await execute(args, opts) + const result = await execute(args, opts).catch((err) => { + log.error("Error executing tool", { error: err, tool: key }) + return { + content: [ + { + type: "text", + text: `Failed to execute tool: ${err instanceof Error ? err.message : String(err)}`, + }, + ], + } + }) await Plugin.trigger( "tool.execute.after", From 643c22d21fb438236ed9e218f085aad0c73ca8c1 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 28 Oct 2025 10:22:53 -0500 Subject: [PATCH 033/609] add catch for mcp tool execution --- packages/opencode/src/session/prompt.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index d27dc24bc0..adaa79f31f 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -582,7 +582,7 @@ export namespace SessionPrompt { args, }, ) - const result = await execute(args, opts).catch((err) => { + const result = await execute(args, opts).catch((err: unknown) => { log.error("Error executing tool", { error: err, tool: key }) return { content: [ From eb398f1951764af812c7ef01f37f01da862a852a Mon Sep 17 00:00:00 2001 From: oribi Date: Tue, 28 Oct 2025 18:50:09 +0200 Subject: [PATCH 034/609] add OPENCODE_CONFIG_DIR to allow loading a custom config directory (#3504) Co-authored-by: opencode-agent[bot] Co-authored-by: rekram1-node --- packages/opencode/src/config/config.ts | 5 +++++ packages/opencode/src/flag/flag.ts | 1 + packages/web/src/content/docs/config.mdx | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 4c6003b9e2..42d59226ec 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -61,6 +61,11 @@ export namespace Config { )), ] + if (Flag.OPENCODE_CONFIG_DIR) { + directories.push(Flag.OPENCODE_CONFIG_DIR) + log.debug("loading config from OPENCODE_CONFIG_DIR", { path: Flag.OPENCODE_CONFIG_DIR }) + } + for (const dir of directories) { await assertValid(dir) installDependencies(dir) diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts index 879aa758a7..86ca076520 100644 --- a/packages/opencode/src/flag/flag.ts +++ b/packages/opencode/src/flag/flag.ts @@ -1,6 +1,7 @@ export namespace Flag { export const OPENCODE_AUTO_SHARE = truthy("OPENCODE_AUTO_SHARE") export const OPENCODE_CONFIG = process.env["OPENCODE_CONFIG"] + export const OPENCODE_CONFIG_DIR = process.env["OPENCODE_CONFIG_DIR"] export const OPENCODE_CONFIG_CONTENT = process.env["OPENCODE_CONFIG_CONTENT"] export const OPENCODE_DISABLE_AUTOUPDATE = truthy("OPENCODE_DISABLE_AUTOUPDATE") export const OPENCODE_DISABLE_PRUNE = truthy("OPENCODE_DISABLE_PRUNE") diff --git a/packages/web/src/content/docs/config.mdx b/packages/web/src/content/docs/config.mdx index f3b2a05a09..2a259ff371 100644 --- a/packages/web/src/content/docs/config.mdx +++ b/packages/web/src/content/docs/config.mdx @@ -61,6 +61,22 @@ opencode run "Hello world" --- +### Custom directory + +You can specify a custom config directory using the `OPENCODE_CONFIG_DIR` +environment variable. This directory will be searched for agents, commands, +modes, and plugins just like the standard `.opencode` directory, and should +follow the same structure. + +```bash +export OPENCODE_CONFIG_DIR=/path/to/my/config-directory +opencode run "Hello world" +``` + +Note: The custom directory is loaded after the global config and `.opencode` directories, so it can override their settings. + +--- + ## Schema The config file has a schema that's defined in [**`opencode.ai/config.json`**](https://opencode.ai/config.json). From b66e7b6fce07ff9a225dd225fc198b16718a1239 Mon Sep 17 00:00:00 2001 From: Danilo Favato Date: Tue, 28 Oct 2025 14:09:41 -0300 Subject: [PATCH 035/609] tweak: add experimental chatMaxRetries to config (#2116) Co-authored-by: GitHub Action Co-authored-by: Aiden Cline --- packages/opencode/src/config/config.ts | 1 + packages/opencode/src/session/compaction.ts | 9 ++++++--- packages/opencode/src/session/prompt.ts | 9 ++++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 42d59226ec..83c518a680 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -586,6 +586,7 @@ export namespace Config { .optional(), }) .optional(), + chatMaxRetries: z.number().optional().describe("Number of retries for chat completions on failure"), disable_paste_summary: z.boolean().optional(), }) .optional(), diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 657ac4475c..4896d5f5ed 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -16,6 +16,7 @@ import { Log } from "../util/log" import { SessionLock } from "./lock" import { ProviderTransform } from "@/provider/transform" import { SessionRetry } from "./retry" +import { Config } from "@/config/config" export namespace SessionCompaction { const log = Log.create({ service: "session.compaction" }) @@ -258,12 +259,14 @@ export namespace SessionCompaction { } let stream = doStream() + const cfg = await Config.get() + const maxRetries = cfg.experimental?.chatMaxRetries ?? MAX_RETRIES let result = await process(stream, { count: 0, - max: MAX_RETRIES, + max: maxRetries, }) if (result.shouldRetry) { - for (let retry = 1; retry < MAX_RETRIES; retry++) { + for (let retry = 1; retry < maxRetries; retry++) { const lastRetryPart = result.parts.findLast((p) => p.type === "retry") if (lastRetryPart) { @@ -300,7 +303,7 @@ export namespace SessionCompaction { stream = doStream() result = await process(stream, { count: retry, - max: MAX_RETRIES, + max: maxRetries, }) if (!result.shouldRetry) { break diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index adaa79f31f..4d1aa02113 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -50,6 +50,7 @@ import { Command } from "../command" import { $, fileURLToPath } from "bun" import { ConfigMarkdown } from "../config/markdown" import { SessionSummary } from "./summary" +import { Config } from "@/config/config" export namespace SessionPrompt { const log = Log.create({ service: "session.prompt" }) @@ -330,12 +331,14 @@ export namespace SessionPrompt { }) let stream = doStream() + const cfg = await Config.get() + const maxRetries = cfg.experimental?.chatMaxRetries ?? MAX_RETRIES let result = await processor.process(stream, { count: 0, - max: MAX_RETRIES, + max: maxRetries, }) if (result.shouldRetry) { - for (let retry = 1; retry < MAX_RETRIES; retry++) { + for (let retry = 1; retry < maxRetries; retry++) { const lastRetryPart = result.parts.findLast((p) => p.type === "retry") if (lastRetryPart) { @@ -372,7 +375,7 @@ export namespace SessionPrompt { stream = doStream() result = await processor.process(stream, { count: retry, - max: MAX_RETRIES, + max: maxRetries, }) if (!result.shouldRetry) { break From c1515316f54f129aa7f504d1cee79476c194c797 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 28 Oct 2025 14:08:10 -0400 Subject: [PATCH 036/609] core: fix additions and deletions counting in edit tool filediff --- packages/opencode/src/tool/edit.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index a8e6fc3b65..7429c44b83 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -7,7 +7,7 @@ import z from "zod" import * as path from "path" import { Tool } from "./tool" import { LSP } from "../lsp" -import { createTwoFilesPatch } from "diff" +import { createTwoFilesPatch, diffLines } from "diff" import { Permission } from "../permission" import DESCRIPTION from "./edit.txt" import { File } from "../file" @@ -16,6 +16,7 @@ import { FileTime } from "../file/time" import { Filesystem } from "../util/filesystem" import { Instance } from "../project/instance" import { Agent } from "../agent/agent" +import { Snapshot } from "@/snapshot" export const EditTool = Tool.define("edit", { description: DESCRIPTION, @@ -114,10 +115,23 @@ export const EditTool = Tool.define("edit", { } } + const filediff: Snapshot.FileDiff = { + file: filePath, + before: contentOld, + after: contentNew, + additions: 0, + deletions: 0, + } + for (const change of diffLines(contentOld, contentNew)) { + if (change.added) filediff.additions += change.count || 0 + if (change.removed) filediff.deletions += change.count || 0 + } + return { metadata: { diagnostics, diff, + filediff, }, title: `${path.relative(Instance.worktree, filePath)}`, output, From 1309ca7a812cdd548163d7bf8f21cb3c412c040f Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 28 Oct 2025 14:13:47 -0400 Subject: [PATCH 037/609] ignore --- packages/opencode/src/session/summary.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/session/summary.ts b/packages/opencode/src/session/summary.ts index 0e231e6fa5..2a31f39ea5 100644 --- a/packages/opencode/src/session/summary.ts +++ b/packages/opencode/src/session/summary.ts @@ -86,7 +86,7 @@ export namespace SessionSummary { ) { const result = await generateText({ model: small.language, - maxOutputTokens: 50, + maxOutputTokens: 100, messages: [ { role: "user", From 37380e1f945f215be65d108bc8094e0f23b0d897 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:32:36 -0500 Subject: [PATCH 038/609] add --title flag to opencode run (#3507) --- packages/opencode/src/cli/cmd/run.ts | 18 +++++++++++++++++- packages/opencode/src/session/index.ts | 12 +++++++++--- packages/opencode/src/session/prompt.ts | 1 + 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index 60788c7d86..7bde4a3146 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -78,6 +78,10 @@ export const RunCommand = cmd({ array: true, describe: "file(s) to attach to message", }) + .option("title", { + type: "string", + describe: "title for the session (uses truncated prompt if no value provided)", + }) }, handler: async (args) => { let message = args.message.join(" ") @@ -143,7 +147,19 @@ export const RunCommand = cmd({ if (args.session) return Session.get(args.session) - return Session.create({}) + const title = (() => { + if (args.title !== undefined) { + if (args.title === "") { + return message.slice(0, 50) + (message.length > 50 ? "..." : "") + } + return args.title + } + return undefined + })() + + return Session.create({ + title, + }) })() if (!session) { diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index ff9f436e2f..2cd1bcd298 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -23,11 +23,17 @@ import { Snapshot } from "@/snapshot" export namespace Session { const log = Log.create({ service: "session" }) - const parentSessionTitlePrefix = "New session - " - const childSessionTitlePrefix = "Child session - " + const parentTitlePrefix = "New session - " + const childTitlePrefix = "Child session - " function createDefaultTitle(isChild = false) { - return (isChild ? childSessionTitlePrefix : parentSessionTitlePrefix) + new Date().toISOString() + return (isChild ? childTitlePrefix : parentTitlePrefix) + new Date().toISOString() + } + + export function isDefaultTitle(title: string) { + return new RegExp( + `^(${parentTitlePrefix}|${childTitlePrefix})\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$`, + ).test(title) } export const Info = z diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 4d1aa02113..144d61d186 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1703,6 +1703,7 @@ export namespace SessionPrompt { modelID: string }) { if (input.session.parentID) return + if (!Session.isDefaultTitle(input.session.title)) return const isFirst = input.history.filter((m) => m.info.role === "user" && !m.parts.every((p) => "synthetic" in p && p.synthetic)) .length === 1 From e29dd27632da70d6e716fbca8a909b8361e8187f Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 28 Oct 2025 15:55:01 -0400 Subject: [PATCH 039/609] zen: provider affinity --- packages/console/app/src/routes/zen/util/handler.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 85ba5eea1e..f7a1f0e163 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -43,7 +43,7 @@ export async function handler( }) const zenData = ZenData.list() const modelInfo = validateModel(zenData, body.model) - const providerInfo = selectProvider(zenData, modelInfo) + const providerInfo = selectProvider(zenData, modelInfo, input.request.headers.get("x-real-ip") ?? "") const authInfo = await authenticate(modelInfo, providerInfo) validateBilling(modelInfo, authInfo) validateModelSettings(authInfo) @@ -222,11 +222,15 @@ export async function handler( return { id: modelId, ...modelData } } - function selectProvider(zenData: ZenData, model: Awaited>) { + function selectProvider(zenData: ZenData, model: Awaited>, ip: string) { const providers = model.providers .filter((provider) => !provider.disabled) .flatMap((provider) => Array(provider.weight ?? 1).fill(provider)) - const provider = providers[Math.floor(Math.random() * providers.length)] + + // Use last character of IP address to select a provider + const lastChar = ip.charCodeAt(ip.length - 1) || 0 + const index = lastChar % providers.length + const provider = providers[index] if (!(provider.id in zenData.providers)) { throw new ModelError(`Provider ${provider.id} not supported`) From 1da24f6adb7fce37af79678dd053090831fda2f2 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 28 Oct 2025 06:20:43 -0500 Subject: [PATCH 040/609] wip: desktop work --- packages/desktop/index.html | 2 +- .../desktop/src/components/assistant-message.tsx | 14 +++++++------- packages/desktop/src/components/prompt-input.tsx | 2 +- packages/desktop/src/pages/index.tsx | 6 +++--- packages/desktop/src/utils/path.ts | 6 +++++- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/desktop/index.html b/packages/desktop/index.html index c591cb46c6..9209acfc7e 100644 --- a/packages/desktop/index.html +++ b/packages/desktop/index.html @@ -7,7 +7,7 @@ OpenCode - + diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx index 38c06bbe55..7b4cfc71df 100644 --- a/packages/desktop/src/components/assistant-message.tsx +++ b/packages/desktop/src/components/assistant-message.tsx @@ -1,11 +1,11 @@ import type { Part, AssistantMessage, ReasoningPart, TextPart, ToolPart } from "@opencode-ai/sdk" -import type { Tool } from "opencode/tool/tool" -import type { ReadTool } from "opencode/tool/read" import { children, Component, createMemo, For, Match, Show, Switch, type JSX } from "solid-js" import { Dynamic } from "solid-js/web" import { Markdown } from "./markdown" import { Collapsible, Icon, IconProps } from "@opencode-ai/ui" import { getDirectory, getFilename } from "@/utils" +import type { Tool } from "opencode/tool/tool" +import type { ReadTool } from "opencode/tool/read" import type { ListTool } from "opencode/tool/ls" import type { GlobTool } from "opencode/tool/glob" import type { GrepTool } from "opencode/tool/grep" @@ -188,7 +188,7 @@ ToolRegistry.register({ name: "list", render(props) { return ( - +
{props.output}
@@ -205,7 +205,7 @@ ToolRegistry.register({ icon="magnifying-glass-menu" trigger={{ title: props.tool, - subtitle: props.input.path || "/", + subtitle: getDirectory(props.input.path || "/"), args: props.input.pattern ? ["pattern=" + props.input.pattern] : [], }} > @@ -228,7 +228,7 @@ ToolRegistry.register({ icon="magnifying-glass-menu" trigger={{ title: props.tool, - subtitle: props.input.path || "/", + subtitle: getDirectory(props.input.path || "/"), args, }} > @@ -315,7 +315,7 @@ ToolRegistry.register({
Edit
- {getDirectory(props.input.filePath!)}/ + {getDirectory(props.input.filePath!)} {getFilename(props.input.filePath ?? "")}
@@ -344,7 +344,7 @@ ToolRegistry.register({
Write
- {getDirectory(props.input.filePath!)}/ + {getDirectory(props.input.filePath!)} {getFilename(props.input.filePath ?? "")}
diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 3838d19ba1..dd549a0454 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -289,7 +289,7 @@ export const PromptInput: Component = (props) => {
- {getDirectory(i)}/ + {getDirectory(i)} {getFilename(i)}
diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx index 15da87bd67..7da9254598 100644 --- a/packages/desktop/src/pages/index.tsx +++ b/packages/desktop/src/pages/index.tsx @@ -521,7 +521,7 @@ export default function Page() {
- {getDirectory(sync.data.path.directory)}/ + {getDirectory(sync.data.path.directory)} {getFilename(sync.data.path.directory)}
@@ -705,7 +705,7 @@ export default function Page() {
- {getDirectory(diff.file)}/ + {getDirectory(diff.file)} @@ -858,7 +858,7 @@ export default function Page() {
- {getDirectory(i)}/ + {getDirectory(i)} {getFilename(i)}
diff --git a/packages/desktop/src/utils/path.ts b/packages/desktop/src/utils/path.ts index 3ae48cdb31..d23568ae63 100644 --- a/packages/desktop/src/utils/path.ts +++ b/packages/desktop/src/utils/path.ts @@ -1,3 +1,5 @@ +import { useSync } from "@/context/sync" + export function getFilename(path: string) { if (!path) return "" const trimmed = path.replace(/[\/]+$/, "") @@ -6,8 +8,10 @@ export function getFilename(path: string) { } export function getDirectory(path: string) { + const sync = useSync() const parts = path.split("/") - return parts.slice(0, parts.length - 1).join("/") + const dir = parts.slice(0, parts.length - 1).join("/") + return dir ? sync.sanitize(dir + "/") : "" } export function getFileExtension(path: string) { From d36485b7af9646f78fdab84c174cede47ddc4c60 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 28 Oct 2025 06:43:09 -0500 Subject: [PATCH 041/609] wip: desktop work --- packages/desktop/package.json | 3 ++- packages/ui/package.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/desktop/package.json b/packages/desktop/package.json index a2184a75a0..936bd8f5af 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -7,7 +7,8 @@ "start": "vite", "dev": "vite", "build": "vite build", - "serve": "vite preview" + "serve": "vite preview", + "typecheck": "tsgo --noEmit" }, "license": "MIT", "devDependencies": { diff --git a/packages/ui/package.json b/packages/ui/package.json index d85dbee58a..a57f91418c 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -12,6 +12,7 @@ }, "scripts": { "dev": "vite", + "typecheck": "tsgo --noEmit", "generate:tailwind": "bun run script/tailwind.ts" }, "devDependencies": { From 4e0ab6b6346606bc07918c6d10981729994d0cc7 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:48:54 -0500 Subject: [PATCH 042/609] wip: desktop work --- .../src/components/assistant-message.tsx | 111 +++++++++++++----- packages/desktop/src/pages/index.tsx | 14 +-- packages/ui/src/styles/tailwind/utilities.css | 8 ++ packages/ui/src/styles/utilities.css | 8 ++ 4 files changed, 103 insertions(+), 38 deletions(-) diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx index 7b4cfc71df..248af53132 100644 --- a/packages/desktop/src/components/assistant-message.tsx +++ b/packages/desktop/src/components/assistant-message.tsx @@ -15,11 +15,13 @@ import type { BashTool } from "opencode/tool/bash" import type { EditTool } from "opencode/tool/edit" import type { WriteTool } from "opencode/tool/write" import { DiffChanges } from "./diff-changes" +import { TodoWriteTool } from "opencode/tool/todo" export function AssistantMessage(props: { message: AssistantMessage; parts: Part[] }) { + const filteredParts = createMemo(() => props.parts.filter((x) => x.type !== "tool" || x.tool !== "todoread")) return (
- + {(part) => { const component = createMemo(() => PART_MAPPING[part.type as keyof typeof PART_MAPPING]) return ( @@ -88,8 +90,11 @@ function ToolPart(props: { part: ToolPart; message: AssistantMessage }) { type TriggerTitle = { title: string + titleClass?: string subtitle?: string + subtitleClass?: string args?: string[] + argsClass?: string action?: JSX.Element } @@ -99,34 +104,58 @@ const isTriggerTitle = (val: any): val is TriggerTitle => { function BasicTool(props: { icon: IconProps["name"]; trigger: TriggerTitle | JSX.Element; children?: JSX.Element }) { const resolved = children(() => props.children) - return (
- - - -
-
- - {(props.trigger as TriggerTitle).title} - - - {(props.trigger as TriggerTitle).subtitle} - - - - {(arg) => {arg}} - - -
- {(props.trigger as TriggerTitle).action} -
-
- {props.trigger as JSX.Element} -
+ +
+ + + {(trigger) => ( +
+
+ + {trigger().title} + + + + {trigger().subtitle} + + + + + {(arg) => ( + + {arg} + + )} + + +
+ {trigger().action} +
+ )} +
+ {props.trigger as JSX.Element} +
+
@@ -178,7 +207,7 @@ ToolRegistry.register({ return ( ) }, @@ -188,7 +217,7 @@ ToolRegistry.register({ name: "list", render(props) { return ( - +
{props.output}
@@ -204,7 +233,7 @@ ToolRegistry.register({ ({ @@ -311,7 +341,7 @@ ToolRegistry.register({ icon="code-lines" trigger={
-
+
Edit
@@ -340,7 +370,7 @@ ToolRegistry.register({ icon="code-lines" trigger={
-
+
Write
@@ -360,3 +390,22 @@ ToolRegistry.register({ ) }, }) + +ToolRegistry.register({ + name: "todowrite", + render(props) { + return ( + t.status === "completed").length}/${props.input.todos?.length}`, + }} + > + +
{props.output}
+
+
+ ) + }, +}) diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx index 7da9254598..42e96e32e6 100644 --- a/packages/desktop/src/pages/index.tsx +++ b/packages/desktop/src/pages/index.tsx @@ -696,24 +696,24 @@ export default function Page() { -
-
+
+
-
+
- - {getDirectory(diff.file)} + + {getDirectory(diff.file)}‎ - + {getFilename(diff.file)}
-
+
diff --git a/packages/ui/src/styles/tailwind/utilities.css b/packages/ui/src/styles/tailwind/utilities.css index f3bedca375..fbb407b1d6 100644 --- a/packages/ui/src/styles/tailwind/utilities.css +++ b/packages/ui/src/styles/tailwind/utilities.css @@ -7,3 +7,11 @@ scrollbar-width: none; /* Firefox */ } } + +@utility truncate-start { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + direction: rtl; + text-align: left; +} diff --git a/packages/ui/src/styles/utilities.css b/packages/ui/src/styles/utilities.css index 7d14b6539f..99b7760a00 100644 --- a/packages/ui/src/styles/utilities.css +++ b/packages/ui/src/styles/utilities.css @@ -48,6 +48,14 @@ border-width: 0; } +.truncate-start { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + direction: rtl; + text-align: left; +} + .text-12-regular { font-family: var(--font-family-sans); font-size: var(--font-size-small); From a7a88d01efc9d0d8d0c9d273c275f37d1277b43f Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:49:28 -0500 Subject: [PATCH 043/609] wip: desktop work --- packages/desktop/package.json | 3 +-- packages/ui/package.json | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 936bd8f5af..a2184a75a0 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -7,8 +7,7 @@ "start": "vite", "dev": "vite", "build": "vite build", - "serve": "vite preview", - "typecheck": "tsgo --noEmit" + "serve": "vite preview" }, "license": "MIT", "devDependencies": { diff --git a/packages/ui/package.json b/packages/ui/package.json index a57f91418c..d85dbee58a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -12,7 +12,6 @@ }, "scripts": { "dev": "vite", - "typecheck": "tsgo --noEmit", "generate:tailwind": "bun run script/tailwind.ts" }, "devDependencies": { From c1278109c9600ded4ab937686d4c7288fda2524d Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:46:46 -0500 Subject: [PATCH 044/609] wip: desktop work --- .../src/components/assistant-message.tsx | 19 ++- packages/ui/src/components/checkbox.css | 121 ++++++++++++++++++ packages/ui/src/components/checkbox.tsx | 44 +++++++ packages/ui/src/components/index.ts | 1 + packages/ui/src/demo.tsx | 25 ++++ packages/ui/src/styles/index.css | 1 + 6 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 packages/ui/src/components/checkbox.css create mode 100644 packages/ui/src/components/checkbox.tsx diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx index 248af53132..cfc9d1a495 100644 --- a/packages/desktop/src/components/assistant-message.tsx +++ b/packages/desktop/src/components/assistant-message.tsx @@ -2,7 +2,7 @@ import type { Part, AssistantMessage, ReasoningPart, TextPart, ToolPart } from " import { children, Component, createMemo, For, Match, Show, Switch, type JSX } from "solid-js" import { Dynamic } from "solid-js/web" import { Markdown } from "./markdown" -import { Collapsible, Icon, IconProps } from "@opencode-ai/ui" +import { Checkbox, Collapsible, Icon, IconProps } from "@opencode-ai/ui" import { getDirectory, getFilename } from "@/utils" import type { Tool } from "opencode/tool/tool" import type { ReadTool } from "opencode/tool/read" @@ -14,11 +14,11 @@ import type { TaskTool } from "opencode/tool/task" import type { BashTool } from "opencode/tool/bash" import type { EditTool } from "opencode/tool/edit" import type { WriteTool } from "opencode/tool/write" +import type { TodoWriteTool } from "opencode/tool/todo" import { DiffChanges } from "./diff-changes" -import { TodoWriteTool } from "opencode/tool/todo" export function AssistantMessage(props: { message: AssistantMessage; parts: Part[] }) { - const filteredParts = createMemo(() => props.parts.filter((x) => x.type !== "tool" || x.tool !== "todoread")) + const filteredParts = createMemo(() => props.parts?.filter((x) => x.type !== "tool" || x.tool !== "todoread")) return (
@@ -394,6 +394,7 @@ ToolRegistry.register({ ToolRegistry.register({ name: "todowrite", render(props) { + console.log(props.input.todos) return ( ({ subtitle: `${props.input.todos?.filter((t) => t.status === "completed").length}/${props.input.todos?.length}`, }} > - -
{props.output}
+ +
+ + {(todo) => ( + +
{todo.content}
+
+ )} +
+
) diff --git a/packages/ui/src/components/checkbox.css b/packages/ui/src/components/checkbox.css new file mode 100644 index 0000000000..6e1e5ddd5e --- /dev/null +++ b/packages/ui/src/components/checkbox.css @@ -0,0 +1,121 @@ +[data-component="checkbox"] { + display: flex; + align-items: center; + gap: 12px; + cursor: default; + + [data-slot="checkbox-input"] { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } + + [data-slot="checkbox-control"] { + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + padding: 2px; + aspect-ratio: 1; + flex-shrink: 0; + border-radius: 4px; + border: 1px solid var(--border-weak-base); + /* background-color: var(--surface-weak); */ + } + + [data-slot="checkbox-indicator"] { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + color: var(--icon-base); + opacity: 0; + } + + /* [data-slot="checkbox-content"] { */ + /* } */ + + [data-slot="checkbox-label"] { + user-select: none; + color: var(--text-base); + + /* text-12-regular */ + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-style: normal; + font-weight: var(--font-weight-regular); + line-height: var(--line-height-large); /* 166.667% */ + letter-spacing: var(--letter-spacing-normal); + } + + [data-slot="checkbox-description"] { + color: var(--text-base); + font-family: var(--font-family-sans); + font-size: 12px; + font-weight: var(--font-weight-regular); + line-height: var(--line-height-normal); + letter-spacing: var(--letter-spacing-normal); + } + + [data-slot="checkbox-error"] { + color: var(--text-error); + font-family: var(--font-family-sans); + font-size: 12px; + font-weight: var(--font-weight-regular); + line-height: var(--line-height-normal); + letter-spacing: var(--letter-spacing-normal); + } + + &:hover:not([data-disabled], [data-readonly]) [data-slot="checkbox-control"] { + border-color: var(--border-hover); + background-color: var(--surface-hover); + } + + &:focus-within:not([data-readonly]) [data-slot="checkbox-control"] { + border-color: var(--border-focus); + box-shadow: 0 0 0 2px var(--surface-focus); + } + + &[data-checked] [data-slot="checkbox-control"], + &[data-indeterminate] [data-slot="checkbox-control"] { + border-color: var(--border-base); + background-color: var(--surface-weak); + } + + &[data-checked]:hover:not([data-disabled], [data-readonly]) [data-slot="checkbox-control"], + &[data-indeterminate]:hover:not([data-disabled]) [data-slot="checkbox-control"] { + border-color: var(--border-hover); + background-color: var(--surface-hover); + } + + &[data-checked] [data-slot="checkbox-indicator"], + &[data-indeterminate] [data-slot="checkbox-indicator"] { + opacity: 1; + } + + &[data-disabled] { + cursor: not-allowed; + } + + &[data-disabled] [data-slot="checkbox-control"] { + border-color: var(--border-disabled); + background-color: var(--surface-disabled); + } + + &[data-invalid] [data-slot="checkbox-control"] { + border-color: var(--border-error); + } + + &[data-readonly] { + cursor: default; + pointer-events: none; + } +} diff --git a/packages/ui/src/components/checkbox.tsx b/packages/ui/src/components/checkbox.tsx new file mode 100644 index 0000000000..2009a430b9 --- /dev/null +++ b/packages/ui/src/components/checkbox.tsx @@ -0,0 +1,44 @@ +import { Checkbox as Kobalte } from "@kobalte/core/checkbox" +import { children, Show, splitProps } from "solid-js" +import type { ComponentProps, JSX, ParentProps } from "solid-js" + +export interface CheckboxProps extends ParentProps> { + hideLabel?: boolean + description?: string + icon?: JSX.Element +} + +export function Checkbox(props: CheckboxProps) { + const [local, others] = splitProps(props, ["children", "class", "label", "hideLabel", "description", "icon"]) + const resolved = children(() => local.children) + return ( + + + + + {local.icon || ( + + + + )} + + +
+ + + {resolved()} + + + + {local.description} + + +
+
+ ) +} diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index 31672001b1..0024c9e76f 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -1,5 +1,6 @@ export * from "./accordion" export * from "./button" +export * from "./checkbox" export * from "./collapsible" export * from "./dialog" export * from "./icon" diff --git a/packages/ui/src/demo.tsx b/packages/ui/src/demo.tsx index 7912818154..5893ca7516 100644 --- a/packages/ui/src/demo.tsx +++ b/packages/ui/src/demo.tsx @@ -3,6 +3,7 @@ import { createSignal } from "solid-js" import { Accordion, Button, + Checkbox, Select, Tabs, Tooltip, @@ -21,6 +22,8 @@ const Demo: Component = () => { const [dialogOpen, setDialogOpen] = createSignal(false) const [selectDialogOpen, setSelectDialogOpen] = createSignal(false) const [inputValue, setInputValue] = createSignal("") + const [checked, setChecked] = createSignal(false) + const [termsAccepted, setTermsAccepted] = createSignal(false) const Content = (props: { dark?: boolean }) => (
@@ -143,6 +146,28 @@ const Demo: Component = () => { +

Checkbox

+
+ + + + + + + + +

Icons

diff --git a/packages/ui/src/styles/index.css b/packages/ui/src/styles/index.css index 7d426a83e6..7ae6b73e44 100644 --- a/packages/ui/src/styles/index.css +++ b/packages/ui/src/styles/index.css @@ -7,6 +7,7 @@ @import "../components/accordion.css" layer(components); @import "../components/button.css" layer(components); +@import "../components/checkbox.css" layer(components); @import "../components/collapsible.css" layer(components); @import "../components/dialog.css" layer(components); @import "../components/icon.css" layer(components); From 77ae0b527e4b1a8277b0391d0acbc7d82b08e4ea Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 28 Oct 2025 12:15:46 -0500 Subject: [PATCH 045/609] wip: desktop work --- bun.lock | 38 +--------- package.json | 2 +- packages/desktop/package.json | 2 +- .../src/components/assistant-message.tsx | 1 - packages/desktop/src/pages/index.tsx | 5 +- packages/ui/src/components/diff.css | 24 ++++++ .../{desktop => ui}/src/components/diff.tsx | 32 ++++---- packages/ui/src/components/index.ts | 1 + packages/ui/src/styles/colors.css | 76 ++++--------------- packages/ui/src/styles/index.css | 1 + 10 files changed, 59 insertions(+), 123 deletions(-) create mode 100644 packages/ui/src/components/diff.css rename packages/{desktop => ui}/src/components/diff.tsx (79%) diff --git a/bun.lock b/bun.lock index 7e1fceab33..e976f47c41 100644 --- a/bun.lock +++ b/bun.lock @@ -344,7 +344,7 @@ "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.3.2", + "@pierre/precision-diffs": "0.3.5", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "@tsconfig/bun": "1.0.9", @@ -3498,8 +3498,6 @@ "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], - "@opencode-ai/ui/@pierre/precision-diffs": ["@pierre/precision-diffs@0.3.2", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-HE+wFB0TV+wmjur/J+qI5PsRQl5RN6tCEFTusW0S5FDfZJUIpkxJCacqUxyEI0DriXMKhgGQ+oCQShfaFELdrQ=="], - "@opencode-ai/web/@shikijs/transformers": ["@shikijs/transformers@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/types": "3.4.2" } }, "sha512-I5baLVi/ynLEOZoWSAMlACHNnG+yw5HDmse0oe+GW6U1u+ULdEB3UHiVWaHoJSSONV7tlcVxuaMy74sREDkSvg=="], "@opencode-ai/web/@types/luxon": ["@types/luxon@3.6.2", "", {}, "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw=="], @@ -3736,8 +3734,6 @@ "nypm/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], - "opencode/@pierre/precision-diffs": ["@pierre/precision-diffs@0.3.2", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-HE+wFB0TV+wmjur/J+qI5PsRQl5RN6tCEFTusW0S5FDfZJUIpkxJCacqUxyEI0DriXMKhgGQ+oCQShfaFELdrQ=="], - "opencode/ulid": ["ulid@3.0.1", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-dPJyqPzx8preQhqq24bBG1YNkvigm87K8kVEHCD+ruZg24t6IFEFv00xMWfxcC4djmFtiTLdFuADn4+DOz6R7Q=="], "opencontrol/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.6.1", "", { "dependencies": { "content-type": "^1.0.5", "cors": "^2.8.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^4.1.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-oxzMzYCkZHMntzuyerehK3fV6A2Kwh5BD6CGEJSVDU2QNEhfLOptf2X7esQgaHZXHZY0oHmMsOtIDLP71UJXgA=="], @@ -4072,10 +4068,6 @@ "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="], - "@opencode-ai/ui/@pierre/precision-diffs/@shikijs/transformers": ["@shikijs/transformers@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/types": "3.13.0" } }, "sha512-833lcuVzcRiG+fXvgslWsM2f4gHpjEgui1ipIknSizRuTgMkNZupiXE5/TVJ6eSYfhNBFhBZKkReKWO2GgYmqA=="], - - "@opencode-ai/ui/@pierre/precision-diffs/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="], - "@opencode-ai/web/@shikijs/transformers/@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="], "@opencode-ai/web/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.4.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg=="], @@ -4242,10 +4234,6 @@ "nypm/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], - "opencode/@pierre/precision-diffs/@shikijs/transformers": ["@shikijs/transformers@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/types": "3.13.0" } }, "sha512-833lcuVzcRiG+fXvgslWsM2f4gHpjEgui1ipIknSizRuTgMkNZupiXE5/TVJ6eSYfhNBFhBZKkReKWO2GgYmqA=="], - - "opencode/@pierre/precision-diffs/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="], - "opencontrol/@modelcontextprotocol/sdk/express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], "opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="], @@ -4426,18 +4414,6 @@ "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], - "@opencode-ai/ui/@pierre/precision-diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], - - "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="], - - "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="], - - "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="], - - "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="], - - "@opencode-ai/ui/@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], - "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], "@vercel/nft/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -4460,18 +4436,6 @@ "nitropack/serve-static/send/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], - "opencode/@pierre/precision-diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], - - "opencode/@pierre/precision-diffs/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="], - - "opencode/@pierre/precision-diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="], - - "opencode/@pierre/precision-diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="], - - "opencode/@pierre/precision-diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="], - - "opencode/@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], - "opencontrol/@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "opencontrol/@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], diff --git a/package.json b/package.json index a5e5217977..151fa4d911 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@tsconfig/bun": "1.0.9", "@cloudflare/workers-types": "4.20251008.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.3.2", + "@pierre/precision-diffs": "0.3.5", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "diff": "8.0.2", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index a2184a75a0..3861c49bda 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -26,7 +26,7 @@ "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", "@opencode-ai/ui": "workspace:*", - "@pierre/precision-diffs": "0.3.5", + "@pierre/precision-diffs": "catalog:", "@shikijs/transformers": "3.9.2", "@solid-primitives/active-element": "2.1.3", "@solid-primitives/event-bus": "1.1.2", diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx index cfc9d1a495..738293405e 100644 --- a/packages/desktop/src/components/assistant-message.tsx +++ b/packages/desktop/src/components/assistant-message.tsx @@ -394,7 +394,6 @@ ToolRegistry.register({ ToolRegistry.register({ name: "todowrite", render(props) { - console.log(props.input.todos) return (
-
+
{(message) => { const title = createMemo(() => message.summary?.title) diff --git a/packages/ui/src/components/diff.css b/packages/ui/src/components/diff.css new file mode 100644 index 0000000000..6f9a0d73dd --- /dev/null +++ b/packages/ui/src/components/diff.css @@ -0,0 +1,24 @@ +[data-component="diff"] { + [data-slot="diff-hunk-separator-line-number"] { + position: sticky; + left: 0; + background-color: hsla(209, 96%, 90%, 1); + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + + [data-slot="diff-hunk-separator-line-number-icon"] { + aspect-ratio: 1; + width: 24px; + height: 24px; + } + } + [data-slot="diff-hunk-separator-content"] { + position: sticky; + background-color: hsla(210, 100%, 96%, 1); + width: var(--pjs-column-content-width); + left: var(--pjs-column-number-width); + padding-left: 8px; + } +} diff --git a/packages/desktop/src/components/diff.tsx b/packages/ui/src/components/diff.tsx similarity index 79% rename from packages/desktop/src/components/diff.tsx rename to packages/ui/src/components/diff.tsx index c39ad852e5..88215bcb0e 100644 --- a/packages/desktop/src/components/diff.tsx +++ b/packages/ui/src/components/diff.tsx @@ -97,24 +97,19 @@ export function Diff(props: DiffProps) { // // 'simple': // Just a subtle bar separator between each hunk - hunkSeparators: "line-info", - // hunkSeparators(hunkData: HunkData) { - // const fragment = document.createDocumentFragment() - // const numCol = document.createElement("div") - // numCol.textContent = `${hunkData.lines}` - // numCol.style.position = "sticky" - // numCol.style.left = "0" - // numCol.style.backgroundColor = "var(--pjs-bg)" - // numCol.style.zIndex = "2" - // fragment.appendChild(numCol) - // const contentCol = document.createElement("div") - // contentCol.textContent = "unmodified lines" - // contentCol.style.position = "sticky" - // contentCol.style.width = "var(--pjs-column-content-width)" - // contentCol.style.left = "var(--pjs-column-number-width)" - // fragment.appendChild(contentCol) - // return fragment - // }, + // hunkSeparators: "line-info", + hunkSeparators(hunkData: HunkData) { + const fragment = document.createDocumentFragment() + const numCol = document.createElement("div") + numCol.innerHTML = ` ` + numCol.dataset["slot"] = "diff-hunk-separator-line-number" + fragment.appendChild(numCol) + const contentCol = document.createElement("div") + contentCol.textContent = `${hunkData.lines} unmodified lines` + contentCol.dataset["slot"] = "diff-hunk-separator-content" + fragment.appendChild(contentCol) + return fragment + }, // On lines that have both additions and deletions, we can run a // separate diff check to mark parts of the lines that change. // 'none': @@ -162,6 +157,7 @@ export function Diff(props: DiffProps) { return (
Date: Tue, 28 Oct 2025 15:29:11 -0500 Subject: [PATCH 046/609] wip: desktop work --- .../src/components/assistant-message.tsx | 33 +++-- .../desktop/src/components/prompt-input.tsx | 59 +++++--- packages/desktop/src/context/local.tsx | 12 +- packages/desktop/src/pages/index.tsx | 136 +++++++++--------- packages/ui/src/components/collapsible.css | 21 +++ packages/ui/src/components/collapsible.tsx | 4 +- packages/ui/src/styles/utilities.css | 29 ++++ 7 files changed, 187 insertions(+), 107 deletions(-) diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx index 738293405e..224e3d3902 100644 --- a/packages/desktop/src/components/assistant-message.tsx +++ b/packages/desktop/src/components/assistant-message.tsx @@ -17,8 +17,15 @@ import type { WriteTool } from "opencode/tool/write" import type { TodoWriteTool } from "opencode/tool/todo" import { DiffChanges } from "./diff-changes" -export function AssistantMessage(props: { message: AssistantMessage; parts: Part[] }) { - const filteredParts = createMemo(() => props.parts?.filter((x) => x.type !== "tool" || x.tool !== "todoread")) +export function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; lastToolOnly?: boolean }) { + const filteredParts = createMemo(() => { + let tool = false + return props.parts?.filter((x) => { + if (x.type === "tool" && props.lastToolOnly && tool) return false + if (x.type === "tool") tool = true + return x.type !== "tool" || x.tool !== "todoread" + }) + }) return (
@@ -71,17 +78,14 @@ function ToolPart(props: { part: ToolPart; message: AssistantMessage }) { // const permission = permissions[permissionIndex] return ( - <> - - {/* {props.part.state.error.replace("Error: ", "")} */} - + ) }) @@ -166,6 +170,9 @@ function BasicTool(props: { icon: IconProps["name"]; trigger: TriggerTitle | JSX {props.children} + // <> + // {props.part.state.error.replace("Error: ", "")} + // ) } diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index dd549a0454..e6701bddc5 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -10,13 +10,15 @@ import { DateTime } from "luxon" interface PartBase { content: string + start: number + end: number } -interface TextPart extends PartBase { +export interface TextPart extends PartBase { type: "text" } -interface FileAttachmentPart extends PartBase { +export interface FileAttachmentPart extends PartBase { type: "file" path: string selection?: TextSelection @@ -34,7 +36,7 @@ export const PromptInput: Component = (props) => { const local = useLocal() let editorRef!: HTMLDivElement - const defaultParts = [{ type: "text", content: "" } as const] + const defaultParts = [{ type: "text", content: "", start: 0, end: 0 } as const] const [store, setStore] = createStore<{ contentParts: ContentPart[] popoverIsOpen: boolean @@ -51,7 +53,7 @@ export const PromptInput: Component = (props) => { event.stopPropagation() // @ts-expect-error const plainText = (event.clipboardData || window.clipboardData)?.getData("text/plain") ?? "" - addPart({ type: "text", content: plainText }) + addPart({ type: "text", content: plainText, start: 0, end: 0 }) } onMount(() => { @@ -74,7 +76,7 @@ export const PromptInput: Component = (props) => { key: (x) => x, onSelect: (path) => { if (!path) return - addPart({ type: "file", path, content: "@" + getFilename(path) }) + addPart({ type: "file", path, content: "@" + getFilename(path), start: 0, end: 0 }) setStore("popoverIsOpen", false) }, }) @@ -117,17 +119,26 @@ export const PromptInput: Component = (props) => { const parseFromDOM = (): ContentPart[] => { const newParts: ContentPart[] = [] + let position = 0 editorRef.childNodes.forEach((node) => { if (node.nodeType === Node.TEXT_NODE) { - if (node.textContent) newParts.push({ type: "text", content: node.textContent }) + if (node.textContent) { + const content = node.textContent + newParts.push({ type: "text", content, start: position, end: position + content.length }) + position += content.length + } } else if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).dataset.type) { switch ((node as HTMLElement).dataset.type) { case "file": + const content = node.textContent! newParts.push({ type: "file", path: (node as HTMLElement).dataset.path!, - content: node.textContent!, + content, + start: position, + end: position + content.length, }) + position += content.length break default: break @@ -163,17 +174,19 @@ export const PromptInput: Component = (props) => { const startIndex = atMatch ? atMatch.index! : cursorPosition const endIndex = atMatch ? cursorPosition : cursorPosition - const pushText = (acc: { parts: ContentPart[] }, value: string) => { + const pushText = (acc: { parts: ContentPart[]; runningIndex: number }, value: string) => { if (!value) return const last = acc.parts[acc.parts.length - 1] if (last && last.type === "text") { acc.parts[acc.parts.length - 1] = { type: "text", content: last.content + value, + start: last.start, + end: last.end + value.length, } return } - acc.parts.push({ type: "text", content: value }) + acc.parts.push({ type: "text", content: value, start: acc.runningIndex, end: acc.runningIndex + value.length }) } const { @@ -183,20 +196,20 @@ export const PromptInput: Component = (props) => { } = store.contentParts.reduce( (acc, item) => { if (acc.inserted) { - acc.parts.push(item) + acc.parts.push({ ...item, start: acc.runningIndex, end: acc.runningIndex + item.content.length }) acc.runningIndex += item.content.length return acc } const nextIndex = acc.runningIndex + item.content.length if (nextIndex <= startIndex) { - acc.parts.push(item) + acc.parts.push({ ...item, start: acc.runningIndex, end: acc.runningIndex + item.content.length }) acc.runningIndex = nextIndex return acc } if (item.type !== "text") { - acc.parts.push(item) + acc.parts.push({ ...item, start: acc.runningIndex, end: acc.runningIndex + item.content.length }) acc.runningIndex = nextIndex return acc } @@ -207,24 +220,27 @@ export const PromptInput: Component = (props) => { const tail = item.content.slice(tailLength) pushText(acc, head) + acc.runningIndex += head.length if (part.type === "text") { pushText(acc, part.content) + acc.runningIndex += part.content.length } if (part.type !== "text") { - acc.parts.push({ ...part }) + acc.parts.push({ ...part, start: acc.runningIndex, end: acc.runningIndex + part.content.length }) + acc.runningIndex += part.content.length } const needsGap = Boolean(atMatch) const rest = needsGap ? (tail ? (/^\s/.test(tail) ? tail : ` ${tail}`) : " ") : tail pushText(acc, rest) + acc.runningIndex += rest.length const baseCursor = startIndex + part.content.length const cursorAddition = needsGap && rest.length > 0 ? 1 : 0 acc.cursorPositionAfter = baseCursor + cursorAddition acc.inserted = true - acc.runningIndex = nextIndex return acc }, { @@ -237,9 +253,18 @@ export const PromptInput: Component = (props) => { if (!inserted) { const baseParts = store.contentParts.filter((item) => !(item.type === "text" && item.content === "")) - const appendedAcc = { parts: [...baseParts] as ContentPart[] } - if (part.type === "text") pushText(appendedAcc, part.content) - if (part.type !== "text") appendedAcc.parts.push({ ...part }) + const runningIndex = baseParts.reduce((sum, p) => sum + p.content.length, 0) + const appendedAcc = { parts: [...baseParts] as ContentPart[], runningIndex } + if (part.type === "text") { + pushText(appendedAcc, part.content) + } + if (part.type !== "text") { + appendedAcc.parts.push({ + ...part, + start: appendedAcc.runningIndex, + end: appendedAcc.runningIndex + part.content.length, + }) + } const next = appendedAcc.parts.length > 0 ? appendedAcc.parts : defaultParts setStore("contentParts", next) setStore("popoverIsOpen", false) diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx index 978dbfbc68..91c1d688f5 100644 --- a/packages/desktop/src/context/local.tsx +++ b/packages/desktop/src/context/local.tsx @@ -429,13 +429,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ .sort((a, b) => b.id.localeCompare(a.id)), ) - const working = createMemo(() => { - const last = messages()[messages().length - 1] - if (!last) return false - if (last.role === "user") return true - return !last.time.completed - }) - const cost = createMemo(() => { const total = pipe( messages(), @@ -487,6 +480,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const getMessageText = (message: Message | Message[] | undefined): string => { if (!message) return "" if (Array.isArray(message)) return message.map((m) => getMessageText(m)).join(" ") + const fileParts = sync.data.part[message.id]?.filter((p) => p.type === "file") + console.log(fileParts) + return sync.data.part[message.id] ?.filter((p) => p.type === "text") ?.filter((p) => !p.synthetic) @@ -506,7 +502,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ messages, messagesWithValidParts, userMessages, - working, + // working, getMessageText, setActive(sessionId: string | undefined) { setStore("active", sessionId) diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx index b4bd36162e..c1884b2c0d 100644 --- a/packages/desktop/src/pages/index.tsx +++ b/packages/desktop/src/pages/index.tsx @@ -1,8 +1,19 @@ -import { Button, List, SelectDialog, Tooltip, IconButton, Tabs, Icon, Accordion, Diff } from "@opencode-ai/ui" +import { + Button, + List, + SelectDialog, + Tooltip, + IconButton, + Tabs, + Icon, + Accordion, + Diff, + Collapsible, +} from "@opencode-ai/ui" import { FileIcon } from "@/ui" import FileTree from "@/components/file-tree" import { For, onCleanup, onMount, Show, Match, Switch, createSignal, createEffect, createMemo } from "solid-js" -import { useLocal, type LocalFile, type TextSelection } from "@/context/local" +import { useLocal, type LocalFile } from "@/context/local" import { createStore } from "solid-js/store" import { getDirectory, getFilename } from "@/utils" import { ContentPart, PromptInput } from "@/components/prompt-input" @@ -185,42 +196,10 @@ export default function Page() { } if (!session) return - interface SubmissionAttachment { - path: string - selection?: TextSelection - label: string - } - - const createAttachmentKey = (path: string, selection?: TextSelection) => { - if (!selection) return path - return `${path}:${selection.startLine}:${selection.startChar}:${selection.endLine}:${selection.endChar}` - } - - const formatAttachmentLabel = (path: string, selection?: TextSelection) => { - if (!selection) return getFilename(path) - return `${getFilename(path)} (${selection.startLine}-${selection.endLine})` - } - const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) const text = parts.map((part) => part.content).join("") - const attachments = new Map() - - const registerAttachment = (path: string, selection: TextSelection | undefined, label?: string) => { - if (!path) return - const key = createAttachmentKey(path, selection) - if (attachments.has(key)) return - attachments.set(key, { - path, - selection, - label: label ?? formatAttachmentLabel(path, selection), - }) - } - - const promptAttachments = parts.filter((part) => part.type === "file") - for (const part of promptAttachments) { - registerAttachment(part.path, part.selection, part.content) - } + const attachments = parts.filter((part) => part.type === "file") // const activeFile = local.context.active() // if (activeFile) { @@ -239,7 +218,7 @@ export default function Page() { // ) // } - const attachmentParts = Array.from(attachments.values()).map((attachment) => { + const attachmentParts = attachments.map((attachment) => { const absolute = toAbsolutePath(attachment.path) const query = attachment.selection ? `?start=${attachment.selection.startLine}&end=${attachment.selection.endLine}` @@ -252,9 +231,9 @@ export default function Page() { source: { type: "file" as const, text: { - value: `@${attachment.label}`, - start: 0, - end: 0, + value: attachment.content, + start: attachment.start, + end: attachment.end, }, path: absolute, }, @@ -510,8 +489,8 @@ export default function Page() {
- -
+ +
{(activeSession) => ( -
+
1}>
    @@ -665,30 +644,65 @@ export default function Page() { (m) => m.role === "assistant" && m.parentID == message.id, ) as AssistantMessageType[] }) + const working = createMemo(() => { + const last = assistantMessages()[assistantMessages().length - 1] + if (!last) return false + return !last.time.completed + }) + const lastWithContent = createMemo(() => + assistantMessages().findLast((m) => { + const parts = sync.data.part[m.id] + return parts?.find((p) => p.type === "text" || p.type === "tool") + }), + ) return ( -
    +
    {/* Title */} -
    +

    {title() ?? prompt()}

    - -
    {prompt()}
    +
    + +
    {prompt()}
    +
    + {/* Response */} +
    + + +
    +

    Show steps

    + +
    +
    + +
    + + {(assistantMessage) => { + const parts = createMemo(() => sync.data.part[assistantMessage.id]) + return + }} + +
    +
    +
    + + {(last) => { + const lastParts = createMemo(() => sync.data.part[last().id]) + return ( + + ) + }}
    {/* Summary */} -
    - + +

    Summary

    {summary()}
    - - {(diff) => ( @@ -735,22 +749,8 @@ export default function Page() { )} - -
    - {/* Response */} -
    -
    -

    Response

    -
    - - {(assistantMessage) => { - const parts = createMemo(() => sync.data.part[assistantMessage.id]) - return - }} - -
    -
    +
    ) }} diff --git a/packages/ui/src/components/collapsible.css b/packages/ui/src/components/collapsible.css index 34699fc205..3d8c8ebea2 100644 --- a/packages/ui/src/components/collapsible.css +++ b/packages/ui/src/components/collapsible.css @@ -57,6 +57,27 @@ /* animation: slideDown 250ms ease-out; */ /* } */ } + + &[data-variant="ghost"] { + background-color: transparent; + border: none; + + > [data-slot="collapsible-trigger"] { + background-color: transparent; + border: none; + padding: 0; + + /* &:hover { */ + /* color: var(--text-strong); */ + /* } */ + &:focus-visible { + outline: none; + } + &[data-disabled] { + cursor: not-allowed; + } + } + } } @keyframes slideDown { diff --git a/packages/ui/src/components/collapsible.tsx b/packages/ui/src/components/collapsible.tsx index d2e4a139b4..17fad0b9e4 100644 --- a/packages/ui/src/components/collapsible.tsx +++ b/packages/ui/src/components/collapsible.tsx @@ -5,13 +5,15 @@ import { Icon } from "./icon" export interface CollapsibleProps extends ParentProps { class?: string classList?: ComponentProps<"div">["classList"] + variant?: "normal" | "ghost" } function CollapsibleRoot(props: CollapsibleProps) { - const [local, others] = splitProps(props, ["class", "classList"]) + const [local, others] = splitProps(props, ["class", "classList", "variant"]) return ( Date: Tue, 28 Oct 2025 20:29:47 +0000 Subject: [PATCH 047/609] chore: format code --- bun.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bun.lock b/bun.lock index e976f47c41..aaa44a8b54 100644 --- a/bun.lock +++ b/bun.lock @@ -114,7 +114,7 @@ "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", "@opencode-ai/ui": "workspace:*", - "@pierre/precision-diffs": "0.3.5", + "@pierre/precision-diffs": "catalog:", "@shikijs/transformers": "3.9.2", "@solid-primitives/active-element": "2.1.3", "@solid-primitives/event-bus": "1.1.2", From 832ffd23032c11bc289b36b95399a2b25b9fa779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Haris=20Gu=C5=A1i=C4=87?= Date: Tue, 28 Oct 2025 21:38:08 +0100 Subject: [PATCH 048/609] fix: Use process.stdout.write instead of console.log (#3508) --- packages/opencode/src/cli/cmd/debug/config.ts | 3 ++- packages/opencode/src/cli/cmd/debug/file.ts | 8 ++++---- packages/opencode/src/cli/cmd/debug/lsp.ts | 7 ++++--- packages/opencode/src/cli/cmd/debug/ripgrep.ts | 6 +++--- packages/opencode/src/cli/cmd/debug/scrap.ts | 3 ++- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/opencode/src/cli/cmd/debug/config.ts b/packages/opencode/src/cli/cmd/debug/config.ts index c7ce8d0e7f..aafcf04697 100644 --- a/packages/opencode/src/cli/cmd/debug/config.ts +++ b/packages/opencode/src/cli/cmd/debug/config.ts @@ -1,3 +1,4 @@ +import { EOL } from "os" import { Config } from "../../../config/config" import { bootstrap } from "../../bootstrap" import { cmd } from "../cmd" @@ -8,7 +9,7 @@ export const ConfigCommand = cmd({ async handler() { await bootstrap(process.cwd(), async () => { const config = await Config.get() - console.log(JSON.stringify(config, null, 2)) + process.stdout.write(JSON.stringify(config, null, 2) + EOL) }) }, }) diff --git a/packages/opencode/src/cli/cmd/debug/file.ts b/packages/opencode/src/cli/cmd/debug/file.ts index fabef32b81..3d1e707dbc 100644 --- a/packages/opencode/src/cli/cmd/debug/file.ts +++ b/packages/opencode/src/cli/cmd/debug/file.ts @@ -14,7 +14,7 @@ const FileSearchCommand = cmd({ async handler(args) { await bootstrap(process.cwd(), async () => { const results = await File.search({ query: args.query }) - console.log(results.join(EOL)) + process.stdout.write(results.join(EOL) + EOL) }) }, }) @@ -30,7 +30,7 @@ const FileReadCommand = cmd({ async handler(args) { await bootstrap(process.cwd(), async () => { const content = await File.read(args.path) - console.log(content) + process.stdout.write(JSON.stringify(content, null, 2) + EOL) }) }, }) @@ -41,7 +41,7 @@ const FileStatusCommand = cmd({ async handler() { await bootstrap(process.cwd(), async () => { const status = await File.status() - console.log(JSON.stringify(status, null, 2)) + process.stdout.write(JSON.stringify(status, null, 2) + EOL) }) }, }) @@ -57,7 +57,7 @@ const FileListCommand = cmd({ async handler(args) { await bootstrap(process.cwd(), async () => { const files = await File.list(args.path) - console.log(JSON.stringify(files, null, 2)) + process.stdout.write(JSON.stringify(files, null, 2) + EOL) }) }, }) diff --git a/packages/opencode/src/cli/cmd/debug/lsp.ts b/packages/opencode/src/cli/cmd/debug/lsp.ts index 292c8ba6d3..2f59771958 100644 --- a/packages/opencode/src/cli/cmd/debug/lsp.ts +++ b/packages/opencode/src/cli/cmd/debug/lsp.ts @@ -2,6 +2,7 @@ import { LSP } from "../../../lsp" import { bootstrap } from "../../bootstrap" import { cmd } from "../cmd" import { Log } from "../../../util/log" +import { EOL } from "os" export const LSPCommand = cmd({ command: "lsp", @@ -16,7 +17,7 @@ const DiagnosticsCommand = cmd({ async handler(args) { await bootstrap(process.cwd(), async () => { await LSP.touchFile(args.file, true) - console.log(JSON.stringify(await LSP.diagnostics(), null, 2)) + process.stdout.write(JSON.stringify(await LSP.diagnostics(), null, 2) + EOL) }) }, }) @@ -28,7 +29,7 @@ export const SymbolsCommand = cmd({ await bootstrap(process.cwd(), async () => { using _ = Log.Default.time("symbols") const results = await LSP.workspaceSymbol(args.query) - console.log(JSON.stringify(results, null, 2)) + process.stdout.write(JSON.stringify(results, null, 2) + EOL) }) }, }) @@ -40,7 +41,7 @@ export const DocumentSymbolsCommand = cmd({ await bootstrap(process.cwd(), async () => { using _ = Log.Default.time("document-symbols") const results = await LSP.documentSymbol(args.uri) - console.log(JSON.stringify(results, null, 2)) + process.stdout.write(JSON.stringify(results, null, 2) + EOL) }) }, }) diff --git a/packages/opencode/src/cli/cmd/debug/ripgrep.ts b/packages/opencode/src/cli/cmd/debug/ripgrep.ts index 1c9f899737..66cfba20db 100644 --- a/packages/opencode/src/cli/cmd/debug/ripgrep.ts +++ b/packages/opencode/src/cli/cmd/debug/ripgrep.ts @@ -18,7 +18,7 @@ const TreeCommand = cmd({ }), async handler(args) { await bootstrap(process.cwd(), async () => { - console.log(await Ripgrep.tree({ cwd: Instance.directory, limit: args.limit })) + process.stdout.write(await Ripgrep.tree({ cwd: Instance.directory, limit: args.limit }) + EOL) }) }, }) @@ -49,7 +49,7 @@ const FilesCommand = cmd({ files.push(file) if (args.limit && files.length >= args.limit) break } - console.log(files.join(EOL)) + process.stdout.write(files.join(EOL) + EOL) }) }, }) @@ -78,6 +78,6 @@ const SearchCommand = cmd({ glob: args.glob as string[] | undefined, limit: args.limit, }) - console.log(JSON.stringify(results, null, 2)) + process.stdout.write(JSON.stringify(results, null, 2) + EOL) }, }) diff --git a/packages/opencode/src/cli/cmd/debug/scrap.ts b/packages/opencode/src/cli/cmd/debug/scrap.ts index 9ab3bb2ff3..3580aba909 100644 --- a/packages/opencode/src/cli/cmd/debug/scrap.ts +++ b/packages/opencode/src/cli/cmd/debug/scrap.ts @@ -1,3 +1,4 @@ +import { EOL } from "os" import { Project } from "../../../project/project" import { Log } from "../../../util/log" import { cmd } from "../cmd" @@ -8,7 +9,7 @@ export const ScrapCommand = cmd({ async handler() { const timer = Log.Default.time("scrap") const list = await Project.list() - console.log(list) + process.stdout.write(JSON.stringify(list, null, 2) + EOL) timer.stop() }, }) From 46ad4567188906b0d8e2cf2a67d6add6ec333a61 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:39:34 -0500 Subject: [PATCH 049/609] wip: desktop work --- bun.lock | 4 ++-- package.json | 4 ++-- .../src/components/assistant-message.tsx | 17 +++++++++++++---- packages/ui/src/components/diff.tsx | 9 ++++++++- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/bun.lock b/bun.lock index aaa44a8b54..594cdc5bf1 100644 --- a/bun.lock +++ b/bun.lock @@ -344,7 +344,7 @@ "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.3.5", + "@pierre/precision-diffs": "0.3.6", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "@tsconfig/bun": "1.0.9", @@ -938,7 +938,7 @@ "@petamoriken/float16": ["@petamoriken/float16@3.9.2", "", {}, "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog=="], - "@pierre/precision-diffs": ["@pierre/precision-diffs@0.3.5", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-qbotIS8CahO/7guljDzU3RVpDfg6WViWe0EB0/SZQi3xHD+nzxxlC+pGoyIFSn+47GG0EKxTnvkfaYANm19FCA=="], + "@pierre/precision-diffs": ["@pierre/precision-diffs@0.3.6", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-cKM3HcMmyr5wPFll0bHYcgHplcHgMlL6Dw4Pi4giL0jVt7ySlGwwVyXTRFW5Fva43stOL+EWB+9U5VBDSktBJA=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], diff --git a/package.json b/package.json index 151fa4d911..32e974f5bf 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@tsconfig/bun": "1.0.9", "@cloudflare/workers-types": "4.20251008.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.3.5", + "@pierre/precision-diffs": "0.3.6", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "diff": "8.0.2", @@ -63,7 +63,7 @@ "license": "MIT", "prettier": { "semi": false, - "printWidth": 120 + "printWidth": 100 }, "trustedDependencies": [ "esbuild", diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx index 224e3d3902..90f6e70fec 100644 --- a/packages/desktop/src/components/assistant-message.tsx +++ b/packages/desktop/src/components/assistant-message.tsx @@ -2,7 +2,7 @@ import type { Part, AssistantMessage, ReasoningPart, TextPart, ToolPart } from " import { children, Component, createMemo, For, Match, Show, Switch, type JSX } from "solid-js" import { Dynamic } from "solid-js/web" import { Markdown } from "./markdown" -import { Checkbox, Collapsible, Icon, IconProps } from "@opencode-ai/ui" +import { Checkbox, Collapsible, Diff, Icon, IconProps } from "@opencode-ai/ui" import { getDirectory, getFilename } from "@/utils" import type { Tool } from "opencode/tool/tool" import type { ReadTool } from "opencode/tool/read" @@ -357,12 +357,21 @@ ToolRegistry.register({ {getFilename(props.input.filePath ?? "")}
    -
    {/* */}
    +
    + + + +
    } > - -
    {props.output}
    + +
    + +
    ) diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx index 88215bcb0e..3eeab6d6f8 100644 --- a/packages/ui/src/components/diff.tsx +++ b/packages/ui/src/components/diff.tsx @@ -24,7 +24,13 @@ export type DiffProps = Omit, "themes"> & { export function Diff(props: DiffProps) { let container!: HTMLDivElement - const [local, others] = splitProps(props, ["before", "after", "class", "classList", "annotations"]) + const [local, others] = splitProps(props, [ + "before", + "after", + "class", + "classList", + "annotations", + ]) // const lineAnnotations: DiffLineAnnotation[] = [ // { @@ -165,6 +171,7 @@ export function Diff(props: DiffProps) { "--pjs-tab-size": 4, "--pjs-font-features": "var(--font-family-mono--font-feature-settings)", "--pjs-header-font-family": "var(--font-family-sans)", + "--pjs-gap-block": 0, }} ref={container} /> From 5cc37c4ea01953c9a5ef64f095a300e78ea4a0fa Mon Sep 17 00:00:00 2001 From: kcrommett <523952+kcrommett@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:16:03 -0700 Subject: [PATCH 050/609] mcp: fix status() to not overwrite connected with failed (#3514) --- packages/opencode/src/mcp/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index 1c3b843696..988426b137 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -188,6 +188,7 @@ export namespace MCP { } if (state.clients[key]) { result[key] = "connected" + continue } result[key] = "failed" } From fc8db6cdf9cb81e29c5dda69c8646aa52e453a9c Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 28 Oct 2025 17:32:39 -0500 Subject: [PATCH 051/609] fix: ensure timeout param passed to bash tool is positive --- packages/opencode/src/tool/bash.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index 6a7af3811d..2c377ee14c 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -27,7 +27,9 @@ const parser = lazy(async () => { return p } catch (e) { const { default: Parser } = await import("web-tree-sitter") - const { default: treeWasm } = await import("web-tree-sitter/tree-sitter.wasm" as string, { with: { type: "wasm" } }) + const { default: treeWasm } = await import("web-tree-sitter/tree-sitter.wasm" as string, { + with: { type: "wasm" }, + }) await Parser.init({ locateFile() { return treeWasm @@ -55,6 +57,11 @@ export const BashTool = Tool.define("bash", { ), }), async execute(params, ctx) { + if (params.timeout !== undefined && params.timeout < 0) { + throw new Error( + `Invalid timeout value: ${params.timeout}. Timeout must be a positive number.`, + ) + } const timeout = Math.min(params.timeout ?? DEFAULT_TIMEOUT, MAX_TIMEOUT) const tree = await parser().then((p) => p.parse(params.command)) const permissions = await Agent.get(ctx.agent).then((x) => x.permission.bash) @@ -97,7 +104,10 @@ export const BashTool = Tool.define("bash", { // always allow cd if it passes above check if (command[0] !== "cd") { - const action = Wildcard.allStructured({ head: command[0], tail: command.slice(1) }, permissions) + const action = Wildcard.allStructured( + { head: command[0], tail: command.slice(1) }, + permissions, + ) if (action === "deny") { throw new Error( `The user has specifically restricted access to this command, you are not allowed to execute it. Here is the configuration: ${JSON.stringify(permissions)}`, From 0e60f666043910afb96e9de2f84b0b8a68c7e4d6 Mon Sep 17 00:00:00 2001 From: Kevin King <64164523+Kking112@users.noreply.github.com> Date: Tue, 28 Oct 2025 19:32:45 -0400 Subject: [PATCH 052/609] ignore: python sdk (#2779) Co-authored-by: Aiden Cline --- .github/publish-python-sdk.yml | 71 + packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/sdk/python/.gitignore | 22 + packages/sdk/python/README.md | 82 + packages/sdk/python/docs/generation.md | 19 + packages/sdk/python/docs/index.md | 11 + packages/sdk/python/docs/installation.md | 27 + packages/sdk/python/docs/publishing.md | 24 + packages/sdk/python/docs/quickstart.md | 22 + packages/sdk/python/docs/testing.md | 15 + .../sdk/python/docs/usage/configuration.md | 21 + .../sdk/python/docs/usage/files_projects.md | 22 + packages/sdk/python/docs/usage/sessions.md | 18 + packages/sdk/python/docs/usage/streaming.md | 29 + packages/sdk/python/examples/basic_usage.py | 19 + packages/sdk/python/examples/file_status.py | 6 + packages/sdk/python/examples/session_list.py | 4 + packages/sdk/python/mkdocs.yml | 29 + .../sdk/python/openapi-python-client.yaml | 5 + packages/sdk/python/pyproject.toml | 56 + packages/sdk/python/scripts/generate.py | 210 ++ packages/sdk/python/scripts/publish.py | 68 + .../sdk/python/src/opencode_ai/__init__.py | 14 + .../python/src/opencode_ai/api/__init__.py | 1 + .../src/opencode_ai/api/default/__init__.py | 1 + .../src/opencode_ai/api/default/app_agents.py | 160 + .../opencode_ai/api/default/command_list.py | 164 + .../src/opencode_ai/api/default/config_get.py | 155 + .../api/default/config_providers.py | 159 + .../api/default/event_subscribe.py | 447 +++ .../opencode_ai/api/default/file_status.py | 160 + .../src/opencode_ai/api/default/path_get.py | 155 + .../api/default/project_current.py | 155 + .../opencode_ai/api/default/project_list.py | 164 + .../opencode_ai/api/default/session_list.py | 164 + .../src/opencode_ai/api/default/tool_ids.py | 164 + .../api/default/tui_clear_prompt.py | 153 + .../opencode_ai/api/default/tui_open_help.py | 153 + .../api/default/tui_open_models.py | 153 + .../api/default/tui_open_sessions.py | 153 + .../api/default/tui_open_themes.py | 153 + .../api/default/tui_submit_prompt.py | 153 + packages/sdk/python/src/opencode_ai/client.py | 268 ++ packages/sdk/python/src/opencode_ai/errors.py | 16 + packages/sdk/python/src/opencode_ai/extras.py | 186 ++ .../python/src/opencode_ai/models/__init__.py | 367 +++ .../python/src/opencode_ai/models/agent.py | 180 ++ .../src/opencode_ai/models/agent_config.py | 173 ++ .../models/agent_config_permission.py | 155 + .../agent_config_permission_bash_type_1.py | 74 + .../opencode_ai/models/agent_config_tools.py | 44 + .../src/opencode_ai/models/agent_model.py | 67 + .../src/opencode_ai/models/agent_options.py | 44 + .../src/opencode_ai/models/agent_part.py | 117 + .../opencode_ai/models/agent_part_input.py | 102 + .../models/agent_part_input_source.py | 75 + .../opencode_ai/models/agent_part_source.py | 75 + .../opencode_ai/models/agent_permission.py | 120 + .../models/agent_permission_bash.py | 74 + .../src/opencode_ai/models/agent_tools.py | 44 + .../python/src/opencode_ai/models/api_auth.py | 69 + .../opencode_ai/models/assistant_message.py | 228 ++ .../models/assistant_message_path.py | 67 + .../models/assistant_message_time.py | 70 + .../models/assistant_message_tokens.py | 89 + .../models/assistant_message_tokens_cache.py | 67 + .../python/src/opencode_ai/models/command.py | 105 + .../python/src/opencode_ai/models/config.py | 411 +++ .../src/opencode_ai/models/config_agent.py | 113 + .../src/opencode_ai/models/config_command.py | 57 + .../config_command_additional_property.py | 97 + .../opencode_ai/models/config_experimental.py | 81 + .../models/config_experimental_hook.py | 93 + .../config_experimental_hook_file_edited.py | 73 + ...ok_file_edited_additional_property_item.py | 87 + ...ed_additional_property_item_environment.py | 44 + ...xperimental_hook_session_completed_item.py | 87 + ...hook_session_completed_item_environment.py | 44 + .../opencode_ai/models/config_formatter.py | 57 + .../config_formatter_additional_property.py | 105 + ...rmatter_additional_property_environment.py | 44 + .../src/opencode_ai/models/config_lsp.py | 86 + .../config_lsp_additional_property_type_0.py | 59 + .../config_lsp_additional_property_type_1.py | 125 + ...nfig_lsp_additional_property_type_1_env.py | 44 + ...ditional_property_type_1_initialization.py | 44 + .../src/opencode_ai/models/config_mcp.py | 82 + .../src/opencode_ai/models/config_mode.py | 97 + .../opencode_ai/models/config_permission.py | 155 + .../models/config_permission_bash_type_1.py | 74 + .../src/opencode_ai/models/config_provider.py | 57 + .../config_provider_additional_property.py | 118 + ...fig_provider_additional_property_models.py | 63 + ...nal_property_models_additional_property.py | 214 ++ ...roperty_models_additional_property_cost.py | 87 + ...operty_models_additional_property_limit.py | 67 + ...erty_models_additional_property_options.py | 44 + ...rty_models_additional_property_provider.py | 59 + ...ig_provider_additional_property_options.py | 87 + .../models/config_providers_response_200.py | 83 + .../config_providers_response_200_default.py | 44 + .../src/opencode_ai/models/config_share.py | 10 + .../src/opencode_ai/models/config_tools.py | 44 + .../src/opencode_ai/models/config_tui.py | 60 + .../src/opencode_ai/models/config_watcher.py | 61 + .../python/src/opencode_ai/models/error.py | 65 + .../src/opencode_ai/models/error_data.py | 44 + .../opencode_ai/models/event_file_edited.py | 75 + .../models/event_file_edited_properties.py | 59 + .../models/event_file_watcher_updated.py | 75 + .../event_file_watcher_updated_properties.py | 82 + .../opencode_ai/models/event_ide_installed.py | 75 + .../models/event_ide_installed_properties.py | 59 + .../models/event_installation_updated.py | 75 + .../event_installation_updated_properties.py | 59 + .../models/event_lsp_client_diagnostics.py | 75 + ...event_lsp_client_diagnostics_properties.py | 67 + .../models/event_message_part_removed.py | 75 + .../event_message_part_removed_properties.py | 75 + .../models/event_message_part_updated.py | 75 + .../event_message_part_updated_properties.py | 203 ++ .../models/event_message_removed.py | 75 + .../event_message_removed_properties.py | 67 + .../models/event_message_updated.py | 75 + .../event_message_updated_properties.py | 89 + .../models/event_permission_replied.py | 75 + .../event_permission_replied_properties.py | 75 + .../models/event_permission_updated.py | 75 + .../models/event_server_connected.py | 75 + .../event_server_connected_properties.py | 44 + .../models/event_session_compacted.py | 75 + .../event_session_compacted_properties.py | 59 + .../models/event_session_deleted.py | 75 + .../event_session_deleted_properties.py | 65 + .../opencode_ai/models/event_session_error.py | 75 + .../models/event_session_error_properties.py | 129 + .../opencode_ai/models/event_session_idle.py | 75 + .../models/event_session_idle_properties.py | 59 + .../models/event_session_updated.py | 75 + .../event_session_updated_properties.py | 65 + .../sdk/python/src/opencode_ai/models/file.py | 85 + .../src/opencode_ai/models/file_content.py | 92 + .../opencode_ai/models/file_content_patch.py | 118 + .../models/file_content_patch_hunks_item.py | 91 + .../src/opencode_ai/models/file_node.py | 93 + .../src/opencode_ai/models/file_node_type.py | 9 + .../src/opencode_ai/models/file_part.py | 154 + .../src/opencode_ai/models/file_part_input.py | 139 + .../models/file_part_source_text.py | 75 + .../src/opencode_ai/models/file_source.py | 83 + .../src/opencode_ai/models/file_status.py | 10 + .../src/opencode_ai/models/keybinds_config.py | 474 +++ .../src/opencode_ai/models/layout_config.py | 9 + .../opencode_ai/models/mcp_local_config.py | 83 + .../models/mcp_local_config_environment.py | 44 + .../opencode_ai/models/mcp_remote_config.py | 83 + .../models/mcp_remote_config_headers.py | 44 + .../models/message_aborted_error.py | 75 + .../models/message_aborted_error_data.py | 59 + .../models/message_output_length_error.py | 75 + .../message_output_length_error_data.py | 44 + .../python/src/opencode_ai/models/model.py | 170 ++ .../src/opencode_ai/models/model_cost.py | 87 + .../src/opencode_ai/models/model_limit.py | 67 + .../src/opencode_ai/models/model_options.py | 44 + .../src/opencode_ai/models/model_provider.py | 59 + .../python/src/opencode_ai/models/o_auth.py | 85 + .../src/opencode_ai/models/patch_part.py | 101 + .../sdk/python/src/opencode_ai/models/path.py | 83 + .../src/opencode_ai/models/permission.py | 155 + .../opencode_ai/models/permission_metadata.py | 44 + .../src/opencode_ai/models/permission_time.py | 59 + .../python/src/opencode_ai/models/project.py | 94 + .../src/opencode_ai/models/project_time.py | 70 + .../python/src/opencode_ai/models/provider.py | 109 + .../opencode_ai/models/provider_auth_error.py | 75 + .../models/provider_auth_error_data.py | 67 + .../src/opencode_ai/models/provider_models.py | 57 + .../python/src/opencode_ai/models/range_.py | 75 + .../src/opencode_ai/models/range_end.py | 67 + .../src/opencode_ai/models/range_start.py | 67 + .../src/opencode_ai/models/reasoning_part.py | 127 + .../models/reasoning_part_metadata.py | 44 + .../opencode_ai/models/reasoning_part_time.py | 70 + .../python/src/opencode_ai/models/session.py | 152 + .../src/opencode_ai/models/session_revert.py | 88 + .../src/opencode_ai/models/session_share.py | 59 + .../src/opencode_ai/models/session_time.py | 78 + .../src/opencode_ai/models/snapshot_part.py | 93 + .../opencode_ai/models/step_finish_part.py | 107 + .../models/step_finish_part_tokens.py | 89 + .../models/step_finish_part_tokens_cache.py | 67 + .../src/opencode_ai/models/step_start_part.py | 85 + .../python/src/opencode_ai/models/symbol.py | 81 + .../src/opencode_ai/models/symbol_location.py | 73 + .../src/opencode_ai/models/symbol_source.py | 109 + .../src/opencode_ai/models/text_part.py | 126 + .../src/opencode_ai/models/text_part_input.py | 111 + .../models/text_part_input_time.py | 70 + .../src/opencode_ai/models/text_part_time.py | 70 + .../src/opencode_ai/models/tool_list_item.py | 75 + .../src/opencode_ai/models/tool_part.py | 166 + .../models/tool_state_completed.py | 111 + .../models/tool_state_completed_input.py | 44 + .../models/tool_state_completed_metadata.py | 44 + .../models/tool_state_completed_time.py | 78 + .../opencode_ai/models/tool_state_error.py | 113 + .../models/tool_state_error_input.py | 44 + .../models/tool_state_error_metadata.py | 44 + .../models/tool_state_error_time.py | 67 + .../opencode_ai/models/tool_state_pending.py | 61 + .../opencode_ai/models/tool_state_running.py | 112 + .../models/tool_state_running_metadata.py | 44 + .../models/tool_state_running_time.py | 59 + .../src/opencode_ai/models/unknown_error.py | 75 + .../opencode_ai/models/unknown_error_data.py | 59 + .../src/opencode_ai/models/user_message.py | 91 + .../opencode_ai/models/user_message_time.py | 59 + .../src/opencode_ai/models/well_known_auth.py | 77 + packages/sdk/python/src/opencode_ai/py.typed | 1 + packages/sdk/python/src/opencode_ai/types.py | 54 + packages/sdk/python/templates/extras.py | 106 + packages/sdk/python/tests/__init__.py | 1 + packages/sdk/python/tests/test_integration.py | 93 + packages/sdk/python/tests/test_wrapper.py | 116 + packages/sdk/python/uv.lock | 2700 +++++++++++++++++ packages/sdk/stainless/stainless.yml | 6 - script/hooks | 19 + 229 files changed, 22322 insertions(+), 8 deletions(-) create mode 100644 .github/publish-python-sdk.yml create mode 100644 packages/sdk/python/.gitignore create mode 100644 packages/sdk/python/README.md create mode 100644 packages/sdk/python/docs/generation.md create mode 100644 packages/sdk/python/docs/index.md create mode 100644 packages/sdk/python/docs/installation.md create mode 100644 packages/sdk/python/docs/publishing.md create mode 100644 packages/sdk/python/docs/quickstart.md create mode 100644 packages/sdk/python/docs/testing.md create mode 100644 packages/sdk/python/docs/usage/configuration.md create mode 100644 packages/sdk/python/docs/usage/files_projects.md create mode 100644 packages/sdk/python/docs/usage/sessions.md create mode 100644 packages/sdk/python/docs/usage/streaming.md create mode 100644 packages/sdk/python/examples/basic_usage.py create mode 100644 packages/sdk/python/examples/file_status.py create mode 100644 packages/sdk/python/examples/session_list.py create mode 100644 packages/sdk/python/mkdocs.yml create mode 100644 packages/sdk/python/openapi-python-client.yaml create mode 100644 packages/sdk/python/pyproject.toml create mode 100644 packages/sdk/python/scripts/generate.py create mode 100644 packages/sdk/python/scripts/publish.py create mode 100644 packages/sdk/python/src/opencode_ai/__init__.py create mode 100644 packages/sdk/python/src/opencode_ai/api/__init__.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/__init__.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/app_agents.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/command_list.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/config_get.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/config_providers.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/event_subscribe.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/file_status.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/path_get.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/project_current.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/project_list.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/session_list.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/tool_ids.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/tui_clear_prompt.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/tui_open_help.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/tui_open_models.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/tui_open_sessions.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/tui_open_themes.py create mode 100644 packages/sdk/python/src/opencode_ai/api/default/tui_submit_prompt.py create mode 100644 packages/sdk/python/src/opencode_ai/client.py create mode 100644 packages/sdk/python/src/opencode_ai/errors.py create mode 100644 packages/sdk/python/src/opencode_ai/extras.py create mode 100644 packages/sdk/python/src/opencode_ai/models/__init__.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_config.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_config_permission.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_config_permission_bash_type_1.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_config_tools.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_model.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_options.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_part.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_part_input.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_part_input_source.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_part_source.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_permission.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_permission_bash.py create mode 100644 packages/sdk/python/src/opencode_ai/models/agent_tools.py create mode 100644 packages/sdk/python/src/opencode_ai/models/api_auth.py create mode 100644 packages/sdk/python/src/opencode_ai/models/assistant_message.py create mode 100644 packages/sdk/python/src/opencode_ai/models/assistant_message_path.py create mode 100644 packages/sdk/python/src/opencode_ai/models/assistant_message_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/assistant_message_tokens.py create mode 100644 packages/sdk/python/src/opencode_ai/models/assistant_message_tokens_cache.py create mode 100644 packages/sdk/python/src/opencode_ai/models/command.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_agent.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_command.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_command_additional_property.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_experimental.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_experimental_hook.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited_additional_property_item.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited_additional_property_item_environment.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_experimental_hook_session_completed_item.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_experimental_hook_session_completed_item_environment.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_formatter.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_formatter_additional_property.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_formatter_additional_property_environment.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_lsp.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_0.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1_env.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1_initialization.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_mcp.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_mode.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_permission.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_permission_bash_type_1.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_provider.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_provider_additional_property.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_cost.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_limit.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_options.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_provider.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_options.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_providers_response_200.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_providers_response_200_default.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_share.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_tools.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_tui.py create mode 100644 packages/sdk/python/src/opencode_ai/models/config_watcher.py create mode 100644 packages/sdk/python/src/opencode_ai/models/error.py create mode 100644 packages/sdk/python/src/opencode_ai/models/error_data.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_file_edited.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_file_edited_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_file_watcher_updated.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_file_watcher_updated_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_ide_installed.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_ide_installed_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_installation_updated.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_installation_updated_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_lsp_client_diagnostics.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_lsp_client_diagnostics_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_message_part_removed.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_message_part_removed_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_message_part_updated.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_message_part_updated_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_message_removed.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_message_removed_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_message_updated.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_message_updated_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_permission_replied.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_permission_replied_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_permission_updated.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_server_connected.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_server_connected_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_compacted.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_compacted_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_deleted.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_deleted_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_error.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_error_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_idle.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_idle_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_updated.py create mode 100644 packages/sdk/python/src/opencode_ai/models/event_session_updated_properties.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_content.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_content_patch.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_content_patch_hunks_item.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_node.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_node_type.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_part.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_part_input.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_part_source_text.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_source.py create mode 100644 packages/sdk/python/src/opencode_ai/models/file_status.py create mode 100644 packages/sdk/python/src/opencode_ai/models/keybinds_config.py create mode 100644 packages/sdk/python/src/opencode_ai/models/layout_config.py create mode 100644 packages/sdk/python/src/opencode_ai/models/mcp_local_config.py create mode 100644 packages/sdk/python/src/opencode_ai/models/mcp_local_config_environment.py create mode 100644 packages/sdk/python/src/opencode_ai/models/mcp_remote_config.py create mode 100644 packages/sdk/python/src/opencode_ai/models/mcp_remote_config_headers.py create mode 100644 packages/sdk/python/src/opencode_ai/models/message_aborted_error.py create mode 100644 packages/sdk/python/src/opencode_ai/models/message_aborted_error_data.py create mode 100644 packages/sdk/python/src/opencode_ai/models/message_output_length_error.py create mode 100644 packages/sdk/python/src/opencode_ai/models/message_output_length_error_data.py create mode 100644 packages/sdk/python/src/opencode_ai/models/model.py create mode 100644 packages/sdk/python/src/opencode_ai/models/model_cost.py create mode 100644 packages/sdk/python/src/opencode_ai/models/model_limit.py create mode 100644 packages/sdk/python/src/opencode_ai/models/model_options.py create mode 100644 packages/sdk/python/src/opencode_ai/models/model_provider.py create mode 100644 packages/sdk/python/src/opencode_ai/models/o_auth.py create mode 100644 packages/sdk/python/src/opencode_ai/models/patch_part.py create mode 100644 packages/sdk/python/src/opencode_ai/models/path.py create mode 100644 packages/sdk/python/src/opencode_ai/models/permission.py create mode 100644 packages/sdk/python/src/opencode_ai/models/permission_metadata.py create mode 100644 packages/sdk/python/src/opencode_ai/models/permission_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/project.py create mode 100644 packages/sdk/python/src/opencode_ai/models/project_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/provider.py create mode 100644 packages/sdk/python/src/opencode_ai/models/provider_auth_error.py create mode 100644 packages/sdk/python/src/opencode_ai/models/provider_auth_error_data.py create mode 100644 packages/sdk/python/src/opencode_ai/models/provider_models.py create mode 100644 packages/sdk/python/src/opencode_ai/models/range_.py create mode 100644 packages/sdk/python/src/opencode_ai/models/range_end.py create mode 100644 packages/sdk/python/src/opencode_ai/models/range_start.py create mode 100644 packages/sdk/python/src/opencode_ai/models/reasoning_part.py create mode 100644 packages/sdk/python/src/opencode_ai/models/reasoning_part_metadata.py create mode 100644 packages/sdk/python/src/opencode_ai/models/reasoning_part_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/session.py create mode 100644 packages/sdk/python/src/opencode_ai/models/session_revert.py create mode 100644 packages/sdk/python/src/opencode_ai/models/session_share.py create mode 100644 packages/sdk/python/src/opencode_ai/models/session_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/snapshot_part.py create mode 100644 packages/sdk/python/src/opencode_ai/models/step_finish_part.py create mode 100644 packages/sdk/python/src/opencode_ai/models/step_finish_part_tokens.py create mode 100644 packages/sdk/python/src/opencode_ai/models/step_finish_part_tokens_cache.py create mode 100644 packages/sdk/python/src/opencode_ai/models/step_start_part.py create mode 100644 packages/sdk/python/src/opencode_ai/models/symbol.py create mode 100644 packages/sdk/python/src/opencode_ai/models/symbol_location.py create mode 100644 packages/sdk/python/src/opencode_ai/models/symbol_source.py create mode 100644 packages/sdk/python/src/opencode_ai/models/text_part.py create mode 100644 packages/sdk/python/src/opencode_ai/models/text_part_input.py create mode 100644 packages/sdk/python/src/opencode_ai/models/text_part_input_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/text_part_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_list_item.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_part.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_completed.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_completed_input.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_completed_metadata.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_completed_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_error.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_error_input.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_error_metadata.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_error_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_pending.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_running.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_running_metadata.py create mode 100644 packages/sdk/python/src/opencode_ai/models/tool_state_running_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/unknown_error.py create mode 100644 packages/sdk/python/src/opencode_ai/models/unknown_error_data.py create mode 100644 packages/sdk/python/src/opencode_ai/models/user_message.py create mode 100644 packages/sdk/python/src/opencode_ai/models/user_message_time.py create mode 100644 packages/sdk/python/src/opencode_ai/models/well_known_auth.py create mode 100644 packages/sdk/python/src/opencode_ai/py.typed create mode 100644 packages/sdk/python/src/opencode_ai/types.py create mode 100644 packages/sdk/python/templates/extras.py create mode 100644 packages/sdk/python/tests/__init__.py create mode 100644 packages/sdk/python/tests/test_integration.py create mode 100644 packages/sdk/python/tests/test_wrapper.py create mode 100644 packages/sdk/python/uv.lock create mode 100755 script/hooks diff --git a/.github/publish-python-sdk.yml b/.github/publish-python-sdk.yml new file mode 100644 index 0000000000..151ecb9944 --- /dev/null +++ b/.github/publish-python-sdk.yml @@ -0,0 +1,71 @@ +# +# This file is intentionally in the wrong dir, will move and add later.... +# + +# name: publish-python-sdk + +# on: +# release: +# types: [published] +# workflow_dispatch: + +# jobs: +# publish: +# runs-on: ubuntu-latest +# permissions: +# contents: read +# steps: +# - name: Checkout repository +# uses: actions/checkout@v4 + +# - name: Setup Bun +# uses: oven-sh/setup-bun@v1 +# with: +# bun-version: 1.2.21 + +# - name: Install dependencies (JS/Bun) +# run: bun install + +# - name: Install uv +# shell: bash +# run: curl -LsSf https://astral.sh/uv/install.sh | sh + +# - name: Generate Python SDK from OpenAPI (CLI) +# shell: bash +# run: | +# ~/.local/bin/uv run --project packages/sdk/python python packages/sdk/python/scripts/generate.py --source cli + +# - name: Sync Python dependencies +# shell: bash +# run: | +# ~/.local/bin/uv sync --dev --project packages/sdk/python + +# - name: Set version from release tag +# shell: bash +# run: | +# TAG="${GITHUB_REF_NAME:-}" +# if [ -z "$TAG" ]; then +# TAG="$(git describe --tags --abbrev=0 || echo 0.0.0)" +# fi +# echo "Using version: $TAG" +# VERSION="$TAG" ~/.local/bin/uv run --project packages/sdk/python python - <<'PY' +# import os, re, pathlib +# root = pathlib.Path('packages/sdk/python') +# pt = (root / 'pyproject.toml').read_text() +# version = os.environ.get('VERSION','0.0.0').lstrip('v') +# pt = re.sub(r'(?m)^(version\s*=\s*")[^"]+("\s*)$', f"\\1{version}\\2", pt) +# (root / 'pyproject.toml').write_text(pt) +# # Also update generator config override for consistency +# cfgp = root / 'openapi-python-client.yaml' +# if cfgp.exists(): +# cfg = cfgp.read_text() +# cfg = re.sub(r'(?m)^(package_version_override:\s*)\S+$', f"\\1{version}", cfg) +# cfgp.write_text(cfg) +# PY + +# - name: Build and publish to PyPI +# env: +# PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} +# shell: bash +# run: | +# ~/.local/bin/uv run --project packages/sdk/python python packages/sdk/python/scripts/publish.py diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 27736e2a1c..8f5e6e82d9 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index dbb890f607..559ac6507b 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} diff --git a/packages/sdk/python/.gitignore b/packages/sdk/python/.gitignore new file mode 100644 index 0000000000..58ad275666 --- /dev/null +++ b/packages/sdk/python/.gitignore @@ -0,0 +1,22 @@ +__pycache__/ +*.py[cod] +*.egg-info/ +.build/ +build/ +dist/ +.coverage +htmlcov/ +.mypy_cache/ +.pytest_cache/ +.ruff_cache/ +.venv/ +.conda/ +.env +.DS_Store +openapi.json +site/ + + +# IDE +.vscode/ +.idea/ diff --git a/packages/sdk/python/README.md b/packages/sdk/python/README.md new file mode 100644 index 0000000000..a17c36ab38 --- /dev/null +++ b/packages/sdk/python/README.md @@ -0,0 +1,82 @@ +# Opencode Python SDK + +This package provides a Python SDK for the Opencode API. It is generated using openapi-python-client (not Stainless). + + +Documentation +- Full docs: see `mkdocs` site under `packages/sdk/python/docs/` +- Preview locally: +```bash +uv run --project packages/sdk/python mkdocs serve -f packages/sdk/python/mkdocs.yml +``` + +Badges +- PyPI: https://img.shields.io/pypi/v/opencode-ai?style=flat-square + +Requirements +- Python 3.8+ +- uv (recommended) -> https://docs.astral.sh/uv/ +- openapi-python-client (invoked via `uvx`) + +Install uv +```bash +# macOS/Linux +curl -LsSf https://astral.sh/uv/install.sh | sh +``` + +Set up the environment (from this directory) +```bash +uv sync --dev +``` + +Generate client code (from CLI-generated spec) +```bash +# From repository root OR from this directory +uv run python packages/sdk/python/scripts/generate.py --source cli +``` + +Alternatively, fetch spec from a running server +```bash +uv run python packages/sdk/python/scripts/generate.py --source server --server-url http://localhost:4096/doc +``` + +This will: +1) Produce an OpenAPI spec from the local CLI or a running server +2) Run openapi-python-client (via `uvx`) to generate client code +3) Copy the generated Python package into src/opencode_ai + +Usage (after generation) +```python +from opencode_ai import OpenCodeClient + +client = OpenCodeClient(base_url="http://localhost:4096") +print(client.get_config()) + +# See examples/basic_usage.py for more details + +# Streaming events (sync) +for event in client.subscribe_events(): + print(event) + break + +# Error handling and retries +# Set retries>0 to enable exponential backoff for transient errors like 429/5xx +client = OpenCodeClient(retries=2, backoff_factor=0.1) + +# Async usage example +# uv run --project packages/sdk/python python - <<'PY' +# import asyncio +# from opencode_ai import OpenCodeClient +# async def main(): +# client = OpenCodeClient() +# async for event in client.subscribe_events_async(): +# print(event) +# break +# asyncio.run(main()) +# PY +``` + +Notes +- We intentionally do not use Stainless for the Python SDK. +- The generator targets OpenAPI 3.1 emitted by the opencode server at /doc. +- See scripts/generate.py for details and customization points. diff --git a/packages/sdk/python/docs/generation.md b/packages/sdk/python/docs/generation.md new file mode 100644 index 0000000000..f949760a1b --- /dev/null +++ b/packages/sdk/python/docs/generation.md @@ -0,0 +1,19 @@ +# Generation workflow + +The SDK is generated from the Opencode server's OpenAPI 3.1 spec. + +Two source modes are supported: +- CLI (default): runs `bun dev generate` to emit the OpenAPI JSON +- Server: fetches `http://localhost:4096/doc` from a running server + +Generator command +```bash +# From repo root +uv run --project packages/sdk/python python packages/sdk/python/scripts/generate.py --source cli +# Or +uv run --project packages/sdk/python python packages/sdk/python/scripts/generate.py --source server --server-url http://localhost:4096/doc +``` + +Post-generation +- The generator injects `extras.py` (OpenCodeClient) and patches `__init__.py` to export it +- Code is formatted with `ruff` (imports) and `black` diff --git a/packages/sdk/python/docs/index.md b/packages/sdk/python/docs/index.md new file mode 100644 index 0000000000..bc7b550f9f --- /dev/null +++ b/packages/sdk/python/docs/index.md @@ -0,0 +1,11 @@ +# Opencode Python SDK + +The official Python client for the Opencode API, generated from the OpenAPI spec and extended with ergonomic helpers. + +Highlights +- Provider-agnostic client generated from OpenAPI 3.1 +- Thin convenience wrapper (OpenCodeClient) for common tasks +- Sync and async SSE streaming for live event feeds +- First-class uv support for development + +If you're new, start with Quickstart or Installation in the navigation. diff --git a/packages/sdk/python/docs/installation.md b/packages/sdk/python/docs/installation.md new file mode 100644 index 0000000000..f66e217ae1 --- /dev/null +++ b/packages/sdk/python/docs/installation.md @@ -0,0 +1,27 @@ +# Installation + +Requirements +- Python 3.8+ +- uv (recommended) -> https://docs.astral.sh/uv/ + +Install uv +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +``` + +Project setup +```bash +# From repo root or this directory +uv sync --dev --project packages/sdk/python +``` + +Using pip (alternative) +```bash +pip install opencode-ai +``` + +Preview docs locally +```bash +# From repo root +uv run --project packages/sdk/python mkdocs serve -f packages/sdk/python/mkdocs.yml +``` diff --git a/packages/sdk/python/docs/publishing.md b/packages/sdk/python/docs/publishing.md new file mode 100644 index 0000000000..c598baa88e --- /dev/null +++ b/packages/sdk/python/docs/publishing.md @@ -0,0 +1,24 @@ +# Publishing (maintainers) + +Automated publishing runs on GitHub Releases. + +Workflow +- Create a new Release (the tag value becomes the package version) +- The `publish-python-sdk` workflow will: + - Generate the SDK from OpenAPI (CLI path) + - Set the version in `pyproject.toml` and generator config + - Build wheel/sdist and upload to PyPI + +Prerequisites +- Repository secret: `PYPI_API_TOKEN` + +Manual publish +```bash +# TestPyPI +REPOSITORY=testpypi PYPI_TOKEN=$TEST_PYPI_API_TOKEN \ +uv run --project packages/sdk/python python packages/sdk/python/scripts/publish.py + +# PyPI +REPOSITORY=pypi PYPI_TOKEN=$PYPI_API_TOKEN \ +uv run --project packages/sdk/python python packages/sdk/python/scripts/publish.py +``` diff --git a/packages/sdk/python/docs/quickstart.md b/packages/sdk/python/docs/quickstart.md new file mode 100644 index 0000000000..97465c2031 --- /dev/null +++ b/packages/sdk/python/docs/quickstart.md @@ -0,0 +1,22 @@ +# Quickstart + +Create a client and make your first calls. + +```python +from opencode_ai import OpenCodeClient + +client = OpenCodeClient(base_url="http://localhost:4096") + +# List projects +for p in client.list_projects() or []: + print(p.id, p.directory) + +# Get path info +path = client.get_path() +print(path.directory) + +# Stream events (sync) +for event in client.subscribe_events(): + print(event) + break +``` diff --git a/packages/sdk/python/docs/testing.md b/packages/sdk/python/docs/testing.md new file mode 100644 index 0000000000..3119035d06 --- /dev/null +++ b/packages/sdk/python/docs/testing.md @@ -0,0 +1,15 @@ +# Testing + +Run unit, mock, and integration tests. + +```bash +# Sync dev dependencies +uv sync --dev --project packages/sdk/python + +# Run tests +uv run --project packages/sdk/python pytest -q +``` + +Notes +- Integration test starts a headless opencode server via Bun in a subprocess +- SSE behavior is validated using real streaming from the server diff --git a/packages/sdk/python/docs/usage/configuration.md b/packages/sdk/python/docs/usage/configuration.md new file mode 100644 index 0000000000..f5e0c60bb9 --- /dev/null +++ b/packages/sdk/python/docs/usage/configuration.md @@ -0,0 +1,21 @@ +# Configuration + +OpenCodeClient accepts common options for auth, timeouts, and retries. + +```python +from opencode_ai import OpenCodeClient + +client = OpenCodeClient( + base_url="http://localhost:4096", + token="pypi-or-other-token", + auth_header_name="Authorization", + auth_prefix="Bearer", + timeout=30.0, # seconds + retries=2, + backoff_factor=0.2, # exponential backoff +) +``` + +- Auth: sets the header `{auth_header_name}: {auth_prefix} {token}` when `token` is provided +- Retries: retry on transient httpx.RequestError and 429/5xx +- Timeouts: passed to httpx.Timeout diff --git a/packages/sdk/python/docs/usage/files_projects.md b/packages/sdk/python/docs/usage/files_projects.md new file mode 100644 index 0000000000..47f255e5a7 --- /dev/null +++ b/packages/sdk/python/docs/usage/files_projects.md @@ -0,0 +1,22 @@ +# Files & Projects + +Access file status and project information. + +```python +from opencode_ai import OpenCodeClient + +client = OpenCodeClient() + +# Projects +for p in client.list_projects() or []: + print(p.id, p.directory) + +# Current path +pinfo = client.get_path() +print(pinfo.directory) + +# File status +files = client.file_status() or [] +for f in files: + print(f.path, f.type) +``` diff --git a/packages/sdk/python/docs/usage/sessions.md b/packages/sdk/python/docs/usage/sessions.md new file mode 100644 index 0000000000..61f5b98898 --- /dev/null +++ b/packages/sdk/python/docs/usage/sessions.md @@ -0,0 +1,18 @@ +# Sessions + +List sessions and inspect them. The wrapper exposes a convenience method while the generated API remains available under `opencode_ai.api.default`. + +```python +from opencode_ai import OpenCodeClient +from opencode_ai.api.default import session_list as generated + +client = OpenCodeClient() + +# Wrapper +sessions = client.list_sessions() or [] + +# Generated function +sessions2 = generated.sync(client=client.client) + +print(len(sessions), len(sessions2)) +``` diff --git a/packages/sdk/python/docs/usage/streaming.md b/packages/sdk/python/docs/usage/streaming.md new file mode 100644 index 0000000000..31066e8dec --- /dev/null +++ b/packages/sdk/python/docs/usage/streaming.md @@ -0,0 +1,29 @@ +# Streaming (SSE) + +Subscribe to the event stream. The wrapper provides both sync and async interfaces. + +```python +from opencode_ai import OpenCodeClient + +client = OpenCodeClient() + +# Sync streaming +for event in client.subscribe_events(): + print(event) + break +``` + +Async variant: + +```python +import asyncio +from opencode_ai import OpenCodeClient + +async def main(): + client = OpenCodeClient() + async for event in client.subscribe_events_async(): + print(event) + break + +asyncio.run(main()) +``` diff --git a/packages/sdk/python/examples/basic_usage.py b/packages/sdk/python/examples/basic_usage.py new file mode 100644 index 0000000000..0d83499593 --- /dev/null +++ b/packages/sdk/python/examples/basic_usage.py @@ -0,0 +1,19 @@ +# Basic usage example (placeholder) +# After generating the client, this should reflect actual client entrypoints. + +try: + from opencode_ai import client # type: ignore +except Exception: # pragma: no cover + client = None + + +def main() -> None: + if client is None: + print("Client not generated yet. Run the generator first:") + print(" uv run python packages/sdk/python/scripts/generate.py") + return + print("Replace this with real example code once the client is generated.") + + +if __name__ == "__main__": + main() diff --git a/packages/sdk/python/examples/file_status.py b/packages/sdk/python/examples/file_status.py new file mode 100644 index 0000000000..e86cfa3f64 --- /dev/null +++ b/packages/sdk/python/examples/file_status.py @@ -0,0 +1,6 @@ +from opencode_ai import OpenCodeClient + +client = OpenCodeClient() +files = client.file_status() or [] +for f in files: + print(f.path, f.type) diff --git a/packages/sdk/python/examples/session_list.py b/packages/sdk/python/examples/session_list.py new file mode 100644 index 0000000000..6d4939f129 --- /dev/null +++ b/packages/sdk/python/examples/session_list.py @@ -0,0 +1,4 @@ +from opencode_ai import OpenCodeClient + +client = OpenCodeClient() +print([s.id for s in client.list_sessions() or []]) diff --git a/packages/sdk/python/mkdocs.yml b/packages/sdk/python/mkdocs.yml new file mode 100644 index 0000000000..25de28fb33 --- /dev/null +++ b/packages/sdk/python/mkdocs.yml @@ -0,0 +1,29 @@ +site_name: Opencode Python SDK +site_description: Official Python SDK for the Opencode API +site_url: https://opencode.ai +repo_url: https://github.com/sst/opencode +repo_name: sst/opencode +edit_uri: '' +theme: + name: material + features: + - navigation.tabs + - navigation.sections + - content.code.copy +markdown_extensions: + - admonition + - codehilite + - toc: + permalink: true +nav: + - Overview: index.md + - Installation: installation.md + - Quickstart: quickstart.md + - Usage: + - Configuration: usage/configuration.md + - Sessions: usage/sessions.md + - Files & Projects: usage/files_projects.md + - Streaming (SSE): usage/streaming.md + - Generation: generation.md + - Testing: testing.md + - Publishing (maintainers): publishing.md diff --git a/packages/sdk/python/openapi-python-client.yaml b/packages/sdk/python/openapi-python-client.yaml new file mode 100644 index 0000000000..d7987f9af9 --- /dev/null +++ b/packages/sdk/python/openapi-python-client.yaml @@ -0,0 +1,5 @@ +# Configuration for openapi-python-client +# Ensures consistent project and package names and version when generating. +project_name_override: opencode-ai +package_name_override: opencode_ai +package_version_override: 0.1.0 diff --git a/packages/sdk/python/pyproject.toml b/packages/sdk/python/pyproject.toml new file mode 100644 index 0000000000..47c63a2647 --- /dev/null +++ b/packages/sdk/python/pyproject.toml @@ -0,0 +1,56 @@ +[build-system] +requires = ["hatchling>=1.17.0"] +build-backend = "hatchling.build" + +[project] +name = "opencode-ai" +version = "0.1.0" +description = "Python client for the Opencode API (generated via openapi-python-client)" +readme = "README.md" +requires-python = ">=3.8" +license = {text = "MIT"} +authors = [ + { name = "Opencode Authors", email = "support@sst.dev" } +] +dependencies = [ + "httpx>=0.27.0", + "pydantic>=2.0.0", + "python-dateutil>=2.8.2" +] + +[project.urls] +Homepage = "https://opencode.ai" +Repository = "https://github.com/sst/opencode" + +[tool.uv] +# Development-time dependencies installed with `uv sync --dev` +dev-dependencies = [ + "openapi-python-client", + "black", + "isort", + "ruff", + "pytest", + "pytest-asyncio", + "sseclient-py", + "build", + "twine", + "mkdocs", + "mkdocs-material", +] + +[tool.black] +line-length = 120 +target-version = ["py38", "py39", "py310", "py311", "py312"] + +[tool.isort] +profile = "black" +line_length = 120 + +[tool.ruff] +line-length = 120 +select = ["E", "F", "I", "UP"] +ignore = [] + +[tool.pytest.ini_options] +addopts = "-q" +pythonpath = ["src"] diff --git a/packages/sdk/python/scripts/generate.py b/packages/sdk/python/scripts/generate.py new file mode 100644 index 0000000000..8dc89113b6 --- /dev/null +++ b/packages/sdk/python/scripts/generate.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +""" +Generate the Opencode Python SDK using openapi-python-client and place it under src/opencode_ai. + +Steps: +- Generate OpenAPI JSON from the local CLI (bun dev generate) +- Run openapi-python-client (via `uvx` if available, else fallback to PATH) +- Copy the generated module into src/opencode_ai + +Requires: +- Bun installed (for `bun dev generate`) +- uv installed (recommended) to run `uvx openapi-python-client` +""" +from __future__ import annotations + +import argparse +import json +import shutil +import subprocess +import sys +from pathlib import Path +from urllib.request import urlopen + + +def run(cmd: list[str], cwd: Path | None = None) -> subprocess.CompletedProcess: + print("$", " ".join(cmd)) + return subprocess.run(cmd, cwd=str(cwd) if cwd else None, check=True, capture_output=True, text=True) + + +def find_repo_root(start: Path) -> Path: + p = start + for _ in range(10): + if (p / ".git").exists() or (p / "sst.config.ts").exists(): + return p + if p.parent == p: + break + p = p.parent + # Fallback: assume 4 levels up from scripts/ + return start.parents[4] + + +def write_json(path: Path, content: str) -> None: + # Validate JSON before writing + json.loads(content) + path.write_text(content) + + +def main() -> int: + parser = argparse.ArgumentParser(description="Generate the Opencode Python SDK from OpenAPI spec.") + parser.add_argument( + "--source", choices=["cli", "server"], default="cli", help="Where to fetch the OpenAPI spec from" + ) + parser.add_argument( + "--server-url", + default="http://localhost:4096/doc", + help="OpenAPI document URL when --source=server", + ) + parser.add_argument( + "--out-spec", + default=None, + help="Output path for the OpenAPI spec (defaults to packages/sdk/python/openapi.json)", + ) + parser.add_argument( + "--only-spec", + action="store_true", + help="Only fetch and write the OpenAPI spec without generating the client", + ) + args = parser.parse_args() + + script_dir = Path(__file__).resolve().parent + sdk_dir = script_dir.parent + repo_root = find_repo_root(script_dir) + opencode_dir = repo_root / "packages" / "opencode" + + openapi_json = Path(args.out_spec) if args.out_spec else (sdk_dir / "openapi.json") + build_dir = sdk_dir / ".build" + out_pkg_dir = sdk_dir / "src" / "opencode_ai" + + build_dir.mkdir(parents=True, exist_ok=True) + (sdk_dir / "src").mkdir(parents=True, exist_ok=True) + + # 1) Obtain OpenAPI spec + if args.source == "server": + print(f"Fetching OpenAPI spec from {args.server_url} ...") + try: + with urlopen(args.server_url) as resp: + if resp.status != 200: + print(f"ERROR: GET {args.server_url} -> HTTP {resp.status}", file=sys.stderr) + return 1 + text = resp.read().decode("utf-8") + except Exception as e: + print(f"ERROR: Failed to fetch from server: {e}", file=sys.stderr) + return 1 + try: + write_json(openapi_json, text) + except json.JSONDecodeError as je: + print("ERROR: Response from server was not valid JSON:", file=sys.stderr) + print(str(je), file=sys.stderr) + return 1 + print(f"Wrote OpenAPI spec to {openapi_json}") + else: + print("Generating OpenAPI spec via 'bun dev generate' ...") + try: + proc = run(["bun", "dev", "generate"], cwd=opencode_dir) + except subprocess.CalledProcessError as e: + print(e.stdout) + print(e.stderr, file=sys.stderr) + print( + "ERROR: Failed to run 'bun dev generate'. Ensure Bun is installed and available in PATH.", + file=sys.stderr, + ) + return 1 + try: + write_json(openapi_json, proc.stdout) + except json.JSONDecodeError as je: + print("ERROR: Output from 'bun dev generate' was not valid JSON:", file=sys.stderr) + print(str(je), file=sys.stderr) + return 1 + print(f"Wrote OpenAPI spec to {openapi_json}") + + if args.only_spec: + print("Spec written; skipping client generation (--only-spec).") + return 0 + + # 2) Run openapi-python-client + print("Running openapi-python-client generate ...") + # Prefer uvx if available + use_uvx = shutil.which("uvx") is not None + cmd = (["uvx", "openapi-python-client", "generate"] if use_uvx else ["openapi-python-client", "generate"]) + [ + "--path", + str(openapi_json), + "--output-path", + str(build_dir), + "--overwrite", + "--config", + str(sdk_dir / "openapi-python-client.yaml"), + ] + + try: + run(cmd, cwd=sdk_dir) + except subprocess.CalledProcessError as e: + print(e.stdout) + print(e.stderr, file=sys.stderr) + print( + "ERROR: Failed to run openapi-python-client. Install uv and try again: curl -LsSf https://astral.sh/uv/install.sh | sh", + file=sys.stderr, + ) + return 1 + + # 3) Locate generated module directory and copy to src/opencode_ai + generated_module: Path | None = None + for candidate in build_dir.rglob("__init__.py"): + if candidate.parent.name.startswith("."): + continue + siblings = {p.name for p in candidate.parent.glob("*.py")} + if "client.py" in siblings or "api_client.py" in siblings: + generated_module = candidate.parent + break + + if not generated_module: + print("ERROR: Could not locate generated module directory in .build", file=sys.stderr) + return 1 + + print(f"Found generated module at {generated_module}") + + # Clean target then copy + if out_pkg_dir.exists(): + shutil.rmtree(out_pkg_dir) + shutil.copytree(generated_module, out_pkg_dir) + + # Inject local extras from template if present + extras_template = sdk_dir / "templates" / "extras.py" + if extras_template.exists(): + (out_pkg_dir / "extras.py").write_text(extras_template.read_text()) + + # Patch __init__ to export OpenCodeClient if present + init_path = out_pkg_dir / "__init__.py" + if init_path.exists() and (out_pkg_dir / "extras.py").exists(): + init_text = ( + '"""A client library for accessing opencode\n\n' + "This package is generated by openapi-python-client.\n" + "A thin convenience wrapper `OpenCodeClient` is also provided.\n" + '"""\n\n' + "from .client import AuthenticatedClient, Client\n" + "from .extras import OpenCodeClient\n\n" + "__all__ = (\n" + ' "AuthenticatedClient",\n' + ' "Client",\n' + ' "OpenCodeClient",\n' + ")\n" + ) + init_path.write_text(init_text) + + print(f"Copied generated client to {out_pkg_dir}") + + # 4) Format generated code + try: + run(["uv", "run", "--project", str(sdk_dir), "ruff", "check", "--select", "I", "--fix", str(out_pkg_dir)]) + run(["uv", "run", "--project", str(sdk_dir), "black", str(out_pkg_dir)]) + except subprocess.CalledProcessError as e: + print("WARNING: formatting failed; continuing", file=sys.stderr) + print(e.stdout) + print(e.stderr, file=sys.stderr) + + print("Done.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/packages/sdk/python/scripts/publish.py b/packages/sdk/python/scripts/publish.py new file mode 100644 index 0000000000..f591006a09 --- /dev/null +++ b/packages/sdk/python/scripts/publish.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +""" +Python SDK publishing helper. + +- Builds sdist and wheel using `python -m build` into dist/ +- Uploads using twine. Configure either TestPyPI or PyPI via environment: + +Environment variables: + REPOSITORY : "pypi" (default) or "testpypi" + PYPI_TOKEN : API token (e.g., pypi-XXXX). For TestPyPI, use the TestPyPI token. + +Examples: + REPOSITORY=testpypi PYPI_TOKEN=${{TEST_PYPI_API_TOKEN}} uv run --project packages/sdk/python python packages/sdk/python/scripts/publish.py +""" +from __future__ import annotations + +import os +import subprocess +from pathlib import Path + + +def run(cmd: list[str], cwd: Path | None = None) -> None: + print("$", " ".join(cmd)) + subprocess.run(cmd, cwd=str(cwd) if cwd else None, check=True) + + +def main() -> int: + sdk_dir = Path(__file__).resolve().parent.parent + repo = os.environ.get("REPOSITORY", "pypi").strip() + token = os.environ.get("PYPI_TOKEN") + if not token: + print("ERROR: PYPI_TOKEN not set", flush=True) + return 1 + + dist = sdk_dir / "dist" + if dist.exists(): + for f in dist.iterdir(): + f.unlink() + + # Build + run(["python", "-m", "build"], cwd=sdk_dir) + + # Upload + repo_url = { + "pypi": "https://upload.pypi.org/legacy/", + "testpypi": "https://test.pypi.org/legacy/", + }.get(repo, repo) + + env = os.environ.copy() + env["TWINE_USERNAME"] = "__token__" + env["TWINE_PASSWORD"] = token + + print(f"Uploading to {repo_url}") + subprocess.run( + ["python", "-m", "twine", "check", "dist/*"], cwd=sdk_dir, check=True + ) + subprocess.run( + ["python", "-m", "twine", "upload", "--repository-url", repo_url, "dist/*"], + cwd=sdk_dir, + check=True, + env=env, + ) + print("Publish complete") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/packages/sdk/python/src/opencode_ai/__init__.py b/packages/sdk/python/src/opencode_ai/__init__.py new file mode 100644 index 0000000000..846209d2ec --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/__init__.py @@ -0,0 +1,14 @@ +"""A client library for accessing opencode + +This package is generated by openapi-python-client. +A thin convenience wrapper `OpenCodeClient` is also provided. +""" + +from .client import AuthenticatedClient, Client +from .extras import OpenCodeClient + +__all__ = ( + "AuthenticatedClient", + "Client", + "OpenCodeClient", +) diff --git a/packages/sdk/python/src/opencode_ai/api/__init__.py b/packages/sdk/python/src/opencode_ai/api/__init__.py new file mode 100644 index 0000000000..81f9fa241b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/__init__.py @@ -0,0 +1 @@ +"""Contains methods for accessing the API""" diff --git a/packages/sdk/python/src/opencode_ai/api/default/__init__.py b/packages/sdk/python/src/opencode_ai/api/default/__init__.py new file mode 100644 index 0000000000..2d7c0b23da --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/packages/sdk/python/src/opencode_ai/api/default/app_agents.py b/packages/sdk/python/src/opencode_ai/api/default/app_agents.py new file mode 100644 index 0000000000..075b6ed2bb --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/app_agents.py @@ -0,0 +1,160 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.agent import Agent +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/agent", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[list["Agent"]]: + if response.status_code == 200: + response_200 = [] + _response_200 = response.json() + for response_200_item_data in _response_200: + response_200_item = Agent.from_dict(response_200_item_data) + + response_200.append(response_200_item) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[list["Agent"]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["Agent"]]: + """List all agents + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['Agent']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["Agent"]]: + """List all agents + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['Agent'] + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["Agent"]]: + """List all agents + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['Agent']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["Agent"]]: + """List all agents + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['Agent'] + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/command_list.py b/packages/sdk/python/src/opencode_ai/api/default/command_list.py new file mode 100644 index 0000000000..976a245848 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/command_list.py @@ -0,0 +1,164 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.command import Command +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/command", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[list["Command"]]: + if response.status_code == 200: + response_200 = [] + _response_200 = response.json() + for response_200_item_data in _response_200: + response_200_item = Command.from_dict(response_200_item_data) + + response_200.append(response_200_item) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[list["Command"]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["Command"]]: + """List all commands + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['Command']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["Command"]]: + """List all commands + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['Command'] + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["Command"]]: + """List all commands + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['Command']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["Command"]]: + """List all commands + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['Command'] + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/config_get.py b/packages/sdk/python/src/opencode_ai/api/default/config_get.py new file mode 100644 index 0000000000..71e387ffb4 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/config_get.py @@ -0,0 +1,155 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.config import Config +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/config", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Config]: + if response.status_code == 200: + response_200 = Config.from_dict(response.json()) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Config]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[Config]: + """Get config info + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Config] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[Config]: + """Get config info + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Config + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[Config]: + """Get config info + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Config] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[Config]: + """Get config info + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Config + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/config_providers.py b/packages/sdk/python/src/opencode_ai/api/default/config_providers.py new file mode 100644 index 0000000000..a7f031c497 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/config_providers.py @@ -0,0 +1,159 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.config_providers_response_200 import ConfigProvidersResponse200 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/config/providers", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[ConfigProvidersResponse200]: + if response.status_code == 200: + response_200 = ConfigProvidersResponse200.from_dict(response.json()) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[ConfigProvidersResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[ConfigProvidersResponse200]: + """List all providers + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ConfigProvidersResponse200] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[ConfigProvidersResponse200]: + """List all providers + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ConfigProvidersResponse200 + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[ConfigProvidersResponse200]: + """List all providers + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ConfigProvidersResponse200] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[ConfigProvidersResponse200]: + """List all providers + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ConfigProvidersResponse200 + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/event_subscribe.py b/packages/sdk/python/src/opencode_ai/api/default/event_subscribe.py new file mode 100644 index 0000000000..9b86214e28 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/event_subscribe.py @@ -0,0 +1,447 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.event_file_edited import EventFileEdited +from ...models.event_file_watcher_updated import EventFileWatcherUpdated +from ...models.event_ide_installed import EventIdeInstalled +from ...models.event_installation_updated import EventInstallationUpdated +from ...models.event_lsp_client_diagnostics import EventLspClientDiagnostics +from ...models.event_message_part_removed import EventMessagePartRemoved +from ...models.event_message_part_updated import EventMessagePartUpdated +from ...models.event_message_removed import EventMessageRemoved +from ...models.event_message_updated import EventMessageUpdated +from ...models.event_permission_replied import EventPermissionReplied +from ...models.event_permission_updated import EventPermissionUpdated +from ...models.event_server_connected import EventServerConnected +from ...models.event_session_compacted import EventSessionCompacted +from ...models.event_session_deleted import EventSessionDeleted +from ...models.event_session_error import EventSessionError +from ...models.event_session_idle import EventSessionIdle +from ...models.event_session_updated import EventSessionUpdated +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/event", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[ + Union[ + "EventFileEdited", + "EventFileWatcherUpdated", + "EventIdeInstalled", + "EventInstallationUpdated", + "EventLspClientDiagnostics", + "EventMessagePartRemoved", + "EventMessagePartUpdated", + "EventMessageRemoved", + "EventMessageUpdated", + "EventPermissionReplied", + "EventPermissionUpdated", + "EventServerConnected", + "EventSessionCompacted", + "EventSessionDeleted", + "EventSessionError", + "EventSessionIdle", + "EventSessionUpdated", + ] +]: + if response.status_code == 200: + + def _parse_response_200( + data: object, + ) -> Union[ + "EventFileEdited", + "EventFileWatcherUpdated", + "EventIdeInstalled", + "EventInstallationUpdated", + "EventLspClientDiagnostics", + "EventMessagePartRemoved", + "EventMessagePartUpdated", + "EventMessageRemoved", + "EventMessageUpdated", + "EventPermissionReplied", + "EventPermissionUpdated", + "EventServerConnected", + "EventSessionCompacted", + "EventSessionDeleted", + "EventSessionError", + "EventSessionIdle", + "EventSessionUpdated", + ]: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_0 = EventInstallationUpdated.from_dict(data) + + return componentsschemas_event_type_0 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_1 = EventLspClientDiagnostics.from_dict(data) + + return componentsschemas_event_type_1 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_2 = EventMessageUpdated.from_dict(data) + + return componentsschemas_event_type_2 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_3 = EventMessageRemoved.from_dict(data) + + return componentsschemas_event_type_3 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_4 = EventMessagePartUpdated.from_dict(data) + + return componentsschemas_event_type_4 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_5 = EventMessagePartRemoved.from_dict(data) + + return componentsschemas_event_type_5 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_6 = EventSessionCompacted.from_dict(data) + + return componentsschemas_event_type_6 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_7 = EventPermissionUpdated.from_dict(data) + + return componentsschemas_event_type_7 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_8 = EventPermissionReplied.from_dict(data) + + return componentsschemas_event_type_8 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_9 = EventFileEdited.from_dict(data) + + return componentsschemas_event_type_9 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_10 = EventSessionIdle.from_dict(data) + + return componentsschemas_event_type_10 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_11 = EventSessionUpdated.from_dict(data) + + return componentsschemas_event_type_11 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_12 = EventSessionDeleted.from_dict(data) + + return componentsschemas_event_type_12 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_13 = EventSessionError.from_dict(data) + + return componentsschemas_event_type_13 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_14 = EventFileWatcherUpdated.from_dict(data) + + return componentsschemas_event_type_14 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_15 = EventServerConnected.from_dict(data) + + return componentsschemas_event_type_15 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_event_type_16 = EventIdeInstalled.from_dict(data) + + return componentsschemas_event_type_16 + + response_200 = _parse_response_200(response.text) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[ + Union[ + "EventFileEdited", + "EventFileWatcherUpdated", + "EventIdeInstalled", + "EventInstallationUpdated", + "EventLspClientDiagnostics", + "EventMessagePartRemoved", + "EventMessagePartUpdated", + "EventMessageRemoved", + "EventMessageUpdated", + "EventPermissionReplied", + "EventPermissionUpdated", + "EventServerConnected", + "EventSessionCompacted", + "EventSessionDeleted", + "EventSessionError", + "EventSessionIdle", + "EventSessionUpdated", + ] +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[ + Union[ + "EventFileEdited", + "EventFileWatcherUpdated", + "EventIdeInstalled", + "EventInstallationUpdated", + "EventLspClientDiagnostics", + "EventMessagePartRemoved", + "EventMessagePartUpdated", + "EventMessageRemoved", + "EventMessageUpdated", + "EventPermissionReplied", + "EventPermissionUpdated", + "EventServerConnected", + "EventSessionCompacted", + "EventSessionDeleted", + "EventSessionError", + "EventSessionIdle", + "EventSessionUpdated", + ] +]: + """Get events + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union['EventFileEdited', 'EventFileWatcherUpdated', 'EventIdeInstalled', 'EventInstallationUpdated', 'EventLspClientDiagnostics', 'EventMessagePartRemoved', 'EventMessagePartUpdated', 'EventMessageRemoved', 'EventMessageUpdated', 'EventPermissionReplied', 'EventPermissionUpdated', 'EventServerConnected', 'EventSessionCompacted', 'EventSessionDeleted', 'EventSessionError', 'EventSessionIdle', 'EventSessionUpdated']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[ + Union[ + "EventFileEdited", + "EventFileWatcherUpdated", + "EventIdeInstalled", + "EventInstallationUpdated", + "EventLspClientDiagnostics", + "EventMessagePartRemoved", + "EventMessagePartUpdated", + "EventMessageRemoved", + "EventMessageUpdated", + "EventPermissionReplied", + "EventPermissionUpdated", + "EventServerConnected", + "EventSessionCompacted", + "EventSessionDeleted", + "EventSessionError", + "EventSessionIdle", + "EventSessionUpdated", + ] +]: + """Get events + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union['EventFileEdited', 'EventFileWatcherUpdated', 'EventIdeInstalled', 'EventInstallationUpdated', 'EventLspClientDiagnostics', 'EventMessagePartRemoved', 'EventMessagePartUpdated', 'EventMessageRemoved', 'EventMessageUpdated', 'EventPermissionReplied', 'EventPermissionUpdated', 'EventServerConnected', 'EventSessionCompacted', 'EventSessionDeleted', 'EventSessionError', 'EventSessionIdle', 'EventSessionUpdated'] + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[ + Union[ + "EventFileEdited", + "EventFileWatcherUpdated", + "EventIdeInstalled", + "EventInstallationUpdated", + "EventLspClientDiagnostics", + "EventMessagePartRemoved", + "EventMessagePartUpdated", + "EventMessageRemoved", + "EventMessageUpdated", + "EventPermissionReplied", + "EventPermissionUpdated", + "EventServerConnected", + "EventSessionCompacted", + "EventSessionDeleted", + "EventSessionError", + "EventSessionIdle", + "EventSessionUpdated", + ] +]: + """Get events + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union['EventFileEdited', 'EventFileWatcherUpdated', 'EventIdeInstalled', 'EventInstallationUpdated', 'EventLspClientDiagnostics', 'EventMessagePartRemoved', 'EventMessagePartUpdated', 'EventMessageRemoved', 'EventMessageUpdated', 'EventPermissionReplied', 'EventPermissionUpdated', 'EventServerConnected', 'EventSessionCompacted', 'EventSessionDeleted', 'EventSessionError', 'EventSessionIdle', 'EventSessionUpdated']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[ + Union[ + "EventFileEdited", + "EventFileWatcherUpdated", + "EventIdeInstalled", + "EventInstallationUpdated", + "EventLspClientDiagnostics", + "EventMessagePartRemoved", + "EventMessagePartUpdated", + "EventMessageRemoved", + "EventMessageUpdated", + "EventPermissionReplied", + "EventPermissionUpdated", + "EventServerConnected", + "EventSessionCompacted", + "EventSessionDeleted", + "EventSessionError", + "EventSessionIdle", + "EventSessionUpdated", + ] +]: + """Get events + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union['EventFileEdited', 'EventFileWatcherUpdated', 'EventIdeInstalled', 'EventInstallationUpdated', 'EventLspClientDiagnostics', 'EventMessagePartRemoved', 'EventMessagePartUpdated', 'EventMessageRemoved', 'EventMessageUpdated', 'EventPermissionReplied', 'EventPermissionUpdated', 'EventServerConnected', 'EventSessionCompacted', 'EventSessionDeleted', 'EventSessionError', 'EventSessionIdle', 'EventSessionUpdated'] + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/file_status.py b/packages/sdk/python/src/opencode_ai/api/default/file_status.py new file mode 100644 index 0000000000..8eecc3f2d4 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/file_status.py @@ -0,0 +1,160 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.file import File +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/file/status", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[list["File"]]: + if response.status_code == 200: + response_200 = [] + _response_200 = response.json() + for response_200_item_data in _response_200: + response_200_item = File.from_dict(response_200_item_data) + + response_200.append(response_200_item) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[list["File"]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["File"]]: + """Get file status + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['File']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["File"]]: + """Get file status + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['File'] + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["File"]]: + """Get file status + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['File']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["File"]]: + """Get file status + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['File'] + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/path_get.py b/packages/sdk/python/src/opencode_ai/api/default/path_get.py new file mode 100644 index 0000000000..c869a4586d --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/path_get.py @@ -0,0 +1,155 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.path import Path +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/path", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Path]: + if response.status_code == 200: + response_200 = Path.from_dict(response.json()) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Path]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[Path]: + """Get the current path + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Path] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[Path]: + """Get the current path + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Path + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[Path]: + """Get the current path + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Path] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[Path]: + """Get the current path + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Path + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/project_current.py b/packages/sdk/python/src/opencode_ai/api/default/project_current.py new file mode 100644 index 0000000000..712c6fd43b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/project_current.py @@ -0,0 +1,155 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.project import Project +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/project/current", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Project]: + if response.status_code == 200: + response_200 = Project.from_dict(response.json()) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Project]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[Project]: + """Get the current project + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Project] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[Project]: + """Get the current project + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Project + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[Project]: + """Get the current project + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Project] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[Project]: + """Get the current project + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Project + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/project_list.py b/packages/sdk/python/src/opencode_ai/api/default/project_list.py new file mode 100644 index 0000000000..5ec38ae2b8 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/project_list.py @@ -0,0 +1,164 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.project import Project +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/project", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[list["Project"]]: + if response.status_code == 200: + response_200 = [] + _response_200 = response.json() + for response_200_item_data in _response_200: + response_200_item = Project.from_dict(response_200_item_data) + + response_200.append(response_200_item) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[list["Project"]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["Project"]]: + """List all projects + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['Project']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["Project"]]: + """List all projects + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['Project'] + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["Project"]]: + """List all projects + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['Project']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["Project"]]: + """List all projects + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['Project'] + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/session_list.py b/packages/sdk/python/src/opencode_ai/api/default/session_list.py new file mode 100644 index 0000000000..8e7fd6a6fd --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/session_list.py @@ -0,0 +1,164 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.session import Session +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/session", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[list["Session"]]: + if response.status_code == 200: + response_200 = [] + _response_200 = response.json() + for response_200_item_data in _response_200: + response_200_item = Session.from_dict(response_200_item_data) + + response_200.append(response_200_item) + + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[list["Session"]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["Session"]]: + """List all sessions + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['Session']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["Session"]]: + """List all sessions + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['Session'] + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[list["Session"]]: + """List all sessions + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[list['Session']] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[list["Session"]]: + """List all sessions + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + list['Session'] + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/tool_ids.py b/packages/sdk/python/src/opencode_ai/api/default/tool_ids.py new file mode 100644 index 0000000000..0315cd1950 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/tool_ids.py @@ -0,0 +1,164 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/experimental/tool/ids", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Error, list[str]]]: + if response.status_code == 200: + response_200 = cast(list[str], response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = Error.from_dict(response.json()) + + return response_400 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Error, list[str]]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[Union[Error, list[str]]]: + """List all tool IDs (including built-in and dynamically registered) + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, list[str]]] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[Union[Error, list[str]]]: + """List all tool IDs (including built-in and dynamically registered) + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, list[str]] + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[Union[Error, list[str]]]: + """List all tool IDs (including built-in and dynamically registered) + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, list[str]]] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[Union[Error, list[str]]]: + """List all tool IDs (including built-in and dynamically registered) + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, list[str]] + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/tui_clear_prompt.py b/packages/sdk/python/src/opencode_ai/api/default/tui_clear_prompt.py new file mode 100644 index 0000000000..a7c5ef50d2 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/tui_clear_prompt.py @@ -0,0 +1,153 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tui/clear-prompt", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[bool]: + if response.status_code == 200: + response_200 = cast(bool, response.json()) + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[bool]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Clear the prompt + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Clear the prompt + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Clear the prompt + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Clear the prompt + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/tui_open_help.py b/packages/sdk/python/src/opencode_ai/api/default/tui_open_help.py new file mode 100644 index 0000000000..e7ae959a7b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/tui_open_help.py @@ -0,0 +1,153 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tui/open-help", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[bool]: + if response.status_code == 200: + response_200 = cast(bool, response.json()) + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[bool]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Open the help dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Open the help dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Open the help dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Open the help dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/tui_open_models.py b/packages/sdk/python/src/opencode_ai/api/default/tui_open_models.py new file mode 100644 index 0000000000..a6dddf1363 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/tui_open_models.py @@ -0,0 +1,153 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tui/open-models", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[bool]: + if response.status_code == 200: + response_200 = cast(bool, response.json()) + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[bool]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Open the model dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Open the model dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Open the model dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Open the model dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/tui_open_sessions.py b/packages/sdk/python/src/opencode_ai/api/default/tui_open_sessions.py new file mode 100644 index 0000000000..579934f26b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/tui_open_sessions.py @@ -0,0 +1,153 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tui/open-sessions", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[bool]: + if response.status_code == 200: + response_200 = cast(bool, response.json()) + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[bool]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Open the session dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Open the session dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Open the session dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Open the session dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/tui_open_themes.py b/packages/sdk/python/src/opencode_ai/api/default/tui_open_themes.py new file mode 100644 index 0000000000..05db1aadfd --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/tui_open_themes.py @@ -0,0 +1,153 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tui/open-themes", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[bool]: + if response.status_code == 200: + response_200 = cast(bool, response.json()) + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[bool]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Open the theme dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Open the theme dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Open the theme dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Open the theme dialog + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/api/default/tui_submit_prompt.py b/packages/sdk/python/src/opencode_ai/api/default/tui_submit_prompt.py new file mode 100644 index 0000000000..d16a75d279 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/api/default/tui_submit_prompt.py @@ -0,0 +1,153 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + directory: Union[Unset, str] = UNSET, +) -> dict[str, Any]: + params: dict[str, Any] = {} + + params["directory"] = directory + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/tui/submit-prompt", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[bool]: + if response.status_code == 200: + response_200 = cast(bool, response.json()) + return response_200 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[bool]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Submit the prompt + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Submit the prompt + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return sync_detailed( + client=client, + directory=directory, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Response[bool]: + """Submit the prompt + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[bool] + """ + + kwargs = _get_kwargs( + directory=directory, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + directory: Union[Unset, str] = UNSET, +) -> Optional[bool]: + """Submit the prompt + + Args: + directory (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + bool + """ + + return ( + await asyncio_detailed( + client=client, + directory=directory, + ) + ).parsed diff --git a/packages/sdk/python/src/opencode_ai/client.py b/packages/sdk/python/src/opencode_ai/client.py new file mode 100644 index 0000000000..e80446f108 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/client.py @@ -0,0 +1,268 @@ +import ssl +from typing import Any, Optional, Union + +import httpx +from attrs import define, evolve, field + + +@define +class Client: + """A class for keeping track of data related to the API + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + def with_headers(self, headers: dict[str, str]) -> "Client": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "Client": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "Client": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "Client": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "Client": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "Client": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + token: The token to use for authentication + prefix: The prefix to use for the Authorization header + auth_header_name: The name of the Authorization header + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) diff --git a/packages/sdk/python/src/opencode_ai/errors.py b/packages/sdk/python/src/opencode_ai/errors.py new file mode 100644 index 0000000000..5f92e76aca --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/errors.py @@ -0,0 +1,16 @@ +"""Contains shared errors types that can be raised from API functions""" + + +class UnexpectedStatus(Exception): + """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" + + def __init__(self, status_code: int, content: bytes): + self.status_code = status_code + self.content = content + + super().__init__( + f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}" + ) + + +__all__ = ["UnexpectedStatus"] diff --git a/packages/sdk/python/src/opencode_ai/extras.py b/packages/sdk/python/src/opencode_ai/extras.py new file mode 100644 index 0000000000..1a91101960 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/extras.py @@ -0,0 +1,186 @@ +from __future__ import annotations + +import time +from typing import AsyncIterator, Dict, Iterator, Optional + +import httpx + +from .api.default import ( + app_agents, + command_list, + config_get, + config_providers, + file_status, + path_get, + project_current, + project_list, + session_list, + tool_ids, +) +from .client import Client +from .types import UNSET, Unset + + +class OpenCodeClient: + """High-level convenience wrapper around the generated Client. + + Provides sensible defaults and a couple of helper methods, with optional retries. + """ + + def __init__( + self, + base_url: str = "http://localhost:4096", + *, + headers: Optional[Dict[str, str]] = None, + timeout: Optional[float] = None, + verify_ssl: bool | str | httpx.URLTypes | None = True, + token: Optional[str] = None, + auth_header_name: str = "Authorization", + auth_prefix: str = "Bearer", + retries: int = 0, + backoff_factor: float = 0.5, + status_forcelist: tuple[int, ...] = (429, 500, 502, 503, 504), + ) -> None: + httpx_timeout = None if timeout is None else httpx.Timeout(timeout) + all_headers = dict(headers or {}) + if token: + all_headers[auth_header_name] = f"{auth_prefix} {token}".strip() + self._client = Client( + base_url=base_url, + headers=all_headers, + timeout=httpx_timeout, + verify_ssl=verify_ssl if isinstance(verify_ssl, bool) else True, + ) + self._retries = max(0, int(retries)) + self._backoff = float(backoff_factor) + self._status_forcelist = set(status_forcelist) + + @property + def client(self) -> Client: + return self._client + + # ---- Internal retry helper ---- + + def _call_with_retries(self, fn, *args, **kwargs): + attempt = 0 + while True: + try: + return fn(*args, **kwargs) + except httpx.RequestError: + pass + except httpx.HTTPStatusError as e: + if e.response is None or e.response.status_code not in self._status_forcelist: + raise + if attempt >= self._retries: + # re-raise last exception if we have one + raise + sleep = self._backoff * (2**attempt) + time.sleep(sleep) + attempt += 1 + + # ---- Convenience wrappers over generated endpoints ---- + + def list_sessions(self, *, directory: str | Unset = UNSET): + """Return sessions in the current project. + + Wraps GET /session. Pass `directory` to target a specific project/directory if needed. + """ + return self._call_with_retries(session_list.sync, client=self._client, directory=directory) + + def get_config(self, *, directory: str | Unset = UNSET): + """Return opencode configuration for the current project (GET /config).""" + return self._call_with_retries(config_get.sync, client=self._client, directory=directory) + + def list_agents(self, *, directory: str | Unset = UNSET): + """List configured agents (GET /agent).""" + return self._call_with_retries(app_agents.sync, client=self._client, directory=directory) + + def list_projects(self, *, directory: str | Unset = UNSET): + """List known projects (GET /project).""" + return self._call_with_retries(project_list.sync, client=self._client, directory=directory) + + def current_project(self, *, directory: str | Unset = UNSET): + """Return current project (GET /project/current).""" + return self._call_with_retries(project_current.sync, client=self._client, directory=directory) + + def file_status(self, *, directory: str | Unset = UNSET): + """Return file status list (GET /file/status).""" + return self._call_with_retries(file_status.sync, client=self._client, directory=directory) + + def get_path(self, *, directory: str | Unset = UNSET): + """Return opencode path info (GET /path).""" + return self._call_with_retries(path_get.sync, client=self._client, directory=directory) + + def config_providers(self, *, directory: str | Unset = UNSET): + """Return configured providers (GET /config/providers).""" + return self._call_with_retries(config_providers.sync, client=self._client, directory=directory) + + def tool_ids(self, *, directory: str | Unset = UNSET): + """Return tool identifiers for a provider/model pair (GET /experimental/tool).""" + return self._call_with_retries(tool_ids.sync, client=self._client, directory=directory) + + def list_commands(self, *, directory: str | Unset = UNSET): + """List commands (GET /command).""" + return self._call_with_retries(command_list.sync, client=self._client, directory=directory) + + # ---- Server-Sent Events (SSE) streaming ---- + + def subscribe_events(self, *, directory: str | Unset = UNSET) -> Iterator[dict]: + """Subscribe to /event SSE endpoint and yield parsed JSON events. + + This is a blocking generator which yields one event dict per message. + """ + client = self._client.get_httpx_client() + params: dict[str, str] = {} + if directory is not UNSET and directory is not None: + params["directory"] = str(directory) + with client.stream("GET", "/event", headers={"Accept": "text/event-stream"}, params=params) as r: + r.raise_for_status() + buf = "" + for line_bytes in r.iter_lines(): + line = line_bytes.decode("utf-8") if isinstance(line_bytes, (bytes, bytearray)) else str(line_bytes) + if line.startswith(":"): + # comment/heartbeat + continue + if line == "": + if buf: + # end of event + for part in buf.split("\n"): + if part.startswith("data:"): + data = part[5:].strip() + if data: + try: + yield httpx._models.jsonlib.loads(data) # type: ignore[attr-defined] + except Exception: + # fall back: skip malformed + pass + buf = "" + continue + buf += line + "\n" + + async def subscribe_events_async(self, *, directory: str | Unset = UNSET) -> AsyncIterator[dict]: + """Async variant of subscribe_events using httpx.AsyncClient.""" + aclient = self._client.get_async_httpx_client() + params: dict[str, str] = {} + if directory is not UNSET and directory is not None: + params["directory"] = str(directory) + async with aclient.stream("GET", "/event", headers={"Accept": "text/event-stream"}, params=params) as r: + r.raise_for_status() + buf = "" + async for line_bytes in r.aiter_lines(): + line = line_bytes + if line.startswith(":"): + continue + if line == "": + if buf: + for part in buf.split("\n"): + if part.startswith("data:"): + data = part[5:].strip() + if data: + try: + yield httpx._models.jsonlib.loads(data) # type: ignore[attr-defined] + except Exception: + pass + buf = "" + continue + buf += line + "\n" diff --git a/packages/sdk/python/src/opencode_ai/models/__init__.py b/packages/sdk/python/src/opencode_ai/models/__init__.py new file mode 100644 index 0000000000..6c20f75662 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/__init__.py @@ -0,0 +1,367 @@ +"""Contains all the data models used in inputs/outputs""" + +from .agent import Agent +from .agent_config import AgentConfig +from .agent_config_permission import AgentConfigPermission +from .agent_config_permission_bash_type_1 import AgentConfigPermissionBashType1 +from .agent_config_tools import AgentConfigTools +from .agent_model import AgentModel +from .agent_options import AgentOptions +from .agent_part import AgentPart +from .agent_part_input import AgentPartInput +from .agent_part_input_source import AgentPartInputSource +from .agent_part_source import AgentPartSource +from .agent_permission import AgentPermission +from .agent_permission_bash import AgentPermissionBash +from .agent_tools import AgentTools +from .api_auth import ApiAuth +from .assistant_message import AssistantMessage +from .assistant_message_path import AssistantMessagePath +from .assistant_message_time import AssistantMessageTime +from .assistant_message_tokens import AssistantMessageTokens +from .assistant_message_tokens_cache import AssistantMessageTokensCache +from .command import Command +from .config import Config +from .config_agent import ConfigAgent +from .config_command import ConfigCommand +from .config_command_additional_property import ConfigCommandAdditionalProperty +from .config_experimental import ConfigExperimental +from .config_experimental_hook import ConfigExperimentalHook +from .config_experimental_hook_file_edited import ConfigExperimentalHookFileEdited +from .config_experimental_hook_file_edited_additional_property_item import ( + ConfigExperimentalHookFileEditedAdditionalPropertyItem, +) +from .config_experimental_hook_file_edited_additional_property_item_environment import ( + ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment, +) +from .config_experimental_hook_session_completed_item import ConfigExperimentalHookSessionCompletedItem +from .config_experimental_hook_session_completed_item_environment import ( + ConfigExperimentalHookSessionCompletedItemEnvironment, +) +from .config_formatter import ConfigFormatter +from .config_formatter_additional_property import ConfigFormatterAdditionalProperty +from .config_formatter_additional_property_environment import ConfigFormatterAdditionalPropertyEnvironment +from .config_lsp import ConfigLsp +from .config_lsp_additional_property_type_0 import ConfigLspAdditionalPropertyType0 +from .config_lsp_additional_property_type_1 import ConfigLspAdditionalPropertyType1 +from .config_lsp_additional_property_type_1_env import ConfigLspAdditionalPropertyType1Env +from .config_lsp_additional_property_type_1_initialization import ConfigLspAdditionalPropertyType1Initialization +from .config_mcp import ConfigMcp +from .config_mode import ConfigMode +from .config_permission import ConfigPermission +from .config_permission_bash_type_1 import ConfigPermissionBashType1 +from .config_provider import ConfigProvider +from .config_provider_additional_property import ConfigProviderAdditionalProperty +from .config_provider_additional_property_models import ConfigProviderAdditionalPropertyModels +from .config_provider_additional_property_models_additional_property import ( + ConfigProviderAdditionalPropertyModelsAdditionalProperty, +) +from .config_provider_additional_property_models_additional_property_cost import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost, +) +from .config_provider_additional_property_models_additional_property_limit import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit, +) +from .config_provider_additional_property_models_additional_property_options import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions, +) +from .config_provider_additional_property_models_additional_property_provider import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider, +) +from .config_provider_additional_property_options import ConfigProviderAdditionalPropertyOptions +from .config_providers_response_200 import ConfigProvidersResponse200 +from .config_providers_response_200_default import ConfigProvidersResponse200Default +from .config_share import ConfigShare +from .config_tools import ConfigTools +from .config_tui import ConfigTui +from .config_watcher import ConfigWatcher +from .error import Error +from .error_data import ErrorData +from .event_file_edited import EventFileEdited +from .event_file_edited_properties import EventFileEditedProperties +from .event_file_watcher_updated import EventFileWatcherUpdated +from .event_file_watcher_updated_properties import EventFileWatcherUpdatedProperties +from .event_ide_installed import EventIdeInstalled +from .event_ide_installed_properties import EventIdeInstalledProperties +from .event_installation_updated import EventInstallationUpdated +from .event_installation_updated_properties import EventInstallationUpdatedProperties +from .event_lsp_client_diagnostics import EventLspClientDiagnostics +from .event_lsp_client_diagnostics_properties import EventLspClientDiagnosticsProperties +from .event_message_part_removed import EventMessagePartRemoved +from .event_message_part_removed_properties import EventMessagePartRemovedProperties +from .event_message_part_updated import EventMessagePartUpdated +from .event_message_part_updated_properties import EventMessagePartUpdatedProperties +from .event_message_removed import EventMessageRemoved +from .event_message_removed_properties import EventMessageRemovedProperties +from .event_message_updated import EventMessageUpdated +from .event_message_updated_properties import EventMessageUpdatedProperties +from .event_permission_replied import EventPermissionReplied +from .event_permission_replied_properties import EventPermissionRepliedProperties +from .event_permission_updated import EventPermissionUpdated +from .event_server_connected import EventServerConnected +from .event_server_connected_properties import EventServerConnectedProperties +from .event_session_compacted import EventSessionCompacted +from .event_session_compacted_properties import EventSessionCompactedProperties +from .event_session_deleted import EventSessionDeleted +from .event_session_deleted_properties import EventSessionDeletedProperties +from .event_session_error import EventSessionError +from .event_session_error_properties import EventSessionErrorProperties +from .event_session_idle import EventSessionIdle +from .event_session_idle_properties import EventSessionIdleProperties +from .event_session_updated import EventSessionUpdated +from .event_session_updated_properties import EventSessionUpdatedProperties +from .file import File +from .file_content import FileContent +from .file_content_patch import FileContentPatch +from .file_content_patch_hunks_item import FileContentPatchHunksItem +from .file_node import FileNode +from .file_node_type import FileNodeType +from .file_part import FilePart +from .file_part_input import FilePartInput +from .file_part_source_text import FilePartSourceText +from .file_source import FileSource +from .file_status import FileStatus +from .keybinds_config import KeybindsConfig +from .layout_config import LayoutConfig +from .mcp_local_config import McpLocalConfig +from .mcp_local_config_environment import McpLocalConfigEnvironment +from .mcp_remote_config import McpRemoteConfig +from .mcp_remote_config_headers import McpRemoteConfigHeaders +from .message_aborted_error import MessageAbortedError +from .message_aborted_error_data import MessageAbortedErrorData +from .message_output_length_error import MessageOutputLengthError +from .message_output_length_error_data import MessageOutputLengthErrorData +from .model import Model +from .model_cost import ModelCost +from .model_limit import ModelLimit +from .model_options import ModelOptions +from .model_provider import ModelProvider +from .o_auth import OAuth +from .patch_part import PatchPart +from .path import Path +from .permission import Permission +from .permission_metadata import PermissionMetadata +from .permission_time import PermissionTime +from .project import Project +from .project_time import ProjectTime +from .provider import Provider +from .provider_auth_error import ProviderAuthError +from .provider_auth_error_data import ProviderAuthErrorData +from .provider_models import ProviderModels +from .range_ import Range +from .range_end import RangeEnd +from .range_start import RangeStart +from .reasoning_part import ReasoningPart +from .reasoning_part_metadata import ReasoningPartMetadata +from .reasoning_part_time import ReasoningPartTime +from .session import Session +from .session_revert import SessionRevert +from .session_share import SessionShare +from .session_time import SessionTime +from .snapshot_part import SnapshotPart +from .step_finish_part import StepFinishPart +from .step_finish_part_tokens import StepFinishPartTokens +from .step_finish_part_tokens_cache import StepFinishPartTokensCache +from .step_start_part import StepStartPart +from .symbol import Symbol +from .symbol_location import SymbolLocation +from .symbol_source import SymbolSource +from .text_part import TextPart +from .text_part_input import TextPartInput +from .text_part_input_time import TextPartInputTime +from .text_part_time import TextPartTime +from .tool_list_item import ToolListItem +from .tool_part import ToolPart +from .tool_state_completed import ToolStateCompleted +from .tool_state_completed_input import ToolStateCompletedInput +from .tool_state_completed_metadata import ToolStateCompletedMetadata +from .tool_state_completed_time import ToolStateCompletedTime +from .tool_state_error import ToolStateError +from .tool_state_error_input import ToolStateErrorInput +from .tool_state_error_metadata import ToolStateErrorMetadata +from .tool_state_error_time import ToolStateErrorTime +from .tool_state_pending import ToolStatePending +from .tool_state_running import ToolStateRunning +from .tool_state_running_metadata import ToolStateRunningMetadata +from .tool_state_running_time import ToolStateRunningTime +from .unknown_error import UnknownError +from .unknown_error_data import UnknownErrorData +from .user_message import UserMessage +from .user_message_time import UserMessageTime +from .well_known_auth import WellKnownAuth + +__all__ = ( + "Agent", + "AgentConfig", + "AgentConfigPermission", + "AgentConfigPermissionBashType1", + "AgentConfigTools", + "AgentModel", + "AgentOptions", + "AgentPart", + "AgentPartInput", + "AgentPartInputSource", + "AgentPartSource", + "AgentPermission", + "AgentPermissionBash", + "AgentTools", + "ApiAuth", + "AssistantMessage", + "AssistantMessagePath", + "AssistantMessageTime", + "AssistantMessageTokens", + "AssistantMessageTokensCache", + "Command", + "Config", + "ConfigAgent", + "ConfigCommand", + "ConfigCommandAdditionalProperty", + "ConfigExperimental", + "ConfigExperimentalHook", + "ConfigExperimentalHookFileEdited", + "ConfigExperimentalHookFileEditedAdditionalPropertyItem", + "ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment", + "ConfigExperimentalHookSessionCompletedItem", + "ConfigExperimentalHookSessionCompletedItemEnvironment", + "ConfigFormatter", + "ConfigFormatterAdditionalProperty", + "ConfigFormatterAdditionalPropertyEnvironment", + "ConfigLsp", + "ConfigLspAdditionalPropertyType0", + "ConfigLspAdditionalPropertyType1", + "ConfigLspAdditionalPropertyType1Env", + "ConfigLspAdditionalPropertyType1Initialization", + "ConfigMcp", + "ConfigMode", + "ConfigPermission", + "ConfigPermissionBashType1", + "ConfigProvider", + "ConfigProviderAdditionalProperty", + "ConfigProviderAdditionalPropertyModels", + "ConfigProviderAdditionalPropertyModelsAdditionalProperty", + "ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost", + "ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit", + "ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions", + "ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider", + "ConfigProviderAdditionalPropertyOptions", + "ConfigProvidersResponse200", + "ConfigProvidersResponse200Default", + "ConfigShare", + "ConfigTools", + "ConfigTui", + "ConfigWatcher", + "Error", + "ErrorData", + "EventFileEdited", + "EventFileEditedProperties", + "EventFileWatcherUpdated", + "EventFileWatcherUpdatedProperties", + "EventIdeInstalled", + "EventIdeInstalledProperties", + "EventInstallationUpdated", + "EventInstallationUpdatedProperties", + "EventLspClientDiagnostics", + "EventLspClientDiagnosticsProperties", + "EventMessagePartRemoved", + "EventMessagePartRemovedProperties", + "EventMessagePartUpdated", + "EventMessagePartUpdatedProperties", + "EventMessageRemoved", + "EventMessageRemovedProperties", + "EventMessageUpdated", + "EventMessageUpdatedProperties", + "EventPermissionReplied", + "EventPermissionRepliedProperties", + "EventPermissionUpdated", + "EventServerConnected", + "EventServerConnectedProperties", + "EventSessionCompacted", + "EventSessionCompactedProperties", + "EventSessionDeleted", + "EventSessionDeletedProperties", + "EventSessionError", + "EventSessionErrorProperties", + "EventSessionIdle", + "EventSessionIdleProperties", + "EventSessionUpdated", + "EventSessionUpdatedProperties", + "File", + "FileContent", + "FileContentPatch", + "FileContentPatchHunksItem", + "FileNode", + "FileNodeType", + "FilePart", + "FilePartInput", + "FilePartSourceText", + "FileSource", + "FileStatus", + "KeybindsConfig", + "LayoutConfig", + "McpLocalConfig", + "McpLocalConfigEnvironment", + "McpRemoteConfig", + "McpRemoteConfigHeaders", + "MessageAbortedError", + "MessageAbortedErrorData", + "MessageOutputLengthError", + "MessageOutputLengthErrorData", + "Model", + "ModelCost", + "ModelLimit", + "ModelOptions", + "ModelProvider", + "OAuth", + "PatchPart", + "Path", + "Permission", + "PermissionMetadata", + "PermissionTime", + "Project", + "ProjectTime", + "Provider", + "ProviderAuthError", + "ProviderAuthErrorData", + "ProviderModels", + "Range", + "RangeEnd", + "RangeStart", + "ReasoningPart", + "ReasoningPartMetadata", + "ReasoningPartTime", + "Session", + "SessionRevert", + "SessionShare", + "SessionTime", + "SnapshotPart", + "StepFinishPart", + "StepFinishPartTokens", + "StepFinishPartTokensCache", + "StepStartPart", + "Symbol", + "SymbolLocation", + "SymbolSource", + "TextPart", + "TextPartInput", + "TextPartInputTime", + "TextPartTime", + "ToolListItem", + "ToolPart", + "ToolStateCompleted", + "ToolStateCompletedInput", + "ToolStateCompletedMetadata", + "ToolStateCompletedTime", + "ToolStateError", + "ToolStateErrorInput", + "ToolStateErrorMetadata", + "ToolStateErrorTime", + "ToolStatePending", + "ToolStateRunning", + "ToolStateRunningMetadata", + "ToolStateRunningTime", + "UnknownError", + "UnknownErrorData", + "UserMessage", + "UserMessageTime", + "WellKnownAuth", +) diff --git a/packages/sdk/python/src/opencode_ai/models/agent.py b/packages/sdk/python/src/opencode_ai/models/agent.py new file mode 100644 index 0000000000..8044d73a09 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent.py @@ -0,0 +1,180 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.agent_model import AgentModel + from ..models.agent_options import AgentOptions + from ..models.agent_permission import AgentPermission + from ..models.agent_tools import AgentTools + + +T = TypeVar("T", bound="Agent") + + +@_attrs_define +class Agent: + """ + Attributes: + name (str): + mode (Union[Literal['all'], Literal['primary'], Literal['subagent']]): + built_in (bool): + permission (AgentPermission): + tools (AgentTools): + options (AgentOptions): + description (Union[Unset, str]): + top_p (Union[Unset, float]): + temperature (Union[Unset, float]): + model (Union[Unset, AgentModel]): + prompt (Union[Unset, str]): + """ + + name: str + mode: Union[Literal["all"], Literal["primary"], Literal["subagent"]] + built_in: bool + permission: "AgentPermission" + tools: "AgentTools" + options: "AgentOptions" + description: Union[Unset, str] = UNSET + top_p: Union[Unset, float] = UNSET + temperature: Union[Unset, float] = UNSET + model: Union[Unset, "AgentModel"] = UNSET + prompt: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + mode: Union[Literal["all"], Literal["primary"], Literal["subagent"]] + mode = self.mode + + built_in = self.built_in + + permission = self.permission.to_dict() + + tools = self.tools.to_dict() + + options = self.options.to_dict() + + description = self.description + + top_p = self.top_p + + temperature = self.temperature + + model: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.model, Unset): + model = self.model.to_dict() + + prompt = self.prompt + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "mode": mode, + "builtIn": built_in, + "permission": permission, + "tools": tools, + "options": options, + } + ) + if description is not UNSET: + field_dict["description"] = description + if top_p is not UNSET: + field_dict["topP"] = top_p + if temperature is not UNSET: + field_dict["temperature"] = temperature + if model is not UNSET: + field_dict["model"] = model + if prompt is not UNSET: + field_dict["prompt"] = prompt + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agent_model import AgentModel + from ..models.agent_options import AgentOptions + from ..models.agent_permission import AgentPermission + from ..models.agent_tools import AgentTools + + d = dict(src_dict) + name = d.pop("name") + + def _parse_mode(data: object) -> Union[Literal["all"], Literal["primary"], Literal["subagent"]]: + mode_type_0 = cast(Literal["subagent"], data) + if mode_type_0 != "subagent": + raise ValueError(f"mode_type_0 must match const 'subagent', got '{mode_type_0}'") + return mode_type_0 + mode_type_1 = cast(Literal["primary"], data) + if mode_type_1 != "primary": + raise ValueError(f"mode_type_1 must match const 'primary', got '{mode_type_1}'") + return mode_type_1 + mode_type_2 = cast(Literal["all"], data) + if mode_type_2 != "all": + raise ValueError(f"mode_type_2 must match const 'all', got '{mode_type_2}'") + return mode_type_2 + + mode = _parse_mode(d.pop("mode")) + + built_in = d.pop("builtIn") + + permission = AgentPermission.from_dict(d.pop("permission")) + + tools = AgentTools.from_dict(d.pop("tools")) + + options = AgentOptions.from_dict(d.pop("options")) + + description = d.pop("description", UNSET) + + top_p = d.pop("topP", UNSET) + + temperature = d.pop("temperature", UNSET) + + _model = d.pop("model", UNSET) + model: Union[Unset, AgentModel] + if isinstance(_model, Unset): + model = UNSET + else: + model = AgentModel.from_dict(_model) + + prompt = d.pop("prompt", UNSET) + + agent = cls( + name=name, + mode=mode, + built_in=built_in, + permission=permission, + tools=tools, + options=options, + description=description, + top_p=top_p, + temperature=temperature, + model=model, + prompt=prompt, + ) + + agent.additional_properties = d + return agent + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_config.py b/packages/sdk/python/src/opencode_ai/models/agent_config.py new file mode 100644 index 0000000000..5c56c8b48d --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_config.py @@ -0,0 +1,173 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.agent_config_permission import AgentConfigPermission + from ..models.agent_config_tools import AgentConfigTools + + +T = TypeVar("T", bound="AgentConfig") + + +@_attrs_define +class AgentConfig: + """ + Attributes: + model (Union[Unset, str]): + temperature (Union[Unset, float]): + top_p (Union[Unset, float]): + prompt (Union[Unset, str]): + tools (Union[Unset, AgentConfigTools]): + disable (Union[Unset, bool]): + description (Union[Unset, str]): Description of when to use the agent + mode (Union[Literal['all'], Literal['primary'], Literal['subagent'], Unset]): + permission (Union[Unset, AgentConfigPermission]): + """ + + model: Union[Unset, str] = UNSET + temperature: Union[Unset, float] = UNSET + top_p: Union[Unset, float] = UNSET + prompt: Union[Unset, str] = UNSET + tools: Union[Unset, "AgentConfigTools"] = UNSET + disable: Union[Unset, bool] = UNSET + description: Union[Unset, str] = UNSET + mode: Union[Literal["all"], Literal["primary"], Literal["subagent"], Unset] = UNSET + permission: Union[Unset, "AgentConfigPermission"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + model = self.model + + temperature = self.temperature + + top_p = self.top_p + + prompt = self.prompt + + tools: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.tools, Unset): + tools = self.tools.to_dict() + + disable = self.disable + + description = self.description + + mode: Union[Literal["all"], Literal["primary"], Literal["subagent"], Unset] + if isinstance(self.mode, Unset): + mode = UNSET + else: + mode = self.mode + + permission: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.permission, Unset): + permission = self.permission.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if model is not UNSET: + field_dict["model"] = model + if temperature is not UNSET: + field_dict["temperature"] = temperature + if top_p is not UNSET: + field_dict["top_p"] = top_p + if prompt is not UNSET: + field_dict["prompt"] = prompt + if tools is not UNSET: + field_dict["tools"] = tools + if disable is not UNSET: + field_dict["disable"] = disable + if description is not UNSET: + field_dict["description"] = description + if mode is not UNSET: + field_dict["mode"] = mode + if permission is not UNSET: + field_dict["permission"] = permission + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agent_config_permission import AgentConfigPermission + from ..models.agent_config_tools import AgentConfigTools + + d = dict(src_dict) + model = d.pop("model", UNSET) + + temperature = d.pop("temperature", UNSET) + + top_p = d.pop("top_p", UNSET) + + prompt = d.pop("prompt", UNSET) + + _tools = d.pop("tools", UNSET) + tools: Union[Unset, AgentConfigTools] + if isinstance(_tools, Unset): + tools = UNSET + else: + tools = AgentConfigTools.from_dict(_tools) + + disable = d.pop("disable", UNSET) + + description = d.pop("description", UNSET) + + def _parse_mode(data: object) -> Union[Literal["all"], Literal["primary"], Literal["subagent"], Unset]: + if isinstance(data, Unset): + return data + mode_type_0 = cast(Literal["subagent"], data) + if mode_type_0 != "subagent": + raise ValueError(f"mode_type_0 must match const 'subagent', got '{mode_type_0}'") + return mode_type_0 + mode_type_1 = cast(Literal["primary"], data) + if mode_type_1 != "primary": + raise ValueError(f"mode_type_1 must match const 'primary', got '{mode_type_1}'") + return mode_type_1 + mode_type_2 = cast(Literal["all"], data) + if mode_type_2 != "all": + raise ValueError(f"mode_type_2 must match const 'all', got '{mode_type_2}'") + return mode_type_2 + + mode = _parse_mode(d.pop("mode", UNSET)) + + _permission = d.pop("permission", UNSET) + permission: Union[Unset, AgentConfigPermission] + if isinstance(_permission, Unset): + permission = UNSET + else: + permission = AgentConfigPermission.from_dict(_permission) + + agent_config = cls( + model=model, + temperature=temperature, + top_p=top_p, + prompt=prompt, + tools=tools, + disable=disable, + description=description, + mode=mode, + permission=permission, + ) + + agent_config.additional_properties = d + return agent_config + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_config_permission.py b/packages/sdk/python/src/opencode_ai/models/agent_config_permission.py new file mode 100644 index 0000000000..d7a499fbe3 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_config_permission.py @@ -0,0 +1,155 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.agent_config_permission_bash_type_1 import AgentConfigPermissionBashType1 + + +T = TypeVar("T", bound="AgentConfigPermission") + + +@_attrs_define +class AgentConfigPermission: + """ + Attributes: + edit (Union[Literal['allow'], Literal['ask'], Literal['deny'], Unset]): + bash (Union['AgentConfigPermissionBashType1', Literal['allow'], Literal['ask'], Literal['deny'], Unset]): + webfetch (Union[Literal['allow'], Literal['ask'], Literal['deny'], Unset]): + """ + + edit: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] = UNSET + bash: Union["AgentConfigPermissionBashType1", Literal["allow"], Literal["ask"], Literal["deny"], Unset] = UNSET + webfetch: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.agent_config_permission_bash_type_1 import AgentConfigPermissionBashType1 + + edit: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] + if isinstance(self.edit, Unset): + edit = UNSET + else: + edit = self.edit + + bash: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset, dict[str, Any]] + if isinstance(self.bash, Unset): + bash = UNSET + elif isinstance(self.bash, AgentConfigPermissionBashType1): + bash = self.bash.to_dict() + else: + bash = self.bash + + webfetch: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] + if isinstance(self.webfetch, Unset): + webfetch = UNSET + else: + webfetch = self.webfetch + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if edit is not UNSET: + field_dict["edit"] = edit + if bash is not UNSET: + field_dict["bash"] = bash + if webfetch is not UNSET: + field_dict["webfetch"] = webfetch + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agent_config_permission_bash_type_1 import AgentConfigPermissionBashType1 + + d = dict(src_dict) + + def _parse_edit(data: object) -> Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset]: + if isinstance(data, Unset): + return data + edit_type_0 = cast(Literal["ask"], data) + if edit_type_0 != "ask": + raise ValueError(f"edit_type_0 must match const 'ask', got '{edit_type_0}'") + return edit_type_0 + edit_type_1 = cast(Literal["allow"], data) + if edit_type_1 != "allow": + raise ValueError(f"edit_type_1 must match const 'allow', got '{edit_type_1}'") + return edit_type_1 + edit_type_2 = cast(Literal["deny"], data) + if edit_type_2 != "deny": + raise ValueError(f"edit_type_2 must match const 'deny', got '{edit_type_2}'") + return edit_type_2 + + edit = _parse_edit(d.pop("edit", UNSET)) + + def _parse_bash( + data: object, + ) -> Union["AgentConfigPermissionBashType1", Literal["allow"], Literal["ask"], Literal["deny"], Unset]: + if isinstance(data, Unset): + return data + bash_type_0_type_0 = cast(Literal["ask"], data) + if bash_type_0_type_0 != "ask": + raise ValueError(f"bash_type_0_type_0 must match const 'ask', got '{bash_type_0_type_0}'") + return bash_type_0_type_0 + bash_type_0_type_1 = cast(Literal["allow"], data) + if bash_type_0_type_1 != "allow": + raise ValueError(f"bash_type_0_type_1 must match const 'allow', got '{bash_type_0_type_1}'") + return bash_type_0_type_1 + bash_type_0_type_2 = cast(Literal["deny"], data) + if bash_type_0_type_2 != "deny": + raise ValueError(f"bash_type_0_type_2 must match const 'deny', got '{bash_type_0_type_2}'") + return bash_type_0_type_2 + if not isinstance(data, dict): + raise TypeError() + bash_type_1 = AgentConfigPermissionBashType1.from_dict(data) + + return bash_type_1 + + bash = _parse_bash(d.pop("bash", UNSET)) + + def _parse_webfetch(data: object) -> Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset]: + if isinstance(data, Unset): + return data + webfetch_type_0 = cast(Literal["ask"], data) + if webfetch_type_0 != "ask": + raise ValueError(f"webfetch_type_0 must match const 'ask', got '{webfetch_type_0}'") + return webfetch_type_0 + webfetch_type_1 = cast(Literal["allow"], data) + if webfetch_type_1 != "allow": + raise ValueError(f"webfetch_type_1 must match const 'allow', got '{webfetch_type_1}'") + return webfetch_type_1 + webfetch_type_2 = cast(Literal["deny"], data) + if webfetch_type_2 != "deny": + raise ValueError(f"webfetch_type_2 must match const 'deny', got '{webfetch_type_2}'") + return webfetch_type_2 + + webfetch = _parse_webfetch(d.pop("webfetch", UNSET)) + + agent_config_permission = cls( + edit=edit, + bash=bash, + webfetch=webfetch, + ) + + agent_config_permission.additional_properties = d + return agent_config_permission + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_config_permission_bash_type_1.py b/packages/sdk/python/src/opencode_ai/models/agent_config_permission_bash_type_1.py new file mode 100644 index 0000000000..a80581bec8 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_config_permission_bash_type_1.py @@ -0,0 +1,74 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AgentConfigPermissionBashType1") + + +@_attrs_define +class AgentConfigPermissionBashType1: + """ """ + + additional_properties: dict[str, Union[Literal["allow"], Literal["ask"], Literal["deny"]]] = _attrs_field( + init=False, factory=dict + ) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + agent_config_permission_bash_type_1 = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property(data: object) -> Union[Literal["allow"], Literal["ask"], Literal["deny"]]: + additional_property_type_0 = cast(Literal["ask"], data) + if additional_property_type_0 != "ask": + raise ValueError( + f"AdditionalProperty_type_0 must match const 'ask', got '{additional_property_type_0}'" + ) + return additional_property_type_0 + additional_property_type_1 = cast(Literal["allow"], data) + if additional_property_type_1 != "allow": + raise ValueError( + f"AdditionalProperty_type_1 must match const 'allow', got '{additional_property_type_1}'" + ) + return additional_property_type_1 + additional_property_type_2 = cast(Literal["deny"], data) + if additional_property_type_2 != "deny": + raise ValueError( + f"AdditionalProperty_type_2 must match const 'deny', got '{additional_property_type_2}'" + ) + return additional_property_type_2 + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + agent_config_permission_bash_type_1.additional_properties = additional_properties + return agent_config_permission_bash_type_1 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Union[Literal["allow"], Literal["ask"], Literal["deny"]]: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Union[Literal["allow"], Literal["ask"], Literal["deny"]]) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_config_tools.py b/packages/sdk/python/src/opencode_ai/models/agent_config_tools.py new file mode 100644 index 0000000000..beef8aef53 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_config_tools.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AgentConfigTools") + + +@_attrs_define +class AgentConfigTools: + """ """ + + additional_properties: dict[str, bool] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + agent_config_tools = cls() + + agent_config_tools.additional_properties = d + return agent_config_tools + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> bool: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: bool) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_model.py b/packages/sdk/python/src/opencode_ai/models/agent_model.py new file mode 100644 index 0000000000..2d98ee5162 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_model.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AgentModel") + + +@_attrs_define +class AgentModel: + """ + Attributes: + model_id (str): + provider_id (str): + """ + + model_id: str + provider_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + model_id = self.model_id + + provider_id = self.provider_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "modelID": model_id, + "providerID": provider_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + model_id = d.pop("modelID") + + provider_id = d.pop("providerID") + + agent_model = cls( + model_id=model_id, + provider_id=provider_id, + ) + + agent_model.additional_properties = d + return agent_model + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_options.py b/packages/sdk/python/src/opencode_ai/models/agent_options.py new file mode 100644 index 0000000000..f681655142 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_options.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AgentOptions") + + +@_attrs_define +class AgentOptions: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + agent_options = cls() + + agent_options.additional_properties = d + return agent_options + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_part.py b/packages/sdk/python/src/opencode_ai/models/agent_part.py new file mode 100644 index 0000000000..252e670709 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_part.py @@ -0,0 +1,117 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.agent_part_source import AgentPartSource + + +T = TypeVar("T", bound="AgentPart") + + +@_attrs_define +class AgentPart: + """ + Attributes: + id (str): + session_id (str): + message_id (str): + type_ (Literal['agent']): + name (str): + source (Union[Unset, AgentPartSource]): + """ + + id: str + session_id: str + message_id: str + type_: Literal["agent"] + name: str + source: Union[Unset, "AgentPartSource"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + session_id = self.session_id + + message_id = self.message_id + + type_ = self.type_ + + name = self.name + + source: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.source, Unset): + source = self.source.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "messageID": message_id, + "type": type_, + "name": name, + } + ) + if source is not UNSET: + field_dict["source"] = source + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agent_part_source import AgentPartSource + + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + type_ = cast(Literal["agent"], d.pop("type")) + if type_ != "agent": + raise ValueError(f"type must match const 'agent', got '{type_}'") + + name = d.pop("name") + + _source = d.pop("source", UNSET) + source: Union[Unset, AgentPartSource] + if isinstance(_source, Unset): + source = UNSET + else: + source = AgentPartSource.from_dict(_source) + + agent_part = cls( + id=id, + session_id=session_id, + message_id=message_id, + type_=type_, + name=name, + source=source, + ) + + agent_part.additional_properties = d + return agent_part + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_part_input.py b/packages/sdk/python/src/opencode_ai/models/agent_part_input.py new file mode 100644 index 0000000000..e3ed1b7b79 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_part_input.py @@ -0,0 +1,102 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.agent_part_input_source import AgentPartInputSource + + +T = TypeVar("T", bound="AgentPartInput") + + +@_attrs_define +class AgentPartInput: + """ + Attributes: + type_ (Literal['agent']): + name (str): + id (Union[Unset, str]): + source (Union[Unset, AgentPartInputSource]): + """ + + type_: Literal["agent"] + name: str + id: Union[Unset, str] = UNSET + source: Union[Unset, "AgentPartInputSource"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + name = self.name + + id = self.id + + source: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.source, Unset): + source = self.source.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "name": name, + } + ) + if id is not UNSET: + field_dict["id"] = id + if source is not UNSET: + field_dict["source"] = source + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agent_part_input_source import AgentPartInputSource + + d = dict(src_dict) + type_ = cast(Literal["agent"], d.pop("type")) + if type_ != "agent": + raise ValueError(f"type must match const 'agent', got '{type_}'") + + name = d.pop("name") + + id = d.pop("id", UNSET) + + _source = d.pop("source", UNSET) + source: Union[Unset, AgentPartInputSource] + if isinstance(_source, Unset): + source = UNSET + else: + source = AgentPartInputSource.from_dict(_source) + + agent_part_input = cls( + type_=type_, + name=name, + id=id, + source=source, + ) + + agent_part_input.additional_properties = d + return agent_part_input + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_part_input_source.py b/packages/sdk/python/src/opencode_ai/models/agent_part_input_source.py new file mode 100644 index 0000000000..f49bb6aba9 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_part_input_source.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AgentPartInputSource") + + +@_attrs_define +class AgentPartInputSource: + """ + Attributes: + value (str): + start (int): + end (int): + """ + + value: str + start: int + end: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + value = self.value + + start = self.start + + end = self.end + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "value": value, + "start": start, + "end": end, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + value = d.pop("value") + + start = d.pop("start") + + end = d.pop("end") + + agent_part_input_source = cls( + value=value, + start=start, + end=end, + ) + + agent_part_input_source.additional_properties = d + return agent_part_input_source + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_part_source.py b/packages/sdk/python/src/opencode_ai/models/agent_part_source.py new file mode 100644 index 0000000000..fad27f861b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_part_source.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AgentPartSource") + + +@_attrs_define +class AgentPartSource: + """ + Attributes: + value (str): + start (int): + end (int): + """ + + value: str + start: int + end: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + value = self.value + + start = self.start + + end = self.end + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "value": value, + "start": start, + "end": end, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + value = d.pop("value") + + start = d.pop("start") + + end = d.pop("end") + + agent_part_source = cls( + value=value, + start=start, + end=end, + ) + + agent_part_source.additional_properties = d + return agent_part_source + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_permission.py b/packages/sdk/python/src/opencode_ai/models/agent_permission.py new file mode 100644 index 0000000000..19e00c8914 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_permission.py @@ -0,0 +1,120 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.agent_permission_bash import AgentPermissionBash + + +T = TypeVar("T", bound="AgentPermission") + + +@_attrs_define +class AgentPermission: + """ + Attributes: + edit (Union[Literal['allow'], Literal['ask'], Literal['deny']]): + bash (AgentPermissionBash): + webfetch (Union[Literal['allow'], Literal['ask'], Literal['deny'], Unset]): + """ + + edit: Union[Literal["allow"], Literal["ask"], Literal["deny"]] + bash: "AgentPermissionBash" + webfetch: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + edit: Union[Literal["allow"], Literal["ask"], Literal["deny"]] + edit = self.edit + + bash = self.bash.to_dict() + + webfetch: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] + if isinstance(self.webfetch, Unset): + webfetch = UNSET + else: + webfetch = self.webfetch + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "edit": edit, + "bash": bash, + } + ) + if webfetch is not UNSET: + field_dict["webfetch"] = webfetch + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agent_permission_bash import AgentPermissionBash + + d = dict(src_dict) + + def _parse_edit(data: object) -> Union[Literal["allow"], Literal["ask"], Literal["deny"]]: + edit_type_0 = cast(Literal["ask"], data) + if edit_type_0 != "ask": + raise ValueError(f"edit_type_0 must match const 'ask', got '{edit_type_0}'") + return edit_type_0 + edit_type_1 = cast(Literal["allow"], data) + if edit_type_1 != "allow": + raise ValueError(f"edit_type_1 must match const 'allow', got '{edit_type_1}'") + return edit_type_1 + edit_type_2 = cast(Literal["deny"], data) + if edit_type_2 != "deny": + raise ValueError(f"edit_type_2 must match const 'deny', got '{edit_type_2}'") + return edit_type_2 + + edit = _parse_edit(d.pop("edit")) + + bash = AgentPermissionBash.from_dict(d.pop("bash")) + + def _parse_webfetch(data: object) -> Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset]: + if isinstance(data, Unset): + return data + webfetch_type_0 = cast(Literal["ask"], data) + if webfetch_type_0 != "ask": + raise ValueError(f"webfetch_type_0 must match const 'ask', got '{webfetch_type_0}'") + return webfetch_type_0 + webfetch_type_1 = cast(Literal["allow"], data) + if webfetch_type_1 != "allow": + raise ValueError(f"webfetch_type_1 must match const 'allow', got '{webfetch_type_1}'") + return webfetch_type_1 + webfetch_type_2 = cast(Literal["deny"], data) + if webfetch_type_2 != "deny": + raise ValueError(f"webfetch_type_2 must match const 'deny', got '{webfetch_type_2}'") + return webfetch_type_2 + + webfetch = _parse_webfetch(d.pop("webfetch", UNSET)) + + agent_permission = cls( + edit=edit, + bash=bash, + webfetch=webfetch, + ) + + agent_permission.additional_properties = d + return agent_permission + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_permission_bash.py b/packages/sdk/python/src/opencode_ai/models/agent_permission_bash.py new file mode 100644 index 0000000000..ea03328f91 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_permission_bash.py @@ -0,0 +1,74 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AgentPermissionBash") + + +@_attrs_define +class AgentPermissionBash: + """ """ + + additional_properties: dict[str, Union[Literal["allow"], Literal["ask"], Literal["deny"]]] = _attrs_field( + init=False, factory=dict + ) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + agent_permission_bash = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property(data: object) -> Union[Literal["allow"], Literal["ask"], Literal["deny"]]: + additional_property_type_0 = cast(Literal["ask"], data) + if additional_property_type_0 != "ask": + raise ValueError( + f"AdditionalProperty_type_0 must match const 'ask', got '{additional_property_type_0}'" + ) + return additional_property_type_0 + additional_property_type_1 = cast(Literal["allow"], data) + if additional_property_type_1 != "allow": + raise ValueError( + f"AdditionalProperty_type_1 must match const 'allow', got '{additional_property_type_1}'" + ) + return additional_property_type_1 + additional_property_type_2 = cast(Literal["deny"], data) + if additional_property_type_2 != "deny": + raise ValueError( + f"AdditionalProperty_type_2 must match const 'deny', got '{additional_property_type_2}'" + ) + return additional_property_type_2 + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + agent_permission_bash.additional_properties = additional_properties + return agent_permission_bash + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Union[Literal["allow"], Literal["ask"], Literal["deny"]]: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Union[Literal["allow"], Literal["ask"], Literal["deny"]]) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/agent_tools.py b/packages/sdk/python/src/opencode_ai/models/agent_tools.py new file mode 100644 index 0000000000..4f60bb9ddc --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/agent_tools.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AgentTools") + + +@_attrs_define +class AgentTools: + """ """ + + additional_properties: dict[str, bool] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + agent_tools = cls() + + agent_tools.additional_properties = d + return agent_tools + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> bool: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: bool) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/api_auth.py b/packages/sdk/python/src/opencode_ai/models/api_auth.py new file mode 100644 index 0000000000..6cc3a3910e --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/api_auth.py @@ -0,0 +1,69 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiAuth") + + +@_attrs_define +class ApiAuth: + """ + Attributes: + type_ (Literal['api']): + key (str): + """ + + type_: Literal["api"] + key: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + key = self.key + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "key": key, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = cast(Literal["api"], d.pop("type")) + if type_ != "api": + raise ValueError(f"type must match const 'api', got '{type_}'") + + key = d.pop("key") + + api_auth = cls( + type_=type_, + key=key, + ) + + api_auth.additional_properties = d + return api_auth + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/assistant_message.py b/packages/sdk/python/src/opencode_ai/models/assistant_message.py new file mode 100644 index 0000000000..88aa440e5b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/assistant_message.py @@ -0,0 +1,228 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.assistant_message_path import AssistantMessagePath + from ..models.assistant_message_time import AssistantMessageTime + from ..models.assistant_message_tokens import AssistantMessageTokens + from ..models.message_aborted_error import MessageAbortedError + from ..models.message_output_length_error import MessageOutputLengthError + from ..models.provider_auth_error import ProviderAuthError + from ..models.unknown_error import UnknownError + + +T = TypeVar("T", bound="AssistantMessage") + + +@_attrs_define +class AssistantMessage: + """ + Attributes: + id (str): + session_id (str): + role (Literal['assistant']): + time (AssistantMessageTime): + system (list[str]): + model_id (str): + provider_id (str): + mode (str): + path (AssistantMessagePath): + cost (float): + tokens (AssistantMessageTokens): + error (Union['MessageAbortedError', 'MessageOutputLengthError', 'ProviderAuthError', 'UnknownError', Unset]): + summary (Union[Unset, bool]): + """ + + id: str + session_id: str + role: Literal["assistant"] + time: "AssistantMessageTime" + system: list[str] + model_id: str + provider_id: str + mode: str + path: "AssistantMessagePath" + cost: float + tokens: "AssistantMessageTokens" + error: Union["MessageAbortedError", "MessageOutputLengthError", "ProviderAuthError", "UnknownError", Unset] = UNSET + summary: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.message_output_length_error import MessageOutputLengthError + from ..models.provider_auth_error import ProviderAuthError + from ..models.unknown_error import UnknownError + + id = self.id + + session_id = self.session_id + + role = self.role + + time = self.time.to_dict() + + system = self.system + + model_id = self.model_id + + provider_id = self.provider_id + + mode = self.mode + + path = self.path.to_dict() + + cost = self.cost + + tokens = self.tokens.to_dict() + + error: Union[Unset, dict[str, Any]] + if isinstance(self.error, Unset): + error = UNSET + elif isinstance(self.error, ProviderAuthError): + error = self.error.to_dict() + elif isinstance(self.error, UnknownError): + error = self.error.to_dict() + elif isinstance(self.error, MessageOutputLengthError): + error = self.error.to_dict() + else: + error = self.error.to_dict() + + summary = self.summary + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "role": role, + "time": time, + "system": system, + "modelID": model_id, + "providerID": provider_id, + "mode": mode, + "path": path, + "cost": cost, + "tokens": tokens, + } + ) + if error is not UNSET: + field_dict["error"] = error + if summary is not UNSET: + field_dict["summary"] = summary + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.assistant_message_path import AssistantMessagePath + from ..models.assistant_message_time import AssistantMessageTime + from ..models.assistant_message_tokens import AssistantMessageTokens + from ..models.message_aborted_error import MessageAbortedError + from ..models.message_output_length_error import MessageOutputLengthError + from ..models.provider_auth_error import ProviderAuthError + from ..models.unknown_error import UnknownError + + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + role = cast(Literal["assistant"], d.pop("role")) + if role != "assistant": + raise ValueError(f"role must match const 'assistant', got '{role}'") + + time = AssistantMessageTime.from_dict(d.pop("time")) + + system = cast(list[str], d.pop("system")) + + model_id = d.pop("modelID") + + provider_id = d.pop("providerID") + + mode = d.pop("mode") + + path = AssistantMessagePath.from_dict(d.pop("path")) + + cost = d.pop("cost") + + tokens = AssistantMessageTokens.from_dict(d.pop("tokens")) + + def _parse_error( + data: object, + ) -> Union["MessageAbortedError", "MessageOutputLengthError", "ProviderAuthError", "UnknownError", Unset]: + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + error_type_0 = ProviderAuthError.from_dict(data) + + return error_type_0 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + error_type_1 = UnknownError.from_dict(data) + + return error_type_1 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + error_type_2 = MessageOutputLengthError.from_dict(data) + + return error_type_2 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + error_type_3 = MessageAbortedError.from_dict(data) + + return error_type_3 + + error = _parse_error(d.pop("error", UNSET)) + + summary = d.pop("summary", UNSET) + + assistant_message = cls( + id=id, + session_id=session_id, + role=role, + time=time, + system=system, + model_id=model_id, + provider_id=provider_id, + mode=mode, + path=path, + cost=cost, + tokens=tokens, + error=error, + summary=summary, + ) + + assistant_message.additional_properties = d + return assistant_message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/assistant_message_path.py b/packages/sdk/python/src/opencode_ai/models/assistant_message_path.py new file mode 100644 index 0000000000..0781b5b1eb --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/assistant_message_path.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AssistantMessagePath") + + +@_attrs_define +class AssistantMessagePath: + """ + Attributes: + cwd (str): + root (str): + """ + + cwd: str + root: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + cwd = self.cwd + + root = self.root + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "cwd": cwd, + "root": root, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + cwd = d.pop("cwd") + + root = d.pop("root") + + assistant_message_path = cls( + cwd=cwd, + root=root, + ) + + assistant_message_path.additional_properties = d + return assistant_message_path + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/assistant_message_time.py b/packages/sdk/python/src/opencode_ai/models/assistant_message_time.py new file mode 100644 index 0000000000..64aac074e2 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/assistant_message_time.py @@ -0,0 +1,70 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AssistantMessageTime") + + +@_attrs_define +class AssistantMessageTime: + """ + Attributes: + created (float): + completed (Union[Unset, float]): + """ + + created: float + completed: Union[Unset, float] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created = self.created + + completed = self.completed + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created": created, + } + ) + if completed is not UNSET: + field_dict["completed"] = completed + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + created = d.pop("created") + + completed = d.pop("completed", UNSET) + + assistant_message_time = cls( + created=created, + completed=completed, + ) + + assistant_message_time.additional_properties = d + return assistant_message_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/assistant_message_tokens.py b/packages/sdk/python/src/opencode_ai/models/assistant_message_tokens.py new file mode 100644 index 0000000000..6e7bc4e8b7 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/assistant_message_tokens.py @@ -0,0 +1,89 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.assistant_message_tokens_cache import AssistantMessageTokensCache + + +T = TypeVar("T", bound="AssistantMessageTokens") + + +@_attrs_define +class AssistantMessageTokens: + """ + Attributes: + input_ (float): + output (float): + reasoning (float): + cache (AssistantMessageTokensCache): + """ + + input_: float + output: float + reasoning: float + cache: "AssistantMessageTokensCache" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + input_ = self.input_ + + output = self.output + + reasoning = self.reasoning + + cache = self.cache.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "input": input_, + "output": output, + "reasoning": reasoning, + "cache": cache, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.assistant_message_tokens_cache import AssistantMessageTokensCache + + d = dict(src_dict) + input_ = d.pop("input") + + output = d.pop("output") + + reasoning = d.pop("reasoning") + + cache = AssistantMessageTokensCache.from_dict(d.pop("cache")) + + assistant_message_tokens = cls( + input_=input_, + output=output, + reasoning=reasoning, + cache=cache, + ) + + assistant_message_tokens.additional_properties = d + return assistant_message_tokens + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/assistant_message_tokens_cache.py b/packages/sdk/python/src/opencode_ai/models/assistant_message_tokens_cache.py new file mode 100644 index 0000000000..6d631fea08 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/assistant_message_tokens_cache.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AssistantMessageTokensCache") + + +@_attrs_define +class AssistantMessageTokensCache: + """ + Attributes: + read (float): + write (float): + """ + + read: float + write: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + read = self.read + + write = self.write + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "read": read, + "write": write, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + read = d.pop("read") + + write = d.pop("write") + + assistant_message_tokens_cache = cls( + read=read, + write=write, + ) + + assistant_message_tokens_cache.additional_properties = d + return assistant_message_tokens_cache + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/command.py b/packages/sdk/python/src/opencode_ai/models/command.py new file mode 100644 index 0000000000..a6abf3d2ff --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/command.py @@ -0,0 +1,105 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="Command") + + +@_attrs_define +class Command: + """ + Attributes: + name (str): + template (str): + description (Union[Unset, str]): + agent (Union[Unset, str]): + model (Union[Unset, str]): + subtask (Union[Unset, bool]): + """ + + name: str + template: str + description: Union[Unset, str] = UNSET + agent: Union[Unset, str] = UNSET + model: Union[Unset, str] = UNSET + subtask: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + template = self.template + + description = self.description + + agent = self.agent + + model = self.model + + subtask = self.subtask + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "template": template, + } + ) + if description is not UNSET: + field_dict["description"] = description + if agent is not UNSET: + field_dict["agent"] = agent + if model is not UNSET: + field_dict["model"] = model + if subtask is not UNSET: + field_dict["subtask"] = subtask + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + template = d.pop("template") + + description = d.pop("description", UNSET) + + agent = d.pop("agent", UNSET) + + model = d.pop("model", UNSET) + + subtask = d.pop("subtask", UNSET) + + command = cls( + name=name, + template=template, + description=description, + agent=agent, + model=model, + subtask=subtask, + ) + + command.additional_properties = d + return command + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config.py b/packages/sdk/python/src/opencode_ai/models/config.py new file mode 100644 index 0000000000..38b97637e6 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config.py @@ -0,0 +1,411 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define + +from ..models.config_share import ConfigShare +from ..models.layout_config import LayoutConfig +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_agent import ConfigAgent + from ..models.config_command import ConfigCommand + from ..models.config_experimental import ConfigExperimental + from ..models.config_formatter import ConfigFormatter + from ..models.config_lsp import ConfigLsp + from ..models.config_mcp import ConfigMcp + from ..models.config_mode import ConfigMode + from ..models.config_permission import ConfigPermission + from ..models.config_provider import ConfigProvider + from ..models.config_tools import ConfigTools + from ..models.config_tui import ConfigTui + from ..models.config_watcher import ConfigWatcher + from ..models.keybinds_config import KeybindsConfig + + +T = TypeVar("T", bound="Config") + + +@_attrs_define +class Config: + """ + Attributes: + schema (Union[Unset, str]): JSON schema reference for configuration validation + theme (Union[Unset, str]): Theme name to use for the interface + keybinds (Union[Unset, KeybindsConfig]): Custom keybind configurations + tui (Union[Unset, ConfigTui]): TUI specific settings + command (Union[Unset, ConfigCommand]): Command configuration, see https://opencode.ai/docs/commands + watcher (Union[Unset, ConfigWatcher]): + plugin (Union[Unset, list[str]]): + snapshot (Union[Unset, bool]): + share (Union[Unset, ConfigShare]): Control sharing behavior:'manual' allows manual sharing via commands, 'auto' + enables automatic sharing, 'disabled' disables all sharing + autoshare (Union[Unset, bool]): @deprecated Use 'share' field instead. Share newly created sessions + automatically + autoupdate (Union[Unset, bool]): Automatically update to the latest version + disabled_providers (Union[Unset, list[str]]): Disable providers that are loaded automatically + model (Union[Unset, str]): Model to use in the format of provider/model, eg anthropic/claude-2 + small_model (Union[Unset, str]): Small model to use for tasks like title generation in the format of + provider/model + username (Union[Unset, str]): Custom username to display in conversations instead of system username + mode (Union[Unset, ConfigMode]): @deprecated Use `agent` field instead. + agent (Union[Unset, ConfigAgent]): Agent configuration, see https://opencode.ai/docs/agent + provider (Union[Unset, ConfigProvider]): Custom provider configurations and model overrides + mcp (Union[Unset, ConfigMcp]): MCP (Model Context Protocol) server configurations + formatter (Union[Unset, ConfigFormatter]): + lsp (Union[Unset, ConfigLsp]): + instructions (Union[Unset, list[str]]): Additional instruction files or patterns to include + layout (Union[Unset, LayoutConfig]): @deprecated Always uses stretch layout. + permission (Union[Unset, ConfigPermission]): + tools (Union[Unset, ConfigTools]): + experimental (Union[Unset, ConfigExperimental]): + """ + + schema: Union[Unset, str] = UNSET + theme: Union[Unset, str] = UNSET + keybinds: Union[Unset, "KeybindsConfig"] = UNSET + tui: Union[Unset, "ConfigTui"] = UNSET + command: Union[Unset, "ConfigCommand"] = UNSET + watcher: Union[Unset, "ConfigWatcher"] = UNSET + plugin: Union[Unset, list[str]] = UNSET + snapshot: Union[Unset, bool] = UNSET + share: Union[Unset, ConfigShare] = UNSET + autoshare: Union[Unset, bool] = UNSET + autoupdate: Union[Unset, bool] = UNSET + disabled_providers: Union[Unset, list[str]] = UNSET + model: Union[Unset, str] = UNSET + small_model: Union[Unset, str] = UNSET + username: Union[Unset, str] = UNSET + mode: Union[Unset, "ConfigMode"] = UNSET + agent: Union[Unset, "ConfigAgent"] = UNSET + provider: Union[Unset, "ConfigProvider"] = UNSET + mcp: Union[Unset, "ConfigMcp"] = UNSET + formatter: Union[Unset, "ConfigFormatter"] = UNSET + lsp: Union[Unset, "ConfigLsp"] = UNSET + instructions: Union[Unset, list[str]] = UNSET + layout: Union[Unset, LayoutConfig] = UNSET + permission: Union[Unset, "ConfigPermission"] = UNSET + tools: Union[Unset, "ConfigTools"] = UNSET + experimental: Union[Unset, "ConfigExperimental"] = UNSET + + def to_dict(self) -> dict[str, Any]: + schema = self.schema + + theme = self.theme + + keybinds: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.keybinds, Unset): + keybinds = self.keybinds.to_dict() + + tui: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.tui, Unset): + tui = self.tui.to_dict() + + command: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.command, Unset): + command = self.command.to_dict() + + watcher: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.watcher, Unset): + watcher = self.watcher.to_dict() + + plugin: Union[Unset, list[str]] = UNSET + if not isinstance(self.plugin, Unset): + plugin = self.plugin + + snapshot = self.snapshot + + share: Union[Unset, str] = UNSET + if not isinstance(self.share, Unset): + share = self.share.value + + autoshare = self.autoshare + + autoupdate = self.autoupdate + + disabled_providers: Union[Unset, list[str]] = UNSET + if not isinstance(self.disabled_providers, Unset): + disabled_providers = self.disabled_providers + + model = self.model + + small_model = self.small_model + + username = self.username + + mode: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.mode, Unset): + mode = self.mode.to_dict() + + agent: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.agent, Unset): + agent = self.agent.to_dict() + + provider: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.provider, Unset): + provider = self.provider.to_dict() + + mcp: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.mcp, Unset): + mcp = self.mcp.to_dict() + + formatter: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.formatter, Unset): + formatter = self.formatter.to_dict() + + lsp: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.lsp, Unset): + lsp = self.lsp.to_dict() + + instructions: Union[Unset, list[str]] = UNSET + if not isinstance(self.instructions, Unset): + instructions = self.instructions + + layout: Union[Unset, str] = UNSET + if not isinstance(self.layout, Unset): + layout = self.layout.value + + permission: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.permission, Unset): + permission = self.permission.to_dict() + + tools: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.tools, Unset): + tools = self.tools.to_dict() + + experimental: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.experimental, Unset): + experimental = self.experimental.to_dict() + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if schema is not UNSET: + field_dict["$schema"] = schema + if theme is not UNSET: + field_dict["theme"] = theme + if keybinds is not UNSET: + field_dict["keybinds"] = keybinds + if tui is not UNSET: + field_dict["tui"] = tui + if command is not UNSET: + field_dict["command"] = command + if watcher is not UNSET: + field_dict["watcher"] = watcher + if plugin is not UNSET: + field_dict["plugin"] = plugin + if snapshot is not UNSET: + field_dict["snapshot"] = snapshot + if share is not UNSET: + field_dict["share"] = share + if autoshare is not UNSET: + field_dict["autoshare"] = autoshare + if autoupdate is not UNSET: + field_dict["autoupdate"] = autoupdate + if disabled_providers is not UNSET: + field_dict["disabled_providers"] = disabled_providers + if model is not UNSET: + field_dict["model"] = model + if small_model is not UNSET: + field_dict["small_model"] = small_model + if username is not UNSET: + field_dict["username"] = username + if mode is not UNSET: + field_dict["mode"] = mode + if agent is not UNSET: + field_dict["agent"] = agent + if provider is not UNSET: + field_dict["provider"] = provider + if mcp is not UNSET: + field_dict["mcp"] = mcp + if formatter is not UNSET: + field_dict["formatter"] = formatter + if lsp is not UNSET: + field_dict["lsp"] = lsp + if instructions is not UNSET: + field_dict["instructions"] = instructions + if layout is not UNSET: + field_dict["layout"] = layout + if permission is not UNSET: + field_dict["permission"] = permission + if tools is not UNSET: + field_dict["tools"] = tools + if experimental is not UNSET: + field_dict["experimental"] = experimental + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_agent import ConfigAgent + from ..models.config_command import ConfigCommand + from ..models.config_experimental import ConfigExperimental + from ..models.config_formatter import ConfigFormatter + from ..models.config_lsp import ConfigLsp + from ..models.config_mcp import ConfigMcp + from ..models.config_mode import ConfigMode + from ..models.config_permission import ConfigPermission + from ..models.config_provider import ConfigProvider + from ..models.config_tools import ConfigTools + from ..models.config_tui import ConfigTui + from ..models.config_watcher import ConfigWatcher + from ..models.keybinds_config import KeybindsConfig + + d = dict(src_dict) + schema = d.pop("$schema", UNSET) + + theme = d.pop("theme", UNSET) + + _keybinds = d.pop("keybinds", UNSET) + keybinds: Union[Unset, KeybindsConfig] + if isinstance(_keybinds, Unset): + keybinds = UNSET + else: + keybinds = KeybindsConfig.from_dict(_keybinds) + + _tui = d.pop("tui", UNSET) + tui: Union[Unset, ConfigTui] + if isinstance(_tui, Unset): + tui = UNSET + else: + tui = ConfigTui.from_dict(_tui) + + _command = d.pop("command", UNSET) + command: Union[Unset, ConfigCommand] + if isinstance(_command, Unset): + command = UNSET + else: + command = ConfigCommand.from_dict(_command) + + _watcher = d.pop("watcher", UNSET) + watcher: Union[Unset, ConfigWatcher] + if isinstance(_watcher, Unset): + watcher = UNSET + else: + watcher = ConfigWatcher.from_dict(_watcher) + + plugin = cast(list[str], d.pop("plugin", UNSET)) + + snapshot = d.pop("snapshot", UNSET) + + _share = d.pop("share", UNSET) + share: Union[Unset, ConfigShare] + if isinstance(_share, Unset): + share = UNSET + else: + share = ConfigShare(_share) + + autoshare = d.pop("autoshare", UNSET) + + autoupdate = d.pop("autoupdate", UNSET) + + disabled_providers = cast(list[str], d.pop("disabled_providers", UNSET)) + + model = d.pop("model", UNSET) + + small_model = d.pop("small_model", UNSET) + + username = d.pop("username", UNSET) + + _mode = d.pop("mode", UNSET) + mode: Union[Unset, ConfigMode] + if isinstance(_mode, Unset): + mode = UNSET + else: + mode = ConfigMode.from_dict(_mode) + + _agent = d.pop("agent", UNSET) + agent: Union[Unset, ConfigAgent] + if isinstance(_agent, Unset): + agent = UNSET + else: + agent = ConfigAgent.from_dict(_agent) + + _provider = d.pop("provider", UNSET) + provider: Union[Unset, ConfigProvider] + if isinstance(_provider, Unset): + provider = UNSET + else: + provider = ConfigProvider.from_dict(_provider) + + _mcp = d.pop("mcp", UNSET) + mcp: Union[Unset, ConfigMcp] + if isinstance(_mcp, Unset): + mcp = UNSET + else: + mcp = ConfigMcp.from_dict(_mcp) + + _formatter = d.pop("formatter", UNSET) + formatter: Union[Unset, ConfigFormatter] + if isinstance(_formatter, Unset): + formatter = UNSET + else: + formatter = ConfigFormatter.from_dict(_formatter) + + _lsp = d.pop("lsp", UNSET) + lsp: Union[Unset, ConfigLsp] + if isinstance(_lsp, Unset): + lsp = UNSET + else: + lsp = ConfigLsp.from_dict(_lsp) + + instructions = cast(list[str], d.pop("instructions", UNSET)) + + _layout = d.pop("layout", UNSET) + layout: Union[Unset, LayoutConfig] + if isinstance(_layout, Unset): + layout = UNSET + else: + layout = LayoutConfig(_layout) + + _permission = d.pop("permission", UNSET) + permission: Union[Unset, ConfigPermission] + if isinstance(_permission, Unset): + permission = UNSET + else: + permission = ConfigPermission.from_dict(_permission) + + _tools = d.pop("tools", UNSET) + tools: Union[Unset, ConfigTools] + if isinstance(_tools, Unset): + tools = UNSET + else: + tools = ConfigTools.from_dict(_tools) + + _experimental = d.pop("experimental", UNSET) + experimental: Union[Unset, ConfigExperimental] + if isinstance(_experimental, Unset): + experimental = UNSET + else: + experimental = ConfigExperimental.from_dict(_experimental) + + config = cls( + schema=schema, + theme=theme, + keybinds=keybinds, + tui=tui, + command=command, + watcher=watcher, + plugin=plugin, + snapshot=snapshot, + share=share, + autoshare=autoshare, + autoupdate=autoupdate, + disabled_providers=disabled_providers, + model=model, + small_model=small_model, + username=username, + mode=mode, + agent=agent, + provider=provider, + mcp=mcp, + formatter=formatter, + lsp=lsp, + instructions=instructions, + layout=layout, + permission=permission, + tools=tools, + experimental=experimental, + ) + + return config diff --git a/packages/sdk/python/src/opencode_ai/models/config_agent.py b/packages/sdk/python/src/opencode_ai/models/config_agent.py new file mode 100644 index 0000000000..c69897a5b3 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_agent.py @@ -0,0 +1,113 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.agent_config import AgentConfig + + +T = TypeVar("T", bound="ConfigAgent") + + +@_attrs_define +class ConfigAgent: + """Agent configuration, see https://opencode.ai/docs/agent + + Attributes: + plan (Union[Unset, AgentConfig]): + build (Union[Unset, AgentConfig]): + general (Union[Unset, AgentConfig]): + """ + + plan: Union[Unset, "AgentConfig"] = UNSET + build: Union[Unset, "AgentConfig"] = UNSET + general: Union[Unset, "AgentConfig"] = UNSET + additional_properties: dict[str, "AgentConfig"] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + plan: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.plan, Unset): + plan = self.plan.to_dict() + + build: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.build, Unset): + build = self.build.to_dict() + + general: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.general, Unset): + general = self.general.to_dict() + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + field_dict.update({}) + if plan is not UNSET: + field_dict["plan"] = plan + if build is not UNSET: + field_dict["build"] = build + if general is not UNSET: + field_dict["general"] = general + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agent_config import AgentConfig + + d = dict(src_dict) + _plan = d.pop("plan", UNSET) + plan: Union[Unset, AgentConfig] + if isinstance(_plan, Unset): + plan = UNSET + else: + plan = AgentConfig.from_dict(_plan) + + _build = d.pop("build", UNSET) + build: Union[Unset, AgentConfig] + if isinstance(_build, Unset): + build = UNSET + else: + build = AgentConfig.from_dict(_build) + + _general = d.pop("general", UNSET) + general: Union[Unset, AgentConfig] + if isinstance(_general, Unset): + general = UNSET + else: + general = AgentConfig.from_dict(_general) + + config_agent = cls( + plan=plan, + build=build, + general=general, + ) + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = AgentConfig.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + config_agent.additional_properties = additional_properties + return config_agent + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> "AgentConfig": + return self.additional_properties[key] + + def __setitem__(self, key: str, value: "AgentConfig") -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_command.py b/packages/sdk/python/src/opencode_ai/models/config_command.py new file mode 100644 index 0000000000..908f5f44c8 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_command.py @@ -0,0 +1,57 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.config_command_additional_property import ConfigCommandAdditionalProperty + + +T = TypeVar("T", bound="ConfigCommand") + + +@_attrs_define +class ConfigCommand: + """Command configuration, see https://opencode.ai/docs/commands""" + + additional_properties: dict[str, "ConfigCommandAdditionalProperty"] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_command_additional_property import ConfigCommandAdditionalProperty + + d = dict(src_dict) + config_command = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = ConfigCommandAdditionalProperty.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + config_command.additional_properties = additional_properties + return config_command + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> "ConfigCommandAdditionalProperty": + return self.additional_properties[key] + + def __setitem__(self, key: str, value: "ConfigCommandAdditionalProperty") -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_command_additional_property.py b/packages/sdk/python/src/opencode_ai/models/config_command_additional_property.py new file mode 100644 index 0000000000..64c39db18a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_command_additional_property.py @@ -0,0 +1,97 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ConfigCommandAdditionalProperty") + + +@_attrs_define +class ConfigCommandAdditionalProperty: + """ + Attributes: + template (str): + description (Union[Unset, str]): + agent (Union[Unset, str]): + model (Union[Unset, str]): + subtask (Union[Unset, bool]): + """ + + template: str + description: Union[Unset, str] = UNSET + agent: Union[Unset, str] = UNSET + model: Union[Unset, str] = UNSET + subtask: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + template = self.template + + description = self.description + + agent = self.agent + + model = self.model + + subtask = self.subtask + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "template": template, + } + ) + if description is not UNSET: + field_dict["description"] = description + if agent is not UNSET: + field_dict["agent"] = agent + if model is not UNSET: + field_dict["model"] = model + if subtask is not UNSET: + field_dict["subtask"] = subtask + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + template = d.pop("template") + + description = d.pop("description", UNSET) + + agent = d.pop("agent", UNSET) + + model = d.pop("model", UNSET) + + subtask = d.pop("subtask", UNSET) + + config_command_additional_property = cls( + template=template, + description=description, + agent=agent, + model=model, + subtask=subtask, + ) + + config_command_additional_property.additional_properties = d + return config_command_additional_property + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_experimental.py b/packages/sdk/python/src/opencode_ai/models/config_experimental.py new file mode 100644 index 0000000000..f67c0422af --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_experimental.py @@ -0,0 +1,81 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_experimental_hook import ConfigExperimentalHook + + +T = TypeVar("T", bound="ConfigExperimental") + + +@_attrs_define +class ConfigExperimental: + """ + Attributes: + hook (Union[Unset, ConfigExperimentalHook]): + disable_paste_summary (Union[Unset, bool]): + """ + + hook: Union[Unset, "ConfigExperimentalHook"] = UNSET + disable_paste_summary: Union[Unset, bool] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + hook: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.hook, Unset): + hook = self.hook.to_dict() + + disable_paste_summary = self.disable_paste_summary + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if hook is not UNSET: + field_dict["hook"] = hook + if disable_paste_summary is not UNSET: + field_dict["disable_paste_summary"] = disable_paste_summary + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_experimental_hook import ConfigExperimentalHook + + d = dict(src_dict) + _hook = d.pop("hook", UNSET) + hook: Union[Unset, ConfigExperimentalHook] + if isinstance(_hook, Unset): + hook = UNSET + else: + hook = ConfigExperimentalHook.from_dict(_hook) + + disable_paste_summary = d.pop("disable_paste_summary", UNSET) + + config_experimental = cls( + hook=hook, + disable_paste_summary=disable_paste_summary, + ) + + config_experimental.additional_properties = d + return config_experimental + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_experimental_hook.py b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook.py new file mode 100644 index 0000000000..014e97a0a0 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook.py @@ -0,0 +1,93 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_experimental_hook_file_edited import ConfigExperimentalHookFileEdited + from ..models.config_experimental_hook_session_completed_item import ConfigExperimentalHookSessionCompletedItem + + +T = TypeVar("T", bound="ConfigExperimentalHook") + + +@_attrs_define +class ConfigExperimentalHook: + """ + Attributes: + file_edited (Union[Unset, ConfigExperimentalHookFileEdited]): + session_completed (Union[Unset, list['ConfigExperimentalHookSessionCompletedItem']]): + """ + + file_edited: Union[Unset, "ConfigExperimentalHookFileEdited"] = UNSET + session_completed: Union[Unset, list["ConfigExperimentalHookSessionCompletedItem"]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + file_edited: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.file_edited, Unset): + file_edited = self.file_edited.to_dict() + + session_completed: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.session_completed, Unset): + session_completed = [] + for session_completed_item_data in self.session_completed: + session_completed_item = session_completed_item_data.to_dict() + session_completed.append(session_completed_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if file_edited is not UNSET: + field_dict["file_edited"] = file_edited + if session_completed is not UNSET: + field_dict["session_completed"] = session_completed + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_experimental_hook_file_edited import ConfigExperimentalHookFileEdited + from ..models.config_experimental_hook_session_completed_item import ConfigExperimentalHookSessionCompletedItem + + d = dict(src_dict) + _file_edited = d.pop("file_edited", UNSET) + file_edited: Union[Unset, ConfigExperimentalHookFileEdited] + if isinstance(_file_edited, Unset): + file_edited = UNSET + else: + file_edited = ConfigExperimentalHookFileEdited.from_dict(_file_edited) + + session_completed = [] + _session_completed = d.pop("session_completed", UNSET) + for session_completed_item_data in _session_completed or []: + session_completed_item = ConfigExperimentalHookSessionCompletedItem.from_dict(session_completed_item_data) + + session_completed.append(session_completed_item) + + config_experimental_hook = cls( + file_edited=file_edited, + session_completed=session_completed, + ) + + config_experimental_hook.additional_properties = d + return config_experimental_hook + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited.py b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited.py new file mode 100644 index 0000000000..8d662f1ce0 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited.py @@ -0,0 +1,73 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.config_experimental_hook_file_edited_additional_property_item import ( + ConfigExperimentalHookFileEditedAdditionalPropertyItem, + ) + + +T = TypeVar("T", bound="ConfigExperimentalHookFileEdited") + + +@_attrs_define +class ConfigExperimentalHookFileEdited: + """ """ + + additional_properties: dict[str, list["ConfigExperimentalHookFileEditedAdditionalPropertyItem"]] = _attrs_field( + init=False, factory=dict + ) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = [] + for additional_property_item_data in prop: + additional_property_item = additional_property_item_data.to_dict() + field_dict[prop_name].append(additional_property_item) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_experimental_hook_file_edited_additional_property_item import ( + ConfigExperimentalHookFileEditedAdditionalPropertyItem, + ) + + d = dict(src_dict) + config_experimental_hook_file_edited = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = [] + _additional_property = prop_dict + for additional_property_item_data in _additional_property: + additional_property_item = ConfigExperimentalHookFileEditedAdditionalPropertyItem.from_dict( + additional_property_item_data + ) + + additional_property.append(additional_property_item) + + additional_properties[prop_name] = additional_property + + config_experimental_hook_file_edited.additional_properties = additional_properties + return config_experimental_hook_file_edited + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> list["ConfigExperimentalHookFileEditedAdditionalPropertyItem"]: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: list["ConfigExperimentalHookFileEditedAdditionalPropertyItem"]) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited_additional_property_item.py b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited_additional_property_item.py new file mode 100644 index 0000000000..a9f27a17e1 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited_additional_property_item.py @@ -0,0 +1,87 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_experimental_hook_file_edited_additional_property_item_environment import ( + ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment, + ) + + +T = TypeVar("T", bound="ConfigExperimentalHookFileEditedAdditionalPropertyItem") + + +@_attrs_define +class ConfigExperimentalHookFileEditedAdditionalPropertyItem: + """ + Attributes: + command (list[str]): + environment (Union[Unset, ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment]): + """ + + command: list[str] + environment: Union[Unset, "ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + command = self.command + + environment: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.environment, Unset): + environment = self.environment.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "command": command, + } + ) + if environment is not UNSET: + field_dict["environment"] = environment + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_experimental_hook_file_edited_additional_property_item_environment import ( + ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment, + ) + + d = dict(src_dict) + command = cast(list[str], d.pop("command")) + + _environment = d.pop("environment", UNSET) + environment: Union[Unset, ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment] + if isinstance(_environment, Unset): + environment = UNSET + else: + environment = ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment.from_dict(_environment) + + config_experimental_hook_file_edited_additional_property_item = cls( + command=command, + environment=environment, + ) + + config_experimental_hook_file_edited_additional_property_item.additional_properties = d + return config_experimental_hook_file_edited_additional_property_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited_additional_property_item_environment.py b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited_additional_property_item_environment.py new file mode 100644 index 0000000000..5454649962 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_file_edited_additional_property_item_environment.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment") + + +@_attrs_define +class ConfigExperimentalHookFileEditedAdditionalPropertyItemEnvironment: + """ """ + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + config_experimental_hook_file_edited_additional_property_item_environment = cls() + + config_experimental_hook_file_edited_additional_property_item_environment.additional_properties = d + return config_experimental_hook_file_edited_additional_property_item_environment + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_session_completed_item.py b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_session_completed_item.py new file mode 100644 index 0000000000..912f1b1e4c --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_session_completed_item.py @@ -0,0 +1,87 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_experimental_hook_session_completed_item_environment import ( + ConfigExperimentalHookSessionCompletedItemEnvironment, + ) + + +T = TypeVar("T", bound="ConfigExperimentalHookSessionCompletedItem") + + +@_attrs_define +class ConfigExperimentalHookSessionCompletedItem: + """ + Attributes: + command (list[str]): + environment (Union[Unset, ConfigExperimentalHookSessionCompletedItemEnvironment]): + """ + + command: list[str] + environment: Union[Unset, "ConfigExperimentalHookSessionCompletedItemEnvironment"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + command = self.command + + environment: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.environment, Unset): + environment = self.environment.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "command": command, + } + ) + if environment is not UNSET: + field_dict["environment"] = environment + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_experimental_hook_session_completed_item_environment import ( + ConfigExperimentalHookSessionCompletedItemEnvironment, + ) + + d = dict(src_dict) + command = cast(list[str], d.pop("command")) + + _environment = d.pop("environment", UNSET) + environment: Union[Unset, ConfigExperimentalHookSessionCompletedItemEnvironment] + if isinstance(_environment, Unset): + environment = UNSET + else: + environment = ConfigExperimentalHookSessionCompletedItemEnvironment.from_dict(_environment) + + config_experimental_hook_session_completed_item = cls( + command=command, + environment=environment, + ) + + config_experimental_hook_session_completed_item.additional_properties = d + return config_experimental_hook_session_completed_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_session_completed_item_environment.py b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_session_completed_item_environment.py new file mode 100644 index 0000000000..ca87e07289 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_experimental_hook_session_completed_item_environment.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigExperimentalHookSessionCompletedItemEnvironment") + + +@_attrs_define +class ConfigExperimentalHookSessionCompletedItemEnvironment: + """ """ + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + config_experimental_hook_session_completed_item_environment = cls() + + config_experimental_hook_session_completed_item_environment.additional_properties = d + return config_experimental_hook_session_completed_item_environment + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_formatter.py b/packages/sdk/python/src/opencode_ai/models/config_formatter.py new file mode 100644 index 0000000000..9002e2e873 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_formatter.py @@ -0,0 +1,57 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.config_formatter_additional_property import ConfigFormatterAdditionalProperty + + +T = TypeVar("T", bound="ConfigFormatter") + + +@_attrs_define +class ConfigFormatter: + """ """ + + additional_properties: dict[str, "ConfigFormatterAdditionalProperty"] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_formatter_additional_property import ConfigFormatterAdditionalProperty + + d = dict(src_dict) + config_formatter = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = ConfigFormatterAdditionalProperty.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + config_formatter.additional_properties = additional_properties + return config_formatter + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> "ConfigFormatterAdditionalProperty": + return self.additional_properties[key] + + def __setitem__(self, key: str, value: "ConfigFormatterAdditionalProperty") -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_formatter_additional_property.py b/packages/sdk/python/src/opencode_ai/models/config_formatter_additional_property.py new file mode 100644 index 0000000000..6db1202568 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_formatter_additional_property.py @@ -0,0 +1,105 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_formatter_additional_property_environment import ConfigFormatterAdditionalPropertyEnvironment + + +T = TypeVar("T", bound="ConfigFormatterAdditionalProperty") + + +@_attrs_define +class ConfigFormatterAdditionalProperty: + """ + Attributes: + disabled (Union[Unset, bool]): + command (Union[Unset, list[str]]): + environment (Union[Unset, ConfigFormatterAdditionalPropertyEnvironment]): + extensions (Union[Unset, list[str]]): + """ + + disabled: Union[Unset, bool] = UNSET + command: Union[Unset, list[str]] = UNSET + environment: Union[Unset, "ConfigFormatterAdditionalPropertyEnvironment"] = UNSET + extensions: Union[Unset, list[str]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + disabled = self.disabled + + command: Union[Unset, list[str]] = UNSET + if not isinstance(self.command, Unset): + command = self.command + + environment: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.environment, Unset): + environment = self.environment.to_dict() + + extensions: Union[Unset, list[str]] = UNSET + if not isinstance(self.extensions, Unset): + extensions = self.extensions + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if disabled is not UNSET: + field_dict["disabled"] = disabled + if command is not UNSET: + field_dict["command"] = command + if environment is not UNSET: + field_dict["environment"] = environment + if extensions is not UNSET: + field_dict["extensions"] = extensions + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_formatter_additional_property_environment import ( + ConfigFormatterAdditionalPropertyEnvironment, + ) + + d = dict(src_dict) + disabled = d.pop("disabled", UNSET) + + command = cast(list[str], d.pop("command", UNSET)) + + _environment = d.pop("environment", UNSET) + environment: Union[Unset, ConfigFormatterAdditionalPropertyEnvironment] + if isinstance(_environment, Unset): + environment = UNSET + else: + environment = ConfigFormatterAdditionalPropertyEnvironment.from_dict(_environment) + + extensions = cast(list[str], d.pop("extensions", UNSET)) + + config_formatter_additional_property = cls( + disabled=disabled, + command=command, + environment=environment, + extensions=extensions, + ) + + config_formatter_additional_property.additional_properties = d + return config_formatter_additional_property + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_formatter_additional_property_environment.py b/packages/sdk/python/src/opencode_ai/models/config_formatter_additional_property_environment.py new file mode 100644 index 0000000000..7aa6e91a5c --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_formatter_additional_property_environment.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigFormatterAdditionalPropertyEnvironment") + + +@_attrs_define +class ConfigFormatterAdditionalPropertyEnvironment: + """ """ + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + config_formatter_additional_property_environment = cls() + + config_formatter_additional_property_environment.additional_properties = d + return config_formatter_additional_property_environment + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_lsp.py b/packages/sdk/python/src/opencode_ai/models/config_lsp.py new file mode 100644 index 0000000000..a974f5265a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_lsp.py @@ -0,0 +1,86 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.config_lsp_additional_property_type_0 import ConfigLspAdditionalPropertyType0 + from ..models.config_lsp_additional_property_type_1 import ConfigLspAdditionalPropertyType1 + + +T = TypeVar("T", bound="ConfigLsp") + + +@_attrs_define +class ConfigLsp: + """ """ + + additional_properties: dict[str, Union["ConfigLspAdditionalPropertyType0", "ConfigLspAdditionalPropertyType1"]] = ( + _attrs_field(init=False, factory=dict) + ) + + def to_dict(self) -> dict[str, Any]: + from ..models.config_lsp_additional_property_type_0 import ConfigLspAdditionalPropertyType0 + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + if isinstance(prop, ConfigLspAdditionalPropertyType0): + field_dict[prop_name] = prop.to_dict() + else: + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_lsp_additional_property_type_0 import ConfigLspAdditionalPropertyType0 + from ..models.config_lsp_additional_property_type_1 import ConfigLspAdditionalPropertyType1 + + d = dict(src_dict) + config_lsp = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property( + data: object, + ) -> Union["ConfigLspAdditionalPropertyType0", "ConfigLspAdditionalPropertyType1"]: + try: + if not isinstance(data, dict): + raise TypeError() + additional_property_type_0 = ConfigLspAdditionalPropertyType0.from_dict(data) + + return additional_property_type_0 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + additional_property_type_1 = ConfigLspAdditionalPropertyType1.from_dict(data) + + return additional_property_type_1 + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + config_lsp.additional_properties = additional_properties + return config_lsp + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Union["ConfigLspAdditionalPropertyType0", "ConfigLspAdditionalPropertyType1"]: + return self.additional_properties[key] + + def __setitem__( + self, key: str, value: Union["ConfigLspAdditionalPropertyType0", "ConfigLspAdditionalPropertyType1"] + ) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_0.py b/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_0.py new file mode 100644 index 0000000000..819d7d5972 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_0.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigLspAdditionalPropertyType0") + + +@_attrs_define +class ConfigLspAdditionalPropertyType0: + """ + Attributes: + disabled (bool): + """ + + disabled: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + disabled = self.disabled + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "disabled": disabled, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + disabled = d.pop("disabled") + + config_lsp_additional_property_type_0 = cls( + disabled=disabled, + ) + + config_lsp_additional_property_type_0.additional_properties = d + return config_lsp_additional_property_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1.py b/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1.py new file mode 100644 index 0000000000..cd3d39b2d7 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1.py @@ -0,0 +1,125 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_lsp_additional_property_type_1_env import ConfigLspAdditionalPropertyType1Env + from ..models.config_lsp_additional_property_type_1_initialization import ( + ConfigLspAdditionalPropertyType1Initialization, + ) + + +T = TypeVar("T", bound="ConfigLspAdditionalPropertyType1") + + +@_attrs_define +class ConfigLspAdditionalPropertyType1: + """ + Attributes: + command (list[str]): + extensions (Union[Unset, list[str]]): + disabled (Union[Unset, bool]): + env (Union[Unset, ConfigLspAdditionalPropertyType1Env]): + initialization (Union[Unset, ConfigLspAdditionalPropertyType1Initialization]): + """ + + command: list[str] + extensions: Union[Unset, list[str]] = UNSET + disabled: Union[Unset, bool] = UNSET + env: Union[Unset, "ConfigLspAdditionalPropertyType1Env"] = UNSET + initialization: Union[Unset, "ConfigLspAdditionalPropertyType1Initialization"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + command = self.command + + extensions: Union[Unset, list[str]] = UNSET + if not isinstance(self.extensions, Unset): + extensions = self.extensions + + disabled = self.disabled + + env: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.env, Unset): + env = self.env.to_dict() + + initialization: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.initialization, Unset): + initialization = self.initialization.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "command": command, + } + ) + if extensions is not UNSET: + field_dict["extensions"] = extensions + if disabled is not UNSET: + field_dict["disabled"] = disabled + if env is not UNSET: + field_dict["env"] = env + if initialization is not UNSET: + field_dict["initialization"] = initialization + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_lsp_additional_property_type_1_env import ConfigLspAdditionalPropertyType1Env + from ..models.config_lsp_additional_property_type_1_initialization import ( + ConfigLspAdditionalPropertyType1Initialization, + ) + + d = dict(src_dict) + command = cast(list[str], d.pop("command")) + + extensions = cast(list[str], d.pop("extensions", UNSET)) + + disabled = d.pop("disabled", UNSET) + + _env = d.pop("env", UNSET) + env: Union[Unset, ConfigLspAdditionalPropertyType1Env] + if isinstance(_env, Unset): + env = UNSET + else: + env = ConfigLspAdditionalPropertyType1Env.from_dict(_env) + + _initialization = d.pop("initialization", UNSET) + initialization: Union[Unset, ConfigLspAdditionalPropertyType1Initialization] + if isinstance(_initialization, Unset): + initialization = UNSET + else: + initialization = ConfigLspAdditionalPropertyType1Initialization.from_dict(_initialization) + + config_lsp_additional_property_type_1 = cls( + command=command, + extensions=extensions, + disabled=disabled, + env=env, + initialization=initialization, + ) + + config_lsp_additional_property_type_1.additional_properties = d + return config_lsp_additional_property_type_1 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1_env.py b/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1_env.py new file mode 100644 index 0000000000..0ae2280a51 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1_env.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigLspAdditionalPropertyType1Env") + + +@_attrs_define +class ConfigLspAdditionalPropertyType1Env: + """ """ + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + config_lsp_additional_property_type_1_env = cls() + + config_lsp_additional_property_type_1_env.additional_properties = d + return config_lsp_additional_property_type_1_env + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1_initialization.py b/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1_initialization.py new file mode 100644 index 0000000000..52d192f627 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_lsp_additional_property_type_1_initialization.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigLspAdditionalPropertyType1Initialization") + + +@_attrs_define +class ConfigLspAdditionalPropertyType1Initialization: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + config_lsp_additional_property_type_1_initialization = cls() + + config_lsp_additional_property_type_1_initialization.additional_properties = d + return config_lsp_additional_property_type_1_initialization + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_mcp.py b/packages/sdk/python/src/opencode_ai/models/config_mcp.py new file mode 100644 index 0000000000..dbd0185099 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_mcp.py @@ -0,0 +1,82 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.mcp_local_config import McpLocalConfig + from ..models.mcp_remote_config import McpRemoteConfig + + +T = TypeVar("T", bound="ConfigMcp") + + +@_attrs_define +class ConfigMcp: + """MCP (Model Context Protocol) server configurations""" + + additional_properties: dict[str, Union["McpLocalConfig", "McpRemoteConfig"]] = _attrs_field( + init=False, factory=dict + ) + + def to_dict(self) -> dict[str, Any]: + from ..models.mcp_local_config import McpLocalConfig + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + if isinstance(prop, McpLocalConfig): + field_dict[prop_name] = prop.to_dict() + else: + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.mcp_local_config import McpLocalConfig + from ..models.mcp_remote_config import McpRemoteConfig + + d = dict(src_dict) + config_mcp = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property(data: object) -> Union["McpLocalConfig", "McpRemoteConfig"]: + try: + if not isinstance(data, dict): + raise TypeError() + additional_property_type_0 = McpLocalConfig.from_dict(data) + + return additional_property_type_0 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + additional_property_type_1 = McpRemoteConfig.from_dict(data) + + return additional_property_type_1 + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + config_mcp.additional_properties = additional_properties + return config_mcp + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Union["McpLocalConfig", "McpRemoteConfig"]: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Union["McpLocalConfig", "McpRemoteConfig"]) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_mode.py b/packages/sdk/python/src/opencode_ai/models/config_mode.py new file mode 100644 index 0000000000..8ef64947c4 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_mode.py @@ -0,0 +1,97 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.agent_config import AgentConfig + + +T = TypeVar("T", bound="ConfigMode") + + +@_attrs_define +class ConfigMode: + """@deprecated Use `agent` field instead. + + Attributes: + build (Union[Unset, AgentConfig]): + plan (Union[Unset, AgentConfig]): + """ + + build: Union[Unset, "AgentConfig"] = UNSET + plan: Union[Unset, "AgentConfig"] = UNSET + additional_properties: dict[str, "AgentConfig"] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + build: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.build, Unset): + build = self.build.to_dict() + + plan: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.plan, Unset): + plan = self.plan.to_dict() + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + field_dict.update({}) + if build is not UNSET: + field_dict["build"] = build + if plan is not UNSET: + field_dict["plan"] = plan + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agent_config import AgentConfig + + d = dict(src_dict) + _build = d.pop("build", UNSET) + build: Union[Unset, AgentConfig] + if isinstance(_build, Unset): + build = UNSET + else: + build = AgentConfig.from_dict(_build) + + _plan = d.pop("plan", UNSET) + plan: Union[Unset, AgentConfig] + if isinstance(_plan, Unset): + plan = UNSET + else: + plan = AgentConfig.from_dict(_plan) + + config_mode = cls( + build=build, + plan=plan, + ) + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = AgentConfig.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + config_mode.additional_properties = additional_properties + return config_mode + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> "AgentConfig": + return self.additional_properties[key] + + def __setitem__(self, key: str, value: "AgentConfig") -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_permission.py b/packages/sdk/python/src/opencode_ai/models/config_permission.py new file mode 100644 index 0000000000..baf3c3b520 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_permission.py @@ -0,0 +1,155 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_permission_bash_type_1 import ConfigPermissionBashType1 + + +T = TypeVar("T", bound="ConfigPermission") + + +@_attrs_define +class ConfigPermission: + """ + Attributes: + edit (Union[Literal['allow'], Literal['ask'], Literal['deny'], Unset]): + bash (Union['ConfigPermissionBashType1', Literal['allow'], Literal['ask'], Literal['deny'], Unset]): + webfetch (Union[Literal['allow'], Literal['ask'], Literal['deny'], Unset]): + """ + + edit: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] = UNSET + bash: Union["ConfigPermissionBashType1", Literal["allow"], Literal["ask"], Literal["deny"], Unset] = UNSET + webfetch: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.config_permission_bash_type_1 import ConfigPermissionBashType1 + + edit: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] + if isinstance(self.edit, Unset): + edit = UNSET + else: + edit = self.edit + + bash: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset, dict[str, Any]] + if isinstance(self.bash, Unset): + bash = UNSET + elif isinstance(self.bash, ConfigPermissionBashType1): + bash = self.bash.to_dict() + else: + bash = self.bash + + webfetch: Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset] + if isinstance(self.webfetch, Unset): + webfetch = UNSET + else: + webfetch = self.webfetch + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if edit is not UNSET: + field_dict["edit"] = edit + if bash is not UNSET: + field_dict["bash"] = bash + if webfetch is not UNSET: + field_dict["webfetch"] = webfetch + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_permission_bash_type_1 import ConfigPermissionBashType1 + + d = dict(src_dict) + + def _parse_edit(data: object) -> Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset]: + if isinstance(data, Unset): + return data + edit_type_0 = cast(Literal["ask"], data) + if edit_type_0 != "ask": + raise ValueError(f"edit_type_0 must match const 'ask', got '{edit_type_0}'") + return edit_type_0 + edit_type_1 = cast(Literal["allow"], data) + if edit_type_1 != "allow": + raise ValueError(f"edit_type_1 must match const 'allow', got '{edit_type_1}'") + return edit_type_1 + edit_type_2 = cast(Literal["deny"], data) + if edit_type_2 != "deny": + raise ValueError(f"edit_type_2 must match const 'deny', got '{edit_type_2}'") + return edit_type_2 + + edit = _parse_edit(d.pop("edit", UNSET)) + + def _parse_bash( + data: object, + ) -> Union["ConfigPermissionBashType1", Literal["allow"], Literal["ask"], Literal["deny"], Unset]: + if isinstance(data, Unset): + return data + bash_type_0_type_0 = cast(Literal["ask"], data) + if bash_type_0_type_0 != "ask": + raise ValueError(f"bash_type_0_type_0 must match const 'ask', got '{bash_type_0_type_0}'") + return bash_type_0_type_0 + bash_type_0_type_1 = cast(Literal["allow"], data) + if bash_type_0_type_1 != "allow": + raise ValueError(f"bash_type_0_type_1 must match const 'allow', got '{bash_type_0_type_1}'") + return bash_type_0_type_1 + bash_type_0_type_2 = cast(Literal["deny"], data) + if bash_type_0_type_2 != "deny": + raise ValueError(f"bash_type_0_type_2 must match const 'deny', got '{bash_type_0_type_2}'") + return bash_type_0_type_2 + if not isinstance(data, dict): + raise TypeError() + bash_type_1 = ConfigPermissionBashType1.from_dict(data) + + return bash_type_1 + + bash = _parse_bash(d.pop("bash", UNSET)) + + def _parse_webfetch(data: object) -> Union[Literal["allow"], Literal["ask"], Literal["deny"], Unset]: + if isinstance(data, Unset): + return data + webfetch_type_0 = cast(Literal["ask"], data) + if webfetch_type_0 != "ask": + raise ValueError(f"webfetch_type_0 must match const 'ask', got '{webfetch_type_0}'") + return webfetch_type_0 + webfetch_type_1 = cast(Literal["allow"], data) + if webfetch_type_1 != "allow": + raise ValueError(f"webfetch_type_1 must match const 'allow', got '{webfetch_type_1}'") + return webfetch_type_1 + webfetch_type_2 = cast(Literal["deny"], data) + if webfetch_type_2 != "deny": + raise ValueError(f"webfetch_type_2 must match const 'deny', got '{webfetch_type_2}'") + return webfetch_type_2 + + webfetch = _parse_webfetch(d.pop("webfetch", UNSET)) + + config_permission = cls( + edit=edit, + bash=bash, + webfetch=webfetch, + ) + + config_permission.additional_properties = d + return config_permission + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_permission_bash_type_1.py b/packages/sdk/python/src/opencode_ai/models/config_permission_bash_type_1.py new file mode 100644 index 0000000000..bc7b0dc580 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_permission_bash_type_1.py @@ -0,0 +1,74 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigPermissionBashType1") + + +@_attrs_define +class ConfigPermissionBashType1: + """ """ + + additional_properties: dict[str, Union[Literal["allow"], Literal["ask"], Literal["deny"]]] = _attrs_field( + init=False, factory=dict + ) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + config_permission_bash_type_1 = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property(data: object) -> Union[Literal["allow"], Literal["ask"], Literal["deny"]]: + additional_property_type_0 = cast(Literal["ask"], data) + if additional_property_type_0 != "ask": + raise ValueError( + f"AdditionalProperty_type_0 must match const 'ask', got '{additional_property_type_0}'" + ) + return additional_property_type_0 + additional_property_type_1 = cast(Literal["allow"], data) + if additional_property_type_1 != "allow": + raise ValueError( + f"AdditionalProperty_type_1 must match const 'allow', got '{additional_property_type_1}'" + ) + return additional_property_type_1 + additional_property_type_2 = cast(Literal["deny"], data) + if additional_property_type_2 != "deny": + raise ValueError( + f"AdditionalProperty_type_2 must match const 'deny', got '{additional_property_type_2}'" + ) + return additional_property_type_2 + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + config_permission_bash_type_1.additional_properties = additional_properties + return config_permission_bash_type_1 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Union[Literal["allow"], Literal["ask"], Literal["deny"]]: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Union[Literal["allow"], Literal["ask"], Literal["deny"]]) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_provider.py b/packages/sdk/python/src/opencode_ai/models/config_provider.py new file mode 100644 index 0000000000..577b9b0567 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_provider.py @@ -0,0 +1,57 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.config_provider_additional_property import ConfigProviderAdditionalProperty + + +T = TypeVar("T", bound="ConfigProvider") + + +@_attrs_define +class ConfigProvider: + """Custom provider configurations and model overrides""" + + additional_properties: dict[str, "ConfigProviderAdditionalProperty"] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_provider_additional_property import ConfigProviderAdditionalProperty + + d = dict(src_dict) + config_provider = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = ConfigProviderAdditionalProperty.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + config_provider.additional_properties = additional_properties + return config_provider + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> "ConfigProviderAdditionalProperty": + return self.additional_properties[key] + + def __setitem__(self, key: str, value: "ConfigProviderAdditionalProperty") -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property.py b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property.py new file mode 100644 index 0000000000..a6aef270b7 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property.py @@ -0,0 +1,118 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_provider_additional_property_models import ConfigProviderAdditionalPropertyModels + from ..models.config_provider_additional_property_options import ConfigProviderAdditionalPropertyOptions + + +T = TypeVar("T", bound="ConfigProviderAdditionalProperty") + + +@_attrs_define +class ConfigProviderAdditionalProperty: + """ + Attributes: + api (Union[Unset, str]): + name (Union[Unset, str]): + env (Union[Unset, list[str]]): + id (Union[Unset, str]): + npm (Union[Unset, str]): + models (Union[Unset, ConfigProviderAdditionalPropertyModels]): + options (Union[Unset, ConfigProviderAdditionalPropertyOptions]): + """ + + api: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + env: Union[Unset, list[str]] = UNSET + id: Union[Unset, str] = UNSET + npm: Union[Unset, str] = UNSET + models: Union[Unset, "ConfigProviderAdditionalPropertyModels"] = UNSET + options: Union[Unset, "ConfigProviderAdditionalPropertyOptions"] = UNSET + + def to_dict(self) -> dict[str, Any]: + api = self.api + + name = self.name + + env: Union[Unset, list[str]] = UNSET + if not isinstance(self.env, Unset): + env = self.env + + id = self.id + + npm = self.npm + + models: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.models, Unset): + models = self.models.to_dict() + + options: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.options, Unset): + options = self.options.to_dict() + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if api is not UNSET: + field_dict["api"] = api + if name is not UNSET: + field_dict["name"] = name + if env is not UNSET: + field_dict["env"] = env + if id is not UNSET: + field_dict["id"] = id + if npm is not UNSET: + field_dict["npm"] = npm + if models is not UNSET: + field_dict["models"] = models + if options is not UNSET: + field_dict["options"] = options + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_provider_additional_property_models import ConfigProviderAdditionalPropertyModels + from ..models.config_provider_additional_property_options import ConfigProviderAdditionalPropertyOptions + + d = dict(src_dict) + api = d.pop("api", UNSET) + + name = d.pop("name", UNSET) + + env = cast(list[str], d.pop("env", UNSET)) + + id = d.pop("id", UNSET) + + npm = d.pop("npm", UNSET) + + _models = d.pop("models", UNSET) + models: Union[Unset, ConfigProviderAdditionalPropertyModels] + if isinstance(_models, Unset): + models = UNSET + else: + models = ConfigProviderAdditionalPropertyModels.from_dict(_models) + + _options = d.pop("options", UNSET) + options: Union[Unset, ConfigProviderAdditionalPropertyOptions] + if isinstance(_options, Unset): + options = UNSET + else: + options = ConfigProviderAdditionalPropertyOptions.from_dict(_options) + + config_provider_additional_property = cls( + api=api, + name=name, + env=env, + id=id, + npm=npm, + models=models, + options=options, + ) + + return config_provider_additional_property diff --git a/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models.py b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models.py new file mode 100644 index 0000000000..8277df5ad9 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models.py @@ -0,0 +1,63 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.config_provider_additional_property_models_additional_property import ( + ConfigProviderAdditionalPropertyModelsAdditionalProperty, + ) + + +T = TypeVar("T", bound="ConfigProviderAdditionalPropertyModels") + + +@_attrs_define +class ConfigProviderAdditionalPropertyModels: + """ """ + + additional_properties: dict[str, "ConfigProviderAdditionalPropertyModelsAdditionalProperty"] = _attrs_field( + init=False, factory=dict + ) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_provider_additional_property_models_additional_property import ( + ConfigProviderAdditionalPropertyModelsAdditionalProperty, + ) + + d = dict(src_dict) + config_provider_additional_property_models = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = ConfigProviderAdditionalPropertyModelsAdditionalProperty.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + config_provider_additional_property_models.additional_properties = additional_properties + return config_provider_additional_property_models + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> "ConfigProviderAdditionalPropertyModelsAdditionalProperty": + return self.additional_properties[key] + + def __setitem__(self, key: str, value: "ConfigProviderAdditionalPropertyModelsAdditionalProperty") -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property.py b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property.py new file mode 100644 index 0000000000..eac949c7b0 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property.py @@ -0,0 +1,214 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.config_provider_additional_property_models_additional_property_cost import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost, + ) + from ..models.config_provider_additional_property_models_additional_property_limit import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit, + ) + from ..models.config_provider_additional_property_models_additional_property_options import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions, + ) + from ..models.config_provider_additional_property_models_additional_property_provider import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider, + ) + + +T = TypeVar("T", bound="ConfigProviderAdditionalPropertyModelsAdditionalProperty") + + +@_attrs_define +class ConfigProviderAdditionalPropertyModelsAdditionalProperty: + """ + Attributes: + id (Union[Unset, str]): + name (Union[Unset, str]): + release_date (Union[Unset, str]): + attachment (Union[Unset, bool]): + reasoning (Union[Unset, bool]): + temperature (Union[Unset, bool]): + tool_call (Union[Unset, bool]): + cost (Union[Unset, ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost]): + limit (Union[Unset, ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit]): + experimental (Union[Unset, bool]): + options (Union[Unset, ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions]): + provider (Union[Unset, ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider]): + """ + + id: Union[Unset, str] = UNSET + name: Union[Unset, str] = UNSET + release_date: Union[Unset, str] = UNSET + attachment: Union[Unset, bool] = UNSET + reasoning: Union[Unset, bool] = UNSET + temperature: Union[Unset, bool] = UNSET + tool_call: Union[Unset, bool] = UNSET + cost: Union[Unset, "ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost"] = UNSET + limit: Union[Unset, "ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit"] = UNSET + experimental: Union[Unset, bool] = UNSET + options: Union[Unset, "ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions"] = UNSET + provider: Union[Unset, "ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + release_date = self.release_date + + attachment = self.attachment + + reasoning = self.reasoning + + temperature = self.temperature + + tool_call = self.tool_call + + cost: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.cost, Unset): + cost = self.cost.to_dict() + + limit: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.limit, Unset): + limit = self.limit.to_dict() + + experimental = self.experimental + + options: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.options, Unset): + options = self.options.to_dict() + + provider: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.provider, Unset): + provider = self.provider.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if id is not UNSET: + field_dict["id"] = id + if name is not UNSET: + field_dict["name"] = name + if release_date is not UNSET: + field_dict["release_date"] = release_date + if attachment is not UNSET: + field_dict["attachment"] = attachment + if reasoning is not UNSET: + field_dict["reasoning"] = reasoning + if temperature is not UNSET: + field_dict["temperature"] = temperature + if tool_call is not UNSET: + field_dict["tool_call"] = tool_call + if cost is not UNSET: + field_dict["cost"] = cost + if limit is not UNSET: + field_dict["limit"] = limit + if experimental is not UNSET: + field_dict["experimental"] = experimental + if options is not UNSET: + field_dict["options"] = options + if provider is not UNSET: + field_dict["provider"] = provider + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_provider_additional_property_models_additional_property_cost import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost, + ) + from ..models.config_provider_additional_property_models_additional_property_limit import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit, + ) + from ..models.config_provider_additional_property_models_additional_property_options import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions, + ) + from ..models.config_provider_additional_property_models_additional_property_provider import ( + ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider, + ) + + d = dict(src_dict) + id = d.pop("id", UNSET) + + name = d.pop("name", UNSET) + + release_date = d.pop("release_date", UNSET) + + attachment = d.pop("attachment", UNSET) + + reasoning = d.pop("reasoning", UNSET) + + temperature = d.pop("temperature", UNSET) + + tool_call = d.pop("tool_call", UNSET) + + _cost = d.pop("cost", UNSET) + cost: Union[Unset, ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost] + if isinstance(_cost, Unset): + cost = UNSET + else: + cost = ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost.from_dict(_cost) + + _limit = d.pop("limit", UNSET) + limit: Union[Unset, ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit] + if isinstance(_limit, Unset): + limit = UNSET + else: + limit = ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit.from_dict(_limit) + + experimental = d.pop("experimental", UNSET) + + _options = d.pop("options", UNSET) + options: Union[Unset, ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions] + if isinstance(_options, Unset): + options = UNSET + else: + options = ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions.from_dict(_options) + + _provider = d.pop("provider", UNSET) + provider: Union[Unset, ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider] + if isinstance(_provider, Unset): + provider = UNSET + else: + provider = ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider.from_dict(_provider) + + config_provider_additional_property_models_additional_property = cls( + id=id, + name=name, + release_date=release_date, + attachment=attachment, + reasoning=reasoning, + temperature=temperature, + tool_call=tool_call, + cost=cost, + limit=limit, + experimental=experimental, + options=options, + provider=provider, + ) + + config_provider_additional_property_models_additional_property.additional_properties = d + return config_provider_additional_property_models_additional_property + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_cost.py b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_cost.py new file mode 100644 index 0000000000..07e38e7139 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_cost.py @@ -0,0 +1,87 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost") + + +@_attrs_define +class ConfigProviderAdditionalPropertyModelsAdditionalPropertyCost: + """ + Attributes: + input_ (float): + output (float): + cache_read (Union[Unset, float]): + cache_write (Union[Unset, float]): + """ + + input_: float + output: float + cache_read: Union[Unset, float] = UNSET + cache_write: Union[Unset, float] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + input_ = self.input_ + + output = self.output + + cache_read = self.cache_read + + cache_write = self.cache_write + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "input": input_, + "output": output, + } + ) + if cache_read is not UNSET: + field_dict["cache_read"] = cache_read + if cache_write is not UNSET: + field_dict["cache_write"] = cache_write + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + input_ = d.pop("input") + + output = d.pop("output") + + cache_read = d.pop("cache_read", UNSET) + + cache_write = d.pop("cache_write", UNSET) + + config_provider_additional_property_models_additional_property_cost = cls( + input_=input_, + output=output, + cache_read=cache_read, + cache_write=cache_write, + ) + + config_provider_additional_property_models_additional_property_cost.additional_properties = d + return config_provider_additional_property_models_additional_property_cost + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_limit.py b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_limit.py new file mode 100644 index 0000000000..6e610550f1 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_limit.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit") + + +@_attrs_define +class ConfigProviderAdditionalPropertyModelsAdditionalPropertyLimit: + """ + Attributes: + context (float): + output (float): + """ + + context: float + output: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + context = self.context + + output = self.output + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "context": context, + "output": output, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + context = d.pop("context") + + output = d.pop("output") + + config_provider_additional_property_models_additional_property_limit = cls( + context=context, + output=output, + ) + + config_provider_additional_property_models_additional_property_limit.additional_properties = d + return config_provider_additional_property_models_additional_property_limit + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_options.py b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_options.py new file mode 100644 index 0000000000..f46f1b5044 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_options.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions") + + +@_attrs_define +class ConfigProviderAdditionalPropertyModelsAdditionalPropertyOptions: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + config_provider_additional_property_models_additional_property_options = cls() + + config_provider_additional_property_models_additional_property_options.additional_properties = d + return config_provider_additional_property_models_additional_property_options + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_provider.py b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_provider.py new file mode 100644 index 0000000000..dd3f57c4b9 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_models_additional_property_provider.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider") + + +@_attrs_define +class ConfigProviderAdditionalPropertyModelsAdditionalPropertyProvider: + """ + Attributes: + npm (str): + """ + + npm: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + npm = self.npm + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "npm": npm, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + npm = d.pop("npm") + + config_provider_additional_property_models_additional_property_provider = cls( + npm=npm, + ) + + config_provider_additional_property_models_additional_property_provider.additional_properties = d + return config_provider_additional_property_models_additional_property_provider + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_options.py b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_options.py new file mode 100644 index 0000000000..119523633f --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_provider_additional_property_options.py @@ -0,0 +1,87 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ConfigProviderAdditionalPropertyOptions") + + +@_attrs_define +class ConfigProviderAdditionalPropertyOptions: + """ + Attributes: + api_key (Union[Unset, str]): + base_url (Union[Unset, str]): + timeout (Union[Unset, bool, int]): Timeout in milliseconds for requests to this provider. Default is 300000 (5 + minutes). Set to false to disable timeout. + """ + + api_key: Union[Unset, str] = UNSET + base_url: Union[Unset, str] = UNSET + timeout: Union[Unset, bool, int] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + api_key = self.api_key + + base_url = self.base_url + + timeout: Union[Unset, bool, int] + if isinstance(self.timeout, Unset): + timeout = UNSET + else: + timeout = self.timeout + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if api_key is not UNSET: + field_dict["apiKey"] = api_key + if base_url is not UNSET: + field_dict["baseURL"] = base_url + if timeout is not UNSET: + field_dict["timeout"] = timeout + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + api_key = d.pop("apiKey", UNSET) + + base_url = d.pop("baseURL", UNSET) + + def _parse_timeout(data: object) -> Union[Unset, bool, int]: + if isinstance(data, Unset): + return data + return cast(Union[Unset, bool, int], data) + + timeout = _parse_timeout(d.pop("timeout", UNSET)) + + config_provider_additional_property_options = cls( + api_key=api_key, + base_url=base_url, + timeout=timeout, + ) + + config_provider_additional_property_options.additional_properties = d + return config_provider_additional_property_options + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_providers_response_200.py b/packages/sdk/python/src/opencode_ai/models/config_providers_response_200.py new file mode 100644 index 0000000000..bb245e5ae4 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_providers_response_200.py @@ -0,0 +1,83 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.config_providers_response_200_default import ConfigProvidersResponse200Default + from ..models.provider import Provider + + +T = TypeVar("T", bound="ConfigProvidersResponse200") + + +@_attrs_define +class ConfigProvidersResponse200: + """ + Attributes: + providers (list['Provider']): + default (ConfigProvidersResponse200Default): + """ + + providers: list["Provider"] + default: "ConfigProvidersResponse200Default" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + providers = [] + for providers_item_data in self.providers: + providers_item = providers_item_data.to_dict() + providers.append(providers_item) + + default = self.default.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "providers": providers, + "default": default, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.config_providers_response_200_default import ConfigProvidersResponse200Default + from ..models.provider import Provider + + d = dict(src_dict) + providers = [] + _providers = d.pop("providers") + for providers_item_data in _providers: + providers_item = Provider.from_dict(providers_item_data) + + providers.append(providers_item) + + default = ConfigProvidersResponse200Default.from_dict(d.pop("default")) + + config_providers_response_200 = cls( + providers=providers, + default=default, + ) + + config_providers_response_200.additional_properties = d + return config_providers_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_providers_response_200_default.py b/packages/sdk/python/src/opencode_ai/models/config_providers_response_200_default.py new file mode 100644 index 0000000000..6be679e34d --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_providers_response_200_default.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigProvidersResponse200Default") + + +@_attrs_define +class ConfigProvidersResponse200Default: + """ """ + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + config_providers_response_200_default = cls() + + config_providers_response_200_default.additional_properties = d + return config_providers_response_200_default + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_share.py b/packages/sdk/python/src/opencode_ai/models/config_share.py new file mode 100644 index 0000000000..5979e51e99 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_share.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class ConfigShare(str, Enum): + AUTO = "auto" + DISABLED = "disabled" + MANUAL = "manual" + + def __str__(self) -> str: + return str(self.value) diff --git a/packages/sdk/python/src/opencode_ai/models/config_tools.py b/packages/sdk/python/src/opencode_ai/models/config_tools.py new file mode 100644 index 0000000000..ab14605846 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_tools.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConfigTools") + + +@_attrs_define +class ConfigTools: + """ """ + + additional_properties: dict[str, bool] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + config_tools = cls() + + config_tools.additional_properties = d + return config_tools + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> bool: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: bool) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_tui.py b/packages/sdk/python/src/opencode_ai/models/config_tui.py new file mode 100644 index 0000000000..d28fbdfb21 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_tui.py @@ -0,0 +1,60 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ConfigTui") + + +@_attrs_define +class ConfigTui: + """TUI specific settings + + Attributes: + scroll_speed (Union[Unset, float]): TUI scroll speed Default: 2.0. + """ + + scroll_speed: Union[Unset, float] = 2.0 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + scroll_speed = self.scroll_speed + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if scroll_speed is not UNSET: + field_dict["scroll_speed"] = scroll_speed + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + scroll_speed = d.pop("scroll_speed", UNSET) + + config_tui = cls( + scroll_speed=scroll_speed, + ) + + config_tui.additional_properties = d + return config_tui + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/config_watcher.py b/packages/sdk/python/src/opencode_ai/models/config_watcher.py new file mode 100644 index 0000000000..4cee47b28e --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/config_watcher.py @@ -0,0 +1,61 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ConfigWatcher") + + +@_attrs_define +class ConfigWatcher: + """ + Attributes: + ignore (Union[Unset, list[str]]): + """ + + ignore: Union[Unset, list[str]] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + ignore: Union[Unset, list[str]] = UNSET + if not isinstance(self.ignore, Unset): + ignore = self.ignore + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if ignore is not UNSET: + field_dict["ignore"] = ignore + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ignore = cast(list[str], d.pop("ignore", UNSET)) + + config_watcher = cls( + ignore=ignore, + ) + + config_watcher.additional_properties = d + return config_watcher + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/error.py b/packages/sdk/python/src/opencode_ai/models/error.py new file mode 100644 index 0000000000..18c7ecf47a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/error.py @@ -0,0 +1,65 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.error_data import ErrorData + + +T = TypeVar("T", bound="Error") + + +@_attrs_define +class Error: + """ + Attributes: + data (ErrorData): + """ + + data: "ErrorData" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.error_data import ErrorData + + d = dict(src_dict) + data = ErrorData.from_dict(d.pop("data")) + + error = cls( + data=data, + ) + + error.additional_properties = d + return error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/error_data.py b/packages/sdk/python/src/opencode_ai/models/error_data.py new file mode 100644 index 0000000000..fddda9e2f2 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/error_data.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ErrorData") + + +@_attrs_define +class ErrorData: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + error_data = cls() + + error_data.additional_properties = d + return error_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_file_edited.py b/packages/sdk/python/src/opencode_ai/models/event_file_edited.py new file mode 100644 index 0000000000..2a784b8294 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_file_edited.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_file_edited_properties import EventFileEditedProperties + + +T = TypeVar("T", bound="EventFileEdited") + + +@_attrs_define +class EventFileEdited: + """ + Attributes: + type_ (Literal['file.edited']): + properties (EventFileEditedProperties): + """ + + type_: Literal["file.edited"] + properties: "EventFileEditedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_file_edited_properties import EventFileEditedProperties + + d = dict(src_dict) + type_ = cast(Literal["file.edited"], d.pop("type")) + if type_ != "file.edited": + raise ValueError(f"type must match const 'file.edited', got '{type_}'") + + properties = EventFileEditedProperties.from_dict(d.pop("properties")) + + event_file_edited = cls( + type_=type_, + properties=properties, + ) + + event_file_edited.additional_properties = d + return event_file_edited + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_file_edited_properties.py b/packages/sdk/python/src/opencode_ai/models/event_file_edited_properties.py new file mode 100644 index 0000000000..3fc250cef1 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_file_edited_properties.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventFileEditedProperties") + + +@_attrs_define +class EventFileEditedProperties: + """ + Attributes: + file (str): + """ + + file: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + file = self.file + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "file": file, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + file = d.pop("file") + + event_file_edited_properties = cls( + file=file, + ) + + event_file_edited_properties.additional_properties = d + return event_file_edited_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_file_watcher_updated.py b/packages/sdk/python/src/opencode_ai/models/event_file_watcher_updated.py new file mode 100644 index 0000000000..869545c0ae --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_file_watcher_updated.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_file_watcher_updated_properties import EventFileWatcherUpdatedProperties + + +T = TypeVar("T", bound="EventFileWatcherUpdated") + + +@_attrs_define +class EventFileWatcherUpdated: + """ + Attributes: + type_ (Literal['file.watcher.updated']): + properties (EventFileWatcherUpdatedProperties): + """ + + type_: Literal["file.watcher.updated"] + properties: "EventFileWatcherUpdatedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_file_watcher_updated_properties import EventFileWatcherUpdatedProperties + + d = dict(src_dict) + type_ = cast(Literal["file.watcher.updated"], d.pop("type")) + if type_ != "file.watcher.updated": + raise ValueError(f"type must match const 'file.watcher.updated', got '{type_}'") + + properties = EventFileWatcherUpdatedProperties.from_dict(d.pop("properties")) + + event_file_watcher_updated = cls( + type_=type_, + properties=properties, + ) + + event_file_watcher_updated.additional_properties = d + return event_file_watcher_updated + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_file_watcher_updated_properties.py b/packages/sdk/python/src/opencode_ai/models/event_file_watcher_updated_properties.py new file mode 100644 index 0000000000..4694f7fc80 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_file_watcher_updated_properties.py @@ -0,0 +1,82 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventFileWatcherUpdatedProperties") + + +@_attrs_define +class EventFileWatcherUpdatedProperties: + """ + Attributes: + file (str): + event (Union[Literal['add'], Literal['change'], Literal['unlink']]): + """ + + file: str + event: Union[Literal["add"], Literal["change"], Literal["unlink"]] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + file = self.file + + event: Union[Literal["add"], Literal["change"], Literal["unlink"]] + event = self.event + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "file": file, + "event": event, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + file = d.pop("file") + + def _parse_event(data: object) -> Union[Literal["add"], Literal["change"], Literal["unlink"]]: + event_type_0 = cast(Literal["add"], data) + if event_type_0 != "add": + raise ValueError(f"event_type_0 must match const 'add', got '{event_type_0}'") + return event_type_0 + event_type_1 = cast(Literal["change"], data) + if event_type_1 != "change": + raise ValueError(f"event_type_1 must match const 'change', got '{event_type_1}'") + return event_type_1 + event_type_2 = cast(Literal["unlink"], data) + if event_type_2 != "unlink": + raise ValueError(f"event_type_2 must match const 'unlink', got '{event_type_2}'") + return event_type_2 + + event = _parse_event(d.pop("event")) + + event_file_watcher_updated_properties = cls( + file=file, + event=event, + ) + + event_file_watcher_updated_properties.additional_properties = d + return event_file_watcher_updated_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_ide_installed.py b/packages/sdk/python/src/opencode_ai/models/event_ide_installed.py new file mode 100644 index 0000000000..f30eeb37b3 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_ide_installed.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_ide_installed_properties import EventIdeInstalledProperties + + +T = TypeVar("T", bound="EventIdeInstalled") + + +@_attrs_define +class EventIdeInstalled: + """ + Attributes: + type_ (Literal['ide.installed']): + properties (EventIdeInstalledProperties): + """ + + type_: Literal["ide.installed"] + properties: "EventIdeInstalledProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_ide_installed_properties import EventIdeInstalledProperties + + d = dict(src_dict) + type_ = cast(Literal["ide.installed"], d.pop("type")) + if type_ != "ide.installed": + raise ValueError(f"type must match const 'ide.installed', got '{type_}'") + + properties = EventIdeInstalledProperties.from_dict(d.pop("properties")) + + event_ide_installed = cls( + type_=type_, + properties=properties, + ) + + event_ide_installed.additional_properties = d + return event_ide_installed + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_ide_installed_properties.py b/packages/sdk/python/src/opencode_ai/models/event_ide_installed_properties.py new file mode 100644 index 0000000000..6af1802398 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_ide_installed_properties.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventIdeInstalledProperties") + + +@_attrs_define +class EventIdeInstalledProperties: + """ + Attributes: + ide (str): + """ + + ide: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + ide = self.ide + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "ide": ide, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ide = d.pop("ide") + + event_ide_installed_properties = cls( + ide=ide, + ) + + event_ide_installed_properties.additional_properties = d + return event_ide_installed_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_installation_updated.py b/packages/sdk/python/src/opencode_ai/models/event_installation_updated.py new file mode 100644 index 0000000000..e2831ccb2d --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_installation_updated.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_installation_updated_properties import EventInstallationUpdatedProperties + + +T = TypeVar("T", bound="EventInstallationUpdated") + + +@_attrs_define +class EventInstallationUpdated: + """ + Attributes: + type_ (Literal['installation.updated']): + properties (EventInstallationUpdatedProperties): + """ + + type_: Literal["installation.updated"] + properties: "EventInstallationUpdatedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_installation_updated_properties import EventInstallationUpdatedProperties + + d = dict(src_dict) + type_ = cast(Literal["installation.updated"], d.pop("type")) + if type_ != "installation.updated": + raise ValueError(f"type must match const 'installation.updated', got '{type_}'") + + properties = EventInstallationUpdatedProperties.from_dict(d.pop("properties")) + + event_installation_updated = cls( + type_=type_, + properties=properties, + ) + + event_installation_updated.additional_properties = d + return event_installation_updated + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_installation_updated_properties.py b/packages/sdk/python/src/opencode_ai/models/event_installation_updated_properties.py new file mode 100644 index 0000000000..45c0523e9b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_installation_updated_properties.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventInstallationUpdatedProperties") + + +@_attrs_define +class EventInstallationUpdatedProperties: + """ + Attributes: + version (str): + """ + + version: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + version = self.version + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "version": version, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + version = d.pop("version") + + event_installation_updated_properties = cls( + version=version, + ) + + event_installation_updated_properties.additional_properties = d + return event_installation_updated_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_lsp_client_diagnostics.py b/packages/sdk/python/src/opencode_ai/models/event_lsp_client_diagnostics.py new file mode 100644 index 0000000000..d10dabec7f --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_lsp_client_diagnostics.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_lsp_client_diagnostics_properties import EventLspClientDiagnosticsProperties + + +T = TypeVar("T", bound="EventLspClientDiagnostics") + + +@_attrs_define +class EventLspClientDiagnostics: + """ + Attributes: + type_ (Literal['lsp.client.diagnostics']): + properties (EventLspClientDiagnosticsProperties): + """ + + type_: Literal["lsp.client.diagnostics"] + properties: "EventLspClientDiagnosticsProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_lsp_client_diagnostics_properties import EventLspClientDiagnosticsProperties + + d = dict(src_dict) + type_ = cast(Literal["lsp.client.diagnostics"], d.pop("type")) + if type_ != "lsp.client.diagnostics": + raise ValueError(f"type must match const 'lsp.client.diagnostics', got '{type_}'") + + properties = EventLspClientDiagnosticsProperties.from_dict(d.pop("properties")) + + event_lsp_client_diagnostics = cls( + type_=type_, + properties=properties, + ) + + event_lsp_client_diagnostics.additional_properties = d + return event_lsp_client_diagnostics + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_lsp_client_diagnostics_properties.py b/packages/sdk/python/src/opencode_ai/models/event_lsp_client_diagnostics_properties.py new file mode 100644 index 0000000000..296555fba1 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_lsp_client_diagnostics_properties.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventLspClientDiagnosticsProperties") + + +@_attrs_define +class EventLspClientDiagnosticsProperties: + """ + Attributes: + server_id (str): + path (str): + """ + + server_id: str + path: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + server_id = self.server_id + + path = self.path + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "serverID": server_id, + "path": path, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + server_id = d.pop("serverID") + + path = d.pop("path") + + event_lsp_client_diagnostics_properties = cls( + server_id=server_id, + path=path, + ) + + event_lsp_client_diagnostics_properties.additional_properties = d + return event_lsp_client_diagnostics_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_message_part_removed.py b/packages/sdk/python/src/opencode_ai/models/event_message_part_removed.py new file mode 100644 index 0000000000..3b26f3ec74 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_message_part_removed.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_message_part_removed_properties import EventMessagePartRemovedProperties + + +T = TypeVar("T", bound="EventMessagePartRemoved") + + +@_attrs_define +class EventMessagePartRemoved: + """ + Attributes: + type_ (Literal['message.part.removed']): + properties (EventMessagePartRemovedProperties): + """ + + type_: Literal["message.part.removed"] + properties: "EventMessagePartRemovedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_message_part_removed_properties import EventMessagePartRemovedProperties + + d = dict(src_dict) + type_ = cast(Literal["message.part.removed"], d.pop("type")) + if type_ != "message.part.removed": + raise ValueError(f"type must match const 'message.part.removed', got '{type_}'") + + properties = EventMessagePartRemovedProperties.from_dict(d.pop("properties")) + + event_message_part_removed = cls( + type_=type_, + properties=properties, + ) + + event_message_part_removed.additional_properties = d + return event_message_part_removed + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_message_part_removed_properties.py b/packages/sdk/python/src/opencode_ai/models/event_message_part_removed_properties.py new file mode 100644 index 0000000000..957a4549d3 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_message_part_removed_properties.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventMessagePartRemovedProperties") + + +@_attrs_define +class EventMessagePartRemovedProperties: + """ + Attributes: + session_id (str): + message_id (str): + part_id (str): + """ + + session_id: str + message_id: str + part_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + session_id = self.session_id + + message_id = self.message_id + + part_id = self.part_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "sessionID": session_id, + "messageID": message_id, + "partID": part_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + part_id = d.pop("partID") + + event_message_part_removed_properties = cls( + session_id=session_id, + message_id=message_id, + part_id=part_id, + ) + + event_message_part_removed_properties.additional_properties = d + return event_message_part_removed_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_message_part_updated.py b/packages/sdk/python/src/opencode_ai/models/event_message_part_updated.py new file mode 100644 index 0000000000..75e80bb859 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_message_part_updated.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_message_part_updated_properties import EventMessagePartUpdatedProperties + + +T = TypeVar("T", bound="EventMessagePartUpdated") + + +@_attrs_define +class EventMessagePartUpdated: + """ + Attributes: + type_ (Literal['message.part.updated']): + properties (EventMessagePartUpdatedProperties): + """ + + type_: Literal["message.part.updated"] + properties: "EventMessagePartUpdatedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_message_part_updated_properties import EventMessagePartUpdatedProperties + + d = dict(src_dict) + type_ = cast(Literal["message.part.updated"], d.pop("type")) + if type_ != "message.part.updated": + raise ValueError(f"type must match const 'message.part.updated', got '{type_}'") + + properties = EventMessagePartUpdatedProperties.from_dict(d.pop("properties")) + + event_message_part_updated = cls( + type_=type_, + properties=properties, + ) + + event_message_part_updated.additional_properties = d + return event_message_part_updated + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_message_part_updated_properties.py b/packages/sdk/python/src/opencode_ai/models/event_message_part_updated_properties.py new file mode 100644 index 0000000000..ab8d1b2a94 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_message_part_updated_properties.py @@ -0,0 +1,203 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.agent_part import AgentPart + from ..models.file_part import FilePart + from ..models.patch_part import PatchPart + from ..models.reasoning_part import ReasoningPart + from ..models.snapshot_part import SnapshotPart + from ..models.step_finish_part import StepFinishPart + from ..models.step_start_part import StepStartPart + from ..models.text_part import TextPart + from ..models.tool_part import ToolPart + + +T = TypeVar("T", bound="EventMessagePartUpdatedProperties") + + +@_attrs_define +class EventMessagePartUpdatedProperties: + """ + Attributes: + part (Union['AgentPart', 'FilePart', 'PatchPart', 'ReasoningPart', 'SnapshotPart', 'StepFinishPart', + 'StepStartPart', 'TextPart', 'ToolPart']): + """ + + part: Union[ + "AgentPart", + "FilePart", + "PatchPart", + "ReasoningPart", + "SnapshotPart", + "StepFinishPart", + "StepStartPart", + "TextPart", + "ToolPart", + ] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.file_part import FilePart + from ..models.patch_part import PatchPart + from ..models.reasoning_part import ReasoningPart + from ..models.snapshot_part import SnapshotPart + from ..models.step_finish_part import StepFinishPart + from ..models.step_start_part import StepStartPart + from ..models.text_part import TextPart + from ..models.tool_part import ToolPart + + part: dict[str, Any] + if isinstance(self.part, TextPart): + part = self.part.to_dict() + elif isinstance(self.part, ReasoningPart): + part = self.part.to_dict() + elif isinstance(self.part, FilePart): + part = self.part.to_dict() + elif isinstance(self.part, ToolPart): + part = self.part.to_dict() + elif isinstance(self.part, StepStartPart): + part = self.part.to_dict() + elif isinstance(self.part, StepFinishPart): + part = self.part.to_dict() + elif isinstance(self.part, SnapshotPart): + part = self.part.to_dict() + elif isinstance(self.part, PatchPart): + part = self.part.to_dict() + else: + part = self.part.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "part": part, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agent_part import AgentPart + from ..models.file_part import FilePart + from ..models.patch_part import PatchPart + from ..models.reasoning_part import ReasoningPart + from ..models.snapshot_part import SnapshotPart + from ..models.step_finish_part import StepFinishPart + from ..models.step_start_part import StepStartPart + from ..models.text_part import TextPart + from ..models.tool_part import ToolPart + + d = dict(src_dict) + + def _parse_part( + data: object, + ) -> Union[ + "AgentPart", + "FilePart", + "PatchPart", + "ReasoningPart", + "SnapshotPart", + "StepFinishPart", + "StepStartPart", + "TextPart", + "ToolPart", + ]: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_part_type_0 = TextPart.from_dict(data) + + return componentsschemas_part_type_0 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_part_type_1 = ReasoningPart.from_dict(data) + + return componentsschemas_part_type_1 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_part_type_2 = FilePart.from_dict(data) + + return componentsschemas_part_type_2 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_part_type_3 = ToolPart.from_dict(data) + + return componentsschemas_part_type_3 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_part_type_4 = StepStartPart.from_dict(data) + + return componentsschemas_part_type_4 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_part_type_5 = StepFinishPart.from_dict(data) + + return componentsschemas_part_type_5 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_part_type_6 = SnapshotPart.from_dict(data) + + return componentsschemas_part_type_6 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_part_type_7 = PatchPart.from_dict(data) + + return componentsschemas_part_type_7 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_part_type_8 = AgentPart.from_dict(data) + + return componentsschemas_part_type_8 + + part = _parse_part(d.pop("part")) + + event_message_part_updated_properties = cls( + part=part, + ) + + event_message_part_updated_properties.additional_properties = d + return event_message_part_updated_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_message_removed.py b/packages/sdk/python/src/opencode_ai/models/event_message_removed.py new file mode 100644 index 0000000000..0be4512354 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_message_removed.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_message_removed_properties import EventMessageRemovedProperties + + +T = TypeVar("T", bound="EventMessageRemoved") + + +@_attrs_define +class EventMessageRemoved: + """ + Attributes: + type_ (Literal['message.removed']): + properties (EventMessageRemovedProperties): + """ + + type_: Literal["message.removed"] + properties: "EventMessageRemovedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_message_removed_properties import EventMessageRemovedProperties + + d = dict(src_dict) + type_ = cast(Literal["message.removed"], d.pop("type")) + if type_ != "message.removed": + raise ValueError(f"type must match const 'message.removed', got '{type_}'") + + properties = EventMessageRemovedProperties.from_dict(d.pop("properties")) + + event_message_removed = cls( + type_=type_, + properties=properties, + ) + + event_message_removed.additional_properties = d + return event_message_removed + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_message_removed_properties.py b/packages/sdk/python/src/opencode_ai/models/event_message_removed_properties.py new file mode 100644 index 0000000000..85446e9632 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_message_removed_properties.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventMessageRemovedProperties") + + +@_attrs_define +class EventMessageRemovedProperties: + """ + Attributes: + session_id (str): + message_id (str): + """ + + session_id: str + message_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + session_id = self.session_id + + message_id = self.message_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "sessionID": session_id, + "messageID": message_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + event_message_removed_properties = cls( + session_id=session_id, + message_id=message_id, + ) + + event_message_removed_properties.additional_properties = d + return event_message_removed_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_message_updated.py b/packages/sdk/python/src/opencode_ai/models/event_message_updated.py new file mode 100644 index 0000000000..9a5a8c2ad2 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_message_updated.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_message_updated_properties import EventMessageUpdatedProperties + + +T = TypeVar("T", bound="EventMessageUpdated") + + +@_attrs_define +class EventMessageUpdated: + """ + Attributes: + type_ (Literal['message.updated']): + properties (EventMessageUpdatedProperties): + """ + + type_: Literal["message.updated"] + properties: "EventMessageUpdatedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_message_updated_properties import EventMessageUpdatedProperties + + d = dict(src_dict) + type_ = cast(Literal["message.updated"], d.pop("type")) + if type_ != "message.updated": + raise ValueError(f"type must match const 'message.updated', got '{type_}'") + + properties = EventMessageUpdatedProperties.from_dict(d.pop("properties")) + + event_message_updated = cls( + type_=type_, + properties=properties, + ) + + event_message_updated.additional_properties = d + return event_message_updated + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_message_updated_properties.py b/packages/sdk/python/src/opencode_ai/models/event_message_updated_properties.py new file mode 100644 index 0000000000..1ec6714e8c --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_message_updated_properties.py @@ -0,0 +1,89 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.assistant_message import AssistantMessage + from ..models.user_message import UserMessage + + +T = TypeVar("T", bound="EventMessageUpdatedProperties") + + +@_attrs_define +class EventMessageUpdatedProperties: + """ + Attributes: + info (Union['AssistantMessage', 'UserMessage']): + """ + + info: Union["AssistantMessage", "UserMessage"] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.user_message import UserMessage + + info: dict[str, Any] + if isinstance(self.info, UserMessage): + info = self.info.to_dict() + else: + info = self.info.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "info": info, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.assistant_message import AssistantMessage + from ..models.user_message import UserMessage + + d = dict(src_dict) + + def _parse_info(data: object) -> Union["AssistantMessage", "UserMessage"]: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_message_type_0 = UserMessage.from_dict(data) + + return componentsschemas_message_type_0 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_message_type_1 = AssistantMessage.from_dict(data) + + return componentsschemas_message_type_1 + + info = _parse_info(d.pop("info")) + + event_message_updated_properties = cls( + info=info, + ) + + event_message_updated_properties.additional_properties = d + return event_message_updated_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_permission_replied.py b/packages/sdk/python/src/opencode_ai/models/event_permission_replied.py new file mode 100644 index 0000000000..4fdfa3f94a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_permission_replied.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_permission_replied_properties import EventPermissionRepliedProperties + + +T = TypeVar("T", bound="EventPermissionReplied") + + +@_attrs_define +class EventPermissionReplied: + """ + Attributes: + type_ (Literal['permission.replied']): + properties (EventPermissionRepliedProperties): + """ + + type_: Literal["permission.replied"] + properties: "EventPermissionRepliedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_permission_replied_properties import EventPermissionRepliedProperties + + d = dict(src_dict) + type_ = cast(Literal["permission.replied"], d.pop("type")) + if type_ != "permission.replied": + raise ValueError(f"type must match const 'permission.replied', got '{type_}'") + + properties = EventPermissionRepliedProperties.from_dict(d.pop("properties")) + + event_permission_replied = cls( + type_=type_, + properties=properties, + ) + + event_permission_replied.additional_properties = d + return event_permission_replied + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_permission_replied_properties.py b/packages/sdk/python/src/opencode_ai/models/event_permission_replied_properties.py new file mode 100644 index 0000000000..483cf95084 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_permission_replied_properties.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventPermissionRepliedProperties") + + +@_attrs_define +class EventPermissionRepliedProperties: + """ + Attributes: + session_id (str): + permission_id (str): + response (str): + """ + + session_id: str + permission_id: str + response: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + session_id = self.session_id + + permission_id = self.permission_id + + response = self.response + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "sessionID": session_id, + "permissionID": permission_id, + "response": response, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + session_id = d.pop("sessionID") + + permission_id = d.pop("permissionID") + + response = d.pop("response") + + event_permission_replied_properties = cls( + session_id=session_id, + permission_id=permission_id, + response=response, + ) + + event_permission_replied_properties.additional_properties = d + return event_permission_replied_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_permission_updated.py b/packages/sdk/python/src/opencode_ai/models/event_permission_updated.py new file mode 100644 index 0000000000..8b86333588 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_permission_updated.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.permission import Permission + + +T = TypeVar("T", bound="EventPermissionUpdated") + + +@_attrs_define +class EventPermissionUpdated: + """ + Attributes: + type_ (Literal['permission.updated']): + properties (Permission): + """ + + type_: Literal["permission.updated"] + properties: "Permission" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.permission import Permission + + d = dict(src_dict) + type_ = cast(Literal["permission.updated"], d.pop("type")) + if type_ != "permission.updated": + raise ValueError(f"type must match const 'permission.updated', got '{type_}'") + + properties = Permission.from_dict(d.pop("properties")) + + event_permission_updated = cls( + type_=type_, + properties=properties, + ) + + event_permission_updated.additional_properties = d + return event_permission_updated + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_server_connected.py b/packages/sdk/python/src/opencode_ai/models/event_server_connected.py new file mode 100644 index 0000000000..80393a580a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_server_connected.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_server_connected_properties import EventServerConnectedProperties + + +T = TypeVar("T", bound="EventServerConnected") + + +@_attrs_define +class EventServerConnected: + """ + Attributes: + type_ (Literal['server.connected']): + properties (EventServerConnectedProperties): + """ + + type_: Literal["server.connected"] + properties: "EventServerConnectedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_server_connected_properties import EventServerConnectedProperties + + d = dict(src_dict) + type_ = cast(Literal["server.connected"], d.pop("type")) + if type_ != "server.connected": + raise ValueError(f"type must match const 'server.connected', got '{type_}'") + + properties = EventServerConnectedProperties.from_dict(d.pop("properties")) + + event_server_connected = cls( + type_=type_, + properties=properties, + ) + + event_server_connected.additional_properties = d + return event_server_connected + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_server_connected_properties.py b/packages/sdk/python/src/opencode_ai/models/event_server_connected_properties.py new file mode 100644 index 0000000000..1a0e9191a8 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_server_connected_properties.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventServerConnectedProperties") + + +@_attrs_define +class EventServerConnectedProperties: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + event_server_connected_properties = cls() + + event_server_connected_properties.additional_properties = d + return event_server_connected_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_compacted.py b/packages/sdk/python/src/opencode_ai/models/event_session_compacted.py new file mode 100644 index 0000000000..8d3cfc3a6e --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_compacted.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_session_compacted_properties import EventSessionCompactedProperties + + +T = TypeVar("T", bound="EventSessionCompacted") + + +@_attrs_define +class EventSessionCompacted: + """ + Attributes: + type_ (Literal['session.compacted']): + properties (EventSessionCompactedProperties): + """ + + type_: Literal["session.compacted"] + properties: "EventSessionCompactedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_session_compacted_properties import EventSessionCompactedProperties + + d = dict(src_dict) + type_ = cast(Literal["session.compacted"], d.pop("type")) + if type_ != "session.compacted": + raise ValueError(f"type must match const 'session.compacted', got '{type_}'") + + properties = EventSessionCompactedProperties.from_dict(d.pop("properties")) + + event_session_compacted = cls( + type_=type_, + properties=properties, + ) + + event_session_compacted.additional_properties = d + return event_session_compacted + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_compacted_properties.py b/packages/sdk/python/src/opencode_ai/models/event_session_compacted_properties.py new file mode 100644 index 0000000000..27b1c9455c --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_compacted_properties.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventSessionCompactedProperties") + + +@_attrs_define +class EventSessionCompactedProperties: + """ + Attributes: + session_id (str): + """ + + session_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + session_id = self.session_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "sessionID": session_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + session_id = d.pop("sessionID") + + event_session_compacted_properties = cls( + session_id=session_id, + ) + + event_session_compacted_properties.additional_properties = d + return event_session_compacted_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_deleted.py b/packages/sdk/python/src/opencode_ai/models/event_session_deleted.py new file mode 100644 index 0000000000..3b39c834f3 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_deleted.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_session_deleted_properties import EventSessionDeletedProperties + + +T = TypeVar("T", bound="EventSessionDeleted") + + +@_attrs_define +class EventSessionDeleted: + """ + Attributes: + type_ (Literal['session.deleted']): + properties (EventSessionDeletedProperties): + """ + + type_: Literal["session.deleted"] + properties: "EventSessionDeletedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_session_deleted_properties import EventSessionDeletedProperties + + d = dict(src_dict) + type_ = cast(Literal["session.deleted"], d.pop("type")) + if type_ != "session.deleted": + raise ValueError(f"type must match const 'session.deleted', got '{type_}'") + + properties = EventSessionDeletedProperties.from_dict(d.pop("properties")) + + event_session_deleted = cls( + type_=type_, + properties=properties, + ) + + event_session_deleted.additional_properties = d + return event_session_deleted + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_deleted_properties.py b/packages/sdk/python/src/opencode_ai/models/event_session_deleted_properties.py new file mode 100644 index 0000000000..d630cc31c2 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_deleted_properties.py @@ -0,0 +1,65 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.session import Session + + +T = TypeVar("T", bound="EventSessionDeletedProperties") + + +@_attrs_define +class EventSessionDeletedProperties: + """ + Attributes: + info (Session): + """ + + info: "Session" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + info = self.info.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "info": info, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.session import Session + + d = dict(src_dict) + info = Session.from_dict(d.pop("info")) + + event_session_deleted_properties = cls( + info=info, + ) + + event_session_deleted_properties.additional_properties = d + return event_session_deleted_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_error.py b/packages/sdk/python/src/opencode_ai/models/event_session_error.py new file mode 100644 index 0000000000..eaa85e137b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_error.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_session_error_properties import EventSessionErrorProperties + + +T = TypeVar("T", bound="EventSessionError") + + +@_attrs_define +class EventSessionError: + """ + Attributes: + type_ (Literal['session.error']): + properties (EventSessionErrorProperties): + """ + + type_: Literal["session.error"] + properties: "EventSessionErrorProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_session_error_properties import EventSessionErrorProperties + + d = dict(src_dict) + type_ = cast(Literal["session.error"], d.pop("type")) + if type_ != "session.error": + raise ValueError(f"type must match const 'session.error', got '{type_}'") + + properties = EventSessionErrorProperties.from_dict(d.pop("properties")) + + event_session_error = cls( + type_=type_, + properties=properties, + ) + + event_session_error.additional_properties = d + return event_session_error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_error_properties.py b/packages/sdk/python/src/opencode_ai/models/event_session_error_properties.py new file mode 100644 index 0000000000..420318de1b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_error_properties.py @@ -0,0 +1,129 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.message_aborted_error import MessageAbortedError + from ..models.message_output_length_error import MessageOutputLengthError + from ..models.provider_auth_error import ProviderAuthError + from ..models.unknown_error import UnknownError + + +T = TypeVar("T", bound="EventSessionErrorProperties") + + +@_attrs_define +class EventSessionErrorProperties: + """ + Attributes: + session_id (Union[Unset, str]): + error (Union['MessageAbortedError', 'MessageOutputLengthError', 'ProviderAuthError', 'UnknownError', Unset]): + """ + + session_id: Union[Unset, str] = UNSET + error: Union["MessageAbortedError", "MessageOutputLengthError", "ProviderAuthError", "UnknownError", Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.message_output_length_error import MessageOutputLengthError + from ..models.provider_auth_error import ProviderAuthError + from ..models.unknown_error import UnknownError + + session_id = self.session_id + + error: Union[Unset, dict[str, Any]] + if isinstance(self.error, Unset): + error = UNSET + elif isinstance(self.error, ProviderAuthError): + error = self.error.to_dict() + elif isinstance(self.error, UnknownError): + error = self.error.to_dict() + elif isinstance(self.error, MessageOutputLengthError): + error = self.error.to_dict() + else: + error = self.error.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if session_id is not UNSET: + field_dict["sessionID"] = session_id + if error is not UNSET: + field_dict["error"] = error + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.message_aborted_error import MessageAbortedError + from ..models.message_output_length_error import MessageOutputLengthError + from ..models.provider_auth_error import ProviderAuthError + from ..models.unknown_error import UnknownError + + d = dict(src_dict) + session_id = d.pop("sessionID", UNSET) + + def _parse_error( + data: object, + ) -> Union["MessageAbortedError", "MessageOutputLengthError", "ProviderAuthError", "UnknownError", Unset]: + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + error_type_0 = ProviderAuthError.from_dict(data) + + return error_type_0 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + error_type_1 = UnknownError.from_dict(data) + + return error_type_1 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + error_type_2 = MessageOutputLengthError.from_dict(data) + + return error_type_2 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + error_type_3 = MessageAbortedError.from_dict(data) + + return error_type_3 + + error = _parse_error(d.pop("error", UNSET)) + + event_session_error_properties = cls( + session_id=session_id, + error=error, + ) + + event_session_error_properties.additional_properties = d + return event_session_error_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_idle.py b/packages/sdk/python/src/opencode_ai/models/event_session_idle.py new file mode 100644 index 0000000000..d4b688abbf --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_idle.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_session_idle_properties import EventSessionIdleProperties + + +T = TypeVar("T", bound="EventSessionIdle") + + +@_attrs_define +class EventSessionIdle: + """ + Attributes: + type_ (Literal['session.idle']): + properties (EventSessionIdleProperties): + """ + + type_: Literal["session.idle"] + properties: "EventSessionIdleProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_session_idle_properties import EventSessionIdleProperties + + d = dict(src_dict) + type_ = cast(Literal["session.idle"], d.pop("type")) + if type_ != "session.idle": + raise ValueError(f"type must match const 'session.idle', got '{type_}'") + + properties = EventSessionIdleProperties.from_dict(d.pop("properties")) + + event_session_idle = cls( + type_=type_, + properties=properties, + ) + + event_session_idle.additional_properties = d + return event_session_idle + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_idle_properties.py b/packages/sdk/python/src/opencode_ai/models/event_session_idle_properties.py new file mode 100644 index 0000000000..1224837e48 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_idle_properties.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EventSessionIdleProperties") + + +@_attrs_define +class EventSessionIdleProperties: + """ + Attributes: + session_id (str): + """ + + session_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + session_id = self.session_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "sessionID": session_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + session_id = d.pop("sessionID") + + event_session_idle_properties = cls( + session_id=session_id, + ) + + event_session_idle_properties.additional_properties = d + return event_session_idle_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_updated.py b/packages/sdk/python/src/opencode_ai/models/event_session_updated.py new file mode 100644 index 0000000000..a99efb4557 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_updated.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.event_session_updated_properties import EventSessionUpdatedProperties + + +T = TypeVar("T", bound="EventSessionUpdated") + + +@_attrs_define +class EventSessionUpdated: + """ + Attributes: + type_ (Literal['session.updated']): + properties (EventSessionUpdatedProperties): + """ + + type_: Literal["session.updated"] + properties: "EventSessionUpdatedProperties" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + properties = self.properties.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "properties": properties, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.event_session_updated_properties import EventSessionUpdatedProperties + + d = dict(src_dict) + type_ = cast(Literal["session.updated"], d.pop("type")) + if type_ != "session.updated": + raise ValueError(f"type must match const 'session.updated', got '{type_}'") + + properties = EventSessionUpdatedProperties.from_dict(d.pop("properties")) + + event_session_updated = cls( + type_=type_, + properties=properties, + ) + + event_session_updated.additional_properties = d + return event_session_updated + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/event_session_updated_properties.py b/packages/sdk/python/src/opencode_ai/models/event_session_updated_properties.py new file mode 100644 index 0000000000..0f9e83e286 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/event_session_updated_properties.py @@ -0,0 +1,65 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.session import Session + + +T = TypeVar("T", bound="EventSessionUpdatedProperties") + + +@_attrs_define +class EventSessionUpdatedProperties: + """ + Attributes: + info (Session): + """ + + info: "Session" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + info = self.info.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "info": info, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.session import Session + + d = dict(src_dict) + info = Session.from_dict(d.pop("info")) + + event_session_updated_properties = cls( + info=info, + ) + + event_session_updated_properties.additional_properties = d + return event_session_updated_properties + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file.py b/packages/sdk/python/src/opencode_ai/models/file.py new file mode 100644 index 0000000000..c18c2feca5 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file.py @@ -0,0 +1,85 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.file_status import FileStatus + +T = TypeVar("T", bound="File") + + +@_attrs_define +class File: + """ + Attributes: + path (str): + added (int): + removed (int): + status (FileStatus): + """ + + path: str + added: int + removed: int + status: FileStatus + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + path = self.path + + added = self.added + + removed = self.removed + + status = self.status.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "path": path, + "added": added, + "removed": removed, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + path = d.pop("path") + + added = d.pop("added") + + removed = d.pop("removed") + + status = FileStatus(d.pop("status")) + + file = cls( + path=path, + added=added, + removed=removed, + status=status, + ) + + file.additional_properties = d + return file + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file_content.py b/packages/sdk/python/src/opencode_ai/models/file_content.py new file mode 100644 index 0000000000..2654d678f1 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_content.py @@ -0,0 +1,92 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.file_content_patch import FileContentPatch + + +T = TypeVar("T", bound="FileContent") + + +@_attrs_define +class FileContent: + """ + Attributes: + content (str): + diff (Union[Unset, str]): + patch (Union[Unset, FileContentPatch]): + """ + + content: str + diff: Union[Unset, str] = UNSET + patch: Union[Unset, "FileContentPatch"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content = self.content + + diff = self.diff + + patch: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.patch, Unset): + patch = self.patch.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "content": content, + } + ) + if diff is not UNSET: + field_dict["diff"] = diff + if patch is not UNSET: + field_dict["patch"] = patch + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.file_content_patch import FileContentPatch + + d = dict(src_dict) + content = d.pop("content") + + diff = d.pop("diff", UNSET) + + _patch = d.pop("patch", UNSET) + patch: Union[Unset, FileContentPatch] + if isinstance(_patch, Unset): + patch = UNSET + else: + patch = FileContentPatch.from_dict(_patch) + + file_content = cls( + content=content, + diff=diff, + patch=patch, + ) + + file_content.additional_properties = d + return file_content + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file_content_patch.py b/packages/sdk/python/src/opencode_ai/models/file_content_patch.py new file mode 100644 index 0000000000..01d29ebf6b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_content_patch.py @@ -0,0 +1,118 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.file_content_patch_hunks_item import FileContentPatchHunksItem + + +T = TypeVar("T", bound="FileContentPatch") + + +@_attrs_define +class FileContentPatch: + """ + Attributes: + old_file_name (str): + new_file_name (str): + hunks (list['FileContentPatchHunksItem']): + old_header (Union[Unset, str]): + new_header (Union[Unset, str]): + index (Union[Unset, str]): + """ + + old_file_name: str + new_file_name: str + hunks: list["FileContentPatchHunksItem"] + old_header: Union[Unset, str] = UNSET + new_header: Union[Unset, str] = UNSET + index: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + old_file_name = self.old_file_name + + new_file_name = self.new_file_name + + hunks = [] + for hunks_item_data in self.hunks: + hunks_item = hunks_item_data.to_dict() + hunks.append(hunks_item) + + old_header = self.old_header + + new_header = self.new_header + + index = self.index + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "oldFileName": old_file_name, + "newFileName": new_file_name, + "hunks": hunks, + } + ) + if old_header is not UNSET: + field_dict["oldHeader"] = old_header + if new_header is not UNSET: + field_dict["newHeader"] = new_header + if index is not UNSET: + field_dict["index"] = index + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.file_content_patch_hunks_item import FileContentPatchHunksItem + + d = dict(src_dict) + old_file_name = d.pop("oldFileName") + + new_file_name = d.pop("newFileName") + + hunks = [] + _hunks = d.pop("hunks") + for hunks_item_data in _hunks: + hunks_item = FileContentPatchHunksItem.from_dict(hunks_item_data) + + hunks.append(hunks_item) + + old_header = d.pop("oldHeader", UNSET) + + new_header = d.pop("newHeader", UNSET) + + index = d.pop("index", UNSET) + + file_content_patch = cls( + old_file_name=old_file_name, + new_file_name=new_file_name, + hunks=hunks, + old_header=old_header, + new_header=new_header, + index=index, + ) + + file_content_patch.additional_properties = d + return file_content_patch + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file_content_patch_hunks_item.py b/packages/sdk/python/src/opencode_ai/models/file_content_patch_hunks_item.py new file mode 100644 index 0000000000..b17688fad1 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_content_patch_hunks_item.py @@ -0,0 +1,91 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="FileContentPatchHunksItem") + + +@_attrs_define +class FileContentPatchHunksItem: + """ + Attributes: + old_start (float): + old_lines (float): + new_start (float): + new_lines (float): + lines (list[str]): + """ + + old_start: float + old_lines: float + new_start: float + new_lines: float + lines: list[str] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + old_start = self.old_start + + old_lines = self.old_lines + + new_start = self.new_start + + new_lines = self.new_lines + + lines = self.lines + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "oldStart": old_start, + "oldLines": old_lines, + "newStart": new_start, + "newLines": new_lines, + "lines": lines, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + old_start = d.pop("oldStart") + + old_lines = d.pop("oldLines") + + new_start = d.pop("newStart") + + new_lines = d.pop("newLines") + + lines = cast(list[str], d.pop("lines")) + + file_content_patch_hunks_item = cls( + old_start=old_start, + old_lines=old_lines, + new_start=new_start, + new_lines=new_lines, + lines=lines, + ) + + file_content_patch_hunks_item.additional_properties = d + return file_content_patch_hunks_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file_node.py b/packages/sdk/python/src/opencode_ai/models/file_node.py new file mode 100644 index 0000000000..feb075f8f8 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_node.py @@ -0,0 +1,93 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.file_node_type import FileNodeType + +T = TypeVar("T", bound="FileNode") + + +@_attrs_define +class FileNode: + """ + Attributes: + name (str): + path (str): + absolute (str): + type_ (FileNodeType): + ignored (bool): + """ + + name: str + path: str + absolute: str + type_: FileNodeType + ignored: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + path = self.path + + absolute = self.absolute + + type_ = self.type_.value + + ignored = self.ignored + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "path": path, + "absolute": absolute, + "type": type_, + "ignored": ignored, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + path = d.pop("path") + + absolute = d.pop("absolute") + + type_ = FileNodeType(d.pop("type")) + + ignored = d.pop("ignored") + + file_node = cls( + name=name, + path=path, + absolute=absolute, + type_=type_, + ignored=ignored, + ) + + file_node.additional_properties = d + return file_node + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file_node_type.py b/packages/sdk/python/src/opencode_ai/models/file_node_type.py new file mode 100644 index 0000000000..8fb88ffe13 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_node_type.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class FileNodeType(str, Enum): + DIRECTORY = "directory" + FILE = "file" + + def __str__(self) -> str: + return str(self.value) diff --git a/packages/sdk/python/src/opencode_ai/models/file_part.py b/packages/sdk/python/src/opencode_ai/models/file_part.py new file mode 100644 index 0000000000..aea82b97c5 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_part.py @@ -0,0 +1,154 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.file_source import FileSource + from ..models.symbol_source import SymbolSource + + +T = TypeVar("T", bound="FilePart") + + +@_attrs_define +class FilePart: + """ + Attributes: + id (str): + session_id (str): + message_id (str): + type_ (Literal['file']): + mime (str): + url (str): + filename (Union[Unset, str]): + source (Union['FileSource', 'SymbolSource', Unset]): + """ + + id: str + session_id: str + message_id: str + type_: Literal["file"] + mime: str + url: str + filename: Union[Unset, str] = UNSET + source: Union["FileSource", "SymbolSource", Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.file_source import FileSource + + id = self.id + + session_id = self.session_id + + message_id = self.message_id + + type_ = self.type_ + + mime = self.mime + + url = self.url + + filename = self.filename + + source: Union[Unset, dict[str, Any]] + if isinstance(self.source, Unset): + source = UNSET + elif isinstance(self.source, FileSource): + source = self.source.to_dict() + else: + source = self.source.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "messageID": message_id, + "type": type_, + "mime": mime, + "url": url, + } + ) + if filename is not UNSET: + field_dict["filename"] = filename + if source is not UNSET: + field_dict["source"] = source + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.file_source import FileSource + from ..models.symbol_source import SymbolSource + + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + type_ = cast(Literal["file"], d.pop("type")) + if type_ != "file": + raise ValueError(f"type must match const 'file', got '{type_}'") + + mime = d.pop("mime") + + url = d.pop("url") + + filename = d.pop("filename", UNSET) + + def _parse_source(data: object) -> Union["FileSource", "SymbolSource", Unset]: + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_file_part_source_type_0 = FileSource.from_dict(data) + + return componentsschemas_file_part_source_type_0 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_file_part_source_type_1 = SymbolSource.from_dict(data) + + return componentsschemas_file_part_source_type_1 + + source = _parse_source(d.pop("source", UNSET)) + + file_part = cls( + id=id, + session_id=session_id, + message_id=message_id, + type_=type_, + mime=mime, + url=url, + filename=filename, + source=source, + ) + + file_part.additional_properties = d + return file_part + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file_part_input.py b/packages/sdk/python/src/opencode_ai/models/file_part_input.py new file mode 100644 index 0000000000..0bebb3cb5d --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_part_input.py @@ -0,0 +1,139 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.file_source import FileSource + from ..models.symbol_source import SymbolSource + + +T = TypeVar("T", bound="FilePartInput") + + +@_attrs_define +class FilePartInput: + """ + Attributes: + type_ (Literal['file']): + mime (str): + url (str): + id (Union[Unset, str]): + filename (Union[Unset, str]): + source (Union['FileSource', 'SymbolSource', Unset]): + """ + + type_: Literal["file"] + mime: str + url: str + id: Union[Unset, str] = UNSET + filename: Union[Unset, str] = UNSET + source: Union["FileSource", "SymbolSource", Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.file_source import FileSource + + type_ = self.type_ + + mime = self.mime + + url = self.url + + id = self.id + + filename = self.filename + + source: Union[Unset, dict[str, Any]] + if isinstance(self.source, Unset): + source = UNSET + elif isinstance(self.source, FileSource): + source = self.source.to_dict() + else: + source = self.source.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "mime": mime, + "url": url, + } + ) + if id is not UNSET: + field_dict["id"] = id + if filename is not UNSET: + field_dict["filename"] = filename + if source is not UNSET: + field_dict["source"] = source + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.file_source import FileSource + from ..models.symbol_source import SymbolSource + + d = dict(src_dict) + type_ = cast(Literal["file"], d.pop("type")) + if type_ != "file": + raise ValueError(f"type must match const 'file', got '{type_}'") + + mime = d.pop("mime") + + url = d.pop("url") + + id = d.pop("id", UNSET) + + filename = d.pop("filename", UNSET) + + def _parse_source(data: object) -> Union["FileSource", "SymbolSource", Unset]: + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_file_part_source_type_0 = FileSource.from_dict(data) + + return componentsschemas_file_part_source_type_0 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_file_part_source_type_1 = SymbolSource.from_dict(data) + + return componentsschemas_file_part_source_type_1 + + source = _parse_source(d.pop("source", UNSET)) + + file_part_input = cls( + type_=type_, + mime=mime, + url=url, + id=id, + filename=filename, + source=source, + ) + + file_part_input.additional_properties = d + return file_part_input + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file_part_source_text.py b/packages/sdk/python/src/opencode_ai/models/file_part_source_text.py new file mode 100644 index 0000000000..b5a3a7f48a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_part_source_text.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="FilePartSourceText") + + +@_attrs_define +class FilePartSourceText: + """ + Attributes: + value (str): + start (int): + end (int): + """ + + value: str + start: int + end: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + value = self.value + + start = self.start + + end = self.end + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "value": value, + "start": start, + "end": end, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + value = d.pop("value") + + start = d.pop("start") + + end = d.pop("end") + + file_part_source_text = cls( + value=value, + start=start, + end=end, + ) + + file_part_source_text.additional_properties = d + return file_part_source_text + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file_source.py b/packages/sdk/python/src/opencode_ai/models/file_source.py new file mode 100644 index 0000000000..a4c64ff748 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_source.py @@ -0,0 +1,83 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.file_part_source_text import FilePartSourceText + + +T = TypeVar("T", bound="FileSource") + + +@_attrs_define +class FileSource: + """ + Attributes: + text (FilePartSourceText): + type_ (Literal['file']): + path (str): + """ + + text: "FilePartSourceText" + type_: Literal["file"] + path: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text.to_dict() + + type_ = self.type_ + + path = self.path + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "text": text, + "type": type_, + "path": path, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.file_part_source_text import FilePartSourceText + + d = dict(src_dict) + text = FilePartSourceText.from_dict(d.pop("text")) + + type_ = cast(Literal["file"], d.pop("type")) + if type_ != "file": + raise ValueError(f"type must match const 'file', got '{type_}'") + + path = d.pop("path") + + file_source = cls( + text=text, + type_=type_, + path=path, + ) + + file_source.additional_properties = d + return file_source + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/file_status.py b/packages/sdk/python/src/opencode_ai/models/file_status.py new file mode 100644 index 0000000000..54d84b84d0 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/file_status.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class FileStatus(str, Enum): + ADDED = "added" + DELETED = "deleted" + MODIFIED = "modified" + + def __str__(self) -> str: + return str(self.value) diff --git a/packages/sdk/python/src/opencode_ai/models/keybinds_config.py b/packages/sdk/python/src/opencode_ai/models/keybinds_config.py new file mode 100644 index 0000000000..05053206da --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/keybinds_config.py @@ -0,0 +1,474 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="KeybindsConfig") + + +@_attrs_define +class KeybindsConfig: + """Custom keybind configurations + + Attributes: + leader (Union[Unset, str]): Leader key for keybind combinations Default: 'ctrl+x'. + app_help (Union[Unset, str]): Show help dialog Default: 'h'. + app_exit (Union[Unset, str]): Exit the application Default: 'ctrl+c,q'. + editor_open (Union[Unset, str]): Open external editor Default: 'e'. + theme_list (Union[Unset, str]): List available themes Default: 't'. + project_init (Union[Unset, str]): Create/update AGENTS.md Default: 'i'. + tool_details (Union[Unset, str]): Toggle tool details Default: 'd'. + thinking_blocks (Union[Unset, str]): Toggle thinking blocks Default: 'b'. + session_export (Union[Unset, str]): Export session to editor Default: 'x'. + session_new (Union[Unset, str]): Create a new session Default: 'n'. + session_list (Union[Unset, str]): List all sessions Default: 'l'. + session_timeline (Union[Unset, str]): Show session timeline Default: 'g'. + session_share (Union[Unset, str]): Share current session Default: 's'. + session_unshare (Union[Unset, str]): Unshare current session Default: 'none'. + session_interrupt (Union[Unset, str]): Interrupt current session Default: 'esc'. + session_compact (Union[Unset, str]): Compact the session Default: 'c'. + session_child_cycle (Union[Unset, str]): Cycle to next child session Default: 'ctrl+right'. + session_child_cycle_reverse (Union[Unset, str]): Cycle to previous child session Default: 'ctrl+left'. + messages_page_up (Union[Unset, str]): Scroll messages up by one page Default: 'pgup'. + messages_page_down (Union[Unset, str]): Scroll messages down by one page Default: 'pgdown'. + messages_half_page_up (Union[Unset, str]): Scroll messages up by half page Default: 'ctrl+alt+u'. + messages_half_page_down (Union[Unset, str]): Scroll messages down by half page Default: 'ctrl+alt+d'. + messages_first (Union[Unset, str]): Navigate to first message Default: 'ctrl+g'. + messages_last (Union[Unset, str]): Navigate to last message Default: 'ctrl+alt+g'. + messages_copy (Union[Unset, str]): Copy message Default: 'y'. + messages_undo (Union[Unset, str]): Undo message Default: 'u'. + messages_redo (Union[Unset, str]): Redo message Default: 'r'. + model_list (Union[Unset, str]): List available models Default: 'm'. + model_cycle_recent (Union[Unset, str]): Next recent model Default: 'f2'. + model_cycle_recent_reverse (Union[Unset, str]): Previous recent model Default: 'shift+f2'. + agent_list (Union[Unset, str]): List agents Default: 'a'. + agent_cycle (Union[Unset, str]): Next agent Default: 'tab'. + agent_cycle_reverse (Union[Unset, str]): Previous agent Default: 'shift+tab'. + input_clear (Union[Unset, str]): Clear input field Default: 'ctrl+c'. + input_paste (Union[Unset, str]): Paste from clipboard Default: 'ctrl+v'. + input_submit (Union[Unset, str]): Submit input Default: 'enter'. + input_newline (Union[Unset, str]): Insert newline in input Default: 'shift+enter,ctrl+j'. + switch_mode (Union[Unset, str]): @deprecated use agent_cycle. Next mode Default: 'none'. + switch_mode_reverse (Union[Unset, str]): @deprecated use agent_cycle_reverse. Previous mode Default: 'none'. + switch_agent (Union[Unset, str]): @deprecated use agent_cycle. Next agent Default: 'tab'. + switch_agent_reverse (Union[Unset, str]): @deprecated use agent_cycle_reverse. Previous agent Default: + 'shift+tab'. + file_list (Union[Unset, str]): @deprecated Currently not available. List files Default: 'none'. + file_close (Union[Unset, str]): @deprecated Close file Default: 'none'. + file_search (Union[Unset, str]): @deprecated Search file Default: 'none'. + file_diff_toggle (Union[Unset, str]): @deprecated Split/unified diff Default: 'none'. + messages_previous (Union[Unset, str]): @deprecated Navigate to previous message Default: 'none'. + messages_next (Union[Unset, str]): @deprecated Navigate to next message Default: 'none'. + messages_layout_toggle (Union[Unset, str]): @deprecated Toggle layout Default: 'none'. + messages_revert (Union[Unset, str]): @deprecated use messages_undo. Revert message Default: 'none'. + """ + + leader: Union[Unset, str] = "ctrl+x" + app_help: Union[Unset, str] = "h" + app_exit: Union[Unset, str] = "ctrl+c,q" + editor_open: Union[Unset, str] = "e" + theme_list: Union[Unset, str] = "t" + project_init: Union[Unset, str] = "i" + tool_details: Union[Unset, str] = "d" + thinking_blocks: Union[Unset, str] = "b" + session_export: Union[Unset, str] = "x" + session_new: Union[Unset, str] = "n" + session_list: Union[Unset, str] = "l" + session_timeline: Union[Unset, str] = "g" + session_share: Union[Unset, str] = "s" + session_unshare: Union[Unset, str] = "none" + session_interrupt: Union[Unset, str] = "esc" + session_compact: Union[Unset, str] = "c" + session_child_cycle: Union[Unset, str] = "ctrl+right" + session_child_cycle_reverse: Union[Unset, str] = "ctrl+left" + messages_page_up: Union[Unset, str] = "pgup" + messages_page_down: Union[Unset, str] = "pgdown" + messages_half_page_up: Union[Unset, str] = "ctrl+alt+u" + messages_half_page_down: Union[Unset, str] = "ctrl+alt+d" + messages_first: Union[Unset, str] = "ctrl+g" + messages_last: Union[Unset, str] = "ctrl+alt+g" + messages_copy: Union[Unset, str] = "y" + messages_undo: Union[Unset, str] = "u" + messages_redo: Union[Unset, str] = "r" + model_list: Union[Unset, str] = "m" + model_cycle_recent: Union[Unset, str] = "f2" + model_cycle_recent_reverse: Union[Unset, str] = "shift+f2" + agent_list: Union[Unset, str] = "a" + agent_cycle: Union[Unset, str] = "tab" + agent_cycle_reverse: Union[Unset, str] = "shift+tab" + input_clear: Union[Unset, str] = "ctrl+c" + input_paste: Union[Unset, str] = "ctrl+v" + input_submit: Union[Unset, str] = "enter" + input_newline: Union[Unset, str] = "shift+enter,ctrl+j" + switch_mode: Union[Unset, str] = "none" + switch_mode_reverse: Union[Unset, str] = "none" + switch_agent: Union[Unset, str] = "tab" + switch_agent_reverse: Union[Unset, str] = "shift+tab" + file_list: Union[Unset, str] = "none" + file_close: Union[Unset, str] = "none" + file_search: Union[Unset, str] = "none" + file_diff_toggle: Union[Unset, str] = "none" + messages_previous: Union[Unset, str] = "none" + messages_next: Union[Unset, str] = "none" + messages_layout_toggle: Union[Unset, str] = "none" + messages_revert: Union[Unset, str] = "none" + + def to_dict(self) -> dict[str, Any]: + leader = self.leader + + app_help = self.app_help + + app_exit = self.app_exit + + editor_open = self.editor_open + + theme_list = self.theme_list + + project_init = self.project_init + + tool_details = self.tool_details + + thinking_blocks = self.thinking_blocks + + session_export = self.session_export + + session_new = self.session_new + + session_list = self.session_list + + session_timeline = self.session_timeline + + session_share = self.session_share + + session_unshare = self.session_unshare + + session_interrupt = self.session_interrupt + + session_compact = self.session_compact + + session_child_cycle = self.session_child_cycle + + session_child_cycle_reverse = self.session_child_cycle_reverse + + messages_page_up = self.messages_page_up + + messages_page_down = self.messages_page_down + + messages_half_page_up = self.messages_half_page_up + + messages_half_page_down = self.messages_half_page_down + + messages_first = self.messages_first + + messages_last = self.messages_last + + messages_copy = self.messages_copy + + messages_undo = self.messages_undo + + messages_redo = self.messages_redo + + model_list = self.model_list + + model_cycle_recent = self.model_cycle_recent + + model_cycle_recent_reverse = self.model_cycle_recent_reverse + + agent_list = self.agent_list + + agent_cycle = self.agent_cycle + + agent_cycle_reverse = self.agent_cycle_reverse + + input_clear = self.input_clear + + input_paste = self.input_paste + + input_submit = self.input_submit + + input_newline = self.input_newline + + switch_mode = self.switch_mode + + switch_mode_reverse = self.switch_mode_reverse + + switch_agent = self.switch_agent + + switch_agent_reverse = self.switch_agent_reverse + + file_list = self.file_list + + file_close = self.file_close + + file_search = self.file_search + + file_diff_toggle = self.file_diff_toggle + + messages_previous = self.messages_previous + + messages_next = self.messages_next + + messages_layout_toggle = self.messages_layout_toggle + + messages_revert = self.messages_revert + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if leader is not UNSET: + field_dict["leader"] = leader + if app_help is not UNSET: + field_dict["app_help"] = app_help + if app_exit is not UNSET: + field_dict["app_exit"] = app_exit + if editor_open is not UNSET: + field_dict["editor_open"] = editor_open + if theme_list is not UNSET: + field_dict["theme_list"] = theme_list + if project_init is not UNSET: + field_dict["project_init"] = project_init + if tool_details is not UNSET: + field_dict["tool_details"] = tool_details + if thinking_blocks is not UNSET: + field_dict["thinking_blocks"] = thinking_blocks + if session_export is not UNSET: + field_dict["session_export"] = session_export + if session_new is not UNSET: + field_dict["session_new"] = session_new + if session_list is not UNSET: + field_dict["session_list"] = session_list + if session_timeline is not UNSET: + field_dict["session_timeline"] = session_timeline + if session_share is not UNSET: + field_dict["session_share"] = session_share + if session_unshare is not UNSET: + field_dict["session_unshare"] = session_unshare + if session_interrupt is not UNSET: + field_dict["session_interrupt"] = session_interrupt + if session_compact is not UNSET: + field_dict["session_compact"] = session_compact + if session_child_cycle is not UNSET: + field_dict["session_child_cycle"] = session_child_cycle + if session_child_cycle_reverse is not UNSET: + field_dict["session_child_cycle_reverse"] = session_child_cycle_reverse + if messages_page_up is not UNSET: + field_dict["messages_page_up"] = messages_page_up + if messages_page_down is not UNSET: + field_dict["messages_page_down"] = messages_page_down + if messages_half_page_up is not UNSET: + field_dict["messages_half_page_up"] = messages_half_page_up + if messages_half_page_down is not UNSET: + field_dict["messages_half_page_down"] = messages_half_page_down + if messages_first is not UNSET: + field_dict["messages_first"] = messages_first + if messages_last is not UNSET: + field_dict["messages_last"] = messages_last + if messages_copy is not UNSET: + field_dict["messages_copy"] = messages_copy + if messages_undo is not UNSET: + field_dict["messages_undo"] = messages_undo + if messages_redo is not UNSET: + field_dict["messages_redo"] = messages_redo + if model_list is not UNSET: + field_dict["model_list"] = model_list + if model_cycle_recent is not UNSET: + field_dict["model_cycle_recent"] = model_cycle_recent + if model_cycle_recent_reverse is not UNSET: + field_dict["model_cycle_recent_reverse"] = model_cycle_recent_reverse + if agent_list is not UNSET: + field_dict["agent_list"] = agent_list + if agent_cycle is not UNSET: + field_dict["agent_cycle"] = agent_cycle + if agent_cycle_reverse is not UNSET: + field_dict["agent_cycle_reverse"] = agent_cycle_reverse + if input_clear is not UNSET: + field_dict["input_clear"] = input_clear + if input_paste is not UNSET: + field_dict["input_paste"] = input_paste + if input_submit is not UNSET: + field_dict["input_submit"] = input_submit + if input_newline is not UNSET: + field_dict["input_newline"] = input_newline + if switch_mode is not UNSET: + field_dict["switch_mode"] = switch_mode + if switch_mode_reverse is not UNSET: + field_dict["switch_mode_reverse"] = switch_mode_reverse + if switch_agent is not UNSET: + field_dict["switch_agent"] = switch_agent + if switch_agent_reverse is not UNSET: + field_dict["switch_agent_reverse"] = switch_agent_reverse + if file_list is not UNSET: + field_dict["file_list"] = file_list + if file_close is not UNSET: + field_dict["file_close"] = file_close + if file_search is not UNSET: + field_dict["file_search"] = file_search + if file_diff_toggle is not UNSET: + field_dict["file_diff_toggle"] = file_diff_toggle + if messages_previous is not UNSET: + field_dict["messages_previous"] = messages_previous + if messages_next is not UNSET: + field_dict["messages_next"] = messages_next + if messages_layout_toggle is not UNSET: + field_dict["messages_layout_toggle"] = messages_layout_toggle + if messages_revert is not UNSET: + field_dict["messages_revert"] = messages_revert + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + leader = d.pop("leader", UNSET) + + app_help = d.pop("app_help", UNSET) + + app_exit = d.pop("app_exit", UNSET) + + editor_open = d.pop("editor_open", UNSET) + + theme_list = d.pop("theme_list", UNSET) + + project_init = d.pop("project_init", UNSET) + + tool_details = d.pop("tool_details", UNSET) + + thinking_blocks = d.pop("thinking_blocks", UNSET) + + session_export = d.pop("session_export", UNSET) + + session_new = d.pop("session_new", UNSET) + + session_list = d.pop("session_list", UNSET) + + session_timeline = d.pop("session_timeline", UNSET) + + session_share = d.pop("session_share", UNSET) + + session_unshare = d.pop("session_unshare", UNSET) + + session_interrupt = d.pop("session_interrupt", UNSET) + + session_compact = d.pop("session_compact", UNSET) + + session_child_cycle = d.pop("session_child_cycle", UNSET) + + session_child_cycle_reverse = d.pop("session_child_cycle_reverse", UNSET) + + messages_page_up = d.pop("messages_page_up", UNSET) + + messages_page_down = d.pop("messages_page_down", UNSET) + + messages_half_page_up = d.pop("messages_half_page_up", UNSET) + + messages_half_page_down = d.pop("messages_half_page_down", UNSET) + + messages_first = d.pop("messages_first", UNSET) + + messages_last = d.pop("messages_last", UNSET) + + messages_copy = d.pop("messages_copy", UNSET) + + messages_undo = d.pop("messages_undo", UNSET) + + messages_redo = d.pop("messages_redo", UNSET) + + model_list = d.pop("model_list", UNSET) + + model_cycle_recent = d.pop("model_cycle_recent", UNSET) + + model_cycle_recent_reverse = d.pop("model_cycle_recent_reverse", UNSET) + + agent_list = d.pop("agent_list", UNSET) + + agent_cycle = d.pop("agent_cycle", UNSET) + + agent_cycle_reverse = d.pop("agent_cycle_reverse", UNSET) + + input_clear = d.pop("input_clear", UNSET) + + input_paste = d.pop("input_paste", UNSET) + + input_submit = d.pop("input_submit", UNSET) + + input_newline = d.pop("input_newline", UNSET) + + switch_mode = d.pop("switch_mode", UNSET) + + switch_mode_reverse = d.pop("switch_mode_reverse", UNSET) + + switch_agent = d.pop("switch_agent", UNSET) + + switch_agent_reverse = d.pop("switch_agent_reverse", UNSET) + + file_list = d.pop("file_list", UNSET) + + file_close = d.pop("file_close", UNSET) + + file_search = d.pop("file_search", UNSET) + + file_diff_toggle = d.pop("file_diff_toggle", UNSET) + + messages_previous = d.pop("messages_previous", UNSET) + + messages_next = d.pop("messages_next", UNSET) + + messages_layout_toggle = d.pop("messages_layout_toggle", UNSET) + + messages_revert = d.pop("messages_revert", UNSET) + + keybinds_config = cls( + leader=leader, + app_help=app_help, + app_exit=app_exit, + editor_open=editor_open, + theme_list=theme_list, + project_init=project_init, + tool_details=tool_details, + thinking_blocks=thinking_blocks, + session_export=session_export, + session_new=session_new, + session_list=session_list, + session_timeline=session_timeline, + session_share=session_share, + session_unshare=session_unshare, + session_interrupt=session_interrupt, + session_compact=session_compact, + session_child_cycle=session_child_cycle, + session_child_cycle_reverse=session_child_cycle_reverse, + messages_page_up=messages_page_up, + messages_page_down=messages_page_down, + messages_half_page_up=messages_half_page_up, + messages_half_page_down=messages_half_page_down, + messages_first=messages_first, + messages_last=messages_last, + messages_copy=messages_copy, + messages_undo=messages_undo, + messages_redo=messages_redo, + model_list=model_list, + model_cycle_recent=model_cycle_recent, + model_cycle_recent_reverse=model_cycle_recent_reverse, + agent_list=agent_list, + agent_cycle=agent_cycle, + agent_cycle_reverse=agent_cycle_reverse, + input_clear=input_clear, + input_paste=input_paste, + input_submit=input_submit, + input_newline=input_newline, + switch_mode=switch_mode, + switch_mode_reverse=switch_mode_reverse, + switch_agent=switch_agent, + switch_agent_reverse=switch_agent_reverse, + file_list=file_list, + file_close=file_close, + file_search=file_search, + file_diff_toggle=file_diff_toggle, + messages_previous=messages_previous, + messages_next=messages_next, + messages_layout_toggle=messages_layout_toggle, + messages_revert=messages_revert, + ) + + return keybinds_config diff --git a/packages/sdk/python/src/opencode_ai/models/layout_config.py b/packages/sdk/python/src/opencode_ai/models/layout_config.py new file mode 100644 index 0000000000..51d0c0b1db --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/layout_config.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class LayoutConfig(str, Enum): + AUTO = "auto" + STRETCH = "stretch" + + def __str__(self) -> str: + return str(self.value) diff --git a/packages/sdk/python/src/opencode_ai/models/mcp_local_config.py b/packages/sdk/python/src/opencode_ai/models/mcp_local_config.py new file mode 100644 index 0000000000..ccaf813c3c --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/mcp_local_config.py @@ -0,0 +1,83 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.mcp_local_config_environment import McpLocalConfigEnvironment + + +T = TypeVar("T", bound="McpLocalConfig") + + +@_attrs_define +class McpLocalConfig: + """ + Attributes: + type_ (Literal['local']): Type of MCP server connection + command (list[str]): Command and arguments to run the MCP server + environment (Union[Unset, McpLocalConfigEnvironment]): Environment variables to set when running the MCP server + enabled (Union[Unset, bool]): Enable or disable the MCP server on startup + """ + + type_: Literal["local"] + command: list[str] + environment: Union[Unset, "McpLocalConfigEnvironment"] = UNSET + enabled: Union[Unset, bool] = UNSET + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + command = self.command + + environment: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.environment, Unset): + environment = self.environment.to_dict() + + enabled = self.enabled + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "type": type_, + "command": command, + } + ) + if environment is not UNSET: + field_dict["environment"] = environment + if enabled is not UNSET: + field_dict["enabled"] = enabled + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.mcp_local_config_environment import McpLocalConfigEnvironment + + d = dict(src_dict) + type_ = cast(Literal["local"], d.pop("type")) + if type_ != "local": + raise ValueError(f"type must match const 'local', got '{type_}'") + + command = cast(list[str], d.pop("command")) + + _environment = d.pop("environment", UNSET) + environment: Union[Unset, McpLocalConfigEnvironment] + if isinstance(_environment, Unset): + environment = UNSET + else: + environment = McpLocalConfigEnvironment.from_dict(_environment) + + enabled = d.pop("enabled", UNSET) + + mcp_local_config = cls( + type_=type_, + command=command, + environment=environment, + enabled=enabled, + ) + + return mcp_local_config diff --git a/packages/sdk/python/src/opencode_ai/models/mcp_local_config_environment.py b/packages/sdk/python/src/opencode_ai/models/mcp_local_config_environment.py new file mode 100644 index 0000000000..89c3d2254e --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/mcp_local_config_environment.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="McpLocalConfigEnvironment") + + +@_attrs_define +class McpLocalConfigEnvironment: + """Environment variables to set when running the MCP server""" + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + mcp_local_config_environment = cls() + + mcp_local_config_environment.additional_properties = d + return mcp_local_config_environment + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/mcp_remote_config.py b/packages/sdk/python/src/opencode_ai/models/mcp_remote_config.py new file mode 100644 index 0000000000..182553cc25 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/mcp_remote_config.py @@ -0,0 +1,83 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.mcp_remote_config_headers import McpRemoteConfigHeaders + + +T = TypeVar("T", bound="McpRemoteConfig") + + +@_attrs_define +class McpRemoteConfig: + """ + Attributes: + type_ (Literal['remote']): Type of MCP server connection + url (str): URL of the remote MCP server + enabled (Union[Unset, bool]): Enable or disable the MCP server on startup + headers (Union[Unset, McpRemoteConfigHeaders]): Headers to send with the request + """ + + type_: Literal["remote"] + url: str + enabled: Union[Unset, bool] = UNSET + headers: Union[Unset, "McpRemoteConfigHeaders"] = UNSET + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + url = self.url + + enabled = self.enabled + + headers: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.headers, Unset): + headers = self.headers.to_dict() + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "type": type_, + "url": url, + } + ) + if enabled is not UNSET: + field_dict["enabled"] = enabled + if headers is not UNSET: + field_dict["headers"] = headers + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.mcp_remote_config_headers import McpRemoteConfigHeaders + + d = dict(src_dict) + type_ = cast(Literal["remote"], d.pop("type")) + if type_ != "remote": + raise ValueError(f"type must match const 'remote', got '{type_}'") + + url = d.pop("url") + + enabled = d.pop("enabled", UNSET) + + _headers = d.pop("headers", UNSET) + headers: Union[Unset, McpRemoteConfigHeaders] + if isinstance(_headers, Unset): + headers = UNSET + else: + headers = McpRemoteConfigHeaders.from_dict(_headers) + + mcp_remote_config = cls( + type_=type_, + url=url, + enabled=enabled, + headers=headers, + ) + + return mcp_remote_config diff --git a/packages/sdk/python/src/opencode_ai/models/mcp_remote_config_headers.py b/packages/sdk/python/src/opencode_ai/models/mcp_remote_config_headers.py new file mode 100644 index 0000000000..5f437d8aea --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/mcp_remote_config_headers.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="McpRemoteConfigHeaders") + + +@_attrs_define +class McpRemoteConfigHeaders: + """Headers to send with the request""" + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + mcp_remote_config_headers = cls() + + mcp_remote_config_headers.additional_properties = d + return mcp_remote_config_headers + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/message_aborted_error.py b/packages/sdk/python/src/opencode_ai/models/message_aborted_error.py new file mode 100644 index 0000000000..6b2d489f0a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/message_aborted_error.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.message_aborted_error_data import MessageAbortedErrorData + + +T = TypeVar("T", bound="MessageAbortedError") + + +@_attrs_define +class MessageAbortedError: + """ + Attributes: + name (Literal['MessageAbortedError']): + data (MessageAbortedErrorData): + """ + + name: Literal["MessageAbortedError"] + data: "MessageAbortedErrorData" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "data": data, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.message_aborted_error_data import MessageAbortedErrorData + + d = dict(src_dict) + name = cast(Literal["MessageAbortedError"], d.pop("name")) + if name != "MessageAbortedError": + raise ValueError(f"name must match const 'MessageAbortedError', got '{name}'") + + data = MessageAbortedErrorData.from_dict(d.pop("data")) + + message_aborted_error = cls( + name=name, + data=data, + ) + + message_aborted_error.additional_properties = d + return message_aborted_error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/message_aborted_error_data.py b/packages/sdk/python/src/opencode_ai/models/message_aborted_error_data.py new file mode 100644 index 0000000000..948ac5f61c --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/message_aborted_error_data.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="MessageAbortedErrorData") + + +@_attrs_define +class MessageAbortedErrorData: + """ + Attributes: + message (str): + """ + + message: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + message_aborted_error_data = cls( + message=message, + ) + + message_aborted_error_data.additional_properties = d + return message_aborted_error_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/message_output_length_error.py b/packages/sdk/python/src/opencode_ai/models/message_output_length_error.py new file mode 100644 index 0000000000..86ba76ff2e --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/message_output_length_error.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.message_output_length_error_data import MessageOutputLengthErrorData + + +T = TypeVar("T", bound="MessageOutputLengthError") + + +@_attrs_define +class MessageOutputLengthError: + """ + Attributes: + name (Literal['MessageOutputLengthError']): + data (MessageOutputLengthErrorData): + """ + + name: Literal["MessageOutputLengthError"] + data: "MessageOutputLengthErrorData" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "data": data, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.message_output_length_error_data import MessageOutputLengthErrorData + + d = dict(src_dict) + name = cast(Literal["MessageOutputLengthError"], d.pop("name")) + if name != "MessageOutputLengthError": + raise ValueError(f"name must match const 'MessageOutputLengthError', got '{name}'") + + data = MessageOutputLengthErrorData.from_dict(d.pop("data")) + + message_output_length_error = cls( + name=name, + data=data, + ) + + message_output_length_error.additional_properties = d + return message_output_length_error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/message_output_length_error_data.py b/packages/sdk/python/src/opencode_ai/models/message_output_length_error_data.py new file mode 100644 index 0000000000..2541d9a933 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/message_output_length_error_data.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="MessageOutputLengthErrorData") + + +@_attrs_define +class MessageOutputLengthErrorData: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message_output_length_error_data = cls() + + message_output_length_error_data.additional_properties = d + return message_output_length_error_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/model.py b/packages/sdk/python/src/opencode_ai/models/model.py new file mode 100644 index 0000000000..bcdf1fefcd --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/model.py @@ -0,0 +1,170 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.model_cost import ModelCost + from ..models.model_limit import ModelLimit + from ..models.model_options import ModelOptions + from ..models.model_provider import ModelProvider + + +T = TypeVar("T", bound="Model") + + +@_attrs_define +class Model: + """ + Attributes: + id (str): + name (str): + release_date (str): + attachment (bool): + reasoning (bool): + temperature (bool): + tool_call (bool): + cost (ModelCost): + limit (ModelLimit): + options (ModelOptions): + experimental (Union[Unset, bool]): + provider (Union[Unset, ModelProvider]): + """ + + id: str + name: str + release_date: str + attachment: bool + reasoning: bool + temperature: bool + tool_call: bool + cost: "ModelCost" + limit: "ModelLimit" + options: "ModelOptions" + experimental: Union[Unset, bool] = UNSET + provider: Union[Unset, "ModelProvider"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + release_date = self.release_date + + attachment = self.attachment + + reasoning = self.reasoning + + temperature = self.temperature + + tool_call = self.tool_call + + cost = self.cost.to_dict() + + limit = self.limit.to_dict() + + options = self.options.to_dict() + + experimental = self.experimental + + provider: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.provider, Unset): + provider = self.provider.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "release_date": release_date, + "attachment": attachment, + "reasoning": reasoning, + "temperature": temperature, + "tool_call": tool_call, + "cost": cost, + "limit": limit, + "options": options, + } + ) + if experimental is not UNSET: + field_dict["experimental"] = experimental + if provider is not UNSET: + field_dict["provider"] = provider + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.model_cost import ModelCost + from ..models.model_limit import ModelLimit + from ..models.model_options import ModelOptions + from ..models.model_provider import ModelProvider + + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + release_date = d.pop("release_date") + + attachment = d.pop("attachment") + + reasoning = d.pop("reasoning") + + temperature = d.pop("temperature") + + tool_call = d.pop("tool_call") + + cost = ModelCost.from_dict(d.pop("cost")) + + limit = ModelLimit.from_dict(d.pop("limit")) + + options = ModelOptions.from_dict(d.pop("options")) + + experimental = d.pop("experimental", UNSET) + + _provider = d.pop("provider", UNSET) + provider: Union[Unset, ModelProvider] + if isinstance(_provider, Unset): + provider = UNSET + else: + provider = ModelProvider.from_dict(_provider) + + model = cls( + id=id, + name=name, + release_date=release_date, + attachment=attachment, + reasoning=reasoning, + temperature=temperature, + tool_call=tool_call, + cost=cost, + limit=limit, + options=options, + experimental=experimental, + provider=provider, + ) + + model.additional_properties = d + return model + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/model_cost.py b/packages/sdk/python/src/opencode_ai/models/model_cost.py new file mode 100644 index 0000000000..9658e9d4f2 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/model_cost.py @@ -0,0 +1,87 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelCost") + + +@_attrs_define +class ModelCost: + """ + Attributes: + input_ (float): + output (float): + cache_read (Union[Unset, float]): + cache_write (Union[Unset, float]): + """ + + input_: float + output: float + cache_read: Union[Unset, float] = UNSET + cache_write: Union[Unset, float] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + input_ = self.input_ + + output = self.output + + cache_read = self.cache_read + + cache_write = self.cache_write + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "input": input_, + "output": output, + } + ) + if cache_read is not UNSET: + field_dict["cache_read"] = cache_read + if cache_write is not UNSET: + field_dict["cache_write"] = cache_write + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + input_ = d.pop("input") + + output = d.pop("output") + + cache_read = d.pop("cache_read", UNSET) + + cache_write = d.pop("cache_write", UNSET) + + model_cost = cls( + input_=input_, + output=output, + cache_read=cache_read, + cache_write=cache_write, + ) + + model_cost.additional_properties = d + return model_cost + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/model_limit.py b/packages/sdk/python/src/opencode_ai/models/model_limit.py new file mode 100644 index 0000000000..701f53130c --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/model_limit.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelLimit") + + +@_attrs_define +class ModelLimit: + """ + Attributes: + context (float): + output (float): + """ + + context: float + output: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + context = self.context + + output = self.output + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "context": context, + "output": output, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + context = d.pop("context") + + output = d.pop("output") + + model_limit = cls( + context=context, + output=output, + ) + + model_limit.additional_properties = d + return model_limit + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/model_options.py b/packages/sdk/python/src/opencode_ai/models/model_options.py new file mode 100644 index 0000000000..cd62bb644e --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/model_options.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelOptions") + + +@_attrs_define +class ModelOptions: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + model_options = cls() + + model_options.additional_properties = d + return model_options + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/model_provider.py b/packages/sdk/python/src/opencode_ai/models/model_provider.py new file mode 100644 index 0000000000..53eb522d78 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/model_provider.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelProvider") + + +@_attrs_define +class ModelProvider: + """ + Attributes: + npm (str): + """ + + npm: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + npm = self.npm + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "npm": npm, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + npm = d.pop("npm") + + model_provider = cls( + npm=npm, + ) + + model_provider.additional_properties = d + return model_provider + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/o_auth.py b/packages/sdk/python/src/opencode_ai/models/o_auth.py new file mode 100644 index 0000000000..470fe6fd06 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/o_auth.py @@ -0,0 +1,85 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="OAuth") + + +@_attrs_define +class OAuth: + """ + Attributes: + type_ (Literal['oauth']): + refresh (str): + access (str): + expires (float): + """ + + type_: Literal["oauth"] + refresh: str + access: str + expires: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + refresh = self.refresh + + access = self.access + + expires = self.expires + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "refresh": refresh, + "access": access, + "expires": expires, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = cast(Literal["oauth"], d.pop("type")) + if type_ != "oauth": + raise ValueError(f"type must match const 'oauth', got '{type_}'") + + refresh = d.pop("refresh") + + access = d.pop("access") + + expires = d.pop("expires") + + o_auth = cls( + type_=type_, + refresh=refresh, + access=access, + expires=expires, + ) + + o_auth.additional_properties = d + return o_auth + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/patch_part.py b/packages/sdk/python/src/opencode_ai/models/patch_part.py new file mode 100644 index 0000000000..25bbc34e89 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/patch_part.py @@ -0,0 +1,101 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PatchPart") + + +@_attrs_define +class PatchPart: + """ + Attributes: + id (str): + session_id (str): + message_id (str): + type_ (Literal['patch']): + hash_ (str): + files (list[str]): + """ + + id: str + session_id: str + message_id: str + type_: Literal["patch"] + hash_: str + files: list[str] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + session_id = self.session_id + + message_id = self.message_id + + type_ = self.type_ + + hash_ = self.hash_ + + files = self.files + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "messageID": message_id, + "type": type_, + "hash": hash_, + "files": files, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + type_ = cast(Literal["patch"], d.pop("type")) + if type_ != "patch": + raise ValueError(f"type must match const 'patch', got '{type_}'") + + hash_ = d.pop("hash") + + files = cast(list[str], d.pop("files")) + + patch_part = cls( + id=id, + session_id=session_id, + message_id=message_id, + type_=type_, + hash_=hash_, + files=files, + ) + + patch_part.additional_properties = d + return patch_part + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/path.py b/packages/sdk/python/src/opencode_ai/models/path.py new file mode 100644 index 0000000000..698d1a0428 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/path.py @@ -0,0 +1,83 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="Path") + + +@_attrs_define +class Path: + """ + Attributes: + state (str): + config (str): + worktree (str): + directory (str): + """ + + state: str + config: str + worktree: str + directory: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + state = self.state + + config = self.config + + worktree = self.worktree + + directory = self.directory + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "state": state, + "config": config, + "worktree": worktree, + "directory": directory, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + state = d.pop("state") + + config = d.pop("config") + + worktree = d.pop("worktree") + + directory = d.pop("directory") + + path = cls( + state=state, + config=config, + worktree=worktree, + directory=directory, + ) + + path.additional_properties = d + return path + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/permission.py b/packages/sdk/python/src/opencode_ai/models/permission.py new file mode 100644 index 0000000000..bd3ea30f17 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/permission.py @@ -0,0 +1,155 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.permission_metadata import PermissionMetadata + from ..models.permission_time import PermissionTime + + +T = TypeVar("T", bound="Permission") + + +@_attrs_define +class Permission: + """ + Attributes: + id (str): + type_ (str): + session_id (str): + message_id (str): + title (str): + metadata (PermissionMetadata): + time (PermissionTime): + pattern (Union[Unset, list[str], str]): + call_id (Union[Unset, str]): + """ + + id: str + type_: str + session_id: str + message_id: str + title: str + metadata: "PermissionMetadata" + time: "PermissionTime" + pattern: Union[Unset, list[str], str] = UNSET + call_id: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + type_ = self.type_ + + session_id = self.session_id + + message_id = self.message_id + + title = self.title + + metadata = self.metadata.to_dict() + + time = self.time.to_dict() + + pattern: Union[Unset, list[str], str] + if isinstance(self.pattern, Unset): + pattern = UNSET + elif isinstance(self.pattern, list): + pattern = self.pattern + + else: + pattern = self.pattern + + call_id = self.call_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "type": type_, + "sessionID": session_id, + "messageID": message_id, + "title": title, + "metadata": metadata, + "time": time, + } + ) + if pattern is not UNSET: + field_dict["pattern"] = pattern + if call_id is not UNSET: + field_dict["callID"] = call_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.permission_metadata import PermissionMetadata + from ..models.permission_time import PermissionTime + + d = dict(src_dict) + id = d.pop("id") + + type_ = d.pop("type") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + title = d.pop("title") + + metadata = PermissionMetadata.from_dict(d.pop("metadata")) + + time = PermissionTime.from_dict(d.pop("time")) + + def _parse_pattern(data: object) -> Union[Unset, list[str], str]: + if isinstance(data, Unset): + return data + try: + if not isinstance(data, list): + raise TypeError() + pattern_type_1 = cast(list[str], data) + + return pattern_type_1 + except: # noqa: E722 + pass + return cast(Union[Unset, list[str], str], data) + + pattern = _parse_pattern(d.pop("pattern", UNSET)) + + call_id = d.pop("callID", UNSET) + + permission = cls( + id=id, + type_=type_, + session_id=session_id, + message_id=message_id, + title=title, + metadata=metadata, + time=time, + pattern=pattern, + call_id=call_id, + ) + + permission.additional_properties = d + return permission + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/permission_metadata.py b/packages/sdk/python/src/opencode_ai/models/permission_metadata.py new file mode 100644 index 0000000000..7379eb3c1d --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/permission_metadata.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PermissionMetadata") + + +@_attrs_define +class PermissionMetadata: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + permission_metadata = cls() + + permission_metadata.additional_properties = d + return permission_metadata + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/permission_time.py b/packages/sdk/python/src/opencode_ai/models/permission_time.py new file mode 100644 index 0000000000..d99bc2ec54 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/permission_time.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PermissionTime") + + +@_attrs_define +class PermissionTime: + """ + Attributes: + created (float): + """ + + created: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created = self.created + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created": created, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + created = d.pop("created") + + permission_time = cls( + created=created, + ) + + permission_time.additional_properties = d + return permission_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/project.py b/packages/sdk/python/src/opencode_ai/models/project.py new file mode 100644 index 0000000000..d6590dbd9d --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/project.py @@ -0,0 +1,94 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.project_time import ProjectTime + + +T = TypeVar("T", bound="Project") + + +@_attrs_define +class Project: + """ + Attributes: + id (str): + worktree (str): + time (ProjectTime): + vcs (Union[Literal['git'], Unset]): + """ + + id: str + worktree: str + time: "ProjectTime" + vcs: Union[Literal["git"], Unset] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + worktree = self.worktree + + time = self.time.to_dict() + + vcs = self.vcs + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "worktree": worktree, + "time": time, + } + ) + if vcs is not UNSET: + field_dict["vcs"] = vcs + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.project_time import ProjectTime + + d = dict(src_dict) + id = d.pop("id") + + worktree = d.pop("worktree") + + time = ProjectTime.from_dict(d.pop("time")) + + vcs = cast(Union[Literal["git"], Unset], d.pop("vcs", UNSET)) + if vcs != "git" and not isinstance(vcs, Unset): + raise ValueError(f"vcs must match const 'git', got '{vcs}'") + + project = cls( + id=id, + worktree=worktree, + time=time, + vcs=vcs, + ) + + project.additional_properties = d + return project + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/project_time.py b/packages/sdk/python/src/opencode_ai/models/project_time.py new file mode 100644 index 0000000000..1d6ef989c4 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/project_time.py @@ -0,0 +1,70 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ProjectTime") + + +@_attrs_define +class ProjectTime: + """ + Attributes: + created (float): + initialized (Union[Unset, float]): + """ + + created: float + initialized: Union[Unset, float] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created = self.created + + initialized = self.initialized + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created": created, + } + ) + if initialized is not UNSET: + field_dict["initialized"] = initialized + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + created = d.pop("created") + + initialized = d.pop("initialized", UNSET) + + project_time = cls( + created=created, + initialized=initialized, + ) + + project_time.additional_properties = d + return project_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/provider.py b/packages/sdk/python/src/opencode_ai/models/provider.py new file mode 100644 index 0000000000..e28076ce55 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/provider.py @@ -0,0 +1,109 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.provider_models import ProviderModels + + +T = TypeVar("T", bound="Provider") + + +@_attrs_define +class Provider: + """ + Attributes: + name (str): + env (list[str]): + id (str): + models (ProviderModels): + api (Union[Unset, str]): + npm (Union[Unset, str]): + """ + + name: str + env: list[str] + id: str + models: "ProviderModels" + api: Union[Unset, str] = UNSET + npm: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + env = self.env + + id = self.id + + models = self.models.to_dict() + + api = self.api + + npm = self.npm + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "env": env, + "id": id, + "models": models, + } + ) + if api is not UNSET: + field_dict["api"] = api + if npm is not UNSET: + field_dict["npm"] = npm + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.provider_models import ProviderModels + + d = dict(src_dict) + name = d.pop("name") + + env = cast(list[str], d.pop("env")) + + id = d.pop("id") + + models = ProviderModels.from_dict(d.pop("models")) + + api = d.pop("api", UNSET) + + npm = d.pop("npm", UNSET) + + provider = cls( + name=name, + env=env, + id=id, + models=models, + api=api, + npm=npm, + ) + + provider.additional_properties = d + return provider + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/provider_auth_error.py b/packages/sdk/python/src/opencode_ai/models/provider_auth_error.py new file mode 100644 index 0000000000..c1b9dd6ccb --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/provider_auth_error.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.provider_auth_error_data import ProviderAuthErrorData + + +T = TypeVar("T", bound="ProviderAuthError") + + +@_attrs_define +class ProviderAuthError: + """ + Attributes: + name (Literal['ProviderAuthError']): + data (ProviderAuthErrorData): + """ + + name: Literal["ProviderAuthError"] + data: "ProviderAuthErrorData" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "data": data, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.provider_auth_error_data import ProviderAuthErrorData + + d = dict(src_dict) + name = cast(Literal["ProviderAuthError"], d.pop("name")) + if name != "ProviderAuthError": + raise ValueError(f"name must match const 'ProviderAuthError', got '{name}'") + + data = ProviderAuthErrorData.from_dict(d.pop("data")) + + provider_auth_error = cls( + name=name, + data=data, + ) + + provider_auth_error.additional_properties = d + return provider_auth_error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/provider_auth_error_data.py b/packages/sdk/python/src/opencode_ai/models/provider_auth_error_data.py new file mode 100644 index 0000000000..d958b0b5f6 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/provider_auth_error_data.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ProviderAuthErrorData") + + +@_attrs_define +class ProviderAuthErrorData: + """ + Attributes: + provider_id (str): + message (str): + """ + + provider_id: str + message: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + provider_id = self.provider_id + + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "providerID": provider_id, + "message": message, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + provider_id = d.pop("providerID") + + message = d.pop("message") + + provider_auth_error_data = cls( + provider_id=provider_id, + message=message, + ) + + provider_auth_error_data.additional_properties = d + return provider_auth_error_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/provider_models.py b/packages/sdk/python/src/opencode_ai/models/provider_models.py new file mode 100644 index 0000000000..461a634182 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/provider_models.py @@ -0,0 +1,57 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.model import Model + + +T = TypeVar("T", bound="ProviderModels") + + +@_attrs_define +class ProviderModels: + """ """ + + additional_properties: dict[str, "Model"] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.model import Model + + d = dict(src_dict) + provider_models = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = Model.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + provider_models.additional_properties = additional_properties + return provider_models + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> "Model": + return self.additional_properties[key] + + def __setitem__(self, key: str, value: "Model") -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/range_.py b/packages/sdk/python/src/opencode_ai/models/range_.py new file mode 100644 index 0000000000..1321aeb662 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/range_.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.range_end import RangeEnd + from ..models.range_start import RangeStart + + +T = TypeVar("T", bound="Range") + + +@_attrs_define +class Range: + """ + Attributes: + start (RangeStart): + end (RangeEnd): + """ + + start: "RangeStart" + end: "RangeEnd" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + start = self.start.to_dict() + + end = self.end.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "start": start, + "end": end, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.range_end import RangeEnd + from ..models.range_start import RangeStart + + d = dict(src_dict) + start = RangeStart.from_dict(d.pop("start")) + + end = RangeEnd.from_dict(d.pop("end")) + + range_ = cls( + start=start, + end=end, + ) + + range_.additional_properties = d + return range_ + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/range_end.py b/packages/sdk/python/src/opencode_ai/models/range_end.py new file mode 100644 index 0000000000..3629c3ae98 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/range_end.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="RangeEnd") + + +@_attrs_define +class RangeEnd: + """ + Attributes: + line (float): + character (float): + """ + + line: float + character: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + line = self.line + + character = self.character + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "line": line, + "character": character, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + line = d.pop("line") + + character = d.pop("character") + + range_end = cls( + line=line, + character=character, + ) + + range_end.additional_properties = d + return range_end + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/range_start.py b/packages/sdk/python/src/opencode_ai/models/range_start.py new file mode 100644 index 0000000000..c53c95f95b --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/range_start.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="RangeStart") + + +@_attrs_define +class RangeStart: + """ + Attributes: + line (float): + character (float): + """ + + line: float + character: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + line = self.line + + character = self.character + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "line": line, + "character": character, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + line = d.pop("line") + + character = d.pop("character") + + range_start = cls( + line=line, + character=character, + ) + + range_start.additional_properties = d + return range_start + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/reasoning_part.py b/packages/sdk/python/src/opencode_ai/models/reasoning_part.py new file mode 100644 index 0000000000..a91df274bb --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/reasoning_part.py @@ -0,0 +1,127 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.reasoning_part_metadata import ReasoningPartMetadata + from ..models.reasoning_part_time import ReasoningPartTime + + +T = TypeVar("T", bound="ReasoningPart") + + +@_attrs_define +class ReasoningPart: + """ + Attributes: + id (str): + session_id (str): + message_id (str): + type_ (Literal['reasoning']): + text (str): + time (ReasoningPartTime): + metadata (Union[Unset, ReasoningPartMetadata]): + """ + + id: str + session_id: str + message_id: str + type_: Literal["reasoning"] + text: str + time: "ReasoningPartTime" + metadata: Union[Unset, "ReasoningPartMetadata"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + session_id = self.session_id + + message_id = self.message_id + + type_ = self.type_ + + text = self.text + + time = self.time.to_dict() + + metadata: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.metadata, Unset): + metadata = self.metadata.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "messageID": message_id, + "type": type_, + "text": text, + "time": time, + } + ) + if metadata is not UNSET: + field_dict["metadata"] = metadata + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.reasoning_part_metadata import ReasoningPartMetadata + from ..models.reasoning_part_time import ReasoningPartTime + + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + type_ = cast(Literal["reasoning"], d.pop("type")) + if type_ != "reasoning": + raise ValueError(f"type must match const 'reasoning', got '{type_}'") + + text = d.pop("text") + + time = ReasoningPartTime.from_dict(d.pop("time")) + + _metadata = d.pop("metadata", UNSET) + metadata: Union[Unset, ReasoningPartMetadata] + if isinstance(_metadata, Unset): + metadata = UNSET + else: + metadata = ReasoningPartMetadata.from_dict(_metadata) + + reasoning_part = cls( + id=id, + session_id=session_id, + message_id=message_id, + type_=type_, + text=text, + time=time, + metadata=metadata, + ) + + reasoning_part.additional_properties = d + return reasoning_part + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/reasoning_part_metadata.py b/packages/sdk/python/src/opencode_ai/models/reasoning_part_metadata.py new file mode 100644 index 0000000000..04a75c6f58 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/reasoning_part_metadata.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ReasoningPartMetadata") + + +@_attrs_define +class ReasoningPartMetadata: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + reasoning_part_metadata = cls() + + reasoning_part_metadata.additional_properties = d + return reasoning_part_metadata + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/reasoning_part_time.py b/packages/sdk/python/src/opencode_ai/models/reasoning_part_time.py new file mode 100644 index 0000000000..603ead6e5d --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/reasoning_part_time.py @@ -0,0 +1,70 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ReasoningPartTime") + + +@_attrs_define +class ReasoningPartTime: + """ + Attributes: + start (float): + end (Union[Unset, float]): + """ + + start: float + end: Union[Unset, float] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + start = self.start + + end = self.end + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "start": start, + } + ) + if end is not UNSET: + field_dict["end"] = end + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + start = d.pop("start") + + end = d.pop("end", UNSET) + + reasoning_part_time = cls( + start=start, + end=end, + ) + + reasoning_part_time.additional_properties = d + return reasoning_part_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/session.py b/packages/sdk/python/src/opencode_ai/models/session.py new file mode 100644 index 0000000000..81bf0dbccc --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/session.py @@ -0,0 +1,152 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.session_revert import SessionRevert + from ..models.session_share import SessionShare + from ..models.session_time import SessionTime + + +T = TypeVar("T", bound="Session") + + +@_attrs_define +class Session: + """ + Attributes: + id (str): + project_id (str): + directory (str): + title (str): + version (str): + time (SessionTime): + parent_id (Union[Unset, str]): + share (Union[Unset, SessionShare]): + revert (Union[Unset, SessionRevert]): + """ + + id: str + project_id: str + directory: str + title: str + version: str + time: "SessionTime" + parent_id: Union[Unset, str] = UNSET + share: Union[Unset, "SessionShare"] = UNSET + revert: Union[Unset, "SessionRevert"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + project_id = self.project_id + + directory = self.directory + + title = self.title + + version = self.version + + time = self.time.to_dict() + + parent_id = self.parent_id + + share: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.share, Unset): + share = self.share.to_dict() + + revert: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.revert, Unset): + revert = self.revert.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "projectID": project_id, + "directory": directory, + "title": title, + "version": version, + "time": time, + } + ) + if parent_id is not UNSET: + field_dict["parentID"] = parent_id + if share is not UNSET: + field_dict["share"] = share + if revert is not UNSET: + field_dict["revert"] = revert + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.session_revert import SessionRevert + from ..models.session_share import SessionShare + from ..models.session_time import SessionTime + + d = dict(src_dict) + id = d.pop("id") + + project_id = d.pop("projectID") + + directory = d.pop("directory") + + title = d.pop("title") + + version = d.pop("version") + + time = SessionTime.from_dict(d.pop("time")) + + parent_id = d.pop("parentID", UNSET) + + _share = d.pop("share", UNSET) + share: Union[Unset, SessionShare] + if isinstance(_share, Unset): + share = UNSET + else: + share = SessionShare.from_dict(_share) + + _revert = d.pop("revert", UNSET) + revert: Union[Unset, SessionRevert] + if isinstance(_revert, Unset): + revert = UNSET + else: + revert = SessionRevert.from_dict(_revert) + + session = cls( + id=id, + project_id=project_id, + directory=directory, + title=title, + version=version, + time=time, + parent_id=parent_id, + share=share, + revert=revert, + ) + + session.additional_properties = d + return session + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/session_revert.py b/packages/sdk/python/src/opencode_ai/models/session_revert.py new file mode 100644 index 0000000000..97397b9d8a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/session_revert.py @@ -0,0 +1,88 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="SessionRevert") + + +@_attrs_define +class SessionRevert: + """ + Attributes: + message_id (str): + part_id (Union[Unset, str]): + snapshot (Union[Unset, str]): + diff (Union[Unset, str]): + """ + + message_id: str + part_id: Union[Unset, str] = UNSET + snapshot: Union[Unset, str] = UNSET + diff: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message_id = self.message_id + + part_id = self.part_id + + snapshot = self.snapshot + + diff = self.diff + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "messageID": message_id, + } + ) + if part_id is not UNSET: + field_dict["partID"] = part_id + if snapshot is not UNSET: + field_dict["snapshot"] = snapshot + if diff is not UNSET: + field_dict["diff"] = diff + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message_id = d.pop("messageID") + + part_id = d.pop("partID", UNSET) + + snapshot = d.pop("snapshot", UNSET) + + diff = d.pop("diff", UNSET) + + session_revert = cls( + message_id=message_id, + part_id=part_id, + snapshot=snapshot, + diff=diff, + ) + + session_revert.additional_properties = d + return session_revert + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/session_share.py b/packages/sdk/python/src/opencode_ai/models/session_share.py new file mode 100644 index 0000000000..c77f7d3880 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/session_share.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SessionShare") + + +@_attrs_define +class SessionShare: + """ + Attributes: + url (str): + """ + + url: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + url = self.url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "url": url, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + url = d.pop("url") + + session_share = cls( + url=url, + ) + + session_share.additional_properties = d + return session_share + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/session_time.py b/packages/sdk/python/src/opencode_ai/models/session_time.py new file mode 100644 index 0000000000..682c3af2bd --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/session_time.py @@ -0,0 +1,78 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="SessionTime") + + +@_attrs_define +class SessionTime: + """ + Attributes: + created (float): + updated (float): + compacting (Union[Unset, float]): + """ + + created: float + updated: float + compacting: Union[Unset, float] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created = self.created + + updated = self.updated + + compacting = self.compacting + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created": created, + "updated": updated, + } + ) + if compacting is not UNSET: + field_dict["compacting"] = compacting + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + created = d.pop("created") + + updated = d.pop("updated") + + compacting = d.pop("compacting", UNSET) + + session_time = cls( + created=created, + updated=updated, + compacting=compacting, + ) + + session_time.additional_properties = d + return session_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/snapshot_part.py b/packages/sdk/python/src/opencode_ai/models/snapshot_part.py new file mode 100644 index 0000000000..9f6f69c2bd --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/snapshot_part.py @@ -0,0 +1,93 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SnapshotPart") + + +@_attrs_define +class SnapshotPart: + """ + Attributes: + id (str): + session_id (str): + message_id (str): + type_ (Literal['snapshot']): + snapshot (str): + """ + + id: str + session_id: str + message_id: str + type_: Literal["snapshot"] + snapshot: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + session_id = self.session_id + + message_id = self.message_id + + type_ = self.type_ + + snapshot = self.snapshot + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "messageID": message_id, + "type": type_, + "snapshot": snapshot, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + type_ = cast(Literal["snapshot"], d.pop("type")) + if type_ != "snapshot": + raise ValueError(f"type must match const 'snapshot', got '{type_}'") + + snapshot = d.pop("snapshot") + + snapshot_part = cls( + id=id, + session_id=session_id, + message_id=message_id, + type_=type_, + snapshot=snapshot, + ) + + snapshot_part.additional_properties = d + return snapshot_part + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/step_finish_part.py b/packages/sdk/python/src/opencode_ai/models/step_finish_part.py new file mode 100644 index 0000000000..6d611e7b41 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/step_finish_part.py @@ -0,0 +1,107 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.step_finish_part_tokens import StepFinishPartTokens + + +T = TypeVar("T", bound="StepFinishPart") + + +@_attrs_define +class StepFinishPart: + """ + Attributes: + id (str): + session_id (str): + message_id (str): + type_ (Literal['step-finish']): + cost (float): + tokens (StepFinishPartTokens): + """ + + id: str + session_id: str + message_id: str + type_: Literal["step-finish"] + cost: float + tokens: "StepFinishPartTokens" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + session_id = self.session_id + + message_id = self.message_id + + type_ = self.type_ + + cost = self.cost + + tokens = self.tokens.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "messageID": message_id, + "type": type_, + "cost": cost, + "tokens": tokens, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.step_finish_part_tokens import StepFinishPartTokens + + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + type_ = cast(Literal["step-finish"], d.pop("type")) + if type_ != "step-finish": + raise ValueError(f"type must match const 'step-finish', got '{type_}'") + + cost = d.pop("cost") + + tokens = StepFinishPartTokens.from_dict(d.pop("tokens")) + + step_finish_part = cls( + id=id, + session_id=session_id, + message_id=message_id, + type_=type_, + cost=cost, + tokens=tokens, + ) + + step_finish_part.additional_properties = d + return step_finish_part + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/step_finish_part_tokens.py b/packages/sdk/python/src/opencode_ai/models/step_finish_part_tokens.py new file mode 100644 index 0000000000..de14a44940 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/step_finish_part_tokens.py @@ -0,0 +1,89 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.step_finish_part_tokens_cache import StepFinishPartTokensCache + + +T = TypeVar("T", bound="StepFinishPartTokens") + + +@_attrs_define +class StepFinishPartTokens: + """ + Attributes: + input_ (float): + output (float): + reasoning (float): + cache (StepFinishPartTokensCache): + """ + + input_: float + output: float + reasoning: float + cache: "StepFinishPartTokensCache" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + input_ = self.input_ + + output = self.output + + reasoning = self.reasoning + + cache = self.cache.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "input": input_, + "output": output, + "reasoning": reasoning, + "cache": cache, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.step_finish_part_tokens_cache import StepFinishPartTokensCache + + d = dict(src_dict) + input_ = d.pop("input") + + output = d.pop("output") + + reasoning = d.pop("reasoning") + + cache = StepFinishPartTokensCache.from_dict(d.pop("cache")) + + step_finish_part_tokens = cls( + input_=input_, + output=output, + reasoning=reasoning, + cache=cache, + ) + + step_finish_part_tokens.additional_properties = d + return step_finish_part_tokens + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/step_finish_part_tokens_cache.py b/packages/sdk/python/src/opencode_ai/models/step_finish_part_tokens_cache.py new file mode 100644 index 0000000000..2677d810c8 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/step_finish_part_tokens_cache.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="StepFinishPartTokensCache") + + +@_attrs_define +class StepFinishPartTokensCache: + """ + Attributes: + read (float): + write (float): + """ + + read: float + write: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + read = self.read + + write = self.write + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "read": read, + "write": write, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + read = d.pop("read") + + write = d.pop("write") + + step_finish_part_tokens_cache = cls( + read=read, + write=write, + ) + + step_finish_part_tokens_cache.additional_properties = d + return step_finish_part_tokens_cache + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/step_start_part.py b/packages/sdk/python/src/opencode_ai/models/step_start_part.py new file mode 100644 index 0000000000..bc3bb2862a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/step_start_part.py @@ -0,0 +1,85 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="StepStartPart") + + +@_attrs_define +class StepStartPart: + """ + Attributes: + id (str): + session_id (str): + message_id (str): + type_ (Literal['step-start']): + """ + + id: str + session_id: str + message_id: str + type_: Literal["step-start"] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + session_id = self.session_id + + message_id = self.message_id + + type_ = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "messageID": message_id, + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + type_ = cast(Literal["step-start"], d.pop("type")) + if type_ != "step-start": + raise ValueError(f"type must match const 'step-start', got '{type_}'") + + step_start_part = cls( + id=id, + session_id=session_id, + message_id=message_id, + type_=type_, + ) + + step_start_part.additional_properties = d + return step_start_part + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/symbol.py b/packages/sdk/python/src/opencode_ai/models/symbol.py new file mode 100644 index 0000000000..f57088931c --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/symbol.py @@ -0,0 +1,81 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.symbol_location import SymbolLocation + + +T = TypeVar("T", bound="Symbol") + + +@_attrs_define +class Symbol: + """ + Attributes: + name (str): + kind (float): + location (SymbolLocation): + """ + + name: str + kind: float + location: "SymbolLocation" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + kind = self.kind + + location = self.location.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "kind": kind, + "location": location, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.symbol_location import SymbolLocation + + d = dict(src_dict) + name = d.pop("name") + + kind = d.pop("kind") + + location = SymbolLocation.from_dict(d.pop("location")) + + symbol = cls( + name=name, + kind=kind, + location=location, + ) + + symbol.additional_properties = d + return symbol + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/symbol_location.py b/packages/sdk/python/src/opencode_ai/models/symbol_location.py new file mode 100644 index 0000000000..6837727627 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/symbol_location.py @@ -0,0 +1,73 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.range_ import Range + + +T = TypeVar("T", bound="SymbolLocation") + + +@_attrs_define +class SymbolLocation: + """ + Attributes: + uri (str): + range_ (Range): + """ + + uri: str + range_: "Range" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + uri = self.uri + + range_ = self.range_.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "uri": uri, + "range": range_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.range_ import Range + + d = dict(src_dict) + uri = d.pop("uri") + + range_ = Range.from_dict(d.pop("range")) + + symbol_location = cls( + uri=uri, + range_=range_, + ) + + symbol_location.additional_properties = d + return symbol_location + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/symbol_source.py b/packages/sdk/python/src/opencode_ai/models/symbol_source.py new file mode 100644 index 0000000000..6cec91d5ec --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/symbol_source.py @@ -0,0 +1,109 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.file_part_source_text import FilePartSourceText + from ..models.range_ import Range + + +T = TypeVar("T", bound="SymbolSource") + + +@_attrs_define +class SymbolSource: + """ + Attributes: + text (FilePartSourceText): + type_ (Literal['symbol']): + path (str): + range_ (Range): + name (str): + kind (int): + """ + + text: "FilePartSourceText" + type_: Literal["symbol"] + path: str + range_: "Range" + name: str + kind: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + text = self.text.to_dict() + + type_ = self.type_ + + path = self.path + + range_ = self.range_.to_dict() + + name = self.name + + kind = self.kind + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "text": text, + "type": type_, + "path": path, + "range": range_, + "name": name, + "kind": kind, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.file_part_source_text import FilePartSourceText + from ..models.range_ import Range + + d = dict(src_dict) + text = FilePartSourceText.from_dict(d.pop("text")) + + type_ = cast(Literal["symbol"], d.pop("type")) + if type_ != "symbol": + raise ValueError(f"type must match const 'symbol', got '{type_}'") + + path = d.pop("path") + + range_ = Range.from_dict(d.pop("range")) + + name = d.pop("name") + + kind = d.pop("kind") + + symbol_source = cls( + text=text, + type_=type_, + path=path, + range_=range_, + name=name, + kind=kind, + ) + + symbol_source.additional_properties = d + return symbol_source + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/text_part.py b/packages/sdk/python/src/opencode_ai/models/text_part.py new file mode 100644 index 0000000000..7c58dcfadd --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/text_part.py @@ -0,0 +1,126 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.text_part_time import TextPartTime + + +T = TypeVar("T", bound="TextPart") + + +@_attrs_define +class TextPart: + """ + Attributes: + id (str): + session_id (str): + message_id (str): + type_ (Literal['text']): + text (str): + synthetic (Union[Unset, bool]): + time (Union[Unset, TextPartTime]): + """ + + id: str + session_id: str + message_id: str + type_: Literal["text"] + text: str + synthetic: Union[Unset, bool] = UNSET + time: Union[Unset, "TextPartTime"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + session_id = self.session_id + + message_id = self.message_id + + type_ = self.type_ + + text = self.text + + synthetic = self.synthetic + + time: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.time, Unset): + time = self.time.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "messageID": message_id, + "type": type_, + "text": text, + } + ) + if synthetic is not UNSET: + field_dict["synthetic"] = synthetic + if time is not UNSET: + field_dict["time"] = time + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.text_part_time import TextPartTime + + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + type_ = cast(Literal["text"], d.pop("type")) + if type_ != "text": + raise ValueError(f"type must match const 'text', got '{type_}'") + + text = d.pop("text") + + synthetic = d.pop("synthetic", UNSET) + + _time = d.pop("time", UNSET) + time: Union[Unset, TextPartTime] + if isinstance(_time, Unset): + time = UNSET + else: + time = TextPartTime.from_dict(_time) + + text_part = cls( + id=id, + session_id=session_id, + message_id=message_id, + type_=type_, + text=text, + synthetic=synthetic, + time=time, + ) + + text_part.additional_properties = d + return text_part + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/text_part_input.py b/packages/sdk/python/src/opencode_ai/models/text_part_input.py new file mode 100644 index 0000000000..b664bc7408 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/text_part_input.py @@ -0,0 +1,111 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.text_part_input_time import TextPartInputTime + + +T = TypeVar("T", bound="TextPartInput") + + +@_attrs_define +class TextPartInput: + """ + Attributes: + type_ (Literal['text']): + text (str): + id (Union[Unset, str]): + synthetic (Union[Unset, bool]): + time (Union[Unset, TextPartInputTime]): + """ + + type_: Literal["text"] + text: str + id: Union[Unset, str] = UNSET + synthetic: Union[Unset, bool] = UNSET + time: Union[Unset, "TextPartInputTime"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + text = self.text + + id = self.id + + synthetic = self.synthetic + + time: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.time, Unset): + time = self.time.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "text": text, + } + ) + if id is not UNSET: + field_dict["id"] = id + if synthetic is not UNSET: + field_dict["synthetic"] = synthetic + if time is not UNSET: + field_dict["time"] = time + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.text_part_input_time import TextPartInputTime + + d = dict(src_dict) + type_ = cast(Literal["text"], d.pop("type")) + if type_ != "text": + raise ValueError(f"type must match const 'text', got '{type_}'") + + text = d.pop("text") + + id = d.pop("id", UNSET) + + synthetic = d.pop("synthetic", UNSET) + + _time = d.pop("time", UNSET) + time: Union[Unset, TextPartInputTime] + if isinstance(_time, Unset): + time = UNSET + else: + time = TextPartInputTime.from_dict(_time) + + text_part_input = cls( + type_=type_, + text=text, + id=id, + synthetic=synthetic, + time=time, + ) + + text_part_input.additional_properties = d + return text_part_input + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/text_part_input_time.py b/packages/sdk/python/src/opencode_ai/models/text_part_input_time.py new file mode 100644 index 0000000000..e325a99ae2 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/text_part_input_time.py @@ -0,0 +1,70 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="TextPartInputTime") + + +@_attrs_define +class TextPartInputTime: + """ + Attributes: + start (float): + end (Union[Unset, float]): + """ + + start: float + end: Union[Unset, float] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + start = self.start + + end = self.end + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "start": start, + } + ) + if end is not UNSET: + field_dict["end"] = end + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + start = d.pop("start") + + end = d.pop("end", UNSET) + + text_part_input_time = cls( + start=start, + end=end, + ) + + text_part_input_time.additional_properties = d + return text_part_input_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/text_part_time.py b/packages/sdk/python/src/opencode_ai/models/text_part_time.py new file mode 100644 index 0000000000..ca36c1eb37 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/text_part_time.py @@ -0,0 +1,70 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="TextPartTime") + + +@_attrs_define +class TextPartTime: + """ + Attributes: + start (float): + end (Union[Unset, float]): + """ + + start: float + end: Union[Unset, float] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + start = self.start + + end = self.end + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "start": start, + } + ) + if end is not UNSET: + field_dict["end"] = end + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + start = d.pop("start") + + end = d.pop("end", UNSET) + + text_part_time = cls( + start=start, + end=end, + ) + + text_part_time.additional_properties = d + return text_part_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_list_item.py b/packages/sdk/python/src/opencode_ai/models/tool_list_item.py new file mode 100644 index 0000000000..77c9bf2caf --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_list_item.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ToolListItem") + + +@_attrs_define +class ToolListItem: + """ + Attributes: + id (str): + description (str): + parameters (Any): + """ + + id: str + description: str + parameters: Any + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + description = self.description + + parameters = self.parameters + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "description": description, + "parameters": parameters, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + description = d.pop("description") + + parameters = d.pop("parameters") + + tool_list_item = cls( + id=id, + description=description, + parameters=parameters, + ) + + tool_list_item.additional_properties = d + return tool_list_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_part.py b/packages/sdk/python/src/opencode_ai/models/tool_part.py new file mode 100644 index 0000000000..a48a5d795a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_part.py @@ -0,0 +1,166 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.tool_state_completed import ToolStateCompleted + from ..models.tool_state_error import ToolStateError + from ..models.tool_state_pending import ToolStatePending + from ..models.tool_state_running import ToolStateRunning + + +T = TypeVar("T", bound="ToolPart") + + +@_attrs_define +class ToolPart: + """ + Attributes: + id (str): + session_id (str): + message_id (str): + type_ (Literal['tool']): + call_id (str): + tool (str): + state (Union['ToolStateCompleted', 'ToolStateError', 'ToolStatePending', 'ToolStateRunning']): + """ + + id: str + session_id: str + message_id: str + type_: Literal["tool"] + call_id: str + tool: str + state: Union["ToolStateCompleted", "ToolStateError", "ToolStatePending", "ToolStateRunning"] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.tool_state_completed import ToolStateCompleted + from ..models.tool_state_pending import ToolStatePending + from ..models.tool_state_running import ToolStateRunning + + id = self.id + + session_id = self.session_id + + message_id = self.message_id + + type_ = self.type_ + + call_id = self.call_id + + tool = self.tool + + state: dict[str, Any] + if isinstance(self.state, ToolStatePending): + state = self.state.to_dict() + elif isinstance(self.state, ToolStateRunning): + state = self.state.to_dict() + elif isinstance(self.state, ToolStateCompleted): + state = self.state.to_dict() + else: + state = self.state.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "messageID": message_id, + "type": type_, + "callID": call_id, + "tool": tool, + "state": state, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.tool_state_completed import ToolStateCompleted + from ..models.tool_state_error import ToolStateError + from ..models.tool_state_pending import ToolStatePending + from ..models.tool_state_running import ToolStateRunning + + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + message_id = d.pop("messageID") + + type_ = cast(Literal["tool"], d.pop("type")) + if type_ != "tool": + raise ValueError(f"type must match const 'tool', got '{type_}'") + + call_id = d.pop("callID") + + tool = d.pop("tool") + + def _parse_state( + data: object, + ) -> Union["ToolStateCompleted", "ToolStateError", "ToolStatePending", "ToolStateRunning"]: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_tool_state_type_0 = ToolStatePending.from_dict(data) + + return componentsschemas_tool_state_type_0 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_tool_state_type_1 = ToolStateRunning.from_dict(data) + + return componentsschemas_tool_state_type_1 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_tool_state_type_2 = ToolStateCompleted.from_dict(data) + + return componentsschemas_tool_state_type_2 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_tool_state_type_3 = ToolStateError.from_dict(data) + + return componentsschemas_tool_state_type_3 + + state = _parse_state(d.pop("state")) + + tool_part = cls( + id=id, + session_id=session_id, + message_id=message_id, + type_=type_, + call_id=call_id, + tool=tool, + state=state, + ) + + tool_part.additional_properties = d + return tool_part + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_completed.py b/packages/sdk/python/src/opencode_ai/models/tool_state_completed.py new file mode 100644 index 0000000000..43155ebdbc --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_completed.py @@ -0,0 +1,111 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.tool_state_completed_input import ToolStateCompletedInput + from ..models.tool_state_completed_metadata import ToolStateCompletedMetadata + from ..models.tool_state_completed_time import ToolStateCompletedTime + + +T = TypeVar("T", bound="ToolStateCompleted") + + +@_attrs_define +class ToolStateCompleted: + """ + Attributes: + status (Literal['completed']): + input_ (ToolStateCompletedInput): + output (str): + title (str): + metadata (ToolStateCompletedMetadata): + time (ToolStateCompletedTime): + """ + + status: Literal["completed"] + input_: "ToolStateCompletedInput" + output: str + title: str + metadata: "ToolStateCompletedMetadata" + time: "ToolStateCompletedTime" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + status = self.status + + input_ = self.input_.to_dict() + + output = self.output + + title = self.title + + metadata = self.metadata.to_dict() + + time = self.time.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "status": status, + "input": input_, + "output": output, + "title": title, + "metadata": metadata, + "time": time, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.tool_state_completed_input import ToolStateCompletedInput + from ..models.tool_state_completed_metadata import ToolStateCompletedMetadata + from ..models.tool_state_completed_time import ToolStateCompletedTime + + d = dict(src_dict) + status = cast(Literal["completed"], d.pop("status")) + if status != "completed": + raise ValueError(f"status must match const 'completed', got '{status}'") + + input_ = ToolStateCompletedInput.from_dict(d.pop("input")) + + output = d.pop("output") + + title = d.pop("title") + + metadata = ToolStateCompletedMetadata.from_dict(d.pop("metadata")) + + time = ToolStateCompletedTime.from_dict(d.pop("time")) + + tool_state_completed = cls( + status=status, + input_=input_, + output=output, + title=title, + metadata=metadata, + time=time, + ) + + tool_state_completed.additional_properties = d + return tool_state_completed + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_completed_input.py b/packages/sdk/python/src/opencode_ai/models/tool_state_completed_input.py new file mode 100644 index 0000000000..346aba2e59 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_completed_input.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ToolStateCompletedInput") + + +@_attrs_define +class ToolStateCompletedInput: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + tool_state_completed_input = cls() + + tool_state_completed_input.additional_properties = d + return tool_state_completed_input + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_completed_metadata.py b/packages/sdk/python/src/opencode_ai/models/tool_state_completed_metadata.py new file mode 100644 index 0000000000..22377cf1a8 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_completed_metadata.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ToolStateCompletedMetadata") + + +@_attrs_define +class ToolStateCompletedMetadata: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + tool_state_completed_metadata = cls() + + tool_state_completed_metadata.additional_properties = d + return tool_state_completed_metadata + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_completed_time.py b/packages/sdk/python/src/opencode_ai/models/tool_state_completed_time.py new file mode 100644 index 0000000000..131c460d01 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_completed_time.py @@ -0,0 +1,78 @@ +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ToolStateCompletedTime") + + +@_attrs_define +class ToolStateCompletedTime: + """ + Attributes: + start (float): + end (float): + compacted (Union[Unset, float]): + """ + + start: float + end: float + compacted: Union[Unset, float] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + start = self.start + + end = self.end + + compacted = self.compacted + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "start": start, + "end": end, + } + ) + if compacted is not UNSET: + field_dict["compacted"] = compacted + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + start = d.pop("start") + + end = d.pop("end") + + compacted = d.pop("compacted", UNSET) + + tool_state_completed_time = cls( + start=start, + end=end, + compacted=compacted, + ) + + tool_state_completed_time.additional_properties = d + return tool_state_completed_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_error.py b/packages/sdk/python/src/opencode_ai/models/tool_state_error.py new file mode 100644 index 0000000000..dcd0e86513 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_error.py @@ -0,0 +1,113 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tool_state_error_input import ToolStateErrorInput + from ..models.tool_state_error_metadata import ToolStateErrorMetadata + from ..models.tool_state_error_time import ToolStateErrorTime + + +T = TypeVar("T", bound="ToolStateError") + + +@_attrs_define +class ToolStateError: + """ + Attributes: + status (Literal['error']): + input_ (ToolStateErrorInput): + error (str): + time (ToolStateErrorTime): + metadata (Union[Unset, ToolStateErrorMetadata]): + """ + + status: Literal["error"] + input_: "ToolStateErrorInput" + error: str + time: "ToolStateErrorTime" + metadata: Union[Unset, "ToolStateErrorMetadata"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + status = self.status + + input_ = self.input_.to_dict() + + error = self.error + + time = self.time.to_dict() + + metadata: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.metadata, Unset): + metadata = self.metadata.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "status": status, + "input": input_, + "error": error, + "time": time, + } + ) + if metadata is not UNSET: + field_dict["metadata"] = metadata + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.tool_state_error_input import ToolStateErrorInput + from ..models.tool_state_error_metadata import ToolStateErrorMetadata + from ..models.tool_state_error_time import ToolStateErrorTime + + d = dict(src_dict) + status = cast(Literal["error"], d.pop("status")) + if status != "error": + raise ValueError(f"status must match const 'error', got '{status}'") + + input_ = ToolStateErrorInput.from_dict(d.pop("input")) + + error = d.pop("error") + + time = ToolStateErrorTime.from_dict(d.pop("time")) + + _metadata = d.pop("metadata", UNSET) + metadata: Union[Unset, ToolStateErrorMetadata] + if isinstance(_metadata, Unset): + metadata = UNSET + else: + metadata = ToolStateErrorMetadata.from_dict(_metadata) + + tool_state_error = cls( + status=status, + input_=input_, + error=error, + time=time, + metadata=metadata, + ) + + tool_state_error.additional_properties = d + return tool_state_error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_error_input.py b/packages/sdk/python/src/opencode_ai/models/tool_state_error_input.py new file mode 100644 index 0000000000..33cb12a3a7 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_error_input.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ToolStateErrorInput") + + +@_attrs_define +class ToolStateErrorInput: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + tool_state_error_input = cls() + + tool_state_error_input.additional_properties = d + return tool_state_error_input + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_error_metadata.py b/packages/sdk/python/src/opencode_ai/models/tool_state_error_metadata.py new file mode 100644 index 0000000000..435567852d --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_error_metadata.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ToolStateErrorMetadata") + + +@_attrs_define +class ToolStateErrorMetadata: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + tool_state_error_metadata = cls() + + tool_state_error_metadata.additional_properties = d + return tool_state_error_metadata + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_error_time.py b/packages/sdk/python/src/opencode_ai/models/tool_state_error_time.py new file mode 100644 index 0000000000..50a4bbd7dc --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_error_time.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ToolStateErrorTime") + + +@_attrs_define +class ToolStateErrorTime: + """ + Attributes: + start (float): + end (float): + """ + + start: float + end: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + start = self.start + + end = self.end + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "start": start, + "end": end, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + start = d.pop("start") + + end = d.pop("end") + + tool_state_error_time = cls( + start=start, + end=end, + ) + + tool_state_error_time.additional_properties = d + return tool_state_error_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_pending.py b/packages/sdk/python/src/opencode_ai/models/tool_state_pending.py new file mode 100644 index 0000000000..3e5efcca21 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_pending.py @@ -0,0 +1,61 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ToolStatePending") + + +@_attrs_define +class ToolStatePending: + """ + Attributes: + status (Literal['pending']): + """ + + status: Literal["pending"] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + status = cast(Literal["pending"], d.pop("status")) + if status != "pending": + raise ValueError(f"status must match const 'pending', got '{status}'") + + tool_state_pending = cls( + status=status, + ) + + tool_state_pending.additional_properties = d + return tool_state_pending + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_running.py b/packages/sdk/python/src/opencode_ai/models/tool_state_running.py new file mode 100644 index 0000000000..ad6bf204eb --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_running.py @@ -0,0 +1,112 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.tool_state_running_metadata import ToolStateRunningMetadata + from ..models.tool_state_running_time import ToolStateRunningTime + + +T = TypeVar("T", bound="ToolStateRunning") + + +@_attrs_define +class ToolStateRunning: + """ + Attributes: + status (Literal['running']): + input_ (Any): + time (ToolStateRunningTime): + title (Union[Unset, str]): + metadata (Union[Unset, ToolStateRunningMetadata]): + """ + + status: Literal["running"] + input_: Any + time: "ToolStateRunningTime" + title: Union[Unset, str] = UNSET + metadata: Union[Unset, "ToolStateRunningMetadata"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + status = self.status + + input_ = self.input_ + + time = self.time.to_dict() + + title = self.title + + metadata: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.metadata, Unset): + metadata = self.metadata.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "status": status, + "input": input_, + "time": time, + } + ) + if title is not UNSET: + field_dict["title"] = title + if metadata is not UNSET: + field_dict["metadata"] = metadata + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.tool_state_running_metadata import ToolStateRunningMetadata + from ..models.tool_state_running_time import ToolStateRunningTime + + d = dict(src_dict) + status = cast(Literal["running"], d.pop("status")) + if status != "running": + raise ValueError(f"status must match const 'running', got '{status}'") + + input_ = d.pop("input") + + time = ToolStateRunningTime.from_dict(d.pop("time")) + + title = d.pop("title", UNSET) + + _metadata = d.pop("metadata", UNSET) + metadata: Union[Unset, ToolStateRunningMetadata] + if isinstance(_metadata, Unset): + metadata = UNSET + else: + metadata = ToolStateRunningMetadata.from_dict(_metadata) + + tool_state_running = cls( + status=status, + input_=input_, + time=time, + title=title, + metadata=metadata, + ) + + tool_state_running.additional_properties = d + return tool_state_running + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_running_metadata.py b/packages/sdk/python/src/opencode_ai/models/tool_state_running_metadata.py new file mode 100644 index 0000000000..5de4c8a2c6 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_running_metadata.py @@ -0,0 +1,44 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ToolStateRunningMetadata") + + +@_attrs_define +class ToolStateRunningMetadata: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + tool_state_running_metadata = cls() + + tool_state_running_metadata.additional_properties = d + return tool_state_running_metadata + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/tool_state_running_time.py b/packages/sdk/python/src/opencode_ai/models/tool_state_running_time.py new file mode 100644 index 0000000000..49b7837825 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/tool_state_running_time.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ToolStateRunningTime") + + +@_attrs_define +class ToolStateRunningTime: + """ + Attributes: + start (float): + """ + + start: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + start = self.start + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "start": start, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + start = d.pop("start") + + tool_state_running_time = cls( + start=start, + ) + + tool_state_running_time.additional_properties = d + return tool_state_running_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/unknown_error.py b/packages/sdk/python/src/opencode_ai/models/unknown_error.py new file mode 100644 index 0000000000..30d4dd9fb1 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/unknown_error.py @@ -0,0 +1,75 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.unknown_error_data import UnknownErrorData + + +T = TypeVar("T", bound="UnknownError") + + +@_attrs_define +class UnknownError: + """ + Attributes: + name (Literal['UnknownError']): + data (UnknownErrorData): + """ + + name: Literal["UnknownError"] + data: "UnknownErrorData" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + data = self.data.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "data": data, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.unknown_error_data import UnknownErrorData + + d = dict(src_dict) + name = cast(Literal["UnknownError"], d.pop("name")) + if name != "UnknownError": + raise ValueError(f"name must match const 'UnknownError', got '{name}'") + + data = UnknownErrorData.from_dict(d.pop("data")) + + unknown_error = cls( + name=name, + data=data, + ) + + unknown_error.additional_properties = d + return unknown_error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/unknown_error_data.py b/packages/sdk/python/src/opencode_ai/models/unknown_error_data.py new file mode 100644 index 0000000000..97139f2782 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/unknown_error_data.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UnknownErrorData") + + +@_attrs_define +class UnknownErrorData: + """ + Attributes: + message (str): + """ + + message: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + unknown_error_data = cls( + message=message, + ) + + unknown_error_data.additional_properties = d + return unknown_error_data + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/user_message.py b/packages/sdk/python/src/opencode_ai/models/user_message.py new file mode 100644 index 0000000000..cd81dafc06 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/user_message.py @@ -0,0 +1,91 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.user_message_time import UserMessageTime + + +T = TypeVar("T", bound="UserMessage") + + +@_attrs_define +class UserMessage: + """ + Attributes: + id (str): + session_id (str): + role (Literal['user']): + time (UserMessageTime): + """ + + id: str + session_id: str + role: Literal["user"] + time: "UserMessageTime" + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + session_id = self.session_id + + role = self.role + + time = self.time.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sessionID": session_id, + "role": role, + "time": time, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.user_message_time import UserMessageTime + + d = dict(src_dict) + id = d.pop("id") + + session_id = d.pop("sessionID") + + role = cast(Literal["user"], d.pop("role")) + if role != "user": + raise ValueError(f"role must match const 'user', got '{role}'") + + time = UserMessageTime.from_dict(d.pop("time")) + + user_message = cls( + id=id, + session_id=session_id, + role=role, + time=time, + ) + + user_message.additional_properties = d + return user_message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/user_message_time.py b/packages/sdk/python/src/opencode_ai/models/user_message_time.py new file mode 100644 index 0000000000..f5ef791751 --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/user_message_time.py @@ -0,0 +1,59 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UserMessageTime") + + +@_attrs_define +class UserMessageTime: + """ + Attributes: + created (float): + """ + + created: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created = self.created + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created": created, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + created = d.pop("created") + + user_message_time = cls( + created=created, + ) + + user_message_time.additional_properties = d + return user_message_time + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/models/well_known_auth.py b/packages/sdk/python/src/opencode_ai/models/well_known_auth.py new file mode 100644 index 0000000000..a52936f31f --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/models/well_known_auth.py @@ -0,0 +1,77 @@ +from collections.abc import Mapping +from typing import Any, Literal, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="WellKnownAuth") + + +@_attrs_define +class WellKnownAuth: + """ + Attributes: + type_ (Literal['wellknown']): + key (str): + token (str): + """ + + type_: Literal["wellknown"] + key: str + token: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_ = self.type_ + + key = self.key + + token = self.token + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "key": key, + "token": token, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = cast(Literal["wellknown"], d.pop("type")) + if type_ != "wellknown": + raise ValueError(f"type must match const 'wellknown', got '{type_}'") + + key = d.pop("key") + + token = d.pop("token") + + well_known_auth = cls( + type_=type_, + key=key, + token=token, + ) + + well_known_auth.additional_properties = d + return well_known_auth + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/sdk/python/src/opencode_ai/py.typed b/packages/sdk/python/src/opencode_ai/py.typed new file mode 100644 index 0000000000..1aad32711f --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 \ No newline at end of file diff --git a/packages/sdk/python/src/opencode_ai/types.py b/packages/sdk/python/src/opencode_ai/types.py new file mode 100644 index 0000000000..1b96ca408a --- /dev/null +++ b/packages/sdk/python/src/opencode_ai/types.py @@ -0,0 +1,54 @@ +"""Contains some shared types for properties""" + +from collections.abc import Mapping, MutableMapping +from http import HTTPStatus +from typing import IO, BinaryIO, Generic, Literal, Optional, TypeVar, Union + +from attrs import define + + +class Unset: + def __bool__(self) -> Literal[False]: + return False + + +UNSET: Unset = Unset() + +# The types that `httpx.Client(files=)` can accept, copied from that library. +FileContent = Union[IO[bytes], bytes, str] +FileTypes = Union[ + # (filename, file (or bytes), content_type) + tuple[Optional[str], FileContent, Optional[str]], + # (filename, file (or bytes), content_type, headers) + tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], +] +RequestFiles = list[tuple[str, FileTypes]] + + +@define +class File: + """Contains information for file uploads""" + + payload: BinaryIO + file_name: Optional[str] = None + mime_type: Optional[str] = None + + def to_tuple(self) -> FileTypes: + """Return a tuple representation that httpx will accept for multipart/form-data""" + return self.file_name, self.payload, self.mime_type + + +T = TypeVar("T") + + +@define +class Response(Generic[T]): + """A response from an endpoint""" + + status_code: HTTPStatus + content: bytes + headers: MutableMapping[str, str] + parsed: Optional[T] + + +__all__ = ["UNSET", "File", "FileTypes", "RequestFiles", "Response", "Unset"] diff --git a/packages/sdk/python/templates/extras.py b/packages/sdk/python/templates/extras.py new file mode 100644 index 0000000000..f34bfdee6f --- /dev/null +++ b/packages/sdk/python/templates/extras.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +from typing import AsyncIterator, Dict, Iterator, Optional + +import httpx + +from opencode_ai.api.default import config_get, session_list +from opencode_ai.client import Client +from opencode_ai.types import UNSET, Unset + + +class OpenCodeClient: + """High-level convenience wrapper around the generated Client. + + Provides sensible defaults and a couple of helper methods. + """ + + def __init__( + self, + base_url: str = "http://localhost:4096", + *, + headers: Optional[Dict[str, str]] = None, + timeout: Optional[float] = None, + verify_ssl: bool | str | httpx.URLTypes | None = True, + ) -> None: + httpx_timeout = None if timeout is None else httpx.Timeout(timeout) + self._client = Client( + base_url=base_url, + headers=headers or {}, + timeout=httpx_timeout, + verify_ssl=verify_ssl if isinstance(verify_ssl, bool) else True, + ) + + @property + def client(self) -> Client: + return self._client + + # ---- Convenience wrappers over generated endpoints ---- + + def list_sessions(self, *, directory: str | Unset = UNSET): + return session_list.sync(client=self._client, directory=directory) + + def get_config(self, *, directory: str | Unset = UNSET): + return config_get.sync(client=self._client, directory=directory) + + # ---- Server-Sent Events (SSE) streaming ---- + + def subscribe_events(self, *, directory: str | Unset = UNSET) -> Iterator[dict]: + """Subscribe to /event SSE endpoint and yield parsed JSON events. + + This is a blocking generator which yields one event dict per message. + """ + client = self._client.get_httpx_client() + params: dict[str, str] = {} + if directory is not UNSET and directory is not None: + params["directory"] = str(directory) + with client.stream("GET", "/event", headers={"Accept": "text/event-stream"}, params=params) as r: + r.raise_for_status() + buf = "" + for line_bytes in r.iter_lines(): + line = line_bytes.decode("utf-8") if isinstance(line_bytes, (bytes, bytearray)) else str(line_bytes) + if line.startswith(":"): + # comment/heartbeat + continue + if line == "": + if buf: + # end of event + for part in buf.split("\n"): + if part.startswith("data:"): + data = part[5:].strip() + if data: + try: + yield httpx._models.jsonlib.loads(data) # type: ignore[attr-defined] + except Exception: + # fall back: skip malformed + pass + buf = "" + continue + buf += line + "\n" + + async def subscribe_events_async(self, *, directory: str | Unset = UNSET) -> AsyncIterator[dict]: + """Async variant of subscribe_events using httpx.AsyncClient.""" + aclient = self._client.get_async_httpx_client() + params: dict[str, str] = {} + if directory is not UNSET and directory is not None: + params["directory"] = str(directory) + async with aclient.stream("GET", "/event", headers={"Accept": "text/event-stream"}, params=params) as r: + r.raise_for_status() + buf = "" + async for line_bytes in r.aiter_lines(): + line = line_bytes + if line.startswith(":"): + continue + if line == "": + if buf: + for part in buf.split("\n"): + if part.startswith("data:"): + data = part[5:].strip() + if data: + try: + yield httpx._models.jsonlib.loads(data) # type: ignore[attr-defined] + except Exception: + pass + buf = "" + continue + buf += line + "\n" diff --git a/packages/sdk/python/tests/__init__.py b/packages/sdk/python/tests/__init__.py new file mode 100644 index 0000000000..1a9709f463 --- /dev/null +++ b/packages/sdk/python/tests/__init__.py @@ -0,0 +1 @@ +# Makes tests/ a package for import-resolution friendliness diff --git a/packages/sdk/python/tests/test_integration.py b/packages/sdk/python/tests/test_integration.py new file mode 100644 index 0000000000..cbb6c39990 --- /dev/null +++ b/packages/sdk/python/tests/test_integration.py @@ -0,0 +1,93 @@ +import os +import re +import signal +import subprocess +import sys +import time +from pathlib import Path + +import httpx +import pytest + +from opencode_ai import OpenCodeClient + + +@pytest.mark.timeout(30) +def test_integration_live_server_endpoints() -> None: + # Locate repo root by finding sst.config.ts upwards from this file + here = Path(__file__).resolve() + p = here + repo_root = None + for _ in range(8): + if (p / "sst.config.ts").exists(): + repo_root = p + break + if p.parent == p: + break + p = p.parent + assert repo_root is not None, "Could not locate repo root (sst.config.ts)" + + # Start opencode headless server on a random port + pkg_opencode = repo_root / "packages" / "opencode" + cmd = [ + "bun", + "run", + "--conditions=development", + "./src/index.ts", + "serve", + "--port", + "0", + "--hostname", + "127.0.0.1", + ] + + proc = subprocess.Popen( + cmd, + cwd=str(pkg_opencode), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + bufsize=1, + universal_newlines=True, + ) + + url = None + start = time.time() + assert proc.stdout is not None + while time.time() - start < 15: + line = proc.stdout.readline() + if not line: + time.sleep(0.05) + if proc.poll() is not None: + break + continue + m = re.search(r"opencode server listening on (http://[^\s]+)", line) + if m: + url = m.group(1) + break + assert url, "Server did not report listening URL" + + try: + client = OpenCodeClient(base_url=url) + # Basic endpoints (avoid complex config model parsing issues) + pinfo = client.get_path() + assert pinfo is not None + projects = client.list_projects() + assert projects is not None + + # SSE: should get the initial server.connected event + it = client.subscribe_events() + evt = next(it) + assert isinstance(evt, dict) + assert evt.get("type") == "server.connected" + finally: + # Cleanup server process + try: + if proc.poll() is None: + proc.terminate() + try: + proc.wait(timeout=5) + except subprocess.TimeoutExpired: + proc.kill() + except Exception: + pass diff --git a/packages/sdk/python/tests/test_wrapper.py b/packages/sdk/python/tests/test_wrapper.py new file mode 100644 index 0000000000..f2003a536e --- /dev/null +++ b/packages/sdk/python/tests/test_wrapper.py @@ -0,0 +1,116 @@ +import json +from typing import Iterator + +import httpx +import pytest + +from opencode_ai import OpenCodeClient +from opencode_ai.api.default import config_get +from opencode_ai.client import Client + + +class _State: + def __init__(self): + self.calls = 0 + + +def test_imports_and_methods_available() -> None: + w = OpenCodeClient() + assert hasattr(w, "list_sessions") + assert hasattr(w, "get_config") + assert hasattr(w, "list_agents") + assert hasattr(w, "list_projects") + assert hasattr(w, "current_project") + assert hasattr(w, "file_status") + assert hasattr(w, "get_path") + assert hasattr(w, "subscribe_events") + + +def test_get_path_with_mock_transport() -> None: + # Arrange a mock transport for GET /path + def handler(request: httpx.Request) -> httpx.Response: + assert request.url.path == "/path" + return httpx.Response( + 200, + json={ + "state": "ok", + "config": "/tmp/config", + "worktree": "/repo", + "directory": "/repo/project", + }, + ) + + transport = httpx.MockTransport(handler) + + w = OpenCodeClient(base_url="http://test") + client = httpx.Client(base_url="http://test", transport=transport) + w.client.set_httpx_client(client) + + # Act + result = w.get_path() + + # Assert + assert result is not None + assert result.directory == "/repo/project" + + +def test_retry_on_request_error_then_success() -> None: + state = _State() + + def handler(request: httpx.Request) -> httpx.Response: + if state.calls == 0: + state.calls += 1 + raise httpx.ConnectError("boom", request=request) + return httpx.Response( + 200, + json={ + "state": "ok", + "config": "/tmp/config", + "worktree": "/repo", + "directory": "/repo/project", + }, + ) + + transport = httpx.MockTransport(handler) + + w = OpenCodeClient(base_url="http://test", retries=1, backoff_factor=0) + client = httpx.Client(base_url="http://test", transport=transport) + w.client.set_httpx_client(client) + + result = w.get_path() + assert result is not None + assert result.directory == "/repo/project" + + +def test_generated_config_get_via_mock() -> None: + def handler(request: httpx.Request) -> httpx.Response: + assert request.url.path == "/config" + return httpx.Response(200, json={}) + + transport = httpx.MockTransport(handler) + c = Client(base_url="http://test") + c.set_httpx_client(httpx.Client(base_url="http://test", transport=transport)) + assert config_get.sync(client=c) is not None + + +def test_sse_streaming_parses_events() -> None: + # Prepare a simple SSE payload with one event + payload = b'data: {"type":"server.connected"}\n\n' + + def handler(request: httpx.Request) -> httpx.Response: + assert request.url.path == "/event" + return httpx.Response( + 200, + headers={"Content-Type": "text/event-stream"}, + content=payload, + ) + + transport = httpx.MockTransport(handler) + w = OpenCodeClient(base_url="http://test") + client = httpx.Client(base_url="http://test", transport=transport) + w.client.set_httpx_client(client) + + it = w.subscribe_events() + first = next(it) + assert isinstance(first, dict) + assert first.get("type") == "server.connected" diff --git a/packages/sdk/python/uv.lock b/packages/sdk/python/uv.lock new file mode 100644 index 0000000000..8191c77fb2 --- /dev/null +++ b/packages/sdk/python/uv.lock @@ -0,0 +1,2700 @@ +version = 1 +revision = 2 +requires-python = ">=3.8" +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.5.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.9'" }, + { name = "idna", marker = "python_full_version < '3.9'" }, + { name = "sniffio", marker = "python_full_version < '3.9'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4d/f9/9a7ce600ebe7804daf90d4d48b1c0510a4561ddce43a596be46676f82343/anyio-4.5.2.tar.gz", hash = "sha256:23009af4ed04ce05991845451e11ef02fc7c5ed29179ac9a420e5ad0ac7ddc5b", size = 171293, upload-time = "2024-10-13T22:18:03.307Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl", hash = "sha256:c011ee36bc1e8ba40e5a81cb9df91925c218fe9b778554e0b56a21e1b5d4716f", size = 89766, upload-time = "2024-10-13T22:18:01.524Z" }, +] + +[[package]] +name = "anyio" +version = "4.10.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, + { name = "idna", marker = "python_full_version >= '3.9'" }, + { name = "sniffio", marker = "python_full_version >= '3.9'" }, + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/b4/636b3b65173d3ce9a38ef5f0522789614e590dab6a8d505340a4efe4c567/anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6", size = 213252, upload-time = "2025-08-04T08:54:26.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" }, +] + +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytz", marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "backports-asyncio-runner" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, +] + +[[package]] +name = "backports-tarfile" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", size = 86406, upload-time = "2024-05-28T17:01:54.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181, upload-time = "2024-05-28T17:01:53.112Z" }, +] + +[[package]] +name = "backrefs" +version = "5.7.post1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/df/30/903f35159c87ff1d92aa3fcf8cb52de97632a21e0ae43ed940f5d033e01a/backrefs-5.7.post1.tar.gz", hash = "sha256:8b0f83b770332ee2f1c8244f4e03c77d127a0fa529328e6a0e77fa25bee99678", size = 6582270, upload-time = "2024-06-16T18:38:20.166Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/bb/47fc255d1060dcfd55b460236380edd8ebfc5b2a42a0799ca90c9fc983e3/backrefs-5.7.post1-py310-none-any.whl", hash = "sha256:c5e3fd8fd185607a7cb1fefe878cfb09c34c0be3c18328f12c574245f1c0287e", size = 380429, upload-time = "2024-06-16T18:38:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/89/72/39ef491caef3abae945f5a5fd72830d3b596bfac0630508629283585e213/backrefs-5.7.post1-py311-none-any.whl", hash = "sha256:712ea7e494c5bf3291156e28954dd96d04dc44681d0e5c030adf2623d5606d51", size = 392234, upload-time = "2024-06-16T18:38:12.283Z" }, + { url = "https://files.pythonhosted.org/packages/6a/00/33403f581b732ca70fdebab558e8bbb426a29c34e0c3ed674a479b74beea/backrefs-5.7.post1-py312-none-any.whl", hash = "sha256:a6142201c8293e75bce7577ac29e1a9438c12e730d73a59efdd1b75528d1a6c5", size = 398110, upload-time = "2024-06-16T18:38:14.257Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ea/df0ac74a26838f6588aa012d5d801831448b87d0a7d0aefbbfabbe894870/backrefs-5.7.post1-py38-none-any.whl", hash = "sha256:ec61b1ee0a4bfa24267f6b67d0f8c5ffdc8e0d7dc2f18a2685fd1d8d9187054a", size = 369477, upload-time = "2024-06-16T18:38:16.196Z" }, + { url = "https://files.pythonhosted.org/packages/6f/e8/e43f535c0a17a695e5768670fc855a0e5d52dc0d4135b3915bfa355f65ac/backrefs-5.7.post1-py39-none-any.whl", hash = "sha256:05c04af2bf752bb9a6c9dcebb2aff2fab372d3d9d311f2a138540e307756bd3a", size = 380429, upload-time = "2024-06-16T18:38:18.079Z" }, +] + +[[package]] +name = "backrefs" +version = "5.9" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/a7/312f673df6a79003279e1f55619abbe7daebbb87c17c976ddc0345c04c7b/backrefs-5.9.tar.gz", hash = "sha256:808548cb708d66b82ee231f962cb36faaf4f2baab032f2fbb783e9c2fdddaa59", size = 5765857, upload-time = "2025-06-22T19:34:13.97Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/4d/798dc1f30468134906575156c089c492cf79b5a5fd373f07fe26c4d046bf/backrefs-5.9-py310-none-any.whl", hash = "sha256:db8e8ba0e9de81fcd635f440deab5ae5f2591b54ac1ebe0550a2ca063488cd9f", size = 380267, upload-time = "2025-06-22T19:34:05.252Z" }, + { url = "https://files.pythonhosted.org/packages/55/07/f0b3375bf0d06014e9787797e6b7cc02b38ac9ff9726ccfe834d94e9991e/backrefs-5.9-py311-none-any.whl", hash = "sha256:6907635edebbe9b2dc3de3a2befff44d74f30a4562adbb8b36f21252ea19c5cf", size = 392072, upload-time = "2025-06-22T19:34:06.743Z" }, + { url = "https://files.pythonhosted.org/packages/9d/12/4f345407259dd60a0997107758ba3f221cf89a9b5a0f8ed5b961aef97253/backrefs-5.9-py312-none-any.whl", hash = "sha256:7fdf9771f63e6028d7fee7e0c497c81abda597ea45d6b8f89e8ad76994f5befa", size = 397947, upload-time = "2025-06-22T19:34:08.172Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/fa31834dc27a7f05e5290eae47c82690edc3a7b37d58f7fb35a1bdbf355b/backrefs-5.9-py313-none-any.whl", hash = "sha256:cc37b19fa219e93ff825ed1fed8879e47b4d89aa7a1884860e2db64ccd7c676b", size = 399843, upload-time = "2025-06-22T19:34:09.68Z" }, + { url = "https://files.pythonhosted.org/packages/fc/24/b29af34b2c9c41645a9f4ff117bae860291780d73880f449e0b5d948c070/backrefs-5.9-py314-none-any.whl", hash = "sha256:df5e169836cc8acb5e440ebae9aad4bf9d15e226d3bad049cf3f6a5c20cc8dc9", size = 411762, upload-time = "2025-06-22T19:34:11.037Z" }, + { url = "https://files.pythonhosted.org/packages/41/ff/392bff89415399a979be4a65357a41d92729ae8580a66073d8ec8d810f98/backrefs-5.9-py39-none-any.whl", hash = "sha256:f48ee18f6252b8f5777a22a00a09a85de0ca931658f1dd96d4406a34f3748c60", size = 380265, upload-time = "2025-06-22T19:34:12.405Z" }, +] + +[[package]] +name = "black" +version = "24.8.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "click", marker = "python_full_version < '3.9'" }, + { name = "mypy-extensions", marker = "python_full_version < '3.9'" }, + { name = "packaging", marker = "python_full_version < '3.9'" }, + { name = "pathspec", marker = "python_full_version < '3.9'" }, + { name = "platformdirs", version = "4.3.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "tomli", marker = "python_full_version < '3.9'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/b0/46fb0d4e00372f4a86a6f8efa3cb193c9f64863615e39010b1477e010578/black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f", size = 644810, upload-time = "2024-08-02T17:43:18.405Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/6e/74e29edf1fba3887ed7066930a87f698ffdcd52c5dbc263eabb06061672d/black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6", size = 1632092, upload-time = "2024-08-02T17:47:26.911Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/575cb6c3faee690b05c9d11ee2e8dba8fbd6d6c134496e644c1feb1b47da/black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb", size = 1457529, upload-time = "2024-08-02T17:47:29.109Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/d34099e95c437b53d01c4aa37cf93944b233066eb034ccf7897fa4e5f286/black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42", size = 1757443, upload-time = "2024-08-02T17:46:20.306Z" }, + { url = "https://files.pythonhosted.org/packages/87/a0/6d2e4175ef364b8c4b64f8441ba041ed65c63ea1db2720d61494ac711c15/black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a", size = 1418012, upload-time = "2024-08-02T17:47:20.33Z" }, + { url = "https://files.pythonhosted.org/packages/08/a6/0a3aa89de9c283556146dc6dbda20cd63a9c94160a6fbdebaf0918e4a3e1/black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1", size = 1615080, upload-time = "2024-08-02T17:48:05.467Z" }, + { url = "https://files.pythonhosted.org/packages/db/94/b803d810e14588bb297e565821a947c108390a079e21dbdcb9ab6956cd7a/black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af", size = 1438143, upload-time = "2024-08-02T17:47:30.247Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b5/f485e1bbe31f768e2e5210f52ea3f432256201289fd1a3c0afda693776b0/black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4", size = 1738774, upload-time = "2024-08-02T17:46:17.837Z" }, + { url = "https://files.pythonhosted.org/packages/a8/69/a000fc3736f89d1bdc7f4a879f8aaf516fb03613bb51a0154070383d95d9/black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af", size = 1427503, upload-time = "2024-08-02T17:46:22.654Z" }, + { url = "https://files.pythonhosted.org/packages/a2/a8/05fb14195cfef32b7c8d4585a44b7499c2a4b205e1662c427b941ed87054/black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368", size = 1646132, upload-time = "2024-08-02T17:49:52.843Z" }, + { url = "https://files.pythonhosted.org/packages/41/77/8d9ce42673e5cb9988f6df73c1c5c1d4e9e788053cccd7f5fb14ef100982/black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed", size = 1448665, upload-time = "2024-08-02T17:47:54.479Z" }, + { url = "https://files.pythonhosted.org/packages/cc/94/eff1ddad2ce1d3cc26c162b3693043c6b6b575f538f602f26fe846dfdc75/black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018", size = 1762458, upload-time = "2024-08-02T17:46:19.384Z" }, + { url = "https://files.pythonhosted.org/packages/28/ea/18b8d86a9ca19a6942e4e16759b2fa5fc02bbc0eb33c1b866fcd387640ab/black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2", size = 1436109, upload-time = "2024-08-02T17:46:52.97Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d4/ae03761ddecc1a37d7e743b89cccbcf3317479ff4b88cfd8818079f890d0/black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd", size = 1617322, upload-time = "2024-08-02T17:51:20.203Z" }, + { url = "https://files.pythonhosted.org/packages/14/4b/4dfe67eed7f9b1ddca2ec8e4418ea74f0d1dc84d36ea874d618ffa1af7d4/black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2", size = 1442108, upload-time = "2024-08-02T17:50:40.824Z" }, + { url = "https://files.pythonhosted.org/packages/97/14/95b3f91f857034686cae0e73006b8391d76a8142d339b42970eaaf0416ea/black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e", size = 1745786, upload-time = "2024-08-02T17:46:02.939Z" }, + { url = "https://files.pythonhosted.org/packages/95/54/68b8883c8aa258a6dde958cd5bdfada8382bec47c5162f4a01e66d839af1/black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920", size = 1426754, upload-time = "2024-08-02T17:46:38.603Z" }, + { url = "https://files.pythonhosted.org/packages/13/b2/b3f24fdbb46f0e7ef6238e131f13572ee8279b70f237f221dd168a9dba1a/black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c", size = 1631706, upload-time = "2024-08-02T17:49:57.606Z" }, + { url = "https://files.pythonhosted.org/packages/d9/35/31010981e4a05202a84a3116423970fd1a59d2eda4ac0b3570fbb7029ddc/black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e", size = 1457429, upload-time = "2024-08-02T17:49:12.764Z" }, + { url = "https://files.pythonhosted.org/packages/27/25/3f706b4f044dd569a20a4835c3b733dedea38d83d2ee0beb8178a6d44945/black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47", size = 1756488, upload-time = "2024-08-02T17:46:08.067Z" }, + { url = "https://files.pythonhosted.org/packages/63/72/79375cd8277cbf1c5670914e6bd4c1b15dea2c8f8e906dc21c448d0535f0/black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb", size = 1417721, upload-time = "2024-08-02T17:46:42.637Z" }, + { url = "https://files.pythonhosted.org/packages/27/1e/83fa8a787180e1632c3d831f7e58994d7aaf23a0961320d21e84f922f919/black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed", size = 206504, upload-time = "2024-08-02T17:43:15.747Z" }, +] + +[[package]] +name = "black" +version = "25.9.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "click", marker = "python_full_version >= '3.9'" }, + { name = "mypy-extensions", marker = "python_full_version >= '3.9'" }, + { name = "packaging", marker = "python_full_version >= '3.9'" }, + { name = "pathspec", marker = "python_full_version >= '3.9'" }, + { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "pytokens", marker = "python_full_version >= '3.9'" }, + { name = "tomli", marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4b/43/20b5c90612d7bdb2bdbcceeb53d588acca3bb8f0e4c5d5c751a2c8fdd55a/black-25.9.0.tar.gz", hash = "sha256:0474bca9a0dd1b51791fcc507a4e02078a1c63f6d4e4ae5544b9848c7adfb619", size = 648393, upload-time = "2025-09-19T00:27:37.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/40/dbe31fc56b218a858c8fc6f5d8d3ba61c1fa7e989d43d4a4574b8b992840/black-25.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ce41ed2614b706fd55fd0b4a6909d06b5bab344ffbfadc6ef34ae50adba3d4f7", size = 1715605, upload-time = "2025-09-19T00:36:13.483Z" }, + { url = "https://files.pythonhosted.org/packages/92/b2/f46800621200eab6479b1f4c0e3ede5b4c06b768e79ee228bc80270bcc74/black-25.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ab0ce111ef026790e9b13bd216fa7bc48edd934ffc4cbf78808b235793cbc92", size = 1571829, upload-time = "2025-09-19T00:32:42.13Z" }, + { url = "https://files.pythonhosted.org/packages/4e/64/5c7f66bd65af5c19b4ea86062bb585adc28d51d37babf70969e804dbd5c2/black-25.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f96b6726d690c96c60ba682955199f8c39abc1ae0c3a494a9c62c0184049a713", size = 1631888, upload-time = "2025-09-19T00:30:54.212Z" }, + { url = "https://files.pythonhosted.org/packages/3b/64/0b9e5bfcf67db25a6eef6d9be6726499a8a72ebab3888c2de135190853d3/black-25.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:d119957b37cc641596063cd7db2656c5be3752ac17877017b2ffcdb9dfc4d2b1", size = 1327056, upload-time = "2025-09-19T00:31:08.877Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f4/7531d4a336d2d4ac6cc101662184c8e7d068b548d35d874415ed9f4116ef/black-25.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:456386fe87bad41b806d53c062e2974615825c7a52159cde7ccaeb0695fa28fa", size = 1698727, upload-time = "2025-09-19T00:31:14.264Z" }, + { url = "https://files.pythonhosted.org/packages/28/f9/66f26bfbbf84b949cc77a41a43e138d83b109502cd9c52dfc94070ca51f2/black-25.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a16b14a44c1af60a210d8da28e108e13e75a284bf21a9afa6b4571f96ab8bb9d", size = 1555679, upload-time = "2025-09-19T00:31:29.265Z" }, + { url = "https://files.pythonhosted.org/packages/bf/59/61475115906052f415f518a648a9ac679d7afbc8da1c16f8fdf68a8cebed/black-25.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aaf319612536d502fdd0e88ce52d8f1352b2c0a955cc2798f79eeca9d3af0608", size = 1617453, upload-time = "2025-09-19T00:30:42.24Z" }, + { url = "https://files.pythonhosted.org/packages/7f/5b/20fd5c884d14550c911e4fb1b0dae00d4abb60a4f3876b449c4d3a9141d5/black-25.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:c0372a93e16b3954208417bfe448e09b0de5cc721d521866cd9e0acac3c04a1f", size = 1333655, upload-time = "2025-09-19T00:30:56.715Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8e/319cfe6c82f7e2d5bfb4d3353c6cc85b523d677ff59edc61fdb9ee275234/black-25.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1b9dc70c21ef8b43248f1d86aedd2aaf75ae110b958a7909ad8463c4aa0880b0", size = 1742012, upload-time = "2025-09-19T00:33:08.678Z" }, + { url = "https://files.pythonhosted.org/packages/94/cc/f562fe5d0a40cd2a4e6ae3f685e4c36e365b1f7e494af99c26ff7f28117f/black-25.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8e46eecf65a095fa62e53245ae2795c90bdecabd53b50c448d0a8bcd0d2e74c4", size = 1581421, upload-time = "2025-09-19T00:35:25.937Z" }, + { url = "https://files.pythonhosted.org/packages/84/67/6db6dff1ebc8965fd7661498aea0da5d7301074b85bba8606a28f47ede4d/black-25.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9101ee58ddc2442199a25cb648d46ba22cd580b00ca4b44234a324e3ec7a0f7e", size = 1655619, upload-time = "2025-09-19T00:30:49.241Z" }, + { url = "https://files.pythonhosted.org/packages/10/10/3faef9aa2a730306cf469d76f7f155a8cc1f66e74781298df0ba31f8b4c8/black-25.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:77e7060a00c5ec4b3367c55f39cf9b06e68965a4f2e61cecacd6d0d9b7ec945a", size = 1342481, upload-time = "2025-09-19T00:31:29.625Z" }, + { url = "https://files.pythonhosted.org/packages/48/99/3acfea65f5e79f45472c45f87ec13037b506522719cd9d4ac86484ff51ac/black-25.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0172a012f725b792c358d57fe7b6b6e8e67375dd157f64fa7a3097b3ed3e2175", size = 1742165, upload-time = "2025-09-19T00:34:10.402Z" }, + { url = "https://files.pythonhosted.org/packages/3a/18/799285282c8236a79f25d590f0222dbd6850e14b060dfaa3e720241fd772/black-25.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3bec74ee60f8dfef564b573a96b8930f7b6a538e846123d5ad77ba14a8d7a64f", size = 1581259, upload-time = "2025-09-19T00:32:49.685Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ce/883ec4b6303acdeca93ee06b7622f1fa383c6b3765294824165d49b1a86b/black-25.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b756fc75871cb1bcac5499552d771822fd9db5a2bb8db2a7247936ca48f39831", size = 1655583, upload-time = "2025-09-19T00:30:44.505Z" }, + { url = "https://files.pythonhosted.org/packages/21/17/5c253aa80a0639ccc427a5c7144534b661505ae2b5a10b77ebe13fa25334/black-25.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:846d58e3ce7879ec1ffe816bb9df6d006cd9590515ed5d17db14e17666b2b357", size = 1343428, upload-time = "2025-09-19T00:32:13.839Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/0f724eb152bc9fc03029a9c903ddd77a288285042222a381050d27e64ac1/black-25.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ef69351df3c84485a8beb6f7b8f9721e2009e20ef80a8d619e2d1788b7816d47", size = 1715243, upload-time = "2025-09-19T00:34:14.216Z" }, + { url = "https://files.pythonhosted.org/packages/fb/be/cb986ea2f0fabd0ee58668367724ba16c3a042842e9ebe009c139f8221c9/black-25.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e3c1f4cd5e93842774d9ee4ef6cd8d17790e65f44f7cdbaab5f2cf8ccf22a823", size = 1571246, upload-time = "2025-09-19T00:31:39.624Z" }, + { url = "https://files.pythonhosted.org/packages/82/ce/74cf4d66963fca33ab710e4c5817ceeff843c45649f61f41d88694c2e5db/black-25.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:154b06d618233fe468236ba1f0e40823d4eb08b26f5e9261526fde34916b9140", size = 1631265, upload-time = "2025-09-19T00:31:05.341Z" }, + { url = "https://files.pythonhosted.org/packages/ff/f3/9b11e001e84b4d1721f75e20b3c058854a748407e6fc1abe6da0aa22014f/black-25.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:e593466de7b998374ea2585a471ba90553283fb9beefcfa430d84a2651ed5933", size = 1326615, upload-time = "2025-09-19T00:31:25.347Z" }, + { url = "https://files.pythonhosted.org/packages/1b/46/863c90dcd3f9d41b109b7f19032ae0db021f0b2a81482ba0a1e28c84de86/black-25.9.0-py3-none-any.whl", hash = "sha256:474b34c1342cdc157d307b56c4c65bce916480c4a8f6551fdc6bf9b486a7c4ae", size = 203363, upload-time = "2025-09-19T00:27:35.724Z" }, +] + +[[package]] +name = "build" +version = "1.2.2.post1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version < '3.9' and os_name == 'nt'" }, + { name = "importlib-metadata", version = "8.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "packaging", marker = "python_full_version < '3.9'" }, + { name = "pyproject-hooks", marker = "python_full_version < '3.9'" }, + { name = "tomli", marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/46/aeab111f8e06793e4f0e421fcad593d547fb8313b50990f31681ee2fb1ad/build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7", size = 46701, upload-time = "2024-10-06T17:22:25.251Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/c2/80633736cd183ee4a62107413def345f7e6e3c01563dbca1417363cf957e/build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5", size = 22950, upload-time = "2024-10-06T17:22:23.299Z" }, +] + +[[package]] +name = "build" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version >= '3.9' and os_name == 'nt'" }, + { name = "importlib-metadata", version = "8.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.10.2'" }, + { name = "packaging", marker = "python_full_version >= '3.9'" }, + { name = "pyproject-hooks", marker = "python_full_version >= '3.9'" }, + { name = "tomli", marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/1c/23e33405a7c9eac261dff640926b8b5adaed6a6eb3e1767d441ed611d0c0/build-1.3.0.tar.gz", hash = "sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397", size = 48544, upload-time = "2025-08-01T21:27:09.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/8c/2b30c12155ad8de0cf641d76a8b396a16d2c36bc6d50b621a62b7c4567c1/build-1.3.0-py3-none-any.whl", hash = "sha256:7145f0b5061ba90a1500d60bd1b13ca0a8a4cebdd0cc16ed8adf1c0e739f43b4", size = 23382, upload-time = "2025-08-01T21:27:07.844Z" }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "pycparser", marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024, upload-time = "2024-09-04T20:43:34.186Z" }, + { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188, upload-time = "2024-09-04T20:43:36.286Z" }, + { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571, upload-time = "2024-09-04T20:43:38.586Z" }, + { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687, upload-time = "2024-09-04T20:43:40.084Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211, upload-time = "2024-09-04T20:43:41.526Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325, upload-time = "2024-09-04T20:43:43.117Z" }, + { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784, upload-time = "2024-09-04T20:43:45.256Z" }, + { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564, upload-time = "2024-09-04T20:43:46.779Z" }, + { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, + { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, + { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, + { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, + { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/c2/5b/f1523dd545f92f7df468e5f653ffa4df30ac222f3c884e51e139878f1cb5/cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", size = 425932, upload-time = "2024-09-04T20:44:49.491Z" }, + { url = "https://files.pythonhosted.org/packages/53/93/7e547ab4105969cc8c93b38a667b82a835dd2cc78f3a7dad6130cfd41e1d/cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", size = 448585, upload-time = "2024-09-04T20:44:51.671Z" }, + { url = "https://files.pythonhosted.org/packages/56/c4/a308f2c332006206bb511de219efeff090e9d63529ba0a77aae72e82248b/cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", size = 456268, upload-time = "2024-09-04T20:44:53.51Z" }, + { url = "https://files.pythonhosted.org/packages/ca/5b/b63681518265f2f4060d2b60755c1c77ec89e5e045fc3773b72735ddaad5/cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", size = 436592, upload-time = "2024-09-04T20:44:55.085Z" }, + { url = "https://files.pythonhosted.org/packages/bb/19/b51af9f4a4faa4a8ac5a0e5d5c2522dcd9703d07fac69da34a36c4d960d3/cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", size = 446512, upload-time = "2024-09-04T20:44:57.135Z" }, + { url = "https://files.pythonhosted.org/packages/ed/65/25a8dc32c53bf5b7b6c2686b42ae2ad58743f7ff644844af7cdb29b49361/cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", size = 424910, upload-time = "2024-09-04T20:45:05.315Z" }, + { url = "https://files.pythonhosted.org/packages/42/7a/9d086fab7c66bd7c4d0f27c57a1b6b068ced810afc498cc8c49e0088661c/cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", size = 447200, upload-time = "2024-09-04T20:45:06.903Z" }, + { url = "https://files.pythonhosted.org/packages/da/63/1785ced118ce92a993b0ec9e0d0ac8dc3e5dbfbcaa81135be56c69cabbb6/cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", size = 454565, upload-time = "2024-09-04T20:45:08.975Z" }, + { url = "https://files.pythonhosted.org/packages/74/06/90b8a44abf3556599cdec107f7290277ae8901a58f75e6fe8f970cd72418/cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", size = 435635, upload-time = "2024-09-04T20:45:10.64Z" }, + { url = "https://files.pythonhosted.org/packages/bd/62/a1f468e5708a70b1d86ead5bab5520861d9c7eacce4a885ded9faa7729c3/cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", size = 445218, upload-time = "2024-09-04T20:45:12.366Z" }, + { url = "https://files.pythonhosted.org/packages/5b/95/b34462f3ccb09c2594aa782d90a90b045de4ff1f70148ee79c69d37a0a5a/cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", size = 460486, upload-time = "2024-09-04T20:45:13.935Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fc/a1e4bebd8d680febd29cf6c8a40067182b64f00c7d105f8f26b5bc54317b/cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", size = 437911, upload-time = "2024-09-04T20:45:15.696Z" }, + { url = "https://files.pythonhosted.org/packages/e6/c3/21cab7a6154b6a5ea330ae80de386e7665254835b9e98ecc1340b3a7de9a/cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", size = 460632, upload-time = "2024-09-04T20:45:17.284Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "pycparser", marker = "python_full_version >= '3.9' and implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/9b/13/c92e36358fbcc39cf0962e83223c9522154ee8630e1df7c0b3a39a8124e2/cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c", size = 208813, upload-time = "2025-09-08T23:23:51.263Z" }, + { url = "https://files.pythonhosted.org/packages/15/12/a7a79bd0df4c3bff744b2d7e52cc1b68d5e7e427b384252c42366dc1ecbc/cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165", size = 216498, upload-time = "2025-09-08T23:23:52.494Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/5c51c1c7600bdd7ed9a24a203ec255dccdd0ebf4527f7b922a0bde2fb6ed/cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534", size = 203243, upload-time = "2025-09-08T23:23:53.836Z" }, + { url = "https://files.pythonhosted.org/packages/32/f2/81b63e288295928739d715d00952c8c6034cb6c6a516b17d37e0c8be5600/cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f", size = 203158, upload-time = "2025-09-08T23:23:55.169Z" }, + { url = "https://files.pythonhosted.org/packages/1f/74/cc4096ce66f5939042ae094e2e96f53426a979864aa1f96a621ad128be27/cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63", size = 216548, upload-time = "2025-09-08T23:23:56.506Z" }, + { url = "https://files.pythonhosted.org/packages/e8/be/f6424d1dc46b1091ffcc8964fa7c0ab0cd36839dd2761b49c90481a6ba1b/cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2", size = 218897, upload-time = "2025-09-08T23:23:57.825Z" }, + { url = "https://files.pythonhosted.org/packages/f7/e0/dda537c2309817edf60109e39265f24f24aa7f050767e22c98c53fe7f48b/cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65", size = 211249, upload-time = "2025-09-08T23:23:59.139Z" }, + { url = "https://files.pythonhosted.org/packages/2b/e7/7c769804eb75e4c4b35e658dba01de1640a351a9653c3d49ca89d16ccc91/cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322", size = 218041, upload-time = "2025-09-08T23:24:00.496Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/98/f3b8013223728a99b908c9344da3aa04ee6e3fa235f19409033eda92fb78/charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72", size = 207695, upload-time = "2025-08-09T07:55:36.452Z" }, + { url = "https://files.pythonhosted.org/packages/21/40/5188be1e3118c82dcb7c2a5ba101b783822cfb413a0268ed3be0468532de/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe", size = 147153, upload-time = "2025-08-09T07:55:38.467Z" }, + { url = "https://files.pythonhosted.org/packages/37/60/5d0d74bc1e1380f0b72c327948d9c2aca14b46a9efd87604e724260f384c/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601", size = 160428, upload-time = "2025-08-09T07:55:40.072Z" }, + { url = "https://files.pythonhosted.org/packages/85/9a/d891f63722d9158688de58d050c59dc3da560ea7f04f4c53e769de5140f5/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c", size = 157627, upload-time = "2025-08-09T07:55:41.706Z" }, + { url = "https://files.pythonhosted.org/packages/65/1a/7425c952944a6521a9cfa7e675343f83fd82085b8af2b1373a2409c683dc/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2", size = 152388, upload-time = "2025-08-09T07:55:43.262Z" }, + { url = "https://files.pythonhosted.org/packages/f0/c9/a2c9c2a355a8594ce2446085e2ec97fd44d323c684ff32042e2a6b718e1d/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0", size = 150077, upload-time = "2025-08-09T07:55:44.903Z" }, + { url = "https://files.pythonhosted.org/packages/3b/38/20a1f44e4851aa1c9105d6e7110c9d020e093dfa5836d712a5f074a12bf7/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0", size = 161631, upload-time = "2025-08-09T07:55:46.346Z" }, + { url = "https://files.pythonhosted.org/packages/a4/fa/384d2c0f57edad03d7bec3ebefb462090d8905b4ff5a2d2525f3bb711fac/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0", size = 159210, upload-time = "2025-08-09T07:55:47.539Z" }, + { url = "https://files.pythonhosted.org/packages/33/9e/eca49d35867ca2db336b6ca27617deed4653b97ebf45dfc21311ce473c37/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a", size = 153739, upload-time = "2025-08-09T07:55:48.744Z" }, + { url = "https://files.pythonhosted.org/packages/2a/91/26c3036e62dfe8de8061182d33be5025e2424002125c9500faff74a6735e/charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f", size = 99825, upload-time = "2025-08-09T07:55:50.305Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/f05db471f81af1fa01839d44ae2a8bfeec8d2a8b4590f16c4e7393afd323/charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669", size = 107452, upload-time = "2025-08-09T07:55:51.461Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b5/991245018615474a60965a7c9cd2b4efbaabd16d582a5547c47ee1c7730b/charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b", size = 204483, upload-time = "2025-08-09T07:55:53.12Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2a/ae245c41c06299ec18262825c1569c5d3298fc920e4ddf56ab011b417efd/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64", size = 145520, upload-time = "2025-08-09T07:55:54.712Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a4/b3b6c76e7a635748c4421d2b92c7b8f90a432f98bda5082049af37ffc8e3/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91", size = 158876, upload-time = "2025-08-09T07:55:56.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e6/63bb0e10f90a8243c5def74b5b105b3bbbfb3e7bb753915fe333fb0c11ea/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f", size = 156083, upload-time = "2025-08-09T07:55:57.582Z" }, + { url = "https://files.pythonhosted.org/packages/87/df/b7737ff046c974b183ea9aa111b74185ac8c3a326c6262d413bd5a1b8c69/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07", size = 150295, upload-time = "2025-08-09T07:55:59.147Z" }, + { url = "https://files.pythonhosted.org/packages/61/f1/190d9977e0084d3f1dc169acd060d479bbbc71b90bf3e7bf7b9927dec3eb/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30", size = 148379, upload-time = "2025-08-09T07:56:00.364Z" }, + { url = "https://files.pythonhosted.org/packages/4c/92/27dbe365d34c68cfe0ca76f1edd70e8705d82b378cb54ebbaeabc2e3029d/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14", size = 160018, upload-time = "2025-08-09T07:56:01.678Z" }, + { url = "https://files.pythonhosted.org/packages/99/04/baae2a1ea1893a01635d475b9261c889a18fd48393634b6270827869fa34/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c", size = 157430, upload-time = "2025-08-09T07:56:02.87Z" }, + { url = "https://files.pythonhosted.org/packages/2f/36/77da9c6a328c54d17b960c89eccacfab8271fdaaa228305330915b88afa9/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae", size = 151600, upload-time = "2025-08-09T07:56:04.089Z" }, + { url = "https://files.pythonhosted.org/packages/64/d4/9eb4ff2c167edbbf08cdd28e19078bf195762e9bd63371689cab5ecd3d0d/charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849", size = 99616, upload-time = "2025-08-09T07:56:05.658Z" }, + { url = "https://files.pythonhosted.org/packages/f4/9c/996a4a028222e7761a96634d1820de8a744ff4327a00ada9c8942033089b/charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c", size = 107108, upload-time = "2025-08-09T07:56:07.176Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/22/82/63a45bfc36f73efe46731a3a71cb84e2112f7e0b049507025ce477f0f052/charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c", size = 198805, upload-time = "2025-08-09T07:56:56.496Z" }, + { url = "https://files.pythonhosted.org/packages/0c/52/8b0c6c3e53f7e546a5e49b9edb876f379725914e1130297f3b423c7b71c5/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b", size = 142862, upload-time = "2025-08-09T07:56:57.751Z" }, + { url = "https://files.pythonhosted.org/packages/59/c0/a74f3bd167d311365e7973990243f32c35e7a94e45103125275b9e6c479f/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4", size = 155104, upload-time = "2025-08-09T07:56:58.984Z" }, + { url = "https://files.pythonhosted.org/packages/1a/79/ae516e678d6e32df2e7e740a7be51dc80b700e2697cb70054a0f1ac2c955/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b", size = 152598, upload-time = "2025-08-09T07:57:00.201Z" }, + { url = "https://files.pythonhosted.org/packages/00/bd/ef9c88464b126fa176f4ef4a317ad9b6f4d30b2cffbc43386062367c3e2c/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9", size = 147391, upload-time = "2025-08-09T07:57:01.441Z" }, + { url = "https://files.pythonhosted.org/packages/7a/03/cbb6fac9d3e57f7e07ce062712ee80d80a5ab46614684078461917426279/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb", size = 145037, upload-time = "2025-08-09T07:57:02.638Z" }, + { url = "https://files.pythonhosted.org/packages/64/d1/f9d141c893ef5d4243bc75c130e95af8fd4bc355beff06e9b1e941daad6e/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a", size = 156425, upload-time = "2025-08-09T07:57:03.898Z" }, + { url = "https://files.pythonhosted.org/packages/c5/35/9c99739250742375167bc1b1319cd1cec2bf67438a70d84b2e1ec4c9daa3/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942", size = 153734, upload-time = "2025-08-09T07:57:05.549Z" }, + { url = "https://files.pythonhosted.org/packages/50/10/c117806094d2c956ba88958dab680574019abc0c02bcf57b32287afca544/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b", size = 148551, upload-time = "2025-08-09T07:57:06.823Z" }, + { url = "https://files.pythonhosted.org/packages/61/c5/dc3ba772489c453621ffc27e8978a98fe7e41a93e787e5e5bde797f1dddb/charset_normalizer-3.4.3-cp38-cp38-win32.whl", hash = "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557", size = 98459, upload-time = "2025-08-09T07:57:08.031Z" }, + { url = "https://files.pythonhosted.org/packages/05/35/bb59b1cd012d7196fc81c2f5879113971efc226a63812c9cf7f89fe97c40/charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40", size = 105887, upload-time = "2025-08-09T07:57:09.401Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ca/9a0983dd5c8e9733565cf3db4df2b0a2e9a82659fd8aa2a868ac6e4a991f/charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05", size = 207520, upload-time = "2025-08-09T07:57:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/39/c6/99271dc37243a4f925b09090493fb96c9333d7992c6187f5cfe5312008d2/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e", size = 147307, upload-time = "2025-08-09T07:57:12.4Z" }, + { url = "https://files.pythonhosted.org/packages/e4/69/132eab043356bba06eb333cc2cc60c6340857d0a2e4ca6dc2b51312886b3/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99", size = 160448, upload-time = "2025-08-09T07:57:13.712Z" }, + { url = "https://files.pythonhosted.org/packages/04/9a/914d294daa4809c57667b77470533e65def9c0be1ef8b4c1183a99170e9d/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7", size = 157758, upload-time = "2025-08-09T07:57:14.979Z" }, + { url = "https://files.pythonhosted.org/packages/b0/a8/6f5bcf1bcf63cb45625f7c5cadca026121ff8a6c8a3256d8d8cd59302663/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7", size = 152487, upload-time = "2025-08-09T07:57:16.332Z" }, + { url = "https://files.pythonhosted.org/packages/c4/72/d3d0e9592f4e504f9dea08b8db270821c909558c353dc3b457ed2509f2fb/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19", size = 150054, upload-time = "2025-08-09T07:57:17.576Z" }, + { url = "https://files.pythonhosted.org/packages/20/30/5f64fe3981677fe63fa987b80e6c01042eb5ff653ff7cec1b7bd9268e54e/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312", size = 161703, upload-time = "2025-08-09T07:57:20.012Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ef/dd08b2cac9284fd59e70f7d97382c33a3d0a926e45b15fc21b3308324ffd/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc", size = 159096, upload-time = "2025-08-09T07:57:21.329Z" }, + { url = "https://files.pythonhosted.org/packages/45/8c/dcef87cfc2b3f002a6478f38906f9040302c68aebe21468090e39cde1445/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34", size = 153852, upload-time = "2025-08-09T07:57:22.608Z" }, + { url = "https://files.pythonhosted.org/packages/63/86/9cbd533bd37883d467fcd1bd491b3547a3532d0fbb46de2b99feeebf185e/charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432", size = 99840, upload-time = "2025-08-09T07:57:23.883Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d6/7e805c8e5c46ff9729c49950acc4ee0aeb55efb8b3a56687658ad10c3216/charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca", size = 107438, upload-time = "2025-08-09T07:57:25.287Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] + +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cryptography" +version = "46.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' and platform_python_implementation != 'PyPy'" }, + { name = "cffi", version = "2.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and platform_python_implementation != 'PyPy'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/62/e3664e6ffd7743e1694b244dde70b43a394f6f7fbcacf7014a8ff5197c73/cryptography-46.0.1.tar.gz", hash = "sha256:ed570874e88f213437f5cf758f9ef26cbfc3f336d889b1e592ee11283bb8d1c7", size = 749198, upload-time = "2025-09-17T00:10:35.797Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/59/9ae689a25047e0601adfcb159ec4f83c0b4149fdb5c3030cc94cd218141d/cryptography-46.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0ff483716be32690c14636e54a1f6e2e1b7bf8e22ca50b989f88fa1b2d287080", size = 4308182, upload-time = "2025-09-17T00:08:39.388Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ee/ca6cc9df7118f2fcd142c76b1da0f14340d77518c05b1ebfbbabca6b9e7d/cryptography-46.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9873bf7c1f2a6330bdfe8621e7ce64b725784f9f0c3a6a55c3047af5849f920e", size = 4572393, upload-time = "2025-09-17T00:08:41.663Z" }, + { url = "https://files.pythonhosted.org/packages/7f/a3/0f5296f63815d8e985922b05c31f77ce44787b3127a67c0b7f70f115c45f/cryptography-46.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0dfb7c88d4462a0cfdd0d87a3c245a7bc3feb59de101f6ff88194f740f72eda6", size = 4308400, upload-time = "2025-09-17T00:08:43.559Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8c/74fcda3e4e01be1d32775d5b4dd841acaac3c1b8fa4d0774c7ac8d52463d/cryptography-46.0.1-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e22801b61613ebdebf7deb18b507919e107547a1d39a3b57f5f855032dd7cfb8", size = 4015786, upload-time = "2025-09-17T00:08:45.758Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b8/85d23287baeef273b0834481a3dd55bbed3a53587e3b8d9f0898235b8f91/cryptography-46.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:757af4f6341ce7a1e47c326ca2a81f41d236070217e5fbbad61bbfe299d55d28", size = 4982606, upload-time = "2025-09-17T00:08:47.602Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d3/de61ad5b52433b389afca0bc70f02a7a1f074651221f599ce368da0fe437/cryptography-46.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f7a24ea78de345cfa7f6a8d3bde8b242c7fac27f2bd78fa23474ca38dfaeeab9", size = 4604234, upload-time = "2025-09-17T00:08:49.879Z" }, + { url = "https://files.pythonhosted.org/packages/dc/1f/dbd4d6570d84748439237a7478d124ee0134bf166ad129267b7ed8ea6d22/cryptography-46.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e8776dac9e660c22241b6587fae51a67b4b0147daa4d176b172c3ff768ad736", size = 4307669, upload-time = "2025-09-17T00:08:52.321Z" }, + { url = "https://files.pythonhosted.org/packages/ec/fd/ca0a14ce7f0bfe92fa727aacaf2217eb25eb7e4ed513b14d8e03b26e63ed/cryptography-46.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9f40642a140c0c8649987027867242b801486865277cbabc8c6059ddef16dc8b", size = 4947579, upload-time = "2025-09-17T00:08:54.697Z" }, + { url = "https://files.pythonhosted.org/packages/89/6b/09c30543bb93401f6f88fce556b3bdbb21e55ae14912c04b7bf355f5f96c/cryptography-46.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:449ef2b321bec7d97ef2c944173275ebdab78f3abdd005400cc409e27cd159ab", size = 4603669, upload-time = "2025-09-17T00:08:57.16Z" }, + { url = "https://files.pythonhosted.org/packages/23/9a/38cb01cb09ce0adceda9fc627c9cf98eb890fc8d50cacbe79b011df20f8a/cryptography-46.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2dd339ba3345b908fa3141ddba4025568fa6fd398eabce3ef72a29ac2d73ad75", size = 4435828, upload-time = "2025-09-17T00:08:59.606Z" }, + { url = "https://files.pythonhosted.org/packages/0f/53/435b5c36a78d06ae0bef96d666209b0ecd8f8181bfe4dda46536705df59e/cryptography-46.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7411c910fb2a412053cf33cfad0153ee20d27e256c6c3f14d7d7d1d9fec59fd5", size = 4709553, upload-time = "2025-09-17T00:09:01.832Z" }, + { url = "https://files.pythonhosted.org/packages/26/34/0ff0bb2d2c79f25a2a63109f3b76b9108a906dd2a2eb5c1d460b9938adbb/cryptography-46.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9babb7818fdd71394e576cf26c5452df77a355eac1a27ddfa24096665a27f8fd", size = 4293515, upload-time = "2025-09-17T00:09:12.861Z" }, + { url = "https://files.pythonhosted.org/packages/df/b7/d4f848aee24ecd1be01db6c42c4a270069a4f02a105d9c57e143daf6cf0f/cryptography-46.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9f2c4cc63be3ef43c0221861177cee5d14b505cd4d4599a89e2cd273c4d3542a", size = 4545619, upload-time = "2025-09-17T00:09:15.397Z" }, + { url = "https://files.pythonhosted.org/packages/44/a5/42fedefc754fd1901e2d95a69815ea4ec8a9eed31f4c4361fcab80288661/cryptography-46.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:41c281a74df173876da1dc9a9b6953d387f06e3d3ed9284e3baae3ab3f40883a", size = 4299160, upload-time = "2025-09-17T00:09:17.155Z" }, + { url = "https://files.pythonhosted.org/packages/86/a1/cd21174f56e769c831fbbd6399a1b7519b0ff6280acec1b826d7b072640c/cryptography-46.0.1-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0a17377fa52563d730248ba1f68185461fff36e8bc75d8787a7dd2e20a802b7a", size = 3994491, upload-time = "2025-09-17T00:09:18.971Z" }, + { url = "https://files.pythonhosted.org/packages/8d/2f/a8cbfa1c029987ddc746fd966711d4fa71efc891d37fbe9f030fe5ab4eec/cryptography-46.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:0d1922d9280e08cde90b518a10cd66831f632960a8d08cb3418922d83fce6f12", size = 4960157, upload-time = "2025-09-17T00:09:20.923Z" }, + { url = "https://files.pythonhosted.org/packages/67/ae/63a84e6789e0d5a2502edf06b552bcb0fa9ff16147265d5c44a211942abe/cryptography-46.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:af84e8e99f1a82cea149e253014ea9dc89f75b82c87bb6c7242203186f465129", size = 4577263, upload-time = "2025-09-17T00:09:23.356Z" }, + { url = "https://files.pythonhosted.org/packages/ef/8f/1b9fa8e92bd9cbcb3b7e1e593a5232f2c1e6f9bd72b919c1a6b37d315f92/cryptography-46.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ef648d2c690703501714588b2ba640facd50fd16548133b11b2859e8655a69da", size = 4298703, upload-time = "2025-09-17T00:09:25.566Z" }, + { url = "https://files.pythonhosted.org/packages/c3/af/bb95db070e73fea3fae31d8a69ac1463d89d1c084220f549b00dd01094a8/cryptography-46.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:e94eb5fa32a8a9f9bf991f424f002913e3dd7c699ef552db9b14ba6a76a6313b", size = 4926363, upload-time = "2025-09-17T00:09:27.451Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3b/d8fb17ffeb3a83157a1cc0aa5c60691d062aceecba09c2e5e77ebfc1870c/cryptography-46.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:534b96c0831855e29fc3b069b085fd185aa5353033631a585d5cd4dd5d40d657", size = 4576958, upload-time = "2025-09-17T00:09:29.924Z" }, + { url = "https://files.pythonhosted.org/packages/d9/46/86bc3a05c10c8aa88c8ae7e953a8b4e407c57823ed201dbcba55c4d655f4/cryptography-46.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9b55038b5c6c47559aa33626d8ecd092f354e23de3c6975e4bb205df128a2a0", size = 4422507, upload-time = "2025-09-17T00:09:32.222Z" }, + { url = "https://files.pythonhosted.org/packages/a8/4e/387e5a21dfd2b4198e74968a541cfd6128f66f8ec94ed971776e15091ac3/cryptography-46.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ec13b7105117dbc9afd023300fb9954d72ca855c274fe563e72428ece10191c0", size = 4683964, upload-time = "2025-09-17T00:09:34.118Z" }, + { url = "https://files.pythonhosted.org/packages/56/3e/13ce6eab9ad6eba1b15a7bd476f005a4c1b3f299f4c2f32b22408b0edccf/cryptography-46.0.1-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9ed64e5083fa806709e74fc5ea067dfef9090e5b7a2320a49be3c9df3583a2d8", size = 4301110, upload-time = "2025-09-17T00:09:45.614Z" }, + { url = "https://files.pythonhosted.org/packages/a2/67/65dc233c1ddd688073cf7b136b06ff4b84bf517ba5529607c9d79720fc67/cryptography-46.0.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:341fb7a26bc9d6093c1b124b9f13acc283d2d51da440b98b55ab3f79f2522ead", size = 4562369, upload-time = "2025-09-17T00:09:47.601Z" }, + { url = "https://files.pythonhosted.org/packages/17/db/d64ae4c6f4e98c3dac5bf35dd4d103f4c7c345703e43560113e5e8e31b2b/cryptography-46.0.1-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6ef1488967e729948d424d09c94753d0167ce59afba8d0f6c07a22b629c557b2", size = 4302126, upload-time = "2025-09-17T00:09:49.335Z" }, + { url = "https://files.pythonhosted.org/packages/3d/19/5f1eea17d4805ebdc2e685b7b02800c4f63f3dd46cfa8d4c18373fea46c8/cryptography-46.0.1-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7823bc7cdf0b747ecfb096d004cc41573c2f5c7e3a29861603a2871b43d3ef32", size = 4009431, upload-time = "2025-09-17T00:09:51.239Z" }, + { url = "https://files.pythonhosted.org/packages/81/b5/229ba6088fe7abccbfe4c5edb96c7a5ad547fac5fdd0d40aa6ea540b2985/cryptography-46.0.1-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:f736ab8036796f5a119ff8211deda416f8c15ce03776db704a7a4e17381cb2ef", size = 4980739, upload-time = "2025-09-17T00:09:54.181Z" }, + { url = "https://files.pythonhosted.org/packages/3a/9c/50aa38907b201e74bc43c572f9603fa82b58e831bd13c245613a23cff736/cryptography-46.0.1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:e46710a240a41d594953012213ea8ca398cd2448fbc5d0f1be8160b5511104a0", size = 4592289, upload-time = "2025-09-17T00:09:56.731Z" }, + { url = "https://files.pythonhosted.org/packages/5a/33/229858f8a5bb22f82468bb285e9f4c44a31978d5f5830bb4ea1cf8a4e454/cryptography-46.0.1-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:84ef1f145de5aee82ea2447224dc23f065ff4cc5791bb3b506615957a6ba8128", size = 4301815, upload-time = "2025-09-17T00:09:58.548Z" }, + { url = "https://files.pythonhosted.org/packages/52/cb/b76b2c87fbd6ed4a231884bea3ce073406ba8e2dae9defad910d33cbf408/cryptography-46.0.1-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9394c7d5a7565ac5f7d9ba38b2617448eba384d7b107b262d63890079fad77ca", size = 4943251, upload-time = "2025-09-17T00:10:00.475Z" }, + { url = "https://files.pythonhosted.org/packages/94/0f/f66125ecf88e4cb5b8017ff43f3a87ede2d064cb54a1c5893f9da9d65093/cryptography-46.0.1-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ed957044e368ed295257ae3d212b95456bd9756df490e1ac4538857f67531fcc", size = 4591247, upload-time = "2025-09-17T00:10:02.874Z" }, + { url = "https://files.pythonhosted.org/packages/f6/22/9f3134ae436b63b463cfdf0ff506a0570da6873adb4bf8c19b8a5b4bac64/cryptography-46.0.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f7de12fa0eee6234de9a9ce0ffcfa6ce97361db7a50b09b65c63ac58e5f22fc7", size = 4428534, upload-time = "2025-09-17T00:10:04.994Z" }, + { url = "https://files.pythonhosted.org/packages/89/39/e6042bcb2638650b0005c752c38ea830cbfbcbb1830e4d64d530000aa8dc/cryptography-46.0.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7fab1187b6c6b2f11a326f33b036f7168f5b996aedd0c059f9738915e4e8f53a", size = 4699541, upload-time = "2025-09-17T00:10:06.925Z" }, + { url = "https://files.pythonhosted.org/packages/db/32/6fc7250280920418651640d76cee34d91c1e0601d73acd44364570cf041f/cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0ca4be2af48c24df689a150d9cd37404f689e2968e247b6b8ff09bff5bcd786f", size = 4249030, upload-time = "2025-09-17T00:10:22.396Z" }, + { url = "https://files.pythonhosted.org/packages/32/33/8d5398b2da15a15110b2478480ab512609f95b45ead3a105c9a9c76f9980/cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:13e67c4d3fb8b6bc4ef778a7ccdd8df4cd15b4bcc18f4239c8440891a11245cc", size = 4528009, upload-time = "2025-09-17T00:10:24.418Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1c/4012edad2a8977ab386c36b6e21f5065974d37afa3eade83a9968cba4855/cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:15b5fd9358803b0d1cc42505a18d8bca81dabb35b5cfbfea1505092e13a9d96d", size = 4248902, upload-time = "2025-09-17T00:10:26.255Z" }, + { url = "https://files.pythonhosted.org/packages/58/a3/257cd5ae677302de8fa066fca9de37128f6729d1e63c04dd6a15555dd450/cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e34da95e29daf8a71cb2841fd55df0511539a6cdf33e6f77c1e95e44006b9b46", size = 4527150, upload-time = "2025-09-17T00:10:28.28Z" }, +] + +[[package]] +name = "docutils" +version = "0.20.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/53/a5da4f2c5739cf66290fac1431ee52aff6851c7c8ffd8264f13affd7bcdd/docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b", size = 2058365, upload-time = "2023-05-16T23:39:19.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/87/f238c0670b94533ac0353a4e2a1a771a0cc73277b88bff23d3ae35a256c1/docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", size = 572666, upload-time = "2023-05-16T23:39:15.976Z" }, +] + +[[package]] +name = "docutils" +version = "0.22.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/c0/89fe6215b443b919cb98a5002e107cb5026854ed1ccb6b5833e0768419d1/docutils-0.22.2.tar.gz", hash = "sha256:9fdb771707c8784c8f2728b67cb2c691305933d68137ef95a75db5f4dfbc213d", size = 2289092, upload-time = "2025-09-20T17:55:47.994Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/dd/f95350e853a4468ec37478414fc04ae2d61dad7a947b3015c3dcc51a09b9/docutils-0.22.2-py3-none-any.whl", hash = "sha256:b0e98d679283fc3bb0ead8a5da7f501baa632654e7056e9c5846842213d674d8", size = 632667, upload-time = "2025-09-20T17:55:43.052Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.27.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "anyio", version = "4.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "certifi", marker = "python_full_version < '3.9'" }, + { name = "httpcore", marker = "python_full_version < '3.9'" }, + { name = "idna", marker = "python_full_version < '3.9'" }, + { name = "sniffio", marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189, upload-time = "2024-08-27T12:54:01.334Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395, upload-time = "2024-08-27T12:53:59.653Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "anyio", version = "4.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "certifi", marker = "python_full_version >= '3.9'" }, + { name = "httpcore", marker = "python_full_version >= '3.9'" }, + { name = "idna", marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "id" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests", version = "2.32.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/11/102da08f88412d875fa2f1a9a469ff7ad4c874b0ca6fed0048fe385bdb3d/id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d", size = 15237, upload-time = "2024-12-04T19:53:05.575Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/cb/18326d2d89ad3b0dd143da971e77afd1e6ca6674f1b1c3df4b6bec6279fc/id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658", size = 13611, upload-time = "2024-12-04T19:53:03.02Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.5.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "zipp", version = "3.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", size = 55304, upload-time = "2024-09-11T14:56:08.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514, upload-time = "2024-09-11T14:56:07.019Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.7.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "zipp", version = "3.23.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, +] + +[[package]] +name = "importlib-resources" +version = "6.4.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp", version = "3.20.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/be/f3e8c6081b684f176b761e6a2fef02a0be939740ed6f54109a2951d806f3/importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", size = 43372, upload-time = "2024-09-09T17:03:14.677Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717", size = 36115, upload-time = "2024-09-09T17:03:13.39Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "isort" +version = "5.13.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303, upload-time = "2023-12-13T20:37:26.124Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" }, +] + +[[package]] +name = "isort" +version = "6.0.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/b8/21/1e2a441f74a653a144224d7d21afe8f4169e6c7c20bb13aec3a2dc3815e0/isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450", size = 821955, upload-time = "2025-02-26T21:13:16.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615", size = 94186, upload-time = "2025-02-26T21:13:14.911Z" }, +] + +[[package]] +name = "jaraco-classes" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "more-itertools", version = "10.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "more-itertools", version = "10.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" }, +] + +[[package]] +name = "jaraco-context" +version = "6.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "backports-tarfile", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", size = 13912, upload-time = "2024-08-20T03:39:27.358Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", size = 6825, upload-time = "2024-08-20T03:39:25.966Z" }, +] + +[[package]] +name = "jaraco-functools" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "more-itertools", version = "10.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/23/9894b3df5d0a6eb44611c36aec777823fc2e07740dabbd0b810e19594013/jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", size = 19159, upload-time = "2024-09-27T19:47:09.122Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649", size = 10187, upload-time = "2024-09-27T19:47:07.14Z" }, +] + +[[package]] +name = "jaraco-functools" +version = "4.3.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "more-itertools", version = "10.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f7/ed/1aa2d585304ec07262e1a83a9889880701079dde796ac7b1d1826f40c63d/jaraco_functools-4.3.0.tar.gz", hash = "sha256:cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294", size = 19755, upload-time = "2025-08-18T20:05:09.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/09/726f168acad366b11e420df31bf1c702a54d373a83f968d94141a8c3fde0/jaraco_functools-4.3.0-py3-none-any.whl", hash = "sha256:227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8", size = 10408, upload-time = "2025-08-18T20:05:08.69Z" }, +] + +[[package]] +name = "jeepney" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe", version = "2.1.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "markupsafe", version = "3.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "keyring" +version = "25.5.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "importlib-metadata", version = "8.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "importlib-resources", marker = "python_full_version < '3.9'" }, + { name = "jaraco-classes", marker = "python_full_version < '3.9'" }, + { name = "jaraco-context", marker = "python_full_version < '3.9'" }, + { name = "jaraco-functools", version = "4.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "jeepney", marker = "python_full_version < '3.9' and sys_platform == 'linux'" }, + { name = "pywin32-ctypes", marker = "python_full_version < '3.9' and sys_platform == 'win32'" }, + { name = "secretstorage", version = "3.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' and sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/24/64447b13df6a0e2797b586dad715766d756c932ce8ace7f67bd384d76ae0/keyring-25.5.0.tar.gz", hash = "sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6", size = 62675, upload-time = "2024-10-26T15:40:12.344Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/c9/353c156fa2f057e669106e5d6bcdecf85ef8d3536ce68ca96f18dc7b6d6f/keyring-25.5.0-py3-none-any.whl", hash = "sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741", size = 39096, upload-time = "2024-10-26T15:40:10.296Z" }, +] + +[[package]] +name = "keyring" +version = "25.6.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "importlib-metadata", version = "8.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.12'" }, + { name = "jaraco-classes", marker = "python_full_version >= '3.9'" }, + { name = "jaraco-context", marker = "python_full_version >= '3.9'" }, + { name = "jaraco-functools", version = "4.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "jeepney", marker = "python_full_version >= '3.9' and sys_platform == 'linux'" }, + { name = "pywin32-ctypes", marker = "python_full_version >= '3.9' and sys_platform == 'win32'" }, + { name = "secretstorage", version = "3.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*' and sys_platform == 'linux'" }, + { name = "secretstorage", version = "3.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/09/d904a6e96f76ff214be59e7aa6ef7190008f52a0ab6689760a98de0bf37d/keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", size = 62750, upload-time = "2024-12-25T15:26:45.782Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd", size = 39085, upload-time = "2024-12-25T15:26:44.377Z" }, +] + +[[package]] +name = "markdown" +version = "3.7" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "importlib-metadata", version = "8.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086, upload-time = "2024-08-16T15:55:17.812Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349, upload-time = "2024-08-16T15:55:16.176Z" }, +] + +[[package]] +name = "markdown" +version = "3.9" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "importlib-metadata", version = "8.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.9.*'", + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "mdurl", marker = "python_full_version < '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", +] +dependencies = [ + { name = "mdurl", marker = "python_full_version >= '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markupsafe" +version = "2.1.5" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384, upload-time = "2024-02-02T16:31:22.863Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/54/ad5eb37bf9d51800010a74e4665425831a9db4e7c4e0fde4352e391e808e/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", size = 18206, upload-time = "2024-02-02T16:30:04.105Z" }, + { url = "https://files.pythonhosted.org/packages/6a/4a/a4d49415e600bacae038c67f9fecc1d5433b9d3c71a4de6f33537b89654c/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", size = 14079, upload-time = "2024-02-02T16:30:06.5Z" }, + { url = "https://files.pythonhosted.org/packages/0a/7b/85681ae3c33c385b10ac0f8dd025c30af83c78cec1c37a6aa3b55e67f5ec/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", size = 26620, upload-time = "2024-02-02T16:30:08.31Z" }, + { url = "https://files.pythonhosted.org/packages/7c/52/2b1b570f6b8b803cef5ac28fdf78c0da318916c7d2fe9402a84d591b394c/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", size = 25818, upload-time = "2024-02-02T16:30:09.577Z" }, + { url = "https://files.pythonhosted.org/packages/29/fe/a36ba8c7ca55621620b2d7c585313efd10729e63ef81e4e61f52330da781/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", size = 25493, upload-time = "2024-02-02T16:30:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/60/ae/9c60231cdfda003434e8bd27282b1f4e197ad5a710c14bee8bea8a9ca4f0/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", size = 30630, upload-time = "2024-02-02T16:30:13.144Z" }, + { url = "https://files.pythonhosted.org/packages/65/dc/1510be4d179869f5dafe071aecb3f1f41b45d37c02329dfba01ff59e5ac5/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", size = 29745, upload-time = "2024-02-02T16:30:14.222Z" }, + { url = "https://files.pythonhosted.org/packages/30/39/8d845dd7d0b0613d86e0ef89549bfb5f61ed781f59af45fc96496e897f3a/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", size = 30021, upload-time = "2024-02-02T16:30:16.032Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5c/356a6f62e4f3c5fbf2602b4771376af22a3b16efa74eb8716fb4e328e01e/MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", size = 16659, upload-time = "2024-02-02T16:30:17.079Z" }, + { url = "https://files.pythonhosted.org/packages/69/48/acbf292615c65f0604a0c6fc402ce6d8c991276e16c80c46a8f758fbd30c/MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", size = 17213, upload-time = "2024-02-02T16:30:18.251Z" }, + { url = "https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", size = 18219, upload-time = "2024-02-02T16:30:19.988Z" }, + { url = "https://files.pythonhosted.org/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", size = 14098, upload-time = "2024-02-02T16:30:21.063Z" }, + { url = "https://files.pythonhosted.org/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", size = 29014, upload-time = "2024-02-02T16:30:22.926Z" }, + { url = "https://files.pythonhosted.org/packages/97/18/c30da5e7a0e7f4603abfc6780574131221d9148f323752c2755d48abad30/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", size = 28220, upload-time = "2024-02-02T16:30:24.76Z" }, + { url = "https://files.pythonhosted.org/packages/0c/40/2e73e7d532d030b1e41180807a80d564eda53babaf04d65e15c1cf897e40/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", size = 27756, upload-time = "2024-02-02T16:30:25.877Z" }, + { url = "https://files.pythonhosted.org/packages/18/46/5dca760547e8c59c5311b332f70605d24c99d1303dd9a6e1fc3ed0d73561/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", size = 33988, upload-time = "2024-02-02T16:30:26.935Z" }, + { url = "https://files.pythonhosted.org/packages/6d/c5/27febe918ac36397919cd4a67d5579cbbfa8da027fa1238af6285bb368ea/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", size = 32718, upload-time = "2024-02-02T16:30:28.111Z" }, + { url = "https://files.pythonhosted.org/packages/f8/81/56e567126a2c2bc2684d6391332e357589a96a76cb9f8e5052d85cb0ead8/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", size = 33317, upload-time = "2024-02-02T16:30:29.214Z" }, + { url = "https://files.pythonhosted.org/packages/00/0b/23f4b2470accb53285c613a3ab9ec19dc944eaf53592cb6d9e2af8aa24cc/MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", size = 16670, upload-time = "2024-02-02T16:30:30.915Z" }, + { url = "https://files.pythonhosted.org/packages/b7/a2/c78a06a9ec6d04b3445a949615c4c7ed86a0b2eb68e44e7541b9d57067cc/MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", size = 17224, upload-time = "2024-02-02T16:30:32.09Z" }, + { url = "https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", size = 18215, upload-time = "2024-02-02T16:30:33.081Z" }, + { url = "https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", size = 14069, upload-time = "2024-02-02T16:30:34.148Z" }, + { url = "https://files.pythonhosted.org/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", size = 29452, upload-time = "2024-02-02T16:30:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", size = 28462, upload-time = "2024-02-02T16:30:36.166Z" }, + { url = "https://files.pythonhosted.org/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", size = 27869, upload-time = "2024-02-02T16:30:37.834Z" }, + { url = "https://files.pythonhosted.org/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", size = 33906, upload-time = "2024-02-02T16:30:39.366Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", size = 32296, upload-time = "2024-02-02T16:30:40.413Z" }, + { url = "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038, upload-time = "2024-02-02T16:30:42.243Z" }, + { url = "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572, upload-time = "2024-02-02T16:30:43.326Z" }, + { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127, upload-time = "2024-02-02T16:30:44.418Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", size = 18192, upload-time = "2024-02-02T16:30:57.715Z" }, + { url = "https://files.pythonhosted.org/packages/4f/14/6f294b9c4f969d0c801a4615e221c1e084722ea6114ab2114189c5b8cbe0/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", size = 14072, upload-time = "2024-02-02T16:30:58.844Z" }, + { url = "https://files.pythonhosted.org/packages/81/d4/fd74714ed30a1dedd0b82427c02fa4deec64f173831ec716da11c51a50aa/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", size = 26928, upload-time = "2024-02-02T16:30:59.922Z" }, + { url = "https://files.pythonhosted.org/packages/c7/bd/50319665ce81bb10e90d1cf76f9e1aa269ea6f7fa30ab4521f14d122a3df/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", size = 26106, upload-time = "2024-02-02T16:31:01.582Z" }, + { url = "https://files.pythonhosted.org/packages/4c/6f/f2b0f675635b05f6afd5ea03c094557bdb8622fa8e673387444fe8d8e787/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68", size = 25781, upload-time = "2024-02-02T16:31:02.71Z" }, + { url = "https://files.pythonhosted.org/packages/51/e0/393467cf899b34a9d3678e78961c2c8cdf49fb902a959ba54ece01273fb1/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", size = 30518, upload-time = "2024-02-02T16:31:04.392Z" }, + { url = "https://files.pythonhosted.org/packages/f6/02/5437e2ad33047290dafced9df741d9efc3e716b75583bbd73a9984f1b6f7/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", size = 29669, upload-time = "2024-02-02T16:31:05.53Z" }, + { url = "https://files.pythonhosted.org/packages/0e/7d/968284145ffd9d726183ed6237c77938c021abacde4e073020f920e060b2/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", size = 29933, upload-time = "2024-02-02T16:31:06.636Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f3/ecb00fc8ab02b7beae8699f34db9357ae49d9f21d4d3de6f305f34fa949e/MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", size = 16656, upload-time = "2024-02-02T16:31:07.767Z" }, + { url = "https://files.pythonhosted.org/packages/92/21/357205f03514a49b293e214ac39de01fadd0970a6e05e4bf1ddd0ffd0881/MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", size = 17206, upload-time = "2024-02-02T16:31:08.843Z" }, + { url = "https://files.pythonhosted.org/packages/0f/31/780bb297db036ba7b7bbede5e1d7f1e14d704ad4beb3ce53fb495d22bc62/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", size = 18193, upload-time = "2024-02-02T16:31:10.155Z" }, + { url = "https://files.pythonhosted.org/packages/6c/77/d77701bbef72892affe060cdacb7a2ed7fd68dae3b477a8642f15ad3b132/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", size = 14073, upload-time = "2024-02-02T16:31:11.442Z" }, + { url = "https://files.pythonhosted.org/packages/d9/a7/1e558b4f78454c8a3a0199292d96159eb4d091f983bc35ef258314fe7269/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", size = 26486, upload-time = "2024-02-02T16:31:12.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5a/360da85076688755ea0cceb92472923086993e86b5613bbae9fbc14136b0/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", size = 25685, upload-time = "2024-02-02T16:31:13.726Z" }, + { url = "https://files.pythonhosted.org/packages/6a/18/ae5a258e3401f9b8312f92b028c54d7026a97ec3ab20bfaddbdfa7d8cce8/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", size = 25338, upload-time = "2024-02-02T16:31:14.812Z" }, + { url = "https://files.pythonhosted.org/packages/0b/cc/48206bd61c5b9d0129f4d75243b156929b04c94c09041321456fd06a876d/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", size = 30439, upload-time = "2024-02-02T16:31:15.946Z" }, + { url = "https://files.pythonhosted.org/packages/d1/06/a41c112ab9ffdeeb5f77bc3e331fdadf97fa65e52e44ba31880f4e7f983c/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", size = 29531, upload-time = "2024-02-02T16:31:17.13Z" }, + { url = "https://files.pythonhosted.org/packages/02/8c/ab9a463301a50dab04d5472e998acbd4080597abc048166ded5c7aa768c8/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", size = 29823, upload-time = "2024-02-02T16:31:18.247Z" }, + { url = "https://files.pythonhosted.org/packages/bc/29/9bc18da763496b055d8e98ce476c8e718dcfd78157e17f555ce6dd7d0895/MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", size = 16658, upload-time = "2024-02-02T16:31:19.583Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f8/4da07de16f10551ca1f640c92b5f316f9394088b183c6a57183df6de5ae4/MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", size = 17211, upload-time = "2024-02-02T16:31:20.96Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, + { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, + { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, + { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, + { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, + { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, + { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, + { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, + { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, + { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, + { url = "https://files.pythonhosted.org/packages/a7/ea/9b1530c3fdeeca613faeb0fb5cbcf2389d816072fab72a71b45749ef6062/MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", size = 14344, upload-time = "2024-10-18T15:21:43.721Z" }, + { url = "https://files.pythonhosted.org/packages/4b/c2/fbdbfe48848e7112ab05e627e718e854d20192b674952d9042ebd8c9e5de/MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", size = 12389, upload-time = "2024-10-18T15:21:44.666Z" }, + { url = "https://files.pythonhosted.org/packages/f0/25/7a7c6e4dbd4f867d95d94ca15449e91e52856f6ed1905d58ef1de5e211d0/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", size = 21607, upload-time = "2024-10-18T15:21:45.452Z" }, + { url = "https://files.pythonhosted.org/packages/53/8f/f339c98a178f3c1e545622206b40986a4c3307fe39f70ccd3d9df9a9e425/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", size = 20728, upload-time = "2024-10-18T15:21:46.295Z" }, + { url = "https://files.pythonhosted.org/packages/1a/03/8496a1a78308456dbd50b23a385c69b41f2e9661c67ea1329849a598a8f9/MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", size = 20826, upload-time = "2024-10-18T15:21:47.134Z" }, + { url = "https://files.pythonhosted.org/packages/e6/cf/0a490a4bd363048c3022f2f475c8c05582179bb179defcee4766fb3dcc18/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", size = 21843, upload-time = "2024-10-18T15:21:48.334Z" }, + { url = "https://files.pythonhosted.org/packages/19/a3/34187a78613920dfd3cdf68ef6ce5e99c4f3417f035694074beb8848cd77/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", size = 21219, upload-time = "2024-10-18T15:21:49.587Z" }, + { url = "https://files.pythonhosted.org/packages/17/d8/5811082f85bb88410ad7e452263af048d685669bbbfb7b595e8689152498/MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", size = 20946, upload-time = "2024-10-18T15:21:50.441Z" }, + { url = "https://files.pythonhosted.org/packages/7c/31/bd635fb5989440d9365c5e3c47556cfea121c7803f5034ac843e8f37c2f2/MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", size = 15063, upload-time = "2024-10-18T15:21:51.385Z" }, + { url = "https://files.pythonhosted.org/packages/b3/73/085399401383ce949f727afec55ec3abd76648d04b9f22e1c0e99cb4bec3/MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", size = 15506, upload-time = "2024-10-18T15:21:52.974Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "importlib-metadata", version = "8.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "importlib-metadata", version = "8.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, + { name = "jinja2" }, + { name = "markdown", version = "3.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "markupsafe", version = "2.1.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "markupsafe", version = "3.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag", version = "0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "pyyaml-env-tag", version = "1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "watchdog", version = "4.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "watchdog", version = "6.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata", version = "8.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "importlib-metadata", version = "8.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, + { name = "mergedeep" }, + { name = "platformdirs", version = "4.3.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.6.20" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs", version = "5.7.post1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "backrefs", version = "5.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "click" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown", version = "3.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions", version = "10.15", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "pymdown-extensions", version = "10.16.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "requests", version = "2.32.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/ee/6ed7fc739bd7591485c8bec67d5984508d3f2733e708f32714c21593341a/mkdocs_material-9.6.20.tar.gz", hash = "sha256:e1f84d21ec5fb730673c4259b2e0d39f8d32a3fef613e3a8e7094b012d43e790", size = 4037822, upload-time = "2025-09-15T08:48:01.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/d8/a31dd52e657bf12b20574706d07df8d767e1ab4340f9bfb9ce73950e5e59/mkdocs_material-9.6.20-py3-none-any.whl", hash = "sha256:b8d8c8b0444c7c06dd984b55ba456ce731f0035c5a1533cc86793618eb1e6c82", size = 9193367, upload-time = "2025-09-15T08:47:58.722Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "more-itertools" +version = "10.5.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/51/78/65922308c4248e0eb08ebcbe67c95d48615cc6f27854b6f2e57143e9178f/more-itertools-10.5.0.tar.gz", hash = "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6", size = 121020, upload-time = "2024-09-05T15:28:22.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/7e/3a64597054a70f7c86eb0a7d4fc315b8c1ab932f64883a297bdffeb5f967/more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", size = 60952, upload-time = "2024-09-05T15:28:20.141Z" }, +] + +[[package]] +name = "more-itertools" +version = "10.8.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nh3" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/a4/96cff0977357f60f06ec4368c4c7a7a26cccfe7c9fcd54f5378bf0428fd3/nh3-0.3.0.tar.gz", hash = "sha256:d8ba24cb31525492ea71b6aac11a4adac91d828aadeff7c4586541bf5dc34d2f", size = 19655, upload-time = "2025-07-17T14:43:37.05Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/11/340b7a551916a4b2b68c54799d710f86cf3838a4abaad8e74d35360343bb/nh3-0.3.0-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a537ece1bf513e5a88d8cff8a872e12fe8d0f42ef71dd15a5e7520fecd191bbb", size = 1427992, upload-time = "2025-07-17T14:43:06.848Z" }, + { url = "https://files.pythonhosted.org/packages/ad/7f/7c6b8358cf1222921747844ab0eef81129e9970b952fcb814df417159fb9/nh3-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c915060a2c8131bef6a29f78debc29ba40859b6dbe2362ef9e5fd44f11487c2", size = 798194, upload-time = "2025-07-17T14:43:08.263Z" }, + { url = "https://files.pythonhosted.org/packages/63/da/c5fd472b700ba37d2df630a9e0d8cc156033551ceb8b4c49cc8a5f606b68/nh3-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba0caa8aa184196daa6e574d997a33867d6d10234018012d35f86d46024a2a95", size = 837884, upload-time = "2025-07-17T14:43:09.233Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3c/cba7b26ccc0ef150c81646478aa32f9c9535234f54845603c838a1dc955c/nh3-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80fe20171c6da69c7978ecba33b638e951b85fb92059259edd285ff108b82a6d", size = 996365, upload-time = "2025-07-17T14:43:10.243Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ba/59e204d90727c25b253856e456ea61265ca810cda8ee802c35f3fadaab00/nh3-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e90883f9f85288f423c77b3f5a6f4486375636f25f793165112679a7b6363b35", size = 1071042, upload-time = "2025-07-17T14:43:11.57Z" }, + { url = "https://files.pythonhosted.org/packages/10/71/2fb1834c10fab6d9291d62c95192ea2f4c7518bd32ad6c46aab5d095cb87/nh3-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0649464ac8eee018644aacbc103874ccbfac80e3035643c3acaab4287e36e7f5", size = 995737, upload-time = "2025-07-17T14:43:12.659Z" }, + { url = "https://files.pythonhosted.org/packages/33/c1/8f8ccc2492a000b6156dce68a43253fcff8b4ce70ab4216d08f90a2ac998/nh3-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1adeb1062a1c2974bc75b8d1ecb014c5fd4daf2df646bbe2831f7c23659793f9", size = 980552, upload-time = "2025-07-17T14:43:13.763Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d6/f1c6e091cbe8700401c736c2bc3980c46dca770a2cf6a3b48a175114058e/nh3-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:7275fdffaab10cc5801bf026e3c089d8de40a997afc9e41b981f7ac48c5aa7d5", size = 593618, upload-time = "2025-07-17T14:43:15.098Z" }, + { url = "https://files.pythonhosted.org/packages/23/1e/80a8c517655dd40bb13363fc4d9e66b2f13245763faab1a20f1df67165a7/nh3-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:423201bbdf3164a9e09aa01e540adbb94c9962cc177d5b1cbb385f5e1e79216e", size = 598948, upload-time = "2025-07-17T14:43:16.064Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e0/af86d2a974c87a4ba7f19bc3b44a8eaa3da480de264138fec82fe17b340b/nh3-0.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:16f8670201f7e8e0e05ed1a590eb84bfa51b01a69dd5caf1d3ea57733de6a52f", size = 580479, upload-time = "2025-07-17T14:43:17.038Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e0/cf1543e798ba86d838952e8be4cb8d18e22999be2a24b112a671f1c04fd6/nh3-0.3.0-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:ec6cfdd2e0399cb79ba4dcffb2332b94d9696c52272ff9d48a630c5dca5e325a", size = 1442218, upload-time = "2025-07-17T14:43:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/5c/86/a96b1453c107b815f9ab8fac5412407c33cc5c7580a4daf57aabeb41b774/nh3-0.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5e7185599f89b0e391e2f29cc12dc2e206167380cea49b33beda4891be2fe1", size = 823791, upload-time = "2025-07-17T14:43:19.721Z" }, + { url = "https://files.pythonhosted.org/packages/97/33/11e7273b663839626f714cb68f6eb49899da5a0d9b6bc47b41fe870259c2/nh3-0.3.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:389d93d59b8214d51c400fb5b07866c2a4f79e4e14b071ad66c92184fec3a392", size = 811143, upload-time = "2025-07-17T14:43:20.779Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1b/b15bd1ce201a1a610aeb44afd478d55ac018b4475920a3118ffd806e2483/nh3-0.3.0-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e9e6a7e4d38f7e8dda9edd1433af5170c597336c1a74b4693c5cb75ab2b30f2a", size = 1064661, upload-time = "2025-07-17T14:43:21.839Z" }, + { url = "https://files.pythonhosted.org/packages/8f/14/079670fb2e848c4ba2476c5a7a2d1319826053f4f0368f61fca9bb4227ae/nh3-0.3.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7852f038a054e0096dac12b8141191e02e93e0b4608c4b993ec7d4ffafea4e49", size = 997061, upload-time = "2025-07-17T14:43:23.179Z" }, + { url = "https://files.pythonhosted.org/packages/a3/e5/ac7fc565f5d8bce7f979d1afd68e8cb415020d62fa6507133281c7d49f91/nh3-0.3.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af5aa8127f62bbf03d68f67a956627b1bd0469703a35b3dad28d0c1195e6c7fb", size = 924761, upload-time = "2025-07-17T14:43:24.23Z" }, + { url = "https://files.pythonhosted.org/packages/39/2c/6394301428b2017a9d5644af25f487fa557d06bc8a491769accec7524d9a/nh3-0.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f416c35efee3e6a6c9ab7716d9e57aa0a49981be915963a82697952cba1353e1", size = 803959, upload-time = "2025-07-17T14:43:26.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/9a/344b9f9c4bd1c2413a397f38ee6a3d5db30f1a507d4976e046226f12b297/nh3-0.3.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:37d3003d98dedca6cd762bf88f2e70b67f05100f6b949ffe540e189cc06887f9", size = 844073, upload-time = "2025-07-17T14:43:27.375Z" }, + { url = "https://files.pythonhosted.org/packages/66/3f/cd37f76c8ca277b02a84aa20d7bd60fbac85b4e2cbdae77cb759b22de58b/nh3-0.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:634e34e6162e0408e14fb61d5e69dbaea32f59e847cfcfa41b66100a6b796f62", size = 1000680, upload-time = "2025-07-17T14:43:28.452Z" }, + { url = "https://files.pythonhosted.org/packages/ee/db/7aa11b44bae4e7474feb1201d8dee04fabe5651c7cb51409ebda94a4ed67/nh3-0.3.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:b0612ccf5de8a480cf08f047b08f9d3fecc12e63d2ee91769cb19d7290614c23", size = 1076613, upload-time = "2025-07-17T14:43:30.031Z" }, + { url = "https://files.pythonhosted.org/packages/97/03/03f79f7e5178eb1ad5083af84faff471e866801beb980cc72943a4397368/nh3-0.3.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c7a32a7f0d89f7d30cb8f4a84bdbd56d1eb88b78a2434534f62c71dac538c450", size = 1001418, upload-time = "2025-07-17T14:43:31.429Z" }, + { url = "https://files.pythonhosted.org/packages/ce/55/1974bcc16884a397ee699cebd3914e1f59be64ab305533347ca2d983756f/nh3-0.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3f1b4f8a264a0c86ea01da0d0c390fe295ea0bcacc52c2103aca286f6884f518", size = 986499, upload-time = "2025-07-17T14:43:32.459Z" }, + { url = "https://files.pythonhosted.org/packages/c9/50/76936ec021fe1f3270c03278b8af5f2079038116b5d0bfe8538ffe699d69/nh3-0.3.0-cp38-abi3-win32.whl", hash = "sha256:6d68fa277b4a3cf04e5c4b84dd0c6149ff7d56c12b3e3fab304c525b850f613d", size = 599000, upload-time = "2025-07-17T14:43:33.852Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ae/324b165d904dc1672eee5f5661c0a68d4bab5b59fbb07afb6d8d19a30b45/nh3-0.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:bae63772408fd63ad836ec569a7c8f444dd32863d0c67f6e0b25ebbd606afa95", size = 604530, upload-time = "2025-07-17T14:43:34.95Z" }, + { url = "https://files.pythonhosted.org/packages/5b/76/3165e84e5266d146d967a6cc784ff2fbf6ddd00985a55ec006b72bc39d5d/nh3-0.3.0-cp38-abi3-win_arm64.whl", hash = "sha256:d97d3efd61404af7e5721a0e74d81cdbfc6e5f97e11e731bb6d090e30a7b62b2", size = 585971, upload-time = "2025-07-17T14:43:35.936Z" }, +] + +[[package]] +name = "openapi-python-client" +version = "0.21.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "attrs", marker = "python_full_version < '3.8.1'" }, + { name = "colorama", marker = "python_full_version < '3.8.1' and sys_platform == 'win32'" }, + { name = "httpx", version = "0.27.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8.1'" }, + { name = "jinja2", marker = "python_full_version < '3.8.1'" }, + { name = "pydantic", version = "2.10.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8.1'" }, + { name = "python-dateutil", marker = "python_full_version < '3.8.1'" }, + { name = "ruamel-yaml", marker = "python_full_version < '3.8.1'" }, + { name = "ruff", version = "0.4.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8.1'" }, + { name = "shellingham", marker = "python_full_version < '3.8.1'" }, + { name = "typer", version = "0.12.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8.1'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8.1'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/7d/1fe6ba1eab5c6874495d60206ba0ed146e5f78644694f411fa14e1f038c7/openapi_python_client-0.21.0.tar.gz", hash = "sha256:94a428024bc125a24d1b56e2518b65730d176394a274c5610f3619bf99bb70d6", size = 118854, upload-time = "2024-06-08T21:27:54.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/c8/a7d93391a9c842cd057f837bc8c65a0bd0129b330c7b37b7c6b500031ffd/openapi_python_client-0.21.0-py3-none-any.whl", hash = "sha256:318eb48ad9a942ec3342d6a8b9706ef24dcafd189a8373ca39042e42135c6085", size = 169715, upload-time = "2024-06-08T21:27:52.555Z" }, +] + +[[package]] +name = "openapi-python-client" +version = "0.21.7" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", +] +dependencies = [ + { name = "attrs", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "colorama", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9' and sys_platform == 'win32'" }, + { name = "httpx", version = "0.27.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "jinja2", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "pydantic", version = "2.10.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "python-dateutil", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "ruamel-yaml", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "ruff", version = "0.7.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "shellingham", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "typer", version = "0.12.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a5/09/6b9207bcbf7b468c7c008b8344d6571beb5634325642e9ab1139c91ff151/openapi_python_client-0.21.7.tar.gz", hash = "sha256:02a4800f6191237e5d9abd9b727d0bcf9165e2617f597c03eaa23a5625f466e3", size = 122985, upload-time = "2024-11-23T01:40:11.338Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/59/746b87fe547ef4de65bea74bcbbcde3cb279b935bdc03396f384c81e1796/openapi_python_client-0.21.7-py3-none-any.whl", hash = "sha256:bbef6dda2be4b5540f3fdae89374c68462f4dc18126b222fbb0a7cd2da78c31d", size = 179162, upload-time = "2024-11-23T01:40:08.64Z" }, +] + +[[package]] +name = "openapi-python-client" +version = "0.26.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "attrs", marker = "python_full_version >= '3.9'" }, + { name = "colorama", marker = "python_full_version >= '3.9' and sys_platform == 'win32'" }, + { name = "httpx", version = "0.28.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "jinja2", marker = "python_full_version >= '3.9'" }, + { name = "pydantic", version = "2.11.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "python-dateutil", marker = "python_full_version >= '3.9'" }, + { name = "ruamel-yaml", marker = "python_full_version >= '3.9'" }, + { name = "ruff", version = "0.13.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "shellingham", marker = "python_full_version >= '3.9'" }, + { name = "typer", version = "0.17.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/31/264cf223b301186cfd2f3a78f962ee641e3b7794ec7b483380c56d59e824/openapi_python_client-0.26.1.tar.gz", hash = "sha256:e3832f0ef074a0ab591d1eeb5d3dab2ca820cd0349f7e79d9663b7b21206be5d", size = 126194, upload-time = "2025-09-13T05:49:34.514Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/56/d9304d6b7f8a173c868e10a506b8ccab79305d9e412b06cf89c654155f35/openapi_python_client-0.26.1-py3-none-any.whl", hash = "sha256:415cb8095b1a3f15cec45670c5075c5097f65390a351d21512e8f6ea5c1be644", size = 183638, upload-time = "2025-09-13T05:49:32.55Z" }, +] + +[[package]] +name = "opencode-ai" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "httpx", version = "0.27.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "httpx", version = "0.28.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "pydantic", version = "2.10.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "pydantic", version = "2.11.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "python-dateutil" }, +] + +[package.dev-dependencies] +dev = [ + { name = "black", version = "24.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "black", version = "25.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "build", version = "1.2.2.post1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "build", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "isort", version = "5.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "isort", version = "6.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "mkdocs" }, + { name = "mkdocs-material" }, + { name = "openapi-python-client", version = "0.21.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8.1'" }, + { name = "openapi-python-client", version = "0.21.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "openapi-python-client", version = "0.26.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "pytest", version = "8.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "pytest-asyncio", version = "0.24.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "ruff", version = "0.4.10", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8.1'" }, + { name = "ruff", version = "0.7.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "ruff", version = "0.13.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "sseclient-py" }, + { name = "twine", version = "6.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "twine", version = "6.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] + +[package.metadata] +requires-dist = [ + { name = "httpx", specifier = ">=0.27.0" }, + { name = "pydantic", specifier = ">=2.0.0" }, + { name = "python-dateutil", specifier = ">=2.8.2" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "black" }, + { name = "build" }, + { name = "isort" }, + { name = "mkdocs" }, + { name = "mkdocs-material" }, + { name = "openapi-python-client" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "ruff" }, + { name = "sseclient-py" }, + { name = "twine" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302, upload-time = "2024-09-17T19:06:50.688Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439, upload-time = "2024-09-17T19:06:49.212Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.4.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pydantic" +version = "2.10.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "annotated-types", marker = "python_full_version < '3.9'" }, + { name = "pydantic-core", version = "2.27.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681, upload-time = "2025-01-24T01:42:12.693Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696, upload-time = "2025-01-24T01:42:10.371Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.9" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "annotated-types", marker = "python_full_version >= '3.9'" }, + { name = "pydantic-core", version = "2.33.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "typing-inspection", marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.27.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938, upload-time = "2024-12-18T11:27:14.406Z" }, + { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684, upload-time = "2024-12-18T11:27:16.489Z" }, + { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169, upload-time = "2024-12-18T11:27:22.16Z" }, + { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227, upload-time = "2024-12-18T11:27:25.097Z" }, + { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695, upload-time = "2024-12-18T11:27:28.656Z" }, + { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662, upload-time = "2024-12-18T11:27:30.798Z" }, + { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370, upload-time = "2024-12-18T11:27:33.692Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813, upload-time = "2024-12-18T11:27:37.111Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287, upload-time = "2024-12-18T11:27:40.566Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414, upload-time = "2024-12-18T11:27:43.757Z" }, + { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301, upload-time = "2024-12-18T11:27:47.36Z" }, + { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685, upload-time = "2024-12-18T11:27:50.508Z" }, + { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876, upload-time = "2024-12-18T11:27:53.54Z" }, + { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421, upload-time = "2024-12-18T11:27:55.409Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998, upload-time = "2024-12-18T11:27:57.252Z" }, + { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167, upload-time = "2024-12-18T11:27:59.146Z" }, + { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071, upload-time = "2024-12-18T11:28:02.625Z" }, + { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244, upload-time = "2024-12-18T11:28:04.442Z" }, + { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470, upload-time = "2024-12-18T11:28:07.679Z" }, + { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291, upload-time = "2024-12-18T11:28:10.297Z" }, + { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613, upload-time = "2024-12-18T11:28:13.362Z" }, + { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355, upload-time = "2024-12-18T11:28:16.587Z" }, + { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661, upload-time = "2024-12-18T11:28:18.407Z" }, + { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261, upload-time = "2024-12-18T11:28:21.471Z" }, + { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361, upload-time = "2024-12-18T11:28:23.53Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484, upload-time = "2024-12-18T11:28:25.391Z" }, + { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102, upload-time = "2024-12-18T11:28:28.593Z" }, + { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127, upload-time = "2024-12-18T11:28:30.346Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340, upload-time = "2024-12-18T11:28:32.521Z" }, + { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900, upload-time = "2024-12-18T11:28:34.507Z" }, + { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177, upload-time = "2024-12-18T11:28:36.488Z" }, + { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046, upload-time = "2024-12-18T11:28:39.409Z" }, + { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386, upload-time = "2024-12-18T11:28:41.221Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060, upload-time = "2024-12-18T11:28:44.709Z" }, + { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870, upload-time = "2024-12-18T11:28:46.839Z" }, + { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822, upload-time = "2024-12-18T11:28:48.896Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364, upload-time = "2024-12-18T11:28:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303, upload-time = "2024-12-18T11:28:54.122Z" }, + { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064, upload-time = "2024-12-18T11:28:56.074Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046, upload-time = "2024-12-18T11:28:58.107Z" }, + { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092, upload-time = "2024-12-18T11:29:01.335Z" }, + { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709, upload-time = "2024-12-18T11:29:03.193Z" }, + { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273, upload-time = "2024-12-18T11:29:05.306Z" }, + { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027, upload-time = "2024-12-18T11:29:07.294Z" }, + { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888, upload-time = "2024-12-18T11:29:09.249Z" }, + { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738, upload-time = "2024-12-18T11:29:11.23Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138, upload-time = "2024-12-18T11:29:16.396Z" }, + { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025, upload-time = "2024-12-18T11:29:20.25Z" }, + { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633, upload-time = "2024-12-18T11:29:23.877Z" }, + { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404, upload-time = "2024-12-18T11:29:25.872Z" }, + { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130, upload-time = "2024-12-18T11:29:29.252Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946, upload-time = "2024-12-18T11:29:31.338Z" }, + { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387, upload-time = "2024-12-18T11:29:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453, upload-time = "2024-12-18T11:29:35.533Z" }, + { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186, upload-time = "2024-12-18T11:29:37.649Z" }, + { url = "https://files.pythonhosted.org/packages/43/53/13e9917fc69c0a4aea06fd63ed6a8d6cda9cf140ca9584d49c1650b0ef5e/pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506", size = 1899595, upload-time = "2024-12-18T11:29:40.887Z" }, + { url = "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320", size = 1775010, upload-time = "2024-12-18T11:29:44.823Z" }, + { url = "https://files.pythonhosted.org/packages/35/eb/8234e05452d92d2b102ffa1b56d801c3567e628fdc63f02080fdfc68fd5e/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145", size = 1830727, upload-time = "2024-12-18T11:29:46.904Z" }, + { url = "https://files.pythonhosted.org/packages/8f/df/59f915c8b929d5f61e5a46accf748a87110ba145156f9326d1a7d28912b2/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1", size = 1868393, upload-time = "2024-12-18T11:29:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/d5/52/81cf4071dca654d485c277c581db368b0c95b2b883f4d7b736ab54f72ddf/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228", size = 2040300, upload-time = "2024-12-18T11:29:51.43Z" }, + { url = "https://files.pythonhosted.org/packages/9c/00/05197ce1614f5c08d7a06e1d39d5d8e704dc81971b2719af134b844e2eaf/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046", size = 2738785, upload-time = "2024-12-18T11:29:55.001Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a3/5f19bc495793546825ab160e530330c2afcee2281c02b5ffafd0b32ac05e/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5", size = 1996493, upload-time = "2024-12-18T11:29:57.13Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e8/e0102c2ec153dc3eed88aea03990e1b06cfbca532916b8a48173245afe60/pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a", size = 1998544, upload-time = "2024-12-18T11:30:00.681Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a3/4be70845b555bd80aaee9f9812a7cf3df81550bce6dadb3cfee9c5d8421d/pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d", size = 2007449, upload-time = "2024-12-18T11:30:02.985Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9f/b779ed2480ba355c054e6d7ea77792467631d674b13d8257085a4bc7dcda/pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9", size = 2129460, upload-time = "2024-12-18T11:30:06.55Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f0/a6ab0681f6e95260c7fbf552874af7302f2ea37b459f9b7f00698f875492/pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da", size = 2159609, upload-time = "2024-12-18T11:30:09.428Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2b/e1059506795104349712fbca647b18b3f4a7fd541c099e6259717441e1e0/pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b", size = 1819886, upload-time = "2024-12-18T11:30:11.777Z" }, + { url = "https://files.pythonhosted.org/packages/aa/6d/df49c17f024dfc58db0bacc7b03610058018dd2ea2eaf748ccbada4c3d06/pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad", size = 1980773, upload-time = "2024-12-18T11:30:14.828Z" }, + { url = "https://files.pythonhosted.org/packages/27/97/3aef1ddb65c5ccd6eda9050036c956ff6ecbfe66cb7eb40f280f121a5bb0/pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993", size = 1896475, upload-time = "2024-12-18T11:30:18.316Z" }, + { url = "https://files.pythonhosted.org/packages/ad/d3/5668da70e373c9904ed2f372cb52c0b996426f302e0dee2e65634c92007d/pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308", size = 1772279, upload-time = "2024-12-18T11:30:20.547Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/e44b8cb0edf04a2f0a1f6425a65ee089c1d6f9c4c2dcab0209127b6fdfc2/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4", size = 1829112, upload-time = "2024-12-18T11:30:23.255Z" }, + { url = "https://files.pythonhosted.org/packages/1c/90/1160d7ac700102effe11616e8119e268770f2a2aa5afb935f3ee6832987d/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf", size = 1866780, upload-time = "2024-12-18T11:30:25.742Z" }, + { url = "https://files.pythonhosted.org/packages/ee/33/13983426df09a36d22c15980008f8d9c77674fc319351813b5a2739b70f3/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76", size = 2037943, upload-time = "2024-12-18T11:30:28.036Z" }, + { url = "https://files.pythonhosted.org/packages/01/d7/ced164e376f6747e9158c89988c293cd524ab8d215ae4e185e9929655d5c/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118", size = 2740492, upload-time = "2024-12-18T11:30:30.412Z" }, + { url = "https://files.pythonhosted.org/packages/8b/1f/3dc6e769d5b7461040778816aab2b00422427bcaa4b56cc89e9c653b2605/pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630", size = 1995714, upload-time = "2024-12-18T11:30:34.358Z" }, + { url = "https://files.pythonhosted.org/packages/07/d7/a0bd09bc39283530b3f7c27033a814ef254ba3bd0b5cfd040b7abf1fe5da/pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54", size = 1997163, upload-time = "2024-12-18T11:30:37.979Z" }, + { url = "https://files.pythonhosted.org/packages/2d/bb/2db4ad1762e1c5699d9b857eeb41959191980de6feb054e70f93085e1bcd/pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f", size = 2005217, upload-time = "2024-12-18T11:30:40.367Z" }, + { url = "https://files.pythonhosted.org/packages/53/5f/23a5a3e7b8403f8dd8fc8a6f8b49f6b55c7d715b77dcf1f8ae919eeb5628/pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362", size = 2127899, upload-time = "2024-12-18T11:30:42.737Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ae/aa38bb8dd3d89c2f1d8362dd890ee8f3b967330821d03bbe08fa01ce3766/pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96", size = 2155726, upload-time = "2024-12-18T11:30:45.279Z" }, + { url = "https://files.pythonhosted.org/packages/98/61/4f784608cc9e98f70839187117ce840480f768fed5d386f924074bf6213c/pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e", size = 1817219, upload-time = "2024-12-18T11:30:47.718Z" }, + { url = "https://files.pythonhosted.org/packages/57/82/bb16a68e4a1a858bb3768c2c8f1ff8d8978014e16598f001ea29a25bf1d1/pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67", size = 1985382, upload-time = "2024-12-18T11:30:51.871Z" }, + { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159, upload-time = "2024-12-18T11:30:54.382Z" }, + { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331, upload-time = "2024-12-18T11:30:58.178Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467, upload-time = "2024-12-18T11:31:00.6Z" }, + { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797, upload-time = "2024-12-18T11:31:07.243Z" }, + { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839, upload-time = "2024-12-18T11:31:09.775Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861, upload-time = "2024-12-18T11:31:13.469Z" }, + { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582, upload-time = "2024-12-18T11:31:17.423Z" }, + { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985, upload-time = "2024-12-18T11:31:19.901Z" }, + { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715, upload-time = "2024-12-18T11:31:22.821Z" }, + { url = "https://files.pythonhosted.org/packages/29/0e/dcaea00c9dbd0348b723cae82b0e0c122e0fa2b43fa933e1622fd237a3ee/pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656", size = 1891733, upload-time = "2024-12-18T11:31:26.876Z" }, + { url = "https://files.pythonhosted.org/packages/86/d3/e797bba8860ce650272bda6383a9d8cad1d1c9a75a640c9d0e848076f85e/pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278", size = 1768375, upload-time = "2024-12-18T11:31:29.276Z" }, + { url = "https://files.pythonhosted.org/packages/41/f7/f847b15fb14978ca2b30262548f5fc4872b2724e90f116393eb69008299d/pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb", size = 1822307, upload-time = "2024-12-18T11:31:33.123Z" }, + { url = "https://files.pythonhosted.org/packages/9c/63/ed80ec8255b587b2f108e514dc03eed1546cd00f0af281e699797f373f38/pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd", size = 1979971, upload-time = "2024-12-18T11:31:35.755Z" }, + { url = "https://files.pythonhosted.org/packages/a9/6d/6d18308a45454a0de0e975d70171cadaf454bc7a0bf86b9c7688e313f0bb/pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc", size = 1987616, upload-time = "2024-12-18T11:31:38.534Z" }, + { url = "https://files.pythonhosted.org/packages/82/8a/05f8780f2c1081b800a7ca54c1971e291c2d07d1a50fb23c7e4aef4ed403/pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b", size = 1998943, upload-time = "2024-12-18T11:31:41.853Z" }, + { url = "https://files.pythonhosted.org/packages/5e/3e/fe5b6613d9e4c0038434396b46c5303f5ade871166900b357ada4766c5b7/pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b", size = 2116654, upload-time = "2024-12-18T11:31:44.756Z" }, + { url = "https://files.pythonhosted.org/packages/db/ad/28869f58938fad8cc84739c4e592989730bfb69b7c90a8fff138dff18e1e/pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2", size = 2152292, upload-time = "2024-12-18T11:31:48.613Z" }, + { url = "https://files.pythonhosted.org/packages/a1/0c/c5c5cd3689c32ed1fe8c5d234b079c12c281c051759770c05b8bed6412b5/pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35", size = 2004961, upload-time = "2024-12-18T11:31:52.446Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817, upload-time = "2025-04-23T18:30:43.919Z" }, + { url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357, upload-time = "2025-04-23T18:30:46.372Z" }, + { url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011, upload-time = "2025-04-23T18:30:47.591Z" }, + { url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730, upload-time = "2025-04-23T18:30:49.328Z" }, + { url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178, upload-time = "2025-04-23T18:30:50.907Z" }, + { url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462, upload-time = "2025-04-23T18:30:52.083Z" }, + { url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652, upload-time = "2025-04-23T18:30:53.389Z" }, + { url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306, upload-time = "2025-04-23T18:30:54.661Z" }, + { url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720, upload-time = "2025-04-23T18:30:56.11Z" }, + { url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915, upload-time = "2025-04-23T18:30:57.501Z" }, + { url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884, upload-time = "2025-04-23T18:30:58.867Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496, upload-time = "2025-04-23T18:31:00.078Z" }, + { url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019, upload-time = "2025-04-23T18:31:01.335Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" }, + { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" }, + { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" }, + { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" }, + { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" }, + { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" }, + { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" }, + { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" }, + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, + { url = "https://files.pythonhosted.org/packages/53/ea/bbe9095cdd771987d13c82d104a9c8559ae9aec1e29f139e286fd2e9256e/pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d", size = 2028677, upload-time = "2025-04-23T18:32:27.227Z" }, + { url = "https://files.pythonhosted.org/packages/49/1d/4ac5ed228078737d457a609013e8f7edc64adc37b91d619ea965758369e5/pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954", size = 1864735, upload-time = "2025-04-23T18:32:29.019Z" }, + { url = "https://files.pythonhosted.org/packages/23/9a/2e70d6388d7cda488ae38f57bc2f7b03ee442fbcf0d75d848304ac7e405b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb", size = 1898467, upload-time = "2025-04-23T18:32:31.119Z" }, + { url = "https://files.pythonhosted.org/packages/ff/2e/1568934feb43370c1ffb78a77f0baaa5a8b6897513e7a91051af707ffdc4/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7", size = 1983041, upload-time = "2025-04-23T18:32:33.655Z" }, + { url = "https://files.pythonhosted.org/packages/01/1a/1a1118f38ab64eac2f6269eb8c120ab915be30e387bb561e3af904b12499/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4", size = 2136503, upload-time = "2025-04-23T18:32:35.519Z" }, + { url = "https://files.pythonhosted.org/packages/5c/da/44754d1d7ae0f22d6d3ce6c6b1486fc07ac2c524ed8f6eca636e2e1ee49b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b", size = 2736079, upload-time = "2025-04-23T18:32:37.659Z" }, + { url = "https://files.pythonhosted.org/packages/4d/98/f43cd89172220ec5aa86654967b22d862146bc4d736b1350b4c41e7c9c03/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3", size = 2006508, upload-time = "2025-04-23T18:32:39.637Z" }, + { url = "https://files.pythonhosted.org/packages/2b/cc/f77e8e242171d2158309f830f7d5d07e0531b756106f36bc18712dc439df/pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a", size = 2113693, upload-time = "2025-04-23T18:32:41.818Z" }, + { url = "https://files.pythonhosted.org/packages/54/7a/7be6a7bd43e0a47c147ba7fbf124fe8aaf1200bc587da925509641113b2d/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782", size = 2074224, upload-time = "2025-04-23T18:32:44.033Z" }, + { url = "https://files.pythonhosted.org/packages/2a/07/31cf8fadffbb03be1cb520850e00a8490c0927ec456e8293cafda0726184/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9", size = 2245403, upload-time = "2025-04-23T18:32:45.836Z" }, + { url = "https://files.pythonhosted.org/packages/b6/8d/bbaf4c6721b668d44f01861f297eb01c9b35f612f6b8e14173cb204e6240/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e", size = 2242331, upload-time = "2025-04-23T18:32:47.618Z" }, + { url = "https://files.pythonhosted.org/packages/bb/93/3cc157026bca8f5006250e74515119fcaa6d6858aceee8f67ab6dc548c16/pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9", size = 1910571, upload-time = "2025-04-23T18:32:49.401Z" }, + { url = "https://files.pythonhosted.org/packages/5b/90/7edc3b2a0d9f0dda8806c04e511a67b0b7a41d2187e2003673a996fb4310/pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3", size = 1956504, upload-time = "2025-04-23T18:32:51.287Z" }, + { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" }, + { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" }, + { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" }, + { url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527, upload-time = "2025-04-23T18:32:59.771Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225, upload-time = "2025-04-23T18:33:04.51Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490, upload-time = "2025-04-23T18:33:06.391Z" }, + { url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525, upload-time = "2025-04-23T18:33:08.44Z" }, + { url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446, upload-time = "2025-04-23T18:33:10.313Z" }, + { url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678, upload-time = "2025-04-23T18:33:12.224Z" }, + { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" }, + { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, + { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" }, + { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" }, + { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" }, + { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, + { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" }, + { url = "https://files.pythonhosted.org/packages/08/98/dbf3fdfabaf81cda5622154fda78ea9965ac467e3239078e0dcd6df159e7/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101", size = 2024034, upload-time = "2025-04-23T18:33:32.843Z" }, + { url = "https://files.pythonhosted.org/packages/8d/99/7810aa9256e7f2ccd492590f86b79d370df1e9292f1f80b000b6a75bd2fb/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64", size = 1858578, upload-time = "2025-04-23T18:33:34.912Z" }, + { url = "https://files.pythonhosted.org/packages/d8/60/bc06fa9027c7006cc6dd21e48dbf39076dc39d9abbaf718a1604973a9670/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d", size = 1892858, upload-time = "2025-04-23T18:33:36.933Z" }, + { url = "https://files.pythonhosted.org/packages/f2/40/9d03997d9518816c68b4dfccb88969756b9146031b61cd37f781c74c9b6a/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535", size = 2068498, upload-time = "2025-04-23T18:33:38.997Z" }, + { url = "https://files.pythonhosted.org/packages/d8/62/d490198d05d2d86672dc269f52579cad7261ced64c2df213d5c16e0aecb1/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d", size = 2108428, upload-time = "2025-04-23T18:33:41.18Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ec/4cd215534fd10b8549015f12ea650a1a973da20ce46430b68fc3185573e8/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6", size = 2069854, upload-time = "2025-04-23T18:33:43.446Z" }, + { url = "https://files.pythonhosted.org/packages/1a/1a/abbd63d47e1d9b0d632fee6bb15785d0889c8a6e0a6c3b5a8e28ac1ec5d2/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca", size = 2237859, upload-time = "2025-04-23T18:33:45.56Z" }, + { url = "https://files.pythonhosted.org/packages/80/1c/fa883643429908b1c90598fd2642af8839efd1d835b65af1f75fba4d94fe/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039", size = 2239059, upload-time = "2025-04-23T18:33:47.735Z" }, + { url = "https://files.pythonhosted.org/packages/d4/29/3cade8a924a61f60ccfa10842f75eb12787e1440e2b8660ceffeb26685e7/pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27", size = 2066661, upload-time = "2025-04-23T18:33:49.995Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.15" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "markdown", version = "3.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "pyyaml", marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/92/a7296491dbf5585b3a987f3f3fc87af0e632121ff3e490c14b5f2d2b4eb5/pymdown_extensions-10.15.tar.gz", hash = "sha256:0e5994e32155f4b03504f939e501b981d306daf7ec2aa1cd2eb6bd300784f8f7", size = 852320, upload-time = "2025-04-27T23:48:29.183Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/d1/c54e608505776ce4e7966d03358ae635cfd51dff1da6ee421c090dbc797b/pymdown_extensions-10.15-py3-none-any.whl", hash = "sha256:46e99bb272612b0de3b7e7caf6da8dd5f4ca5212c0b273feb9304e236c484e5f", size = 265845, upload-time = "2025-04-27T23:48:27.359Z" }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.16.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "pyyaml", marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/b3/6d2b3f149bc5413b0a29761c2c5832d8ce904a1d7f621e86616d96f505cc/pymdown_extensions-10.16.1.tar.gz", hash = "sha256:aace82bcccba3efc03e25d584e6a22d27a8e17caa3f4dd9f207e49b787aa9a91", size = 853277, upload-time = "2025-07-28T16:19:34.167Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/06/43084e6cbd4b3bc0e80f6be743b2e79fbc6eed8de9ad8c629939fa55d972/pymdown_extensions-10.16.1-py3-none-any.whl", hash = "sha256:d6ba157a6c03146a7fb122b2b9a121300056384eafeec9c9f9e584adfdb2a32d", size = 266178, upload-time = "2025-07-28T16:19:31.401Z" }, +] + +[[package]] +name = "pyproject-hooks" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228, upload-time = "2024-09-29T09:24:13.293Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216, upload-time = "2024-09-29T09:24:11.978Z" }, +] + +[[package]] +name = "pytest" +version = "8.3.5" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version < '3.9' and sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.9'" }, + { name = "iniconfig", marker = "python_full_version < '3.9'" }, + { name = "packaging", marker = "python_full_version < '3.9'" }, + { name = "pluggy", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "tomli", marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version >= '3.9' and sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, + { name = "iniconfig", marker = "python_full_version >= '3.9'" }, + { name = "packaging", marker = "python_full_version >= '3.9'" }, + { name = "pluggy", version = "1.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "pygments", marker = "python_full_version >= '3.9'" }, + { name = "tomli", marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "pytest", version = "8.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855, upload-time = "2024-08-22T08:03:18.145Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024, upload-time = "2024-08-22T08:03:15.536Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "backports-asyncio-runner", marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, + { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pytokens" +version = "0.1.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/5f/e959a442435e24f6fb5a01aec6c657079ceaca1b3baf18561c3728d681da/pytokens-0.1.10.tar.gz", hash = "sha256:c9a4bfa0be1d26aebce03e6884ba454e842f186a59ea43a6d3b25af58223c044", size = 12171, upload-time = "2025-02-19T14:51:22.001Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/e5/63bed382f6a7a5ba70e7e132b8b7b8abbcf4888ffa6be4877698dcfbed7d/pytokens-0.1.10-py3-none-any.whl", hash = "sha256:db7b72284e480e69fb085d9f251f66b3d2df8b7166059261258ff35f50fb711b", size = 12046, upload-time = "2025-02-19T14:51:18.694Z" }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, +] + +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, + { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, + { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, + { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, + { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, + { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, + { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, + { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, + { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, + { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, + { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, + { url = "https://files.pythonhosted.org/packages/74/d9/323a59d506f12f498c2097488d80d16f4cf965cee1791eab58b56b19f47a/PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", size = 183218, upload-time = "2024-08-06T20:33:06.411Z" }, + { url = "https://files.pythonhosted.org/packages/74/cc/20c34d00f04d785f2028737e2e2a8254e1425102e730fee1d6396f832577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", size = 728067, upload-time = "2024-08-06T20:33:07.879Z" }, + { url = "https://files.pythonhosted.org/packages/20/52/551c69ca1501d21c0de51ddafa8c23a0191ef296ff098e98358f69080577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", size = 757812, upload-time = "2024-08-06T20:33:12.542Z" }, + { url = "https://files.pythonhosted.org/packages/fd/7f/2c3697bba5d4aa5cc2afe81826d73dfae5f049458e44732c7a0938baa673/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", size = 746531, upload-time = "2024-08-06T20:33:14.391Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ab/6226d3df99900e580091bb44258fde77a8433511a86883bd4681ea19a858/PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", size = 800820, upload-time = "2024-08-06T20:33:16.586Z" }, + { url = "https://files.pythonhosted.org/packages/a0/99/a9eb0f3e710c06c5d922026f6736e920d431812ace24aae38228d0d64b04/PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", size = 145514, upload-time = "2024-08-06T20:33:22.414Z" }, + { url = "https://files.pythonhosted.org/packages/75/8a/ee831ad5fafa4431099aa4e078d4c8efd43cd5e48fbc774641d233b683a9/PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", size = 162702, upload-time = "2024-08-06T20:33:23.813Z" }, + { url = "https://files.pythonhosted.org/packages/65/d8/b7a1db13636d7fb7d4ff431593c510c8b8fca920ade06ca8ef20015493c5/PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", size = 184777, upload-time = "2024-08-06T20:33:25.896Z" }, + { url = "https://files.pythonhosted.org/packages/0a/02/6ec546cd45143fdf9840b2c6be8d875116a64076218b61d68e12548e5839/PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", size = 172318, upload-time = "2024-08-06T20:33:27.212Z" }, + { url = "https://files.pythonhosted.org/packages/0e/9a/8cc68be846c972bda34f6c2a93abb644fb2476f4dcc924d52175786932c9/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", size = 720891, upload-time = "2024-08-06T20:33:28.974Z" }, + { url = "https://files.pythonhosted.org/packages/e9/6c/6e1b7f40181bc4805e2e07f4abc10a88ce4648e7e95ff1abe4ae4014a9b2/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", size = 722614, upload-time = "2024-08-06T20:33:34.157Z" }, + { url = "https://files.pythonhosted.org/packages/3d/32/e7bd8535d22ea2874cef6a81021ba019474ace0d13a4819c2a4bce79bd6a/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", size = 737360, upload-time = "2024-08-06T20:33:35.84Z" }, + { url = "https://files.pythonhosted.org/packages/d7/12/7322c1e30b9be969670b672573d45479edef72c9a0deac3bb2868f5d7469/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", size = 699006, upload-time = "2024-08-06T20:33:37.501Z" }, + { url = "https://files.pythonhosted.org/packages/82/72/04fcad41ca56491995076630c3ec1e834be241664c0c09a64c9a2589b507/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", size = 723577, upload-time = "2024-08-06T20:33:39.389Z" }, + { url = "https://files.pythonhosted.org/packages/ed/5e/46168b1f2757f1fcd442bc3029cd8767d88a98c9c05770d8b420948743bb/PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", size = 144593, upload-time = "2024-08-06T20:33:46.63Z" }, + { url = "https://files.pythonhosted.org/packages/19/87/5124b1c1f2412bb95c59ec481eaf936cd32f0fe2a7b16b97b81c4c017a6a/PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", size = 162312, upload-time = "2024-08-06T20:33:49.073Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "pyyaml", marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631, upload-time = "2020-11-12T02:38:26.239Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/66/bbb1dd374f5c870f59c5bb1db0e18cbe7fa739415a24cbd95b2d1f5ae0c4/pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069", size = 3911, upload-time = "2020-11-12T02:38:24.638Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "pyyaml", marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + +[[package]] +name = "readme-renderer" +version = "43.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "docutils", version = "0.20.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "nh3", marker = "python_full_version < '3.9'" }, + { name = "pygments", marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/b5/536c775084d239df6345dccf9b043419c7e3308bc31be4c7882196abc62e/readme_renderer-43.0.tar.gz", hash = "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311", size = 31768, upload-time = "2024-02-26T16:10:59.415Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/be/3ea20dc38b9db08387cf97997a85a7d51527ea2057d71118feb0aa8afa55/readme_renderer-43.0-py3-none-any.whl", hash = "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9", size = 13301, upload-time = "2024-02-26T16:10:57.945Z" }, +] + +[[package]] +name = "readme-renderer" +version = "44.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "docutils", version = "0.22.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "nh3", marker = "python_full_version >= '3.9'" }, + { name = "pygments", marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/a9/104ec9234c8448c4379768221ea6df01260cd6c2ce13182d4eac531c8342/readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1", size = 32056, upload-time = "2024-07-08T15:00:57.805Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", size = 13310, upload-time = "2024-07-08T15:00:56.577Z" }, +] + +[[package]] +name = "requests" +version = "2.32.4" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "certifi", marker = "python_full_version < '3.9'" }, + { name = "charset-normalizer", marker = "python_full_version < '3.9'" }, + { name = "idna", marker = "python_full_version < '3.9'" }, + { name = "urllib3", version = "2.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "certifi", marker = "python_full_version >= '3.9'" }, + { name = "charset-normalizer", marker = "python_full_version >= '3.9'" }, + { name = "idna", marker = "python_full_version >= '3.9'" }, + { name = "urllib3", version = "2.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests", version = "2.32.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, +] + +[[package]] +name = "rfc3986" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c", size = 49026, upload-time = "2022-01-10T00:52:30.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", size = 31326, upload-time = "2022-01-10T00:52:29.594Z" }, +] + +[[package]] +name = "rich" +version = "14.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, +] + +[[package]] +name = "ruamel-yaml" +version = "0.18.15" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ruamel-yaml-clib", version = "0.2.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' and platform_python_implementation == 'CPython'" }, + { name = "ruamel-yaml-clib", version = "0.2.14", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.14' and platform_python_implementation == 'CPython'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/db/f3950f5e5031b618aae9f423a39bf81a55c148aecd15a34527898e752cf4/ruamel.yaml-0.18.15.tar.gz", hash = "sha256:dbfca74b018c4c3fba0b9cc9ee33e53c371194a9000e694995e620490fd40700", size = 146865, upload-time = "2025-08-19T11:15:10.694Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/e5/f2a0621f1781b76a38194acae72f01e37b1941470407345b6e8653ad7640/ruamel.yaml-0.18.15-py3-none-any.whl", hash = "sha256:148f6488d698b7a5eded5ea793a025308b25eca97208181b6a026037f391f701", size = 119702, upload-time = "2025-08-19T11:15:07.696Z" }, +] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/46/ab/bab9eb1566cd16f060b54055dd39cf6a34bfa0240c53a7218c43e974295b/ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512", size = 213824, upload-time = "2023-10-03T18:12:42.315Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/01/37ac131614f71b98e9b148b2d7790662dcee92217d2fb4bac1aa377def33/ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d", size = 148236, upload-time = "2023-10-03T18:12:45.627Z" }, + { url = "https://files.pythonhosted.org/packages/61/ee/4874c9fc96010fce85abefdcbe770650c5324288e988d7a48b527a423815/ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462", size = 133996, upload-time = "2023-10-03T18:12:47.929Z" }, + { url = "https://files.pythonhosted.org/packages/d3/62/c60b034d9a008bbd566eeecf53a5a4c73d191c8de261290db6761802b72d/ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412", size = 526680, upload-time = "2023-10-03T18:12:50.419Z" }, + { url = "https://files.pythonhosted.org/packages/90/8c/6cdb44f548b29eb6328b9e7e175696336bc856de2ff82e5776f860f03822/ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f", size = 605853, upload-time = "2023-11-09T07:40:15.683Z" }, + { url = "https://files.pythonhosted.org/packages/88/30/fc45b45d5eaf2ff36cffd215a2f85e9b90ac04e70b97fd4097017abfb567/ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334", size = 655206, upload-time = "2023-10-22T15:35:29.281Z" }, + { url = "https://files.pythonhosted.org/packages/af/dc/133547f90f744a0c827bac5411d84d4e81da640deb3af1459e38c5f3b6a0/ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d", size = 689649, upload-time = "2023-10-22T15:35:31.554Z" }, + { url = "https://files.pythonhosted.org/packages/23/1d/589139191b187a3c750ae8d983c42fd799246d5f0dd84451a0575c9bdbe9/ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d", size = 100044, upload-time = "2023-10-03T18:12:52.586Z" }, + { url = "https://files.pythonhosted.org/packages/4f/5b/744df20285a75ac4c606452ce9a0fcc42087d122f42294518ded1017697c/ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31", size = 117825, upload-time = "2023-10-03T18:12:55.71Z" }, + { url = "https://files.pythonhosted.org/packages/b1/15/971b385c098e8d0d170893f5ba558452bb7b776a0c90658b8f4dd0e3382b/ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069", size = 148870, upload-time = "2023-10-03T18:12:58.113Z" }, + { url = "https://files.pythonhosted.org/packages/01/b0/4ddef56e9f703d7909febc3a421d709a3482cda25826816ec595b73e3847/ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248", size = 134475, upload-time = "2023-10-03T18:13:00.663Z" }, + { url = "https://files.pythonhosted.org/packages/a4/f7/22d6b620ed895a05d40802d8281eff924dc6190f682d933d4efff60db3b5/ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b", size = 544020, upload-time = "2023-10-03T18:13:03.065Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e4/0d19d65e340f93df1c47f323d95fa4b256bb28320290f5fddef90837853a/ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe", size = 642643, upload-time = "2023-11-09T07:40:18.115Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ff/f781eb5e2ae011e586d5426e2086a011cf1e0f59704a6cad1387975c5a62/ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899", size = 695832, upload-time = "2023-10-22T15:35:34.38Z" }, + { url = "https://files.pythonhosted.org/packages/e3/41/f62e67ac651358b8f0d60cfb12ab2daf99b1b69eeaa188d0cec809d943a6/ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9", size = 730923, upload-time = "2023-10-22T15:35:36.442Z" }, + { url = "https://files.pythonhosted.org/packages/9f/f0/19ab8acbf983cd1b37f47d27ceb8b10a738d60d36316a54bad57e0d73fbb/ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7", size = 99999, upload-time = "2023-10-03T18:13:05.773Z" }, + { url = "https://files.pythonhosted.org/packages/ec/54/d8a795997921d87224c65d44499ca595a833093fb215b133f920c1062956/ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb", size = 118008, upload-time = "2023-10-03T18:13:07.476Z" }, + { url = "https://files.pythonhosted.org/packages/7a/a2/eb5e9d088cb9d15c24d956944c09dca0a89108ad6e2e913c099ef36e3f0d/ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1", size = 144636, upload-time = "2023-10-03T18:13:09.564Z" }, + { url = "https://files.pythonhosted.org/packages/66/98/8de4f22bbfd9135deb3422e96d450c4bc0a57d38c25976119307d2efe0aa/ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2", size = 135684, upload-time = "2023-10-03T18:13:12.11Z" }, + { url = "https://files.pythonhosted.org/packages/30/d3/5fe978cd01a61c12efd24d65fa68c6f28f28c8073a06cf11db3a854390ca/ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92", size = 734571, upload-time = "2023-10-03T18:13:14.523Z" }, + { url = "https://files.pythonhosted.org/packages/55/b3/e2531a050758b717c969cbf76c103b75d8a01e11af931b94ba656117fbe9/ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62", size = 643946, upload-time = "2023-11-09T07:40:20.598Z" }, + { url = "https://files.pythonhosted.org/packages/0d/aa/06db7ca0995b513538402e11280282c615b5ae5f09eb820460d35fb69715/ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9", size = 692169, upload-time = "2023-10-22T15:35:38.378Z" }, + { url = "https://files.pythonhosted.org/packages/27/38/4cf4d482b84ecdf51efae6635cc5483a83cf5ca9d9c13e205a750e251696/ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d", size = 740325, upload-time = "2023-10-22T15:35:40.03Z" }, + { url = "https://files.pythonhosted.org/packages/6f/67/c62c6eea53a4feb042727a3d6c18f50dc99683c2b199c06bd2a9e3db8e22/ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa", size = 98639, upload-time = "2023-10-22T15:01:25.115Z" }, + { url = "https://files.pythonhosted.org/packages/10/d2/52a3d810d0b5b3720725c0504a27b3fced7b6f310fe928f7019d79387bc1/ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b", size = 115305, upload-time = "2023-10-22T15:01:27.265Z" }, + { url = "https://files.pythonhosted.org/packages/18/52/8dc27bbd9ef1d4695975b8dc132c27c431d0186037ad3c731a6dd1c154b9/ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615", size = 146177, upload-time = "2023-10-03T18:13:27.32Z" }, + { url = "https://files.pythonhosted.org/packages/08/4c/5770b8f318fe404a455141a7a33a5568c27a1f944724e82354c8f3554db2/ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337", size = 133289, upload-time = "2023-10-03T18:13:28.463Z" }, + { url = "https://files.pythonhosted.org/packages/5a/45/644d839c09c0717c2d7f26b705560ad74b3056085b3bc7f9c2ac2081317b/ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1", size = 641518, upload-time = "2023-11-09T07:40:24.638Z" }, + { url = "https://files.pythonhosted.org/packages/22/fa/b2a8fd49c92693e9b9b6b11eef4c2a8aedaca2b521ab3e020aa4778efc23/ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91", size = 596029, upload-time = "2023-10-03T18:13:30.125Z" }, + { url = "https://files.pythonhosted.org/packages/5c/f0/702e56e12497da7960ed8a6972e5edc50545757c40f1a86a41a5217da7e9/ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28", size = 724558, upload-time = "2023-10-22T15:35:46.022Z" }, + { url = "https://files.pythonhosted.org/packages/87/a6/efb1add3bac06c25aa4c8ff8c6d3e5e91c539f6600832dd63ff98e2b44cc/ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d", size = 767665, upload-time = "2023-10-22T15:35:48.773Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fe/a638c3ad6e74f4b15c8c1aa7de61a0cfe58c629d48ea59cf07dce5eaee1e/ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe", size = 100578, upload-time = "2023-10-03T18:13:32.734Z" }, + { url = "https://files.pythonhosted.org/packages/24/ce/6f587283caaff93d0b9cac2f244fcda686897e83401bb1aa91803db7bf94/ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312", size = 118511, upload-time = "2023-10-03T18:13:35.308Z" }, + { url = "https://files.pythonhosted.org/packages/56/a9/e3be88fcebe04016c57207260f2b07c5ecacab86e9f585d10daaa2a4074f/ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001", size = 148719, upload-time = "2023-10-03T18:13:37.577Z" }, + { url = "https://files.pythonhosted.org/packages/b2/ed/f221e60a4cdc7996aae23643da44b12ef33f457c2a52d590236a6950ac8e/ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf", size = 134394, upload-time = "2023-10-03T18:13:40.27Z" }, + { url = "https://files.pythonhosted.org/packages/57/e4/f572d7e2502854f15291dfa94eebdc687e04db387559f026995c7697af34/ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c", size = 608071, upload-time = "2023-11-09T07:40:26.502Z" }, + { url = "https://files.pythonhosted.org/packages/7c/b2/389b345a60131593028b0263fddaa580edb4081697a3f3aa1f168f67519f/ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5", size = 562085, upload-time = "2023-10-03T18:13:43.36Z" }, + { url = "https://files.pythonhosted.org/packages/8d/c0/fd7196ca7a1c3867e7068ad1c4ff9230291af3f8adab2f9c2c202ecaf9cb/ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b", size = 658185, upload-time = "2023-10-22T15:35:50.371Z" }, + { url = "https://files.pythonhosted.org/packages/54/61/c18d378caadac66fa97da5d28758c751730dac7510b6a8b8b096da3fff9a/ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880", size = 692222, upload-time = "2023-10-22T15:35:51.835Z" }, + { url = "https://files.pythonhosted.org/packages/68/4c/f55fbf8510d087449b21b4cde4c05726c8dda5f9b25a8fad06d0c4319249/ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5", size = 100563, upload-time = "2023-10-03T18:13:45.931Z" }, + { url = "https://files.pythonhosted.org/packages/74/82/e9bb3a3a2268987b7bc472c5c26b420757e04db0d0408e6626d07e388e4c/ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15", size = 118400, upload-time = "2023-10-03T18:13:48.325Z" }, +] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.14" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/e9/39ec4d4b3f91188fad1842748f67d4e749c77c37e353c4e545052ee8e893/ruamel.yaml.clib-0.2.14.tar.gz", hash = "sha256:803f5044b13602d58ea378576dd75aa759f52116a0232608e8fdada4da33752e", size = 225394, upload-time = "2025-09-22T19:51:23.753Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/56/35a0a752415ae01992c68f5a6513bdef0e1b6fbdb60d7619342ce12346a0/ruamel.yaml.clib-0.2.14-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f8b2acb0ffdd2ce8208accbec2dca4a06937d556fdcaefd6473ba1b5daa7e3c4", size = 269216, upload-time = "2025-09-23T14:24:09.742Z" }, + { url = "https://files.pythonhosted.org/packages/98/6a/9a68184ab93619f4607ff1675e4ef01e8accfcbff0d482f4ca44c10d8eab/ruamel.yaml.clib-0.2.14-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:aef953f3b8bd0b50bd52a2e52fb54a6a2171a1889d8dea4a5959d46c6624c451", size = 137092, upload-time = "2025-09-22T19:50:26.906Z" }, + { url = "https://files.pythonhosted.org/packages/2b/3f/cfed5f088628128a9ec66f46794fd4d165642155c7b78c26d83b16c6bf7b/ruamel.yaml.clib-0.2.14-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a0ac90efbc7a77b0d796c03c8cc4e62fd710b3f1e4c32947713ef2ef52e09543", size = 633768, upload-time = "2025-09-22T19:50:31.228Z" }, + { url = "https://files.pythonhosted.org/packages/3a/d5/5ce2cc156c1da48160171968d91f066d305840fbf930ee955a509d025a44/ruamel.yaml.clib-0.2.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bf6b699223afe6c7fe9f2ef76e0bfa6dd892c21e94ce8c957478987ade76cd8", size = 721253, upload-time = "2025-09-22T19:50:28.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/71/d0b56bc902b38ebe4be8e270f730f929eec4edaf8a0fa7028f4ef64fa950/ruamel.yaml.clib-0.2.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d73a0187718f6eec5b2f729b0f98e4603f7bd9c48aa65d01227d1a5dcdfbe9e8", size = 683823, upload-time = "2025-09-22T19:50:29.993Z" }, + { url = "https://files.pythonhosted.org/packages/4b/db/1f37449dd89c540218598316ccafc1a0aed60215e72efa315c5367cfd015/ruamel.yaml.clib-0.2.14-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81f6d3b19bc703679a5705c6a16dabdc79823c71d791d73c65949be7f3012c02", size = 690370, upload-time = "2025-09-23T18:42:46.797Z" }, + { url = "https://files.pythonhosted.org/packages/5d/53/c498b30f35efcd9f47cb084d7ad9374f2b907470f73913dec6396b81397d/ruamel.yaml.clib-0.2.14-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b28caeaf3e670c08cb7e8de221266df8494c169bd6ed8875493fab45be9607a4", size = 703578, upload-time = "2025-09-22T19:50:32.531Z" }, + { url = "https://files.pythonhosted.org/packages/34/79/492cfad9baed68914840c39e5f3c1cc251f51a897ddb3f532601215cbb12/ruamel.yaml.clib-0.2.14-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94f3efb718f8f49b031f2071ec7a27dd20cbfe511b4dfd54ecee54c956da2b31", size = 722544, upload-time = "2025-09-22T19:50:34.157Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f5/479ebfd5ba396e209ade90f7282d84b90c57b3e07be8dc6fcd02a6df7ffc/ruamel.yaml.clib-0.2.14-cp310-cp310-win32.whl", hash = "sha256:27c070cf3888e90d992be75dd47292ff9aa17dafd36492812a6a304a1aedc182", size = 100375, upload-time = "2025-09-22T19:50:36.832Z" }, + { url = "https://files.pythonhosted.org/packages/57/31/a044520fdb3bd409889f67f1efebda0658033c7ab3f390cee37531cc9a9e/ruamel.yaml.clib-0.2.14-cp310-cp310-win_amd64.whl", hash = "sha256:4f4a150a737fccae13fb51234d41304ff2222e3b7d4c8e9428ed1a6ab48389b8", size = 118129, upload-time = "2025-09-22T19:50:35.545Z" }, + { url = "https://files.pythonhosted.org/packages/b3/9f/3c51e9578b8c36fcc4bdd271a1a5bb65963a74a4b6ad1a989768a22f6c2a/ruamel.yaml.clib-0.2.14-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5bae1a073ca4244620425cd3d3aa9746bde590992b98ee8c7c8be8c597ca0d4e", size = 270207, upload-time = "2025-09-23T14:24:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/4a/16/cb02815bc2ae9c66760c0c061d23c7358f9ba51dae95ac85247662b7fbe2/ruamel.yaml.clib-0.2.14-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:0a54e5e40a7a691a426c2703b09b0d61a14294d25cfacc00631aa6f9c964df0d", size = 137780, upload-time = "2025-09-22T19:50:37.734Z" }, + { url = "https://files.pythonhosted.org/packages/31/c6/fc687cd1b93bff8e40861eea46d6dc1a6a778d9a085684e4045ff26a8e40/ruamel.yaml.clib-0.2.14-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:10d9595b6a19778f3269399eff6bab642608e5966183abc2adbe558a42d4efc9", size = 641590, upload-time = "2025-09-22T19:50:41.978Z" }, + { url = "https://files.pythonhosted.org/packages/45/5d/65a2bc08b709b08576b3f307bf63951ee68a8e047cbbda6f1c9864ecf9a7/ruamel.yaml.clib-0.2.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dba72975485f2b87b786075e18a6e5d07dc2b4d8973beb2732b9b2816f1bad70", size = 738090, upload-time = "2025-09-22T19:50:39.152Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d0/a70a03614d9a6788a3661ab1538879ed2aae4e84d861f101243116308a37/ruamel.yaml.clib-0.2.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29757bdb7c142f9595cc1b62ec49a3d1c83fab9cef92db52b0ccebaad4eafb98", size = 700744, upload-time = "2025-09-22T19:50:40.811Z" }, + { url = "https://files.pythonhosted.org/packages/77/30/c93fa457611f79946d5cb6cc97493ca5425f3f21891d7b1f9b44eaa1b38e/ruamel.yaml.clib-0.2.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:557df28dbccf79b152fe2d1b935f6063d9cc431199ea2b0e84892f35c03bb0ee", size = 742321, upload-time = "2025-09-23T18:42:48.916Z" }, + { url = "https://files.pythonhosted.org/packages/40/85/e2c54ad637117cd13244a4649946eaa00f32edcb882d1f92df90e079ab00/ruamel.yaml.clib-0.2.14-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:26a8de280ab0d22b6e3ec745b4a5a07151a0f74aad92dd76ab9c8d8d7087720d", size = 743805, upload-time = "2025-09-22T19:50:43.58Z" }, + { url = "https://files.pythonhosted.org/packages/81/50/f899072c38877d8ef5382e0b3d47f8c4346226c1f52d6945d6f64fec6a2f/ruamel.yaml.clib-0.2.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e501c096aa3889133d674605ebd018471bc404a59cbc17da3c5924421c54d97c", size = 769529, upload-time = "2025-09-22T19:50:45.707Z" }, + { url = "https://files.pythonhosted.org/packages/99/7c/96d4b5075e30c65ea2064e40c2d657c7c235d7b6ef18751cf89a935b9041/ruamel.yaml.clib-0.2.14-cp311-cp311-win32.whl", hash = "sha256:915748cfc25b8cfd81b14d00f4bfdb2ab227a30d6d43459034533f4d1c207a2a", size = 100256, upload-time = "2025-09-22T19:50:48.26Z" }, + { url = "https://files.pythonhosted.org/packages/7d/8c/73ee2babd04e8bfcf1fd5c20aa553d18bf0ebc24b592b4f831d12ae46cc0/ruamel.yaml.clib-0.2.14-cp311-cp311-win_amd64.whl", hash = "sha256:4ccba93c1e5a40af45b2f08e4591969fa4697eae951c708f3f83dcbf9f6c6bb1", size = 118234, upload-time = "2025-09-22T19:50:47.019Z" }, + { url = "https://files.pythonhosted.org/packages/b4/42/ccfb34a25289afbbc42017e4d3d4288e61d35b2e00cfc6b92974a6a1f94b/ruamel.yaml.clib-0.2.14-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:6aeadc170090ff1889f0d2c3057557f9cd71f975f17535c26a5d37af98f19c27", size = 271775, upload-time = "2025-09-23T14:24:12.771Z" }, + { url = "https://files.pythonhosted.org/packages/82/73/e628a92e80197ff6a79ab81ec3fa00d4cc082d58ab78d3337b7ba7043301/ruamel.yaml.clib-0.2.14-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5e56ac47260c0eed992789fa0b8efe43404a9adb608608631a948cee4fc2b052", size = 138842, upload-time = "2025-09-22T19:50:49.156Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c5/346c7094344a60419764b4b1334d9e0285031c961176ff88ffb652405b0c/ruamel.yaml.clib-0.2.14-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:a911aa73588d9a8b08d662b9484bc0567949529824a55d3885b77e8dd62a127a", size = 647404, upload-time = "2025-09-22T19:50:52.921Z" }, + { url = "https://files.pythonhosted.org/packages/df/99/65080c863eb06d4498de3d6c86f3e90595e02e159fd8529f1565f56cfe2c/ruamel.yaml.clib-0.2.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a05ba88adf3d7189a974b2de7a9d56731548d35dc0a822ec3dc669caa7019b29", size = 753141, upload-time = "2025-09-22T19:50:50.294Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e3/0de85f3e3333f8e29e4b10244374a202a87665d1131798946ee22cf05c7c/ruamel.yaml.clib-0.2.14-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb04c5650de6668b853623eceadcdb1a9f2fee381f5d7b6bc842ee7c239eeec4", size = 703477, upload-time = "2025-09-22T19:50:51.508Z" }, + { url = "https://files.pythonhosted.org/packages/d9/25/0d2f09d8833c7fd77ab8efeff213093c16856479a9d293180a0d89f6bed9/ruamel.yaml.clib-0.2.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:df3ec9959241d07bc261f4983d25a1205ff37703faf42b474f15d54d88b4f8c9", size = 741157, upload-time = "2025-09-23T18:42:50.408Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8c/959f10c2e2153cbdab834c46e6954b6dd9e3b109c8f8c0a3cf1618310985/ruamel.yaml.clib-0.2.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fbc08c02e9b147a11dfcaa1ac8a83168b699863493e183f7c0c8b12850b7d259", size = 745859, upload-time = "2025-09-22T19:50:54.497Z" }, + { url = "https://files.pythonhosted.org/packages/ed/6b/e580a7c18b485e1a5f30a32cda96b20364b0ba649d9d2baaf72f8bd21f83/ruamel.yaml.clib-0.2.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c099cafc1834d3c5dac305865d04235f7c21c167c8dd31ebc3d6bbc357e2f023", size = 770200, upload-time = "2025-09-22T19:50:55.718Z" }, + { url = "https://files.pythonhosted.org/packages/ef/44/3455eebc761dc8e8fdced90f2b0a3fa61e32ba38b50de4130e2d57db0f21/ruamel.yaml.clib-0.2.14-cp312-cp312-win32.whl", hash = "sha256:b5b0f7e294700b615a3bcf6d28b26e6da94e8eba63b079f4ec92e9ba6c0d6b54", size = 98829, upload-time = "2025-09-22T19:50:58.895Z" }, + { url = "https://files.pythonhosted.org/packages/76/ab/5121f7f3b651db93de546f8c982c241397aad0a4765d793aca1dac5eadee/ruamel.yaml.clib-0.2.14-cp312-cp312-win_amd64.whl", hash = "sha256:a37f40a859b503304dd740686359fcf541d6fb3ff7fc10f539af7f7150917c68", size = 115570, upload-time = "2025-09-22T19:50:57.981Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ae/e3811f05415594025e96000349d3400978adaed88d8f98d494352d9761ee/ruamel.yaml.clib-0.2.14-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7e4f9da7e7549946e02a6122dcad00b7c1168513acb1f8a726b1aaf504a99d32", size = 269205, upload-time = "2025-09-23T14:24:15.06Z" }, + { url = "https://files.pythonhosted.org/packages/72/06/7d51f4688d6d72bb72fa74254e1593c4f5ebd0036be5b41fe39315b275e9/ruamel.yaml.clib-0.2.14-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:dd7546c851e59c06197a7c651335755e74aa383a835878ca86d2c650c07a2f85", size = 137417, upload-time = "2025-09-22T19:50:59.82Z" }, + { url = "https://files.pythonhosted.org/packages/5a/08/b4499234a420ef42960eeb05585df5cc7eb25ccb8c980490b079e6367050/ruamel.yaml.clib-0.2.14-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:1c1acc3a0209ea9042cc3cfc0790edd2eddd431a2ec3f8283d081e4d5018571e", size = 642558, upload-time = "2025-09-22T19:51:03.388Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ba/1975a27dedf1c4c33306ee67c948121be8710b19387aada29e2f139c43ee/ruamel.yaml.clib-0.2.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2070bf0ad1540d5c77a664de07ebcc45eebd1ddcab71a7a06f26936920692beb", size = 744087, upload-time = "2025-09-22T19:51:00.897Z" }, + { url = "https://files.pythonhosted.org/packages/20/15/8a19a13d27f3bd09fa18813add8380a29115a47b553845f08802959acbce/ruamel.yaml.clib-0.2.14-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd8fe07f49c170e09d76773fb86ad9135e0beee44f36e1576a201b0676d3d1d", size = 699709, upload-time = "2025-09-22T19:51:02.075Z" }, + { url = "https://files.pythonhosted.org/packages/19/ee/8d6146a079ad21e534b5083c9ee4a4c8bec42f79cf87594b60978286b39a/ruamel.yaml.clib-0.2.14-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ff86876889ea478b1381089e55cf9e345707b312beda4986f823e1d95e8c0f59", size = 708926, upload-time = "2025-09-23T18:42:51.707Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/426b714abdc222392e68f3b8ad323930d05a214a27c7e7a0f06c69126401/ruamel.yaml.clib-0.2.14-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1f118b707eece8cf84ecbc3e3ec94d9db879d85ed608f95870d39b2d2efa5dca", size = 740202, upload-time = "2025-09-22T19:51:04.673Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ac/3c5c2b27a183f4fda8a57c82211721c016bcb689a4a175865f7646db9f94/ruamel.yaml.clib-0.2.14-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b30110b29484adc597df6bd92a37b90e63a8c152ca8136aad100a02f8ba6d1b6", size = 765196, upload-time = "2025-09-22T19:51:05.916Z" }, + { url = "https://files.pythonhosted.org/packages/92/2e/06f56a71fd55021c993ed6e848c9b2e5e9cfce180a42179f0ddd28253f7c/ruamel.yaml.clib-0.2.14-cp313-cp313-win32.whl", hash = "sha256:f4e97a1cf0b7a30af9e1d9dad10a5671157b9acee790d9e26996391f49b965a2", size = 98635, upload-time = "2025-09-22T19:51:08.183Z" }, + { url = "https://files.pythonhosted.org/packages/51/79/76aba16a1689b50528224b182f71097ece338e7a4ab55e84c2e73443b78a/ruamel.yaml.clib-0.2.14-cp313-cp313-win_amd64.whl", hash = "sha256:090782b5fb9d98df96509eecdbcaffd037d47389a89492320280d52f91330d78", size = 115238, upload-time = "2025-09-22T19:51:07.081Z" }, + { url = "https://files.pythonhosted.org/packages/21/e2/a59ff65c26aaf21a24eb38df777cb9af5d87ba8fc8107c163c2da9d1e85e/ruamel.yaml.clib-0.2.14-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:7df6f6e9d0e33c7b1d435defb185095386c469109de723d514142632a7b9d07f", size = 271441, upload-time = "2025-09-23T14:24:16.498Z" }, + { url = "https://files.pythonhosted.org/packages/6b/fa/3234f913fe9a6525a7b97c6dad1f51e72b917e6872e051a5e2ffd8b16fbb/ruamel.yaml.clib-0.2.14-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:70eda7703b8126f5e52fcf276e6c0f40b0d314674f896fc58c47b0aef2b9ae83", size = 137970, upload-time = "2025-09-22T19:51:09.472Z" }, + { url = "https://files.pythonhosted.org/packages/ef/ec/4edbf17ac2c87fa0845dd366ef8d5852b96eb58fcd65fc1ecf5fe27b4641/ruamel.yaml.clib-0.2.14-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a0cb71ccc6ef9ce36eecb6272c81afdc2f565950cdcec33ae8e6cd8f7fc86f27", size = 739639, upload-time = "2025-09-22T19:51:10.566Z" }, + { url = "https://files.pythonhosted.org/packages/15/18/b0e1fafe59051de9e79cdd431863b03593ecfa8341c110affad7c8121efc/ruamel.yaml.clib-0.2.14-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e7cb9ad1d525d40f7d87b6df7c0ff916a66bc52cb61b66ac1b2a16d0c1b07640", size = 764456, upload-time = "2025-09-22T19:51:11.736Z" }, + { url = "https://files.pythonhosted.org/packages/2a/a0/e709dc2f58054049cd154319a7d37917689785b12ec43ea2df47ea5344ef/ruamel.yaml.clib-0.2.14-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:18c041b28f3456ddef1f1951d4492dbebe0f8114157c1b3c981a4611c2020792", size = 270636, upload-time = "2025-09-23T14:24:17.855Z" }, + { url = "https://files.pythonhosted.org/packages/18/81/491c9e394976e10682a596f2b785ba7066db525cc17f267005ae8ca33c73/ruamel.yaml.clib-0.2.14-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:d8354515ab62f95a07deaf7f845886cc50e2f345ceab240a3d2d09a9f7d77853", size = 137954, upload-time = "2025-09-22T19:51:12.851Z" }, + { url = "https://files.pythonhosted.org/packages/ad/a5/c6d1c767e051bbc00146a93132bf199b3e6ec2c219131b9d3e19eff428f3/ruamel.yaml.clib-0.2.14-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:275f938692013a3883edbd848edde6d9f26825d65c9a2eb1db8baa1adc96a05d", size = 636162, upload-time = "2025-09-22T19:51:16.823Z" }, + { url = "https://files.pythonhosted.org/packages/e3/6f/4746e2e8f60b3489b6cd6fad96a8e2aaa0cf7dd6760de3daad1a6e9f5789/ruamel.yaml.clib-0.2.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a60d69f4057ad9a92f3444e2367c08490daed6428291aa16cefb445c29b0e9", size = 723934, upload-time = "2025-09-22T19:51:13.948Z" }, + { url = "https://files.pythonhosted.org/packages/26/47/5446e8cea2f6b5391fba653196f38b3f14030c1c324bd9aa67f1773d24ec/ruamel.yaml.clib-0.2.14-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ac5ff9425d8acb8f59ac5b96bcb7fd3d272dc92d96a7c730025928ffcc88a7a", size = 686265, upload-time = "2025-09-22T19:51:15.142Z" }, + { url = "https://files.pythonhosted.org/packages/52/d7/344d7b3010b6a01af97431bdf89056abb2d8bd704d0f3430e7b50232cce4/ruamel.yaml.clib-0.2.14-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e1d1735d97fd8a48473af048739379975651fab186f8a25a9f683534e6904179", size = 693042, upload-time = "2025-09-23T18:42:53.238Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d5/a0f2cce1b6cfa9bf1921b8a19ebceafc7a9b3c27882e5af5a07ae080b1bd/ruamel.yaml.clib-0.2.14-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:83bbd8354f6abb3fdfb922d1ed47ad8d1db3ea72b0523dac8d07cdacfe1c0fcf", size = 706110, upload-time = "2025-09-22T19:51:18.467Z" }, + { url = "https://files.pythonhosted.org/packages/42/cd/85b422d24ee2096eaf6faa360c95ef9bdb59097d19b9624cebce4dd9bc2a/ruamel.yaml.clib-0.2.14-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:808c7190a0fe7ae7014c42f73897cf8e9ef14ff3aa533450e51b1e72ec5239ad", size = 725028, upload-time = "2025-09-22T19:51:19.782Z" }, + { url = "https://files.pythonhosted.org/packages/4d/ac/99e6e0ea2584f84f447069d0187fe411e9b5deb7e3ddecda25001cfc7a95/ruamel.yaml.clib-0.2.14-cp39-cp39-win32.whl", hash = "sha256:6d5472f63a31b042aadf5ed28dd3ef0523da49ac17f0463e10fda9c4a2773352", size = 100915, upload-time = "2025-09-22T19:51:21.764Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8d/846e43369658958c99d959bb7774136fff9210f9017d91a4277818ceafbf/ruamel.yaml.clib-0.2.14-cp39-cp39-win_amd64.whl", hash = "sha256:8dd3c2cc49caa7a8d64b67146462aed6723a0495e44bf0aa0a2e94beaa8432f6", size = 118706, upload-time = "2025-09-22T19:51:20.878Z" }, +] + +[[package]] +name = "ruff" +version = "0.4.10" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/04/b660bc832ebfa40e1788edf6934388340751cbc6f733d1f807edca9d96e6/ruff-0.4.10.tar.gz", hash = "sha256:3aa4f2bc388a30d346c56524f7cacca85945ba124945fe489952aadb6b5cd804", size = 2577674, upload-time = "2024-06-20T17:42:56.184Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/0d/134fdd72f566d37b0c59b6e55f60993c705f93a0fe3c1faa6f8a269057c7/ruff-0.4.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c2c4d0859305ac5a16310eec40e4e9a9dec5dcdfbe92697acd99624e8638dac", size = 8510271, upload-time = "2024-06-20T17:41:49.591Z" }, + { url = "https://files.pythonhosted.org/packages/46/5e/4ac799ffec39ef5012052c1f144a0f7a63a0322ebd328b802d64beb3d091/ruff-0.4.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a79489607d1495685cdd911a323a35871abfb7a95d4f98fc6f85e799227ac46e", size = 8107776, upload-time = "2024-06-20T17:41:55.14Z" }, + { url = "https://files.pythonhosted.org/packages/78/6f/37af054d3ced5a6196201f6c248eeaec6b3b844136cf3da510d591dbfd89/ruff-0.4.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1dd1681dfa90a41b8376a61af05cc4dc5ff32c8f14f5fe20dba9ff5deb80cd6", size = 9868358, upload-time = "2024-06-20T17:41:58.162Z" }, + { url = "https://files.pythonhosted.org/packages/c7/38/070baf0393ba0da9d85409bdd63874776926acfc372e8e9f0ed21957aeee/ruff-0.4.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c75c53bb79d71310dc79fb69eb4902fba804a81f374bc86a9b117a8d077a1784", size = 9172824, upload-time = "2024-06-20T17:42:02.386Z" }, + { url = "https://files.pythonhosted.org/packages/e7/9d/bad51d81c918e1ce1648b24480a63f5605662efe69b55fad05825b5711ff/ruff-0.4.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739", size = 9997887, upload-time = "2024-06-20T17:42:06.309Z" }, + { url = "https://files.pythonhosted.org/packages/ec/a4/1310b3d003cb67f3c86cb8cc5c5e475dab152b1eef88558abd11e55daaad/ruff-0.4.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d8f71885bce242da344989cae08e263de29752f094233f932d4f5cfb4ef36a81", size = 10743762, upload-time = "2024-06-20T17:42:11.13Z" }, + { url = "https://files.pythonhosted.org/packages/b8/c1/5373bc5a4c3782c0a368ce5ca4ec3a689574daf71f68f55720a6a64321d4/ruff-0.4.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:330421543bd3222cdfec481e8ff3460e8702ed1e58b494cf9d9e4bf90db52b9d", size = 10329524, upload-time = "2024-06-20T17:42:15.294Z" }, + { url = "https://files.pythonhosted.org/packages/48/dc/2c057e7717a3eaaa89ea848a26ef085930a2509f9b66ceae55319668c03d/ruff-0.4.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e9b6fb3a37b772628415b00c4fc892f97954275394ed611056a4b8a2631365e", size = 11208593, upload-time = "2024-06-20T17:42:20.077Z" }, + { url = "https://files.pythonhosted.org/packages/11/c3/3f89b1e967a869642bd9198f27e2b89b8300862555d3e1e39b4ccaf92e8b/ruff-0.4.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6", size = 10041835, upload-time = "2024-06-20T17:42:24.487Z" }, + { url = "https://files.pythonhosted.org/packages/d0/e6/734aed23112de8df5a2f3bc02e9e45cd3910fe83b0d2bb2456e200c52d98/ruff-0.4.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:67fe086b433b965c22de0b4259ddfe6fa541c95bf418499bedb9ad5fb8d1c631", size = 9842683, upload-time = "2024-06-20T17:42:28.324Z" }, + { url = "https://files.pythonhosted.org/packages/cf/13/bc788b2e21d3e4db74d1375da22f50f944bc1fef064c4749f307b0c8794f/ruff-0.4.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:acfaaab59543382085f9eb51f8e87bac26bf96b164839955f244d07125a982ef", size = 9283929, upload-time = "2024-06-20T17:42:32.221Z" }, + { url = "https://files.pythonhosted.org/packages/f0/09/f3c6560f9d81a4c5d800996090c9cc54d794ea14ab8f8af46b7483005963/ruff-0.4.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3cea07079962b2941244191569cf3a05541477286f5cafea638cd3aa94b56815", size = 9617526, upload-time = "2024-06-20T17:42:36.588Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/11ae4e8587efe40aa083835665d0818626f8f4a10aa4ebc097cdbfae7624/ruff-0.4.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:338a64ef0748f8c3a80d7f05785930f7965d71ca260904a9321d13be24b79695", size = 10114053, upload-time = "2024-06-20T17:42:41.144Z" }, + { url = "https://files.pythonhosted.org/packages/e8/94/3bb62a0086e9c61d0506e546e7cf68456fd93bf569a8adfa5e324812970d/ruff-0.4.10-py3-none-win32.whl", hash = "sha256:ffe3cd2f89cb54561c62e5fa20e8f182c0a444934bf430515a4b422f1ab7b7ca", size = 7707741, upload-time = "2024-06-20T17:42:45.061Z" }, + { url = "https://files.pythonhosted.org/packages/d8/4e/6fd32ebd0a09f25ed9911b77c5273b7a6b3b50a78d6ed0508d66a24398b8/ruff-0.4.10-py3-none-win_amd64.whl", hash = "sha256:67f67cef43c55ffc8cc59e8e0b97e9e60b4837c8f21e8ab5ffd5d66e196e25f7", size = 8519153, upload-time = "2024-06-20T17:42:48.907Z" }, + { url = "https://files.pythonhosted.org/packages/dc/78/5109b7db3b44a64157b025e45eec6591e4beb53732104637d8e0ee0c5570/ruff-0.4.10-py3-none-win_arm64.whl", hash = "sha256:dd1fcee327c20addac7916ca4e2653fbbf2e8388d8a6477ce5b4e986b68ae6c0", size = 7906942, upload-time = "2024-06-20T17:42:52.972Z" }, +] + +[[package]] +name = "ruff" +version = "0.7.4" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/8b/bc4e0dfa1245b07cf14300e10319b98e958a53ff074c1dd86b35253a8c2a/ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2", size = 3275547, upload-time = "2024-11-15T11:33:11.853Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/4b/f5094719e254829766b807dadb766841124daba75a37da83e292ae5ad12f/ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478", size = 10447512, upload-time = "2024-11-15T11:32:27.812Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1d/3d2d2c9f601cf6044799c5349ff5267467224cefed9b35edf5f1f36486e9/ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63", size = 10235436, upload-time = "2024-11-15T11:32:30.6Z" }, + { url = "https://files.pythonhosted.org/packages/62/83/42a6ec6216ded30b354b13e0e9327ef75a3c147751aaf10443756cb690e9/ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20", size = 9888936, upload-time = "2024-11-15T11:32:33.287Z" }, + { url = "https://files.pythonhosted.org/packages/4d/26/e1e54893b13046a6ad05ee9b89ee6f71542ba250f72b4c7a7d17c3dbf73d/ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109", size = 10697353, upload-time = "2024-11-15T11:32:35.895Z" }, + { url = "https://files.pythonhosted.org/packages/21/24/98d2e109c4efc02bfef144ec6ea2c3e1217e7ce0cfddda8361d268dfd499/ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452", size = 10228078, upload-time = "2024-11-15T11:32:40.929Z" }, + { url = "https://files.pythonhosted.org/packages/ad/b7/964c75be9bc2945fc3172241b371197bb6d948cc69e28bc4518448c368f3/ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea", size = 11264823, upload-time = "2024-11-15T11:32:43.31Z" }, + { url = "https://files.pythonhosted.org/packages/12/8d/20abdbf705969914ce40988fe71a554a918deaab62c38ec07483e77866f6/ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7", size = 11951855, upload-time = "2024-11-15T11:32:46.038Z" }, + { url = "https://files.pythonhosted.org/packages/b8/fc/6519ce58c57b4edafcdf40920b7273dfbba64fc6ebcaae7b88e4dc1bf0a8/ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05", size = 11516580, upload-time = "2024-11-15T11:32:48.17Z" }, + { url = "https://files.pythonhosted.org/packages/37/1a/5ec1844e993e376a86eb2456496831ed91b4398c434d8244f89094758940/ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06", size = 12692057, upload-time = "2024-11-15T11:32:50.623Z" }, + { url = "https://files.pythonhosted.org/packages/50/90/76867152b0d3c05df29a74bb028413e90f704f0f6701c4801174ba47f959/ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc", size = 11085137, upload-time = "2024-11-15T11:32:52.819Z" }, + { url = "https://files.pythonhosted.org/packages/c8/eb/0a7cb6059ac3555243bd026bb21785bbc812f7bbfa95a36c101bd72b47ae/ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172", size = 10681243, upload-time = "2024-11-15T11:32:55.902Z" }, + { url = "https://files.pythonhosted.org/packages/5e/76/2270719dbee0fd35780b05c08a07b7a726c3da9f67d9ae89ef21fc18e2e5/ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a", size = 10319187, upload-time = "2024-11-15T11:32:58.255Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e5/39100f72f8ba70bec1bd329efc880dea8b6c1765ea1cb9d0c1c5f18b8d7f/ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd", size = 10803715, upload-time = "2024-11-15T11:33:00.88Z" }, + { url = "https://files.pythonhosted.org/packages/a5/89/40e904784f305fb56850063f70a998a64ebba68796d823dde67e89a24691/ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a", size = 11162912, upload-time = "2024-11-15T11:33:03.097Z" }, + { url = "https://files.pythonhosted.org/packages/8d/1b/dd77503b3875c51e3dbc053fd8367b845ab8b01c9ca6d0c237082732856c/ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac", size = 8702767, upload-time = "2024-11-15T11:33:05.15Z" }, + { url = "https://files.pythonhosted.org/packages/63/76/253ddc3e89e70165bba952ecca424b980b8d3c2598ceb4fc47904f424953/ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6", size = 9497534, upload-time = "2024-11-15T11:33:07.359Z" }, + { url = "https://files.pythonhosted.org/packages/aa/70/f8724f31abc0b329ca98b33d73c14020168babcf71b0cba3cded5d9d0e66/ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f", size = 8851590, upload-time = "2024-11-15T11:33:09.664Z" }, +] + +[[package]] +name = "ruff" +version = "0.13.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/33/c8e89216845615d14d2d42ba2bee404e7206a8db782f33400754f3799f05/ruff-0.13.1.tar.gz", hash = "sha256:88074c3849087f153d4bb22e92243ad4c1b366d7055f98726bc19aa08dc12d51", size = 5397987, upload-time = "2025-09-18T19:52:44.33Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/41/ca37e340938f45cfb8557a97a5c347e718ef34702546b174e5300dbb1f28/ruff-0.13.1-py3-none-linux_armv6l.whl", hash = "sha256:b2abff595cc3cbfa55e509d89439b5a09a6ee3c252d92020bd2de240836cf45b", size = 12304308, upload-time = "2025-09-18T19:51:56.253Z" }, + { url = "https://files.pythonhosted.org/packages/ff/84/ba378ef4129415066c3e1c80d84e539a0d52feb250685091f874804f28af/ruff-0.13.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4ee9f4249bf7f8bb3984c41bfaf6a658162cdb1b22e3103eabc7dd1dc5579334", size = 12937258, upload-time = "2025-09-18T19:52:00.184Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b6/ec5e4559ae0ad955515c176910d6d7c93edcbc0ed1a3195a41179c58431d/ruff-0.13.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5c5da4af5f6418c07d75e6f3224e08147441f5d1eac2e6ce10dcce5e616a3bae", size = 12214554, upload-time = "2025-09-18T19:52:02.753Z" }, + { url = "https://files.pythonhosted.org/packages/70/d6/cb3e3b4f03b9b0c4d4d8f06126d34b3394f6b4d764912fe80a1300696ef6/ruff-0.13.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80524f84a01355a59a93cef98d804e2137639823bcee2931f5028e71134a954e", size = 12448181, upload-time = "2025-09-18T19:52:05.279Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ea/bf60cb46d7ade706a246cd3fb99e4cfe854efa3dfbe530d049c684da24ff/ruff-0.13.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff7f5ce8d7988767dd46a148192a14d0f48d1baea733f055d9064875c7d50389", size = 12104599, upload-time = "2025-09-18T19:52:07.497Z" }, + { url = "https://files.pythonhosted.org/packages/2d/3e/05f72f4c3d3a69e65d55a13e1dd1ade76c106d8546e7e54501d31f1dc54a/ruff-0.13.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c55d84715061f8b05469cdc9a446aa6c7294cd4bd55e86a89e572dba14374f8c", size = 13791178, upload-time = "2025-09-18T19:52:10.189Z" }, + { url = "https://files.pythonhosted.org/packages/81/e7/01b1fc403dd45d6cfe600725270ecc6a8f8a48a55bc6521ad820ed3ceaf8/ruff-0.13.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ac57fed932d90fa1624c946dc67a0a3388d65a7edc7d2d8e4ca7bddaa789b3b0", size = 14814474, upload-time = "2025-09-18T19:52:12.866Z" }, + { url = "https://files.pythonhosted.org/packages/fa/92/d9e183d4ed6185a8df2ce9faa3f22e80e95b5f88d9cc3d86a6d94331da3f/ruff-0.13.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c366a71d5b4f41f86a008694f7a0d75fe409ec298685ff72dc882f882d532e36", size = 14217531, upload-time = "2025-09-18T19:52:15.245Z" }, + { url = "https://files.pythonhosted.org/packages/3b/4a/6ddb1b11d60888be224d721e01bdd2d81faaf1720592858ab8bac3600466/ruff-0.13.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4ea9d1b5ad3e7a83ee8ebb1229c33e5fe771e833d6d3dcfca7b77d95b060d38", size = 13265267, upload-time = "2025-09-18T19:52:17.649Z" }, + { url = "https://files.pythonhosted.org/packages/81/98/3f1d18a8d9ea33ef2ad508f0417fcb182c99b23258ec5e53d15db8289809/ruff-0.13.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f70202996055b555d3d74b626406476cc692f37b13bac8828acff058c9966a", size = 13243120, upload-time = "2025-09-18T19:52:20.332Z" }, + { url = "https://files.pythonhosted.org/packages/8d/86/b6ce62ce9c12765fa6c65078d1938d2490b2b1d9273d0de384952b43c490/ruff-0.13.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:f8cff7a105dad631085d9505b491db33848007d6b487c3c1979dd8d9b2963783", size = 13443084, upload-time = "2025-09-18T19:52:23.032Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/af7943466a41338d04503fb5a81b2fd07251bd272f546622e5b1599a7976/ruff-0.13.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:9761e84255443316a258dd7dfbd9bfb59c756e52237ed42494917b2577697c6a", size = 12295105, upload-time = "2025-09-18T19:52:25.263Z" }, + { url = "https://files.pythonhosted.org/packages/3f/97/0249b9a24f0f3ebd12f007e81c87cec6d311de566885e9309fcbac5b24cc/ruff-0.13.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3d376a88c3102ef228b102211ef4a6d13df330cb0f5ca56fdac04ccec2a99700", size = 12072284, upload-time = "2025-09-18T19:52:27.478Z" }, + { url = "https://files.pythonhosted.org/packages/f6/85/0b64693b2c99d62ae65236ef74508ba39c3febd01466ef7f354885e5050c/ruff-0.13.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cbefd60082b517a82c6ec8836989775ac05f8991715d228b3c1d86ccc7df7dae", size = 12970314, upload-time = "2025-09-18T19:52:30.212Z" }, + { url = "https://files.pythonhosted.org/packages/96/fc/342e9f28179915d28b3747b7654f932ca472afbf7090fc0c4011e802f494/ruff-0.13.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dd16b9a5a499fe73f3c2ef09a7885cb1d97058614d601809d37c422ed1525317", size = 13422360, upload-time = "2025-09-18T19:52:32.676Z" }, + { url = "https://files.pythonhosted.org/packages/37/54/6177a0dc10bce6f43e392a2192e6018755473283d0cf43cc7e6afc182aea/ruff-0.13.1-py3-none-win32.whl", hash = "sha256:55e9efa692d7cb18580279f1fbb525146adc401f40735edf0aaeabd93099f9a0", size = 12178448, upload-time = "2025-09-18T19:52:35.545Z" }, + { url = "https://files.pythonhosted.org/packages/64/51/c6a3a33d9938007b8bdc8ca852ecc8d810a407fb513ab08e34af12dc7c24/ruff-0.13.1-py3-none-win_amd64.whl", hash = "sha256:3a3fb595287ee556de947183489f636b9f76a72f0fa9c028bdcabf5bab2cc5e5", size = 13286458, upload-time = "2025-09-18T19:52:38.198Z" }, + { url = "https://files.pythonhosted.org/packages/fd/04/afc078a12cf68592345b1e2d6ecdff837d286bac023d7a22c54c7a698c5b/ruff-0.13.1-py3-none-win_arm64.whl", hash = "sha256:c0bae9ffd92d54e03c2bf266f466da0a65e145f298ee5b5846ed435f6a00518a", size = 12437893, upload-time = "2025-09-18T19:52:41.283Z" }, +] + +[[package]] +name = "secretstorage" +version = "3.3.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.9.*'", + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "cryptography", marker = "python_full_version < '3.10'" }, + { name = "jeepney", marker = "python_full_version < '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", size = 19739, upload-time = "2022-08-13T16:22:46.976Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", size = 15221, upload-time = "2022-08-13T16:22:44.457Z" }, +] + +[[package]] +name = "secretstorage" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", +] +dependencies = [ + { name = "cryptography", marker = "python_full_version >= '3.10'" }, + { name = "jeepney", marker = "python_full_version >= '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/31/9f/11ef35cf1027c1339552ea7bfe6aaa74a8516d8b5caf6e7d338daf54fd80/secretstorage-3.4.0.tar.gz", hash = "sha256:c46e216d6815aff8a8a18706a2fbfd8d53fcbb0dce99301881687a1b0289ef7c", size = 19748, upload-time = "2025-09-09T16:42:13.859Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/ff/2e2eed29e02c14a5cb6c57f09b2d5b40e65d6cc71f45b52e0be295ccbc2f/secretstorage-3.4.0-py3-none-any.whl", hash = "sha256:0e3b6265c2c63509fb7415717607e4b2c9ab767b7f344a57473b779ca13bd02e", size = 15272, upload-time = "2025-09-09T16:42:12.744Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sseclient-py" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/ed/3df5ab8bb0c12f86c28d0cadb11ed1de44a92ed35ce7ff4fd5518a809325/sseclient-py-1.8.0.tar.gz", hash = "sha256:c547c5c1a7633230a38dc599a21a2dc638f9b5c297286b48b46b935c71fac3e8", size = 7791, upload-time = "2023-09-01T19:39:20.45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/58/97655efdfeb5b4eeab85b1fc5d3fa1023661246c2ab2a26ea8e47402d4f2/sseclient_py-1.8.0-py2.py3-none-any.whl", hash = "sha256:4ecca6dc0b9f963f8384e9d7fd529bf93dd7d708144c4fb5da0e0a1a926fee83", size = 8828, upload-time = "2023-09-01T19:39:17.627Z" }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, + { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429, upload-time = "2024-11-27T22:37:56.698Z" }, + { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067, upload-time = "2024-11-27T22:37:57.63Z" }, + { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030, upload-time = "2024-11-27T22:37:59.344Z" }, + { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898, upload-time = "2024-11-27T22:38:00.429Z" }, + { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894, upload-time = "2024-11-27T22:38:02.094Z" }, + { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319, upload-time = "2024-11-27T22:38:03.206Z" }, + { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273, upload-time = "2024-11-27T22:38:04.217Z" }, + { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310, upload-time = "2024-11-27T22:38:05.908Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309, upload-time = "2024-11-27T22:38:06.812Z" }, + { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762, upload-time = "2024-11-27T22:38:07.731Z" }, + { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453, upload-time = "2024-11-27T22:38:09.384Z" }, + { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486, upload-time = "2024-11-27T22:38:10.329Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349, upload-time = "2024-11-27T22:38:11.443Z" }, + { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159, upload-time = "2024-11-27T22:38:13.099Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243, upload-time = "2024-11-27T22:38:14.766Z" }, + { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645, upload-time = "2024-11-27T22:38:15.843Z" }, + { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584, upload-time = "2024-11-27T22:38:17.645Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875, upload-time = "2024-11-27T22:38:19.159Z" }, + { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418, upload-time = "2024-11-27T22:38:20.064Z" }, + { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708, upload-time = "2024-11-27T22:38:21.659Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582, upload-time = "2024-11-27T22:38:22.693Z" }, + { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543, upload-time = "2024-11-27T22:38:24.367Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691, upload-time = "2024-11-27T22:38:26.081Z" }, + { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170, upload-time = "2024-11-27T22:38:27.921Z" }, + { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530, upload-time = "2024-11-27T22:38:29.591Z" }, + { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666, upload-time = "2024-11-27T22:38:30.639Z" }, + { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954, upload-time = "2024-11-27T22:38:31.702Z" }, + { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724, upload-time = "2024-11-27T22:38:32.837Z" }, + { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383, upload-time = "2024-11-27T22:38:34.455Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, +] + +[[package]] +name = "twine" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "id", marker = "python_full_version < '3.9'" }, + { name = "importlib-metadata", version = "8.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "keyring", version = "25.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' and platform_machine != 'ppc64le' and platform_machine != 's390x'" }, + { name = "packaging", marker = "python_full_version < '3.9'" }, + { name = "readme-renderer", version = "43.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "requests", version = "2.32.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, + { name = "requests-toolbelt", marker = "python_full_version < '3.9'" }, + { name = "rfc3986", marker = "python_full_version < '3.9'" }, + { name = "rich", marker = "python_full_version < '3.9'" }, + { name = "urllib3", version = "2.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c8/a2/6df94fc5c8e2170d21d7134a565c3a8fb84f9797c1dd65a5976aaf714418/twine-6.1.0.tar.gz", hash = "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd", size = 168404, upload-time = "2025-01-21T18:45:26.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/b6/74e927715a285743351233f33ea3c684528a0d374d2e43ff9ce9585b73fe/twine-6.1.0-py3-none-any.whl", hash = "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384", size = 40791, upload-time = "2025-01-21T18:45:24.584Z" }, +] + +[[package]] +name = "twine" +version = "6.2.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "id", marker = "python_full_version >= '3.9'" }, + { name = "importlib-metadata", version = "8.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, + { name = "keyring", version = "25.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and platform_machine != 'ppc64le' and platform_machine != 's390x'" }, + { name = "packaging", marker = "python_full_version >= '3.9'" }, + { name = "readme-renderer", version = "44.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "requests-toolbelt", marker = "python_full_version >= '3.9'" }, + { name = "rfc3986", marker = "python_full_version >= '3.9'" }, + { name = "rich", marker = "python_full_version >= '3.9'" }, + { name = "urllib3", version = "2.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/a8/949edebe3a82774c1ec34f637f5dd82d1cf22c25e963b7d63771083bbee5/twine-6.2.0.tar.gz", hash = "sha256:e5ed0d2fd70c9959770dce51c8f39c8945c574e18173a7b81802dab51b4b75cf", size = 172262, upload-time = "2025-09-04T15:43:17.255Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl", hash = "sha256:418ebf08ccda9a8caaebe414433b0ba5e25eb5e4a927667122fbe8f829f985d8", size = 42727, upload-time = "2025-09-04T15:43:15.994Z" }, +] + +[[package]] +name = "typer" +version = "0.12.5" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +dependencies = [ + { name = "click", marker = "python_full_version < '3.9'" }, + { name = "rich", marker = "python_full_version < '3.9'" }, + { name = "shellingham", marker = "python_full_version < '3.9'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/58/a79003b91ac2c6890fc5d90145c662fd5771c6f11447f116b63300436bc9/typer-0.12.5.tar.gz", hash = "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722", size = 98953, upload-time = "2024-08-24T21:17:57.346Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/2b/886d13e742e514f704c33c4caa7df0f3b89e5a25ef8db02aa9ca3d9535d5/typer-0.12.5-py3-none-any.whl", hash = "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b", size = 47288, upload-time = "2024-08-24T21:17:55.451Z" }, +] + +[[package]] +name = "typer" +version = "0.17.4" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +dependencies = [ + { name = "click", marker = "python_full_version >= '3.9'" }, + { name = "rich", marker = "python_full_version >= '3.9'" }, + { name = "shellingham", marker = "python_full_version >= '3.9'" }, + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/92/e8/2a73ccf9874ec4c7638f172efc8972ceab13a0e3480b389d6ed822f7a822/typer-0.17.4.tar.gz", hash = "sha256:b77dc07d849312fd2bb5e7f20a7af8985c7ec360c45b051ed5412f64d8dc1580", size = 103734, upload-time = "2025-09-05T18:14:40.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/72/6b3e70d32e89a5cbb6a4513726c1ae8762165b027af569289e19ec08edd8/typer-0.17.4-py3-none-any.whl", hash = "sha256:015534a6edaa450e7007eba705d5c18c3349dcea50a6ad79a5ed530967575824", size = 46643, upload-time = "2025-09-05T18:14:39.166Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.13.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", version = "4.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677, upload-time = "2024-09-12T10:52:18.401Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338, upload-time = "2024-09-12T10:52:16.589Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "watchdog" +version = "4.0.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/4f/38/764baaa25eb5e35c9a043d4c4588f9836edfe52a708950f4b6d5f714fd42/watchdog-4.0.2.tar.gz", hash = "sha256:b4dfbb6c49221be4535623ea4474a4d6ee0a9cef4a80b20c28db4d858b64e270", size = 126587, upload-time = "2024-08-11T07:38:01.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/b0/219893d41c16d74d0793363bf86df07d50357b81f64bba4cb94fe76e7af4/watchdog-4.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ede7f010f2239b97cc79e6cb3c249e72962404ae3865860855d5cbe708b0fd22", size = 100257, upload-time = "2024-08-11T07:37:04.209Z" }, + { url = "https://files.pythonhosted.org/packages/6d/c6/8e90c65693e87d98310b2e1e5fd7e313266990853b489e85ce8396cc26e3/watchdog-4.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a2cffa171445b0efa0726c561eca9a27d00a1f2b83846dbd5a4f639c4f8ca8e1", size = 92249, upload-time = "2024-08-11T07:37:06.364Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cd/2e306756364a934532ff8388d90eb2dc8bb21fe575cd2b33d791ce05a02f/watchdog-4.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c50f148b31b03fbadd6d0b5980e38b558046b127dc483e5e4505fcef250f9503", size = 92888, upload-time = "2024-08-11T07:37:08.275Z" }, + { url = "https://files.pythonhosted.org/packages/de/78/027ad372d62f97642349a16015394a7680530460b1c70c368c506cb60c09/watchdog-4.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7c7d4bf585ad501c5f6c980e7be9c4f15604c7cc150e942d82083b31a7548930", size = 100256, upload-time = "2024-08-11T07:37:11.017Z" }, + { url = "https://files.pythonhosted.org/packages/59/a9/412b808568c1814d693b4ff1cec0055dc791780b9dc947807978fab86bc1/watchdog-4.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:914285126ad0b6eb2258bbbcb7b288d9dfd655ae88fa28945be05a7b475a800b", size = 92252, upload-time = "2024-08-11T07:37:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/04/57/179d76076cff264982bc335dd4c7da6d636bd3e9860bbc896a665c3447b6/watchdog-4.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:984306dc4720da5498b16fc037b36ac443816125a3705dfde4fd90652d8028ef", size = 92888, upload-time = "2024-08-11T07:37:15.077Z" }, + { url = "https://files.pythonhosted.org/packages/92/f5/ea22b095340545faea37ad9a42353b265ca751f543da3fb43f5d00cdcd21/watchdog-4.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1cdcfd8142f604630deef34722d695fb455d04ab7cfe9963055df1fc69e6727a", size = 100342, upload-time = "2024-08-11T07:37:16.393Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d2/8ce97dff5e465db1222951434e3115189ae54a9863aef99c6987890cc9ef/watchdog-4.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d7ab624ff2f663f98cd03c8b7eedc09375a911794dfea6bf2a359fcc266bff29", size = 92306, upload-time = "2024-08-11T07:37:17.997Z" }, + { url = "https://files.pythonhosted.org/packages/49/c4/1aeba2c31b25f79b03b15918155bc8c0b08101054fc727900f1a577d0d54/watchdog-4.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:132937547a716027bd5714383dfc40dc66c26769f1ce8a72a859d6a48f371f3a", size = 92915, upload-time = "2024-08-11T07:37:19.967Z" }, + { url = "https://files.pythonhosted.org/packages/79/63/eb8994a182672c042d85a33507475c50c2ee930577524dd97aea05251527/watchdog-4.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd67c7df93eb58f360c43802acc945fa8da70c675b6fa37a241e17ca698ca49b", size = 100343, upload-time = "2024-08-11T07:37:21.935Z" }, + { url = "https://files.pythonhosted.org/packages/ce/82/027c0c65c2245769580605bcd20a1dc7dfd6c6683c8c4e2ef43920e38d27/watchdog-4.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcfd02377be80ef3b6bc4ce481ef3959640458d6feaae0bd43dd90a43da90a7d", size = 92313, upload-time = "2024-08-11T07:37:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/2a/89/ad4715cbbd3440cb0d336b78970aba243a33a24b1a79d66f8d16b4590d6a/watchdog-4.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:980b71510f59c884d684b3663d46e7a14b457c9611c481e5cef08f4dd022eed7", size = 92919, upload-time = "2024-08-11T07:37:24.715Z" }, + { url = "https://files.pythonhosted.org/packages/55/08/1a9086a3380e8828f65b0c835b86baf29ebb85e5e94a2811a2eb4f889cfd/watchdog-4.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:aa160781cafff2719b663c8a506156e9289d111d80f3387cf3af49cedee1f040", size = 100255, upload-time = "2024-08-11T07:37:26.862Z" }, + { url = "https://files.pythonhosted.org/packages/6c/3e/064974628cf305831f3f78264800bd03b3358ec181e3e9380a36ff156b93/watchdog-4.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f6ee8dedd255087bc7fe82adf046f0b75479b989185fb0bdf9a98b612170eac7", size = 92257, upload-time = "2024-08-11T07:37:28.253Z" }, + { url = "https://files.pythonhosted.org/packages/23/69/1d2ad9c12d93bc1e445baa40db46bc74757f3ffc3a3be592ba8dbc51b6e5/watchdog-4.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0b4359067d30d5b864e09c8597b112fe0a0a59321a0f331498b013fb097406b4", size = 92886, upload-time = "2024-08-11T07:37:29.52Z" }, + { url = "https://files.pythonhosted.org/packages/68/eb/34d3173eceab490d4d1815ba9a821e10abe1da7a7264a224e30689b1450c/watchdog-4.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:770eef5372f146997638d737c9a3c597a3b41037cfbc5c41538fc27c09c3a3f9", size = 100254, upload-time = "2024-08-11T07:37:30.888Z" }, + { url = "https://files.pythonhosted.org/packages/18/a1/4bbafe7ace414904c2cc9bd93e472133e8ec11eab0b4625017f0e34caad8/watchdog-4.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eeea812f38536a0aa859972d50c76e37f4456474b02bd93674d1947cf1e39578", size = 92249, upload-time = "2024-08-11T07:37:32.193Z" }, + { url = "https://files.pythonhosted.org/packages/f3/11/ec5684e0ca692950826af0de862e5db167523c30c9cbf9b3f4ce7ec9cc05/watchdog-4.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b2c45f6e1e57ebb4687690c05bc3a2c1fb6ab260550c4290b8abb1335e0fd08b", size = 92891, upload-time = "2024-08-11T07:37:34.212Z" }, + { url = "https://files.pythonhosted.org/packages/3b/9a/6f30f023324de7bad8a3eb02b0afb06bd0726003a3550e9964321315df5a/watchdog-4.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:10b6683df70d340ac3279eff0b2766813f00f35a1d37515d2c99959ada8f05fa", size = 91775, upload-time = "2024-08-11T07:37:35.567Z" }, + { url = "https://files.pythonhosted.org/packages/87/62/8be55e605d378a154037b9ba484e00a5478e627b69c53d0f63e3ef413ba6/watchdog-4.0.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f7c739888c20f99824f7aa9d31ac8a97353e22d0c0e54703a547a218f6637eb3", size = 92255, upload-time = "2024-08-11T07:37:37.596Z" }, + { url = "https://files.pythonhosted.org/packages/6b/59/12e03e675d28f450bade6da6bc79ad6616080b317c472b9ae688d2495a03/watchdog-4.0.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c100d09ac72a8a08ddbf0629ddfa0b8ee41740f9051429baa8e31bb903ad7508", size = 91682, upload-time = "2024-08-11T07:37:38.901Z" }, + { url = "https://files.pythonhosted.org/packages/ef/69/241998de9b8e024f5c2fbdf4324ea628b4231925305011ca8b7e1c3329f6/watchdog-4.0.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f5315a8c8dd6dd9425b974515081fc0aadca1d1d61e078d2246509fd756141ee", size = 92249, upload-time = "2024-08-11T07:37:40.143Z" }, + { url = "https://files.pythonhosted.org/packages/70/3f/2173b4d9581bc9b5df4d7f2041b6c58b5e5448407856f68d4be9981000d0/watchdog-4.0.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2d468028a77b42cc685ed694a7a550a8d1771bb05193ba7b24006b8241a571a1", size = 91773, upload-time = "2024-08-11T07:37:42.095Z" }, + { url = "https://files.pythonhosted.org/packages/f0/de/6fff29161d5789048f06ef24d94d3ddcc25795f347202b7ea503c3356acb/watchdog-4.0.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f15edcae3830ff20e55d1f4e743e92970c847bcddc8b7509bcd172aa04de506e", size = 92250, upload-time = "2024-08-11T07:37:44.052Z" }, + { url = "https://files.pythonhosted.org/packages/8a/b1/25acf6767af6f7e44e0086309825bd8c098e301eed5868dc5350642124b9/watchdog-4.0.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:936acba76d636f70db8f3c66e76aa6cb5136a936fc2a5088b9ce1c7a3508fc83", size = 82947, upload-time = "2024-08-11T07:37:45.388Z" }, + { url = "https://files.pythonhosted.org/packages/e8/90/aebac95d6f954bd4901f5d46dcd83d68e682bfd21798fd125a95ae1c9dbf/watchdog-4.0.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:e252f8ca942a870f38cf785aef420285431311652d871409a64e2a0a52a2174c", size = 82942, upload-time = "2024-08-11T07:37:46.722Z" }, + { url = "https://files.pythonhosted.org/packages/15/3a/a4bd8f3b9381824995787488b9282aff1ed4667e1110f31a87b871ea851c/watchdog-4.0.2-py3-none-manylinux2014_i686.whl", hash = "sha256:0e83619a2d5d436a7e58a1aea957a3c1ccbf9782c43c0b4fed80580e5e4acd1a", size = 82947, upload-time = "2024-08-11T07:37:48.941Z" }, + { url = "https://files.pythonhosted.org/packages/09/cc/238998fc08e292a4a18a852ed8274159019ee7a66be14441325bcd811dfd/watchdog-4.0.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:88456d65f207b39f1981bf772e473799fcdc10801062c36fd5ad9f9d1d463a73", size = 82946, upload-time = "2024-08-11T07:37:50.279Z" }, + { url = "https://files.pythonhosted.org/packages/80/f1/d4b915160c9d677174aa5fae4537ae1f5acb23b3745ab0873071ef671f0a/watchdog-4.0.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:32be97f3b75693a93c683787a87a0dc8db98bb84701539954eef991fb35f5fbc", size = 82947, upload-time = "2024-08-11T07:37:51.55Z" }, + { url = "https://files.pythonhosted.org/packages/db/02/56ebe2cf33b352fe3309588eb03f020d4d1c061563d9858a9216ba004259/watchdog-4.0.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:c82253cfc9be68e3e49282831afad2c1f6593af80c0daf1287f6a92657986757", size = 82944, upload-time = "2024-08-11T07:37:52.855Z" }, + { url = "https://files.pythonhosted.org/packages/01/d2/c8931ff840a7e5bd5dcb93f2bb2a1fd18faf8312e9f7f53ff1cf76ecc8ed/watchdog-4.0.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c0b14488bd336c5b1845cee83d3e631a1f8b4e9c5091ec539406e4a324f882d8", size = 82947, upload-time = "2024-08-11T07:37:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d8/cdb0c21a4a988669d7c210c75c6a2c9a0e16a3b08d9f7e633df0d9a16ad8/watchdog-4.0.2-py3-none-win32.whl", hash = "sha256:0d8a7e523ef03757a5aa29f591437d64d0d894635f8a50f370fe37f913ce4e19", size = 82935, upload-time = "2024-08-11T07:37:56.668Z" }, + { url = "https://files.pythonhosted.org/packages/99/2e/b69dfaae7a83ea64ce36538cc103a3065e12c447963797793d5c0a1d5130/watchdog-4.0.2-py3-none-win_amd64.whl", hash = "sha256:c344453ef3bf875a535b0488e3ad28e341adbd5a9ffb0f7d62cefacc8824ef2b", size = 82934, upload-time = "2024-08-11T07:37:57.991Z" }, + { url = "https://files.pythonhosted.org/packages/b0/0b/43b96a9ecdd65ff5545b1b13b687ca486da5c6249475b1a45f24d63a1858/watchdog-4.0.2-py3-none-win_ia64.whl", hash = "sha256:baececaa8edff42cd16558a639a9b0ddf425f93d892e8392a56bf904f5eff22c", size = 82933, upload-time = "2024-08-11T07:37:59.573Z" }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390, upload-time = "2024-11-01T14:06:24.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389, upload-time = "2024-11-01T14:06:27.112Z" }, + { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020, upload-time = "2024-11-01T14:06:29.876Z" }, + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390, upload-time = "2024-11-01T14:06:49.325Z" }, + { url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386, upload-time = "2024-11-01T14:06:50.536Z" }, + { url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017, upload-time = "2024-11-01T14:06:51.717Z" }, + { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, + { url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903, upload-time = "2024-11-01T14:06:57.052Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381, upload-time = "2024-11-01T14:06:58.193Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + +[[package]] +name = "zipp" +version = "3.20.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.8.1' and python_full_version < '3.9'", + "python_full_version < '3.8.1'", +] +sdist = { url = "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", size = 24199, upload-time = "2024-09-13T13:44:16.101Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", size = 9200, upload-time = "2024-09-13T13:44:14.38Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version == '3.9.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, +] diff --git a/packages/sdk/stainless/stainless.yml b/packages/sdk/stainless/stainless.yml index 1efe263a0f..4b7e27ca20 100644 --- a/packages/sdk/stainless/stainless.yml +++ b/packages/sdk/stainless/stainless.yml @@ -14,12 +14,6 @@ targets: go: package_name: opencode production_repo: sst/opencode-sdk-go - python: - project_name: opencode-ai - package_name: opencode_ai - production_repo: sst/opencode-sdk-python - publish: - pypi: true environments: production: http://localhost:54321 diff --git a/script/hooks b/script/hooks new file mode 100755 index 0000000000..ea42297ae8 --- /dev/null +++ b/script/hooks @@ -0,0 +1,19 @@ +#!/bin/sh + +if [ ! -d ".git" ]; then + exit 0 +fi + +mkdir -p .git/hooks + +cat > .git/hooks/pre-push << 'EOF' +#!/bin/sh +# Ensure dependencies are installed before typecheck +if command -v bun >/dev/null 2>&1; then + bun install >/dev/null 2>&1 || true +fi +bun run typecheck +EOF + +chmod +x .git/hooks/pre-push +echo "✅ Pre-push hook installed" From 09e7e0ab70e6d3ff36eed0e77aa99610194e9c59 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 28 Oct 2025 20:28:30 -0400 Subject: [PATCH 053/609] tag majors --- packages/opencode/script/publish.ts | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/opencode/script/publish.ts b/packages/opencode/script/publish.ts index ef35b8514f..a81e7e9e93 100755 --- a/packages/opencode/script/publish.ts +++ b/packages/opencode/script/publish.ts @@ -40,16 +40,33 @@ for (const [name] of Object.entries(binaries)) { } await $`cd ./dist/${pkg.name} && bun publish --access public --tag ${Script.channel}` +if (!Script.preview) { + const major = Script.version.split(".")[0] + const majorTag = `v${major}` + for (const [name] of Object.entries(binaries)) { + await $`cd dist/${name} && npm dist-tag add ${name}@${Script.version} ${majorTag}` + } + await $`cd ./dist/${pkg.name} && npm dist-tag add ${pkg.name}-ai@${Script.version} ${majorTag}` +} + if (!Script.preview) { for (const key of Object.keys(binaries)) { await $`cd dist/${key}/bin && zip -r ../../${key}.zip *` } // Calculate SHA values - const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) - const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) - const macX64Sha = await $`sha256sum ./dist/opencode-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) - const macArm64Sha = await $`sha256sum ./dist/opencode-darwin-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) + const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.zip | cut -d' ' -f1` + .text() + .then((x) => x.trim()) + const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.zip | cut -d' ' -f1` + .text() + .then((x) => x.trim()) + const macX64Sha = await $`sha256sum ./dist/opencode-darwin-x64.zip | cut -d' ' -f1` + .text() + .then((x) => x.trim()) + const macArm64Sha = await $`sha256sum ./dist/opencode-darwin-arm64.zip | cut -d' ' -f1` + .text() + .then((x) => x.trim()) const [pkgver, _subver = ""] = Script.version.split(/(-.*)/, 2) From cd79676b42cefad289c21631605c737fbe461f80 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 28 Oct 2025 20:35:18 -0400 Subject: [PATCH 054/609] sync --- packages/opencode/script/publish.ts | 2 +- packages/script/src/index.ts | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/opencode/script/publish.ts b/packages/opencode/script/publish.ts index a81e7e9e93..833198cb0f 100755 --- a/packages/opencode/script/publish.ts +++ b/packages/opencode/script/publish.ts @@ -42,7 +42,7 @@ await $`cd ./dist/${pkg.name} && bun publish --access public --tag ${Script.chan if (!Script.preview) { const major = Script.version.split(".")[0] - const majorTag = `v${major}` + const majorTag = `latest-${major}` for (const [name] of Object.entries(binaries)) { await $`cd dist/${name} && npm dist-tag add ${name}@${Script.version} ${majorTag}` } diff --git a/packages/script/src/index.ts b/packages/script/src/index.ts index d5b2c9e4a5..090b7396be 100644 --- a/packages/script/src/index.ts +++ b/packages/script/src/index.ts @@ -4,10 +4,13 @@ if (process.versions.bun !== "1.3.0") { throw new Error("This script requires bun@1.3.0") } -const CHANNEL = process.env["OPENCODE_CHANNEL"] ?? (await $`git branch --show-current`.text().then((x) => x.trim())) +const CHANNEL = + process.env["OPENCODE_CHANNEL"] ?? + (await $`git branch --show-current`.text().then((x) => x.trim())) const IS_PREVIEW = CHANNEL !== "latest" const VERSION = await (async () => { - if (IS_PREVIEW) return `0.0.0-${CHANNEL}-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}` + if (IS_PREVIEW) + return `0.0.0-${CHANNEL}-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}` const version = await fetch("https://registry.npmjs.org/opencode-ai/latest") .then((res) => { if (!res.ok) throw new Error(res.statusText) From db3fb9d316d57c0673196a56fbe552d6fe66be26 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 28 Oct 2025 21:28:44 -0400 Subject: [PATCH 055/609] ci: stuff --- .github/workflows/publish.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c88860a0fc..df1a36f775 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -53,13 +53,17 @@ jobs: - name: Install OpenCode run: curl -fsSL https://opencode.ai/install | bash + - name: Setup npm auth + run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc + - name: Publish run: | ./script/publish.ts env: OPENCODE_BUMP: ${{ inputs.bump }} OPENCODE_CHANNEL: latest + NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} AUR_KEY: ${{ secrets.AUR_KEY }} - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} From 4b1c6300a0aff04bed3df3be6143681f6862eb61 Mon Sep 17 00:00:00 2001 From: opencode Date: Wed, 29 Oct 2025 01:35:27 +0000 Subject: [PATCH 056/609] release: v0.15.23 --- bun.lock | 22 +- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 +- packages/sdk/js/package.json | 4 +- packages/sdk/js/src/gen/client.gen.ts | 7 +- packages/sdk/js/src/gen/client/client.gen.ts | 4 +- packages/sdk/js/src/gen/client/types.gen.ts | 19 +- packages/sdk/js/src/gen/client/utils.gen.ts | 37 ++- .../sdk/js/src/gen/core/bodySerializer.gen.ts | 4 +- .../sdk/js/src/gen/core/pathSerializer.gen.ts | 12 +- .../js/src/gen/core/serverSentEvents.gen.ts | 6 +- packages/sdk/js/src/gen/core/types.gen.ts | 11 +- packages/sdk/js/src/gen/core/utils.gen.ts | 4 +- packages/sdk/js/src/gen/sdk.gen.ts | 300 ++++++++++++++---- packages/sdk/js/src/gen/types.gen.ts | 18 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 25 files changed, 358 insertions(+), 116 deletions(-) diff --git a/bun.lock b/bun.lock index 594cdc5bf1..79bdbde5a8 100644 --- a/bun.lock +++ b/bun.lock @@ -37,7 +37,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -64,7 +64,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -88,7 +88,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -109,7 +109,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -150,7 +150,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -166,7 +166,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "0.15.20", + "version": "0.15.23", "bin": { "opencode": "./bin/opencode", }, @@ -230,7 +230,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -250,7 +250,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "0.15.20", + "version": "0.15.23", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -261,7 +261,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -274,7 +274,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@kobalte/core": "catalog:", "@pierre/precision-diffs": "catalog:", @@ -297,7 +297,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 0f36562b4e..d9d0d5ca7e 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "0.15.20" + "version": "0.15.23" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 16de536d60..1361600b1e 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "0.15.20", + "version": "0.15.23", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index f2cb56d29b..6229a5309b 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "0.15.20", + "version": "0.15.23", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index f93660af7d..bd54e9134a 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "0.15.20", + "version": "0.15.23", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 3861c49bda..8e5b0167e5 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "0.15.20", + "version": "0.15.23", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index b1dd969e26..837f093b03 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "0.15.20", + "version": "0.15.23", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index c50d4eae0e..ce7934b100 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "0.15.20", + "version": "0.15.23", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 8f5e6e82d9..037cdb6466 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "0.15.20", + "version": "0.15.23", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 559ac6507b..46ceefd0c0 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "0.15.20", + "version": "0.15.23", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/src/gen/client.gen.ts b/packages/sdk/js/src/gen/client.gen.ts index e7cdb292c6..77ef579a67 100644 --- a/packages/sdk/js/src/gen/client.gen.ts +++ b/packages/sdk/js/src/gen/client.gen.ts @@ -1,7 +1,12 @@ // This file is auto-generated by @hey-api/openapi-ts import type { ClientOptions } from "./types.gen.js" -import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from "./client/index.js" +import { + type Config, + type ClientOptions as DefaultClientOptions, + createClient, + createConfig, +} from "./client/index.js" /** * The `createClientConfig()` function will be called on client initialization diff --git a/packages/sdk/js/src/gen/client/client.gen.ts b/packages/sdk/js/src/gen/client/client.gen.ts index 34a8d0bece..3a2499efbb 100644 --- a/packages/sdk/js/src/gen/client/client.gen.ts +++ b/packages/sdk/js/src/gen/client/client.gen.ts @@ -107,7 +107,9 @@ export const createClient = (config: Config = {}): Client => { } const parseAs = - (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json" + (opts.parseAs === "auto" + ? getParseAs(response.headers.get("Content-Type")) + : opts.parseAs) ?? "json" let data: any switch (parseAs) { diff --git a/packages/sdk/js/src/gen/client/types.gen.ts b/packages/sdk/js/src/gen/client/types.gen.ts index db8e544cfd..1761dacbfc 100644 --- a/packages/sdk/js/src/gen/client/types.gen.ts +++ b/packages/sdk/js/src/gen/client/types.gen.ts @@ -1,7 +1,10 @@ // This file is auto-generated by @hey-api/openapi-ts import type { Auth } from "../core/auth.gen.js" -import type { ServerSentEventsOptions, ServerSentEventsResult } from "../core/serverSentEvents.gen.js" +import type { + ServerSentEventsOptions, + ServerSentEventsResult, +} from "../core/serverSentEvents.gen.js" import type { Client as CoreClient, Config as CoreConfig } from "../core/types.gen.js" import type { Middleware } from "./utils.gen.js" @@ -62,7 +65,11 @@ export interface RequestOptions< }>, Pick< ServerSentEventsOptions, - "onSseError" | "onSseEvent" | "sseDefaultRetryDelay" | "sseMaxRetryAttempts" | "sseMaxRetryDelay" + | "onSseError" + | "onSseEvent" + | "sseDefaultRetryDelay" + | "sseMaxRetryAttempts" + | "sseMaxRetryDelay" > { /** * Any body that you want to add to your request. @@ -202,7 +209,10 @@ export type Options< ThrowOnError extends boolean = boolean, TResponse = unknown, TResponseStyle extends ResponseStyle = "fields", -> = OmitKeys, "body" | "path" | "query" | "url"> & +> = OmitKeys< + RequestOptions, + "body" | "path" | "query" | "url" +> & Omit export type OptionsLegacyParser< @@ -211,7 +221,8 @@ export type OptionsLegacyParser< TResponseStyle extends ResponseStyle = "fields", > = TData extends { body?: any } ? TData extends { headers?: any } - ? OmitKeys, "body" | "headers" | "url"> & TData + ? OmitKeys, "body" | "headers" | "url"> & + TData : OmitKeys, "body" | "url"> & TData & Pick, "headers"> diff --git a/packages/sdk/js/src/gen/client/utils.gen.ts b/packages/sdk/js/src/gen/client/utils.gen.ts index 209bfbe8e6..53ffbad1bc 100644 --- a/packages/sdk/js/src/gen/client/utils.gen.ts +++ b/packages/sdk/js/src/gen/client/utils.gen.ts @@ -3,11 +3,19 @@ import { getAuthToken } from "../core/auth.gen.js" import type { QuerySerializerOptions } from "../core/bodySerializer.gen.js" import { jsonBodySerializer } from "../core/bodySerializer.gen.js" -import { serializeArrayParam, serializeObjectParam, serializePrimitiveParam } from "../core/pathSerializer.gen.js" +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from "../core/pathSerializer.gen.js" import { getUrl } from "../core/utils.gen.js" import type { Client, ClientOptions, Config, RequestOptions } from "./types.gen.js" -export const createQuerySerializer = ({ allowReserved, array, object }: QuerySerializerOptions = {}) => { +export const createQuerySerializer = ({ + allowReserved, + array, + object, +}: QuerySerializerOptions = {}) => { const querySerializer = (queryParams: T) => { const search: string[] = [] if (queryParams && typeof queryParams === "object") { @@ -77,7 +85,9 @@ export const getParseAs = (contentType: string | null): Exclude cleanContent.startsWith(type))) { + if ( + ["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type)) + ) { return "blob" } @@ -97,7 +107,11 @@ const checkForExistence = ( if (!name) { return false } - if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) { + if ( + options.headers.has(name) || + options.query?.[name] || + options.headers.get("Cookie")?.includes(`${name}=`) + ) { return true } return false @@ -162,7 +176,9 @@ export const mergeConfigs = (a: Config, b: Config): Config => { return config } -export const mergeHeaders = (...headers: Array["headers"] | undefined>): Headers => { +export const mergeHeaders = ( + ...headers: Array["headers"] | undefined> +): Headers => { const mergedHeaders = new Headers() for (const header of headers) { if (!header || typeof header !== "object") { @@ -181,7 +197,10 @@ export const mergeHeaders = (...headers: Array["headers"] | und } else if (value !== undefined) { // assume object headers are meant to be JSON stringified, i.e. their // content value in OpenAPI specification is 'application/json' - mergedHeaders.set(key, typeof value === "object" ? JSON.stringify(value) : (value as string)) + mergedHeaders.set( + key, + typeof value === "object" ? JSON.stringify(value) : (value as string), + ) } } } @@ -197,7 +216,11 @@ type ErrInterceptor = ( type ReqInterceptor = (request: Req, options: Options) => Req | Promise -type ResInterceptor = (response: Res, request: Req, options: Options) => Res | Promise +type ResInterceptor = ( + response: Res, + request: Req, + options: Options, +) => Res | Promise class Interceptors { _fns: (Interceptor | null)[] diff --git a/packages/sdk/js/src/gen/core/bodySerializer.gen.ts b/packages/sdk/js/src/gen/core/bodySerializer.gen.ts index 0660616052..83e3f56d7b 100644 --- a/packages/sdk/js/src/gen/core/bodySerializer.gen.ts +++ b/packages/sdk/js/src/gen/core/bodySerializer.gen.ts @@ -31,7 +31,9 @@ const serializeUrlSearchParamsPair = (data: URLSearchParams, key: string, value: } export const formDataBodySerializer = { - bodySerializer: | Array>>(body: T): FormData => { + bodySerializer: | Array>>( + body: T, + ): FormData => { const data = new FormData() Object.entries(body).forEach(([key, value]) => { diff --git a/packages/sdk/js/src/gen/core/pathSerializer.gen.ts b/packages/sdk/js/src/gen/core/pathSerializer.gen.ts index 96be3bc5a3..f135283570 100644 --- a/packages/sdk/js/src/gen/core/pathSerializer.gen.ts +++ b/packages/sdk/js/src/gen/core/pathSerializer.gen.ts @@ -74,9 +74,9 @@ export const serializeArrayParam = ({ value: unknown[] }) => { if (!explode) { - const joinedValues = (allowReserved ? value : value.map((v) => encodeURIComponent(v as string))).join( - separatorArrayNoExplode(style), - ) + const joinedValues = ( + allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) + ).join(separatorArrayNoExplode(style)) switch (style) { case "label": return `.${joinedValues}` @@ -106,7 +106,11 @@ export const serializeArrayParam = ({ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues } -export const serializePrimitiveParam = ({ allowReserved, name, value }: SerializePrimitiveParam) => { +export const serializePrimitiveParam = ({ + allowReserved, + name, + value, +}: SerializePrimitiveParam) => { if (value === undefined || value === null) { return "" } diff --git a/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts b/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts index 8f7fac549d..183855da1c 100644 --- a/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts +++ b/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts @@ -60,7 +60,11 @@ export interface StreamEvent { } export type ServerSentEventsResult = { - stream: AsyncGenerator ? TData[keyof TData] : TData, TReturn, TNext> + stream: AsyncGenerator< + TData extends Record ? TData[keyof TData] : TData, + TReturn, + TNext + > } export const createSseClient = ({ diff --git a/packages/sdk/js/src/gen/core/types.gen.ts b/packages/sdk/js/src/gen/core/types.gen.ts index 16408b2d09..b60604fee4 100644 --- a/packages/sdk/js/src/gen/core/types.gen.ts +++ b/packages/sdk/js/src/gen/core/types.gen.ts @@ -1,7 +1,11 @@ // This file is auto-generated by @hey-api/openapi-ts import type { Auth, AuthToken } from "./auth.gen.js" -import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from "./bodySerializer.gen.js" +import type { + BodySerializer, + QuerySerializer, + QuerySerializerOptions, +} from "./bodySerializer.gen.js" export interface Client { /** @@ -41,7 +45,10 @@ export interface Config { */ headers?: | RequestInit["headers"] - | Record + | Record< + string, + string | number | boolean | (string | number | boolean)[] | null | undefined | unknown + > /** * The request method. * diff --git a/packages/sdk/js/src/gen/core/utils.gen.ts b/packages/sdk/js/src/gen/core/utils.gen.ts index be18c608a5..62e02972c6 100644 --- a/packages/sdk/js/src/gen/core/utils.gen.ts +++ b/packages/sdk/js/src/gen/core/utils.gen.ts @@ -73,7 +73,9 @@ export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { continue } - const replaceValue = encodeURIComponent(style === "label" ? `.${value as string}` : (value as string)) + const replaceValue = encodeURIComponent( + style === "label" ? `.${value as string}` : (value as string), + ) url = url.replace(match, replaceValue) } } diff --git a/packages/sdk/js/src/gen/sdk.gen.ts b/packages/sdk/js/src/gen/sdk.gen.ts index 4f224ea4c4..42e575dc29 100644 --- a/packages/sdk/js/src/gen/sdk.gen.ts +++ b/packages/sdk/js/src/gen/sdk.gen.ts @@ -133,10 +133,10 @@ import type { } from "./types.gen.js" import { client as _heyApiClient } from "./client.gen.js" -export type Options = ClientOptions< - TData, - ThrowOnError -> & { +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, +> = ClientOptions & { /** * You can provide a client instance returned by `createClient()` instead of * individual options. This might be also useful if you want to implement a @@ -164,7 +164,9 @@ class Project extends _HeyApiClient { /** * List all projects */ - public list(options?: Options) { + public list( + options?: Options, + ) { return (options?.client ?? this._client).get({ url: "/project", ...options, @@ -174,7 +176,9 @@ class Project extends _HeyApiClient { /** * Get the current project */ - public current(options?: Options) { + public current( + options?: Options, + ) { return (options?.client ?? this._client).get({ url: "/project/current", ...options, @@ -196,8 +200,14 @@ class Config extends _HeyApiClient { /** * Update config */ - public update(options?: Options) { - return (options?.client ?? this._client).patch({ + public update( + options?: Options, + ) { + return (options?.client ?? this._client).patch< + ConfigUpdateResponses, + ConfigUpdateErrors, + ThrowOnError + >({ url: "/config", ...options, headers: { @@ -210,7 +220,9 @@ class Config extends _HeyApiClient { /** * List all providers */ - public providers(options?: Options) { + public providers( + options?: Options, + ) { return (options?.client ?? this._client).get({ url: "/config/providers", ...options, @@ -256,7 +268,9 @@ class Session extends _HeyApiClient { /** * List all sessions */ - public list(options?: Options) { + public list( + options?: Options, + ) { return (options?.client ?? this._client).get({ url: "/session", ...options, @@ -266,8 +280,14 @@ class Session extends _HeyApiClient { /** * Create a new session */ - public create(options?: Options) { - return (options?.client ?? this._client).post({ + public create( + options?: Options, + ) { + return (options?.client ?? this._client).post< + SessionCreateResponses, + SessionCreateErrors, + ThrowOnError + >({ url: "/session", ...options, headers: { @@ -280,8 +300,14 @@ class Session extends _HeyApiClient { /** * Delete a session and all its data */ - public delete(options: Options) { - return (options.client ?? this._client).delete({ + public delete( + options: Options, + ) { + return (options.client ?? this._client).delete< + SessionDeleteResponses, + SessionDeleteErrors, + ThrowOnError + >({ url: "/session/{id}", ...options, }) @@ -291,7 +317,11 @@ class Session extends _HeyApiClient { * Get session */ public get(options: Options) { - return (options.client ?? this._client).get({ + return (options.client ?? this._client).get< + SessionGetResponses, + SessionGetErrors, + ThrowOnError + >({ url: "/session/{id}", ...options, }) @@ -300,8 +330,14 @@ class Session extends _HeyApiClient { /** * Update session properties */ - public update(options: Options) { - return (options.client ?? this._client).patch({ + public update( + options: Options, + ) { + return (options.client ?? this._client).patch< + SessionUpdateResponses, + SessionUpdateErrors, + ThrowOnError + >({ url: "/session/{id}", ...options, headers: { @@ -314,8 +350,14 @@ class Session extends _HeyApiClient { /** * Get a session's children */ - public children(options: Options) { - return (options.client ?? this._client).get({ + public children( + options: Options, + ) { + return (options.client ?? this._client).get< + SessionChildrenResponses, + SessionChildrenErrors, + ThrowOnError + >({ url: "/session/{id}/children", ...options, }) @@ -324,8 +366,14 @@ class Session extends _HeyApiClient { /** * Get the todo list for a session */ - public todo(options: Options) { - return (options.client ?? this._client).get({ + public todo( + options: Options, + ) { + return (options.client ?? this._client).get< + SessionTodoResponses, + SessionTodoErrors, + ThrowOnError + >({ url: "/session/{id}/todo", ...options, }) @@ -334,8 +382,14 @@ class Session extends _HeyApiClient { /** * Analyze the app and create an AGENTS.md file */ - public init(options: Options) { - return (options.client ?? this._client).post({ + public init( + options: Options, + ) { + return (options.client ?? this._client).post< + SessionInitResponses, + SessionInitErrors, + ThrowOnError + >({ url: "/session/{id}/init", ...options, headers: { @@ -348,7 +402,9 @@ class Session extends _HeyApiClient { /** * Fork an existing session at a specific message */ - public fork(options: Options) { + public fork( + options: Options, + ) { return (options.client ?? this._client).post({ url: "/session/{id}/fork", ...options, @@ -362,8 +418,14 @@ class Session extends _HeyApiClient { /** * Abort a session */ - public abort(options: Options) { - return (options.client ?? this._client).post({ + public abort( + options: Options, + ) { + return (options.client ?? this._client).post< + SessionAbortResponses, + SessionAbortErrors, + ThrowOnError + >({ url: "/session/{id}/abort", ...options, }) @@ -372,8 +434,14 @@ class Session extends _HeyApiClient { /** * Unshare the session */ - public unshare(options: Options) { - return (options.client ?? this._client).delete({ + public unshare( + options: Options, + ) { + return (options.client ?? this._client).delete< + SessionUnshareResponses, + SessionUnshareErrors, + ThrowOnError + >({ url: "/session/{id}/share", ...options, }) @@ -382,8 +450,14 @@ class Session extends _HeyApiClient { /** * Share a session */ - public share(options: Options) { - return (options.client ?? this._client).post({ + public share( + options: Options, + ) { + return (options.client ?? this._client).post< + SessionShareResponses, + SessionShareErrors, + ThrowOnError + >({ url: "/session/{id}/share", ...options, }) @@ -392,7 +466,9 @@ class Session extends _HeyApiClient { /** * Get the diff that resulted from this user message */ - public diff(options: Options) { + public diff( + options: Options, + ) { return (options.client ?? this._client).get({ url: "/session/{id}/diff", ...options, @@ -402,8 +478,14 @@ class Session extends _HeyApiClient { /** * Summarize the session */ - public summarize(options: Options) { - return (options.client ?? this._client).post({ + public summarize( + options: Options, + ) { + return (options.client ?? this._client).post< + SessionSummarizeResponses, + SessionSummarizeErrors, + ThrowOnError + >({ url: "/session/{id}/summarize", ...options, headers: { @@ -416,8 +498,14 @@ class Session extends _HeyApiClient { /** * List messages for a session */ - public messages(options: Options) { - return (options.client ?? this._client).get({ + public messages( + options: Options, + ) { + return (options.client ?? this._client).get< + SessionMessagesResponses, + SessionMessagesErrors, + ThrowOnError + >({ url: "/session/{id}/message", ...options, }) @@ -426,8 +514,14 @@ class Session extends _HeyApiClient { /** * Create and send a new message to a session */ - public prompt(options: Options) { - return (options.client ?? this._client).post({ + public prompt( + options: Options, + ) { + return (options.client ?? this._client).post< + SessionPromptResponses, + SessionPromptErrors, + ThrowOnError + >({ url: "/session/{id}/message", ...options, headers: { @@ -440,8 +534,14 @@ class Session extends _HeyApiClient { /** * Get a message from a session */ - public message(options: Options) { - return (options.client ?? this._client).get({ + public message( + options: Options, + ) { + return (options.client ?? this._client).get< + SessionMessageResponses, + SessionMessageErrors, + ThrowOnError + >({ url: "/session/{id}/message/{messageID}", ...options, }) @@ -450,8 +550,14 @@ class Session extends _HeyApiClient { /** * Send a new command to a session */ - public command(options: Options) { - return (options.client ?? this._client).post({ + public command( + options: Options, + ) { + return (options.client ?? this._client).post< + SessionCommandResponses, + SessionCommandErrors, + ThrowOnError + >({ url: "/session/{id}/command", ...options, headers: { @@ -464,8 +570,14 @@ class Session extends _HeyApiClient { /** * Run a shell command */ - public shell(options: Options) { - return (options.client ?? this._client).post({ + public shell( + options: Options, + ) { + return (options.client ?? this._client).post< + SessionShellResponses, + SessionShellErrors, + ThrowOnError + >({ url: "/session/{id}/shell", ...options, headers: { @@ -478,8 +590,14 @@ class Session extends _HeyApiClient { /** * Revert a message */ - public revert(options: Options) { - return (options.client ?? this._client).post({ + public revert( + options: Options, + ) { + return (options.client ?? this._client).post< + SessionRevertResponses, + SessionRevertErrors, + ThrowOnError + >({ url: "/session/{id}/revert", ...options, headers: { @@ -492,8 +610,14 @@ class Session extends _HeyApiClient { /** * Restore all reverted messages */ - public unrevert(options: Options) { - return (options.client ?? this._client).post({ + public unrevert( + options: Options, + ) { + return (options.client ?? this._client).post< + SessionUnrevertResponses, + SessionUnrevertErrors, + ThrowOnError + >({ url: "/session/{id}/unrevert", ...options, }) @@ -504,7 +628,9 @@ class Command extends _HeyApiClient { /** * List all commands */ - public list(options?: Options) { + public list( + options?: Options, + ) { return (options?.client ?? this._client).get({ url: "/command", ...options, @@ -526,7 +652,9 @@ class Find extends _HeyApiClient { /** * Find files */ - public files(options: Options) { + public files( + options: Options, + ) { return (options.client ?? this._client).get({ url: "/find/file", ...options, @@ -536,7 +664,9 @@ class Find extends _HeyApiClient { /** * Find workspace symbols */ - public symbols(options: Options) { + public symbols( + options: Options, + ) { return (options.client ?? this._client).get({ url: "/find/symbol", ...options, @@ -568,7 +698,9 @@ class File extends _HeyApiClient { /** * Get file status */ - public status(options?: Options) { + public status( + options?: Options, + ) { return (options?.client ?? this._client).get({ url: "/file/status", ...options, @@ -594,7 +726,9 @@ class App extends _HeyApiClient { /** * List all agents */ - public agents(options?: Options) { + public agents( + options?: Options, + ) { return (options?.client ?? this._client).get({ url: "/agent", ...options, @@ -606,7 +740,9 @@ class Mcp extends _HeyApiClient { /** * Get MCP server status */ - public status(options?: Options) { + public status( + options?: Options, + ) { return (options?.client ?? this._client).get({ url: "/mcp", ...options, @@ -618,8 +754,14 @@ class Tui extends _HeyApiClient { /** * Append prompt to the TUI */ - public appendPrompt(options?: Options) { - return (options?.client ?? this._client).post({ + public appendPrompt( + options?: Options, + ) { + return (options?.client ?? this._client).post< + TuiAppendPromptResponses, + TuiAppendPromptErrors, + ThrowOnError + >({ url: "/tui/append-prompt", ...options, headers: { @@ -632,7 +774,9 @@ class Tui extends _HeyApiClient { /** * Open the help dialog */ - public openHelp(options?: Options) { + public openHelp( + options?: Options, + ) { return (options?.client ?? this._client).post({ url: "/tui/open-help", ...options, @@ -642,7 +786,9 @@ class Tui extends _HeyApiClient { /** * Open the session dialog */ - public openSessions(options?: Options) { + public openSessions( + options?: Options, + ) { return (options?.client ?? this._client).post({ url: "/tui/open-sessions", ...options, @@ -652,7 +798,9 @@ class Tui extends _HeyApiClient { /** * Open the theme dialog */ - public openThemes(options?: Options) { + public openThemes( + options?: Options, + ) { return (options?.client ?? this._client).post({ url: "/tui/open-themes", ...options, @@ -662,7 +810,9 @@ class Tui extends _HeyApiClient { /** * Open the model dialog */ - public openModels(options?: Options) { + public openModels( + options?: Options, + ) { return (options?.client ?? this._client).post({ url: "/tui/open-models", ...options, @@ -672,7 +822,9 @@ class Tui extends _HeyApiClient { /** * Submit the prompt */ - public submitPrompt(options?: Options) { + public submitPrompt( + options?: Options, + ) { return (options?.client ?? this._client).post({ url: "/tui/submit-prompt", ...options, @@ -682,7 +834,9 @@ class Tui extends _HeyApiClient { /** * Clear the prompt */ - public clearPrompt(options?: Options) { + public clearPrompt( + options?: Options, + ) { return (options?.client ?? this._client).post({ url: "/tui/clear-prompt", ...options, @@ -692,8 +846,14 @@ class Tui extends _HeyApiClient { /** * Execute a TUI command (e.g. agent_cycle) */ - public executeCommand(options?: Options) { - return (options?.client ?? this._client).post({ + public executeCommand( + options?: Options, + ) { + return (options?.client ?? this._client).post< + TuiExecuteCommandResponses, + TuiExecuteCommandErrors, + ThrowOnError + >({ url: "/tui/execute-command", ...options, headers: { @@ -706,7 +866,9 @@ class Tui extends _HeyApiClient { /** * Show a toast notification in the TUI */ - public showToast(options?: Options) { + public showToast( + options?: Options, + ) { return (options?.client ?? this._client).post({ url: "/tui/show-toast", ...options, @@ -738,8 +900,14 @@ class Event extends _HeyApiClient { /** * Get events */ - public subscribe(options?: Options) { - return (options?.client ?? this._client).get.sse({ + public subscribe( + options?: Options, + ) { + return (options?.client ?? this._client).get.sse< + EventSubscribeResponses, + unknown, + ThrowOnError + >({ url: "/event", ...options, }) diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 0b55cc5b45..0b8948c572 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -505,6 +505,10 @@ export type Config = { } }> } + /** + * Number of retries for chat completions on failure + */ + chatMaxRetries?: number disable_paste_summary?: boolean } } @@ -658,7 +662,12 @@ export type AssistantMessage = { created: number completed?: number } - error?: ProviderAuthError | UnknownError | MessageOutputLengthError | MessageAbortedError | ApiError + error?: + | ProviderAuthError + | UnknownError + | MessageOutputLengthError + | MessageAbortedError + | ApiError system: Array parentID: string modelID: string @@ -1222,7 +1231,12 @@ export type EventSessionError = { type: "session.error" properties: { sessionID?: string - error?: ProviderAuthError | UnknownError | MessageOutputLengthError | MessageAbortedError | ApiError + error?: + | ProviderAuthError + | UnknownError + | MessageOutputLengthError + | MessageAbortedError + | ApiError } } diff --git a/packages/slack/package.json b/packages/slack/package.json index 16756f5a1b..933136c085 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "0.15.20", + "version": "0.15.23", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index d85dbee58a..888bfc369a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "0.15.20", + "version": "0.15.23", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 6cacf9bd05..80c88ebfc1 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "0.15.20", + "version": "0.15.23", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 854797b6e8..c3b801178b 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "0.15.20", + "version": "0.15.23", "publisher": "sst-dev", "repository": { "type": "git", From 1e24514d61556e6681d1fc8738f51e6cc50f096f Mon Sep 17 00:00:00 2001 From: Tyler Gannon Date: Tue, 28 Oct 2025 21:39:22 -0600 Subject: [PATCH 057/609] add OpenAPI annotations to tui.ts control endpoints (#3519) --- packages/opencode/src/server/tui.ts | 65 +++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/packages/opencode/src/server/tui.ts b/packages/opencode/src/server/tui.ts index 60ac5eef59..48c79ae0b8 100644 --- a/packages/opencode/src/server/tui.ts +++ b/packages/opencode/src/server/tui.ts @@ -1,10 +1,14 @@ import { Hono, type Context } from "hono" +import { describeRoute, resolver, validator } from "hono-openapi" +import { z } from "zod" import { AsyncQueue } from "../util/queue" -interface Request { - path: string - body: any -} +const TuiRequest = z.object({ + path: z.string(), + body: z.any(), +}) + +type Request = z.infer const request = new AsyncQueue() const response = new AsyncQueue() @@ -19,12 +23,47 @@ export async function callTui(ctx: Context) { } export const TuiRoute = new Hono() - .get("/next", async (c) => { - const req = await request.next() - return c.json(req) - }) - .post("/response", async (c) => { - const body = await c.req.json() - response.push(body) - return c.json(true) - }) + .get( + "/next", + describeRoute({ + description: "Get the next TUI request from the queue", + operationId: "tui.control.next", + responses: { + 200: { + description: "Next TUI request", + content: { + "application/json": { + schema: resolver(TuiRequest), + }, + }, + }, + }, + }), + async (c) => { + const req = await request.next() + return c.json(req) + }, + ) + .post( + "/response", + describeRoute({ + description: "Submit a response to the TUI request queue", + operationId: "tui.control.response", + responses: { + 200: { + description: "Response submitted successfully", + content: { + "application/json": { + schema: resolver(z.boolean()), + }, + }, + }, + }, + }), + validator("json", z.any()), + async (c) => { + const body = c.req.valid("json") + response.push(body) + return c.json(true) + }, + ) From 4994bf1b464f0be72ba9fcb9c2d139258b2cfa6b Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 28 Oct 2025 22:39:57 -0500 Subject: [PATCH 058/609] ignore: rename type --- packages/opencode/src/server/tui.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/server/tui.ts b/packages/opencode/src/server/tui.ts index 48c79ae0b8..65187dd07f 100644 --- a/packages/opencode/src/server/tui.ts +++ b/packages/opencode/src/server/tui.ts @@ -8,9 +8,9 @@ const TuiRequest = z.object({ body: z.any(), }) -type Request = z.infer +type TuiRequest = z.infer -const request = new AsyncQueue() +const request = new AsyncQueue() const response = new AsyncQueue() export async function callTui(ctx: Context) { From a0541ba57aebcdb21c36540f0efd8a251fdbc2b8 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 28 Oct 2025 22:48:57 -0500 Subject: [PATCH 059/609] zen: fix models endpoint to be openai compatible --- packages/console/app/src/routes/zen/v1/models.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/console/app/src/routes/zen/v1/models.ts b/packages/console/app/src/routes/zen/v1/models.ts index ad5769bb6b..3d0c314702 100644 --- a/packages/console/app/src/routes/zen/v1/models.ts +++ b/packages/console/app/src/routes/zen/v1/models.ts @@ -25,8 +25,8 @@ export async function GET(input: APIEvent) { object: "list", data: Object.entries(zenData.models) .filter(([id]) => !disabledModels.includes(id)) - .map(([id, model]) => ({ - id: `opencode/${id}`, + .map(([id, _model]) => ({ + id, object: "model", created: Math.floor(Date.now() / 1000), owned_by: "opencode", @@ -50,7 +50,10 @@ export async function GET(input: APIEvent) { }) .from(KeyTable) .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) - .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted))) + .leftJoin( + ModelTable, + and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)), + ) .where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted))) .then((rows) => rows.map((row) => row.model)), ) From 792664071c11d8b2867ea3f4e6ddef0d5f7067ce Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 29 Oct 2025 12:04:57 +0000 Subject: [PATCH 060/609] ignore: update download stats 2025-10-29 --- STATS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/STATS.md b/STATS.md index 71fda16842..e35377dbe2 100644 --- a/STATS.md +++ b/STATS.md @@ -122,3 +122,4 @@ | 2025-10-26 | 584,409 (+5,482) | 521,179 (+5,050) | 1,105,588 (+10,532) | | 2025-10-27 | 589,999 (+5,590) | 526,001 (+4,822) | 1,116,000 (+10,412) | | 2025-10-28 | 595,776 (+5,777) | 532,438 (+6,437) | 1,128,214 (+12,214) | +| 2025-10-29 | 606,259 (+10,483) | 542,064 (+9,626) | 1,148,323 (+20,109) | From aa7e008fe1ea1c1ee0e28915b61633865c304152 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 29 Oct 2025 06:05:03 -0500 Subject: [PATCH 061/609] wip: desktop work --- packages/ui/src/components/diff.css | 5 ++- packages/ui/src/styles/colors.css | 52 ++++++++++++++++++++++- packages/ui/src/styles/theme.css | 66 ++++++++++++++++------------- 3 files changed, 89 insertions(+), 34 deletions(-) diff --git a/packages/ui/src/components/diff.css b/packages/ui/src/components/diff.css index 6f9a0d73dd..c3484e2014 100644 --- a/packages/ui/src/components/diff.css +++ b/packages/ui/src/components/diff.css @@ -2,7 +2,7 @@ [data-slot="diff-hunk-separator-line-number"] { position: sticky; left: 0; - background-color: hsla(209, 96%, 90%, 1); + background-color: var(--surface-diff-hidden-strong); z-index: 2; display: flex; align-items: center; @@ -12,11 +12,12 @@ aspect-ratio: 1; width: 24px; height: 24px; + color: var(--icon-strong-base); } } [data-slot="diff-hunk-separator-content"] { position: sticky; - background-color: hsla(210, 100%, 96%, 1); + background-color: var(--surface-diff-hidden-base); width: var(--pjs-column-content-width); left: var(--pjs-column-number-width); padding-left: 8px; diff --git a/packages/ui/src/styles/colors.css b/packages/ui/src/styles/colors.css index 79877d3cf5..c5599686fe 100644 --- a/packages/ui/src/styles/colors.css +++ b/packages/ui/src/styles/colors.css @@ -34,8 +34,8 @@ --smoke-dark-alpha-9: #faf5f467; --smoke-dark-alpha-10: #fbf5f576; --smoke-dark-alpha-11: #fcf9f9b2; - --smoke-light-alpha-1: #55000003; --smoke-dark-alpha-12: #fdfbfbf0; + --smoke-light-alpha-1: #55000003; --smoke-light-alpha-2: #25000007; --smoke-light-alpha-3: #1100000f; --smoke-light-alpha-4: #0c000017; @@ -125,8 +125,8 @@ --cobalt-dark-alpha-9: #034cff; --cobalt-dark-alpha-10: #003bffed; --cobalt-dark-alpha-11: #89b5ff; - --cobalt-light-8: #73a4ff; --cobalt-dark-alpha-12: #cde2ff; + --cobalt-light-8: #73a4ff; --cobalt-light-9: #034cff; --cobalt-light-10: #0443de; --cobalt-light-11: #1251ec; @@ -445,4 +445,52 @@ --mint-light-alpha-10: #0cc7006c; --mint-light-alpha-11: #016800cf; --mint-light-alpha-12: #022e00e2; + --blue-dark-1: #0e161f; + --blue-dark-2: #0f1b2d; + --blue-dark-3: #0f233c; + --blue-dark-4: #10294b; + --blue-dark-5: #0e2f57; + --blue-dark-6: #0c3768; + --blue-dark-7: #094280; + --blue-dark-8: #0854a4; + --blue-dark-9: #0091ff; + --blue-dark-10: #389eff; + --blue-dark-11: #51a8ff; + --blue-dark-12: #eaf6ff; + --blue-light-1: #f9fcff; + --blue-light-2: #f5faff; + --blue-light-3: #eaf4ff; + --blue-light-4: #e0efff; + --blue-light-5: #cde6fd; + --blue-light-6: #b9d9f8; + --blue-light-7: #96c7f2; + --blue-light-8: #5cafee; + --blue-light-9: #0091ff; + --blue-light-10: #007fef; + --blue-light-11: #0069db; + --blue-light-12: #00254d; + --blue-dark-alpha-1: #00000000; + --blue-dark-alpha-2: #0c58fc0f; + --blue-dark-alpha-3: #1576fd23; + --blue-dark-alpha-4: #1576fd33; + --blue-dark-alpha-5: #107bfd3f; + --blue-dark-alpha-6: #0a7cff51; + --blue-dark-alpha-7: #057dff70; + --blue-dark-alpha-8: #057dff99; + --blue-dark-alpha-9: #0094fff9; + --blue-dark-alpha-10: #38a2fff9; + --blue-dark-alpha-11: #51abfff9; + --blue-dark-alpha-12: #effbfff9; + --blue-light-alpha-1: #0582ff05; + --blue-light-alpha-2: #0582ff0a; + --blue-light-alpha-3: #007fff11; + --blue-light-alpha-4: #007fff1e; + --blue-light-alpha-5: #017fee30; + --blue-light-alpha-6: #0176e447; + --blue-light-alpha-7: #0077e068; + --blue-light-alpha-8: #0082e5a0; + --blue-light-alpha-9: #0090fff9; + --blue-light-alpha-10: #007feff9; + --blue-light-alpha-11: #0066dbf9; + --blue-light-alpha-12: #002047f9; } diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css index 0c22bae5a4..600de584aa 100644 --- a/packages/ui/src/styles/theme.css +++ b/packages/ui/src/styles/theme.css @@ -50,9 +50,11 @@ --radius-4xl: 2rem; --shadow-xs: - 0 1px 2px -1px rgba(19, 16, 16, 0.04), 0 1px 2px 0 rgba(19, 16, 16, 0.06), 0 1px 3px 0 rgba(19, 16, 16, 0.08); + 0 1px 2px -1px rgba(19, 16, 16, 0.04), 0 1px 2px 0 rgba(19, 16, 16, 0.06), + 0 1px 3px 0 rgba(19, 16, 16, 0.08); --shadow-md: - 0 6px 8px -4px rgba(19, 16, 16, 0.12), 0 4px 3px -2px rgba(19, 16, 16, 0.12), 0 1px 2px -1px rgba(19, 16, 16, 0.12); + 0 6px 8px -4px rgba(19, 16, 16, 0.12), 0 4px 3px -2px rgba(19, 16, 16, 0.12), + 0 1px 2px -1px rgba(19, 16, 16, 0.12); --shadow-xs-border-selected: 0 0 0 3px var(--border-weak-selected, rgba(1, 103, 255, 0.29)), 0 0 0 1px var(--border-selected, rgba(0, 74, 255, 0.99)), 0 1px 2px -1px rgba(19, 16, 16, 0.25), @@ -66,8 +68,8 @@ --background-weak: var(--smoke-light-3); --background-strong: var(--smoke-light-1); --background-stronger: #fcfcfc; - --base: var(--smoke-light-alpha-2); --surface-base: var(--smoke-light-alpha-2); + --base: var(--smoke-light-alpha-2); --surface-base-hover: #0500000f; --surface-base-active: var(--smoke-light-alpha-3); --surface-base-interactive-active: var(--cobalt-light-alpha-3); @@ -81,6 +83,7 @@ --surface-float-base: var(--smoke-dark-1); --surface-float-base-hover: var(--smoke-dark-2); --surface-raised-base-hover: var(--smoke-light-alpha-2); + --surface-raised-base-active: var(--smoke-light-alpha-3); --surface-raised-strong: var(--smoke-light-1); --surface-raised-strong-hover: var(--white); --surface-raised-stronger: var(--white); @@ -107,9 +110,9 @@ --surface-info-base: var(--lilac-light-3); --surface-info-weak: var(--lilac-light-2); --surface-info-strong: var(--lilac-light-9); - --surface-diff-hidden-base: var(--blue-light-3); - --surface-diff-skip-base: var(--smoke-light-2); --surface-diff-unchanged-base: #ffffff00; + --surface-diff-skip-base: var(--smoke-light-2); + --surface-diff-hidden-base: var(--blue-light-3); --surface-diff-hidden-weak: var(--blue-light-2); --surface-diff-hidden-weaker: var(--blue-light-1); --surface-diff-hidden-strong: var(--blue-light-5); @@ -142,7 +145,7 @@ --text-on-warning-base: var(--smoke-dark-alpha-11); --text-on-info-base: var(--smoke-dark-alpha-11); --text-diff-add-base: var(--mint-light-11); - --text-diff-delete-base: var(--ember-light-11); + --text-diff-delete-base: var(--ember-light-10); --text-diff-delete-strong: var(--ember-light-12); --text-diff-add-strong: var(--mint-light-12); --text-on-info-weak: var(--smoke-dark-alpha-9); @@ -198,19 +201,19 @@ --icon-selected: var(--smoke-light-12); --icon-disabled: var(--smoke-light-8); --icon-focus: var(--smoke-light-12); - --icon-weak-base: var(--smoke-light-7); --icon-invert-base: #ffffff; + --icon-weak-base: var(--smoke-light-7); --icon-weak-hover: var(--smoke-light-8); --icon-weak-active: var(--smoke-light-9); --icon-weak-selected: var(--smoke-light-10); --icon-weak-disabled: var(--smoke-light-6); --icon-weak-focus: var(--smoke-light-9); --icon-strong-base: var(--smoke-light-12); - --icon-strong-hover: var(--smoke-light-12); - --icon-strong-active: var(--smoke-light-12); - --icon-strong-selected: var(--smoke-light-12); + --icon-strong-hover: #151313; + --icon-strong-active: #020202; + --icon-strong-selected: #020202; --icon-strong-disabled: var(--smoke-light-8); - --icon-strong-focus: var(--smoke-light-12); + --icon-strong-focus: #020202; --icon-brand-base: var(--smoke-light-12); --icon-interactive-base: var(--cobalt-light-9); --icon-success-base: var(--apple-light-7); @@ -248,9 +251,8 @@ --icon-diff-add-base: var(--mint-light-11); --icon-diff-add-hover: var(--mint-light-12); --icon-diff-add-active: var(--mint-light-12); - --icon-diff-delete-base: var(--ember-light-9); - --icon-diff-delete-hover: var(--ember-light-10); - --icon-diff-delete-active: var(--ember-light-11); + --icon-diff-delete-base: var(--ember-light-10); + --icon-diff-delete-hover: var(--ember-light-11); --syntax-comment: #8a8a8a; --syntax-string: #d68c27; --syntax-keyword: #3b7dd8; @@ -286,6 +288,8 @@ --border-weaker-selected: var(--cobalt-light-alpha-4); --border-weaker-disabled: var(--smoke-light-alpha-2); --border-weaker-focus: var(--smoke-light-alpha-6); + --button-ghost-hover: var(--smoke-light-alpha-2); + --button-ghost-hover2: var(--smoke-light-alpha-3); @media (prefers-color-scheme: dark) { /* OC-1-Dark */ @@ -294,8 +298,8 @@ --background-weak: #201d1d; --background-strong: #151313; --background-stronger: #201c1c; - --base: var(--smoke-dark-alpha-2); --surface-base: var(--smoke-dark-alpha-2); + --base: var(--smoke-dark-alpha-2); --surface-base-hover: #e0b7b716; --surface-base-active: var(--smoke-dark-alpha-3); --surface-base-interactive-active: var(--cobalt-dark-alpha-2); @@ -309,6 +313,7 @@ --surface-float-base: var(--smoke-dark-1); --surface-float-base-hover: var(--smoke-dark-2); --surface-raised-base-hover: var(--smoke-dark-alpha-4); + --surface-raised-base-active: var(--smoke-dark-alpha-5); --surface-raised-strong: var(--smoke-dark-alpha-4); --surface-raised-strong-hover: var(--smoke-dark-alpha-6); --surface-raised-stronger: var(--smoke-dark-alpha-6); @@ -329,15 +334,15 @@ --surface-warning-base: var(--solaris-light-3); --surface-warning-weak: var(--solaris-light-2); --surface-warning-strong: var(--solaris-light-9); - --surface-critical-base: var(--ember-light-3); - --surface-critical-weak: var(--ember-light-2); - --surface-critical-strong: var(--ember-light-9); + --surface-critical-base: var(--ember-dark-3); + --surface-critical-weak: var(--ember-dark-2); + --surface-critical-strong: var(--ember-dark-9); --surface-info-base: var(--lilac-light-3); --surface-info-weak: var(--lilac-light-2); --surface-info-strong: var(--lilac-light-9); - --surface-diff-hidden-base: var(--blue-dark-2); - --surface-diff-skip-base: var(--smoke-dark-alpha-1); --surface-diff-unchanged-base: var(--smoke-dark-1); + --surface-diff-skip-base: var(--smoke-dark-alpha-1); + --surface-diff-hidden-base: var(--blue-dark-2); --surface-diff-hidden-weak: var(--blue-dark-1); --surface-diff-hidden-weaker: var(--blue-dark-3); --surface-diff-hidden-strong: var(--blue-dark-5); @@ -414,9 +419,9 @@ --border-warning-base: var(--solaris-light-6); --border-warning-hover: var(--solaris-light-7); --border-warning-selected: var(--solaris-light-9); - --border-critical-base: var(--ember-light-6); - --border-critical-hover: var(--ember-light-7); - --border-critical-selected: var(--ember-light-9); + --border-critical-base: var(--ember-dark-5); + --border-critical-hover: var(--ember-dark-7); + --border-critical-selected: var(--ember-dark-9); --border-info-base: var(--lilac-light-6); --border-info-hover: var(--lilac-light-7); --border-info-selected: var(--lilac-light-9); @@ -426,19 +431,19 @@ --icon-selected: var(--smoke-dark-12); --icon-disabled: var(--smoke-dark-7); --icon-focus: var(--smoke-dark-12); - --icon-weak-base: var(--smoke-dark-6); --icon-invert-base: var(--smoke-dark-1); + --icon-weak-base: var(--smoke-dark-6); --icon-weak-hover: var(--smoke-light-7); --icon-weak-active: var(--smoke-light-8); --icon-weak-selected: var(--smoke-light-9); --icon-weak-disabled: var(--smoke-light-4); --icon-weak-focus: var(--smoke-light-9); --icon-strong-base: var(--smoke-dark-12); - --icon-strong-hover: var(--smoke-light-12); - --icon-strong-active: var(--smoke-light-12); - --icon-strong-selected: var(--smoke-light-12); - --icon-strong-disabled: var(--smoke-light-8); - --icon-strong-focus: var(--smoke-light-12); + --icon-strong-hover: #f6f3f3; + --icon-strong-active: #fcfcfc; + --icon-strong-selected: #fdfcfc; + --icon-strong-disabled: var(--smoke-dark-8); + --icon-strong-focus: #fdfcfc; --icon-brand-base: var(--white); --icon-interactive-base: var(--cobalt-dark-9); --icon-success-base: var(--apple-dark-7); @@ -478,7 +483,6 @@ --icon-diff-add-active: var(--mint-dark-11); --icon-diff-delete-base: var(--ember-dark-9); --icon-diff-delete-hover: var(--ember-dark-10); - --icon-diff-delete-active: var(--ember-dark-11); --syntax-comment: #808080; --syntax-string: #9d7cd8; --syntax-keyword: #fab283; @@ -514,5 +518,7 @@ --border-weaker-selected: var(--cobalt-dark-alpha-3); --border-weaker-disabled: var(--smoke-dark-alpha-2); --border-weaker-focus: var(--smoke-dark-alpha-6); + --button-ghost-hover: var(--smoke-dark-alpha-2); + --button-ghost-hover2: var(--smoke-dark-alpha-3); } } From 5b86fa91099d66cdc876cd4209a97ae2c903d510 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 29 Oct 2025 07:31:57 -0500 Subject: [PATCH 062/609] wip: desktop work --- .../src/components/assistant-message.tsx | 72 ++++++++------- packages/desktop/src/pages/index.tsx | 87 +++++++++++++++---- packages/ui/src/components/diff.css | 1 + packages/ui/src/styles/utilities.css | 29 ------- 4 files changed, 107 insertions(+), 82 deletions(-) diff --git a/packages/desktop/src/components/assistant-message.tsx b/packages/desktop/src/components/assistant-message.tsx index 90f6e70fec..8c654660b5 100644 --- a/packages/desktop/src/components/assistant-message.tsx +++ b/packages/desktop/src/components/assistant-message.tsx @@ -1,4 +1,4 @@ -import type { Part, AssistantMessage, ReasoningPart, TextPart, ToolPart } from "@opencode-ai/sdk" +import type { Part, AssistantMessage, ReasoningPart, TextPart, ToolPart, Message } from "@opencode-ai/sdk" import { children, Component, createMemo, For, Match, Show, Switch, type JSX } from "solid-js" import { Dynamic } from "solid-js/web" import { Markdown } from "./markdown" @@ -17,47 +17,36 @@ import type { WriteTool } from "opencode/tool/write" import type { TodoWriteTool } from "opencode/tool/todo" import { DiffChanges } from "./diff-changes" -export function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; lastToolOnly?: boolean }) { +export function AssistantMessage(props: { message: AssistantMessage; parts: Part[] }) { const filteredParts = createMemo(() => { - let tool = false return props.parts?.filter((x) => { - if (x.type === "tool" && props.lastToolOnly && tool) return false - if (x.type === "tool") tool = true + if (x.type === "reasoning") return false return x.type !== "tool" || x.tool !== "todoread" }) }) return (
    - - {(part) => { - const component = createMemo(() => PART_MAPPING[part.type as keyof typeof PART_MAPPING]) - return ( - - - - ) - }} - + {(part) => }
    ) } +export function Part(props: { part: Part; message: Message; readonly?: boolean }) { + const component = createMemo(() => PART_MAPPING[props.part.type as keyof typeof PART_MAPPING]) + return ( + + + + ) +} + const PART_MAPPING = { text: TextPart, tool: ToolPart, reasoning: ReasoningPart, } -function ReasoningPart(props: { part: ReasoningPart; message: AssistantMessage }) { - return null - // return ( - // - //
    {props.part.text}
    - //
    - // ) -} - -function TextPart(props: { part: TextPart; message: AssistantMessage }) { +function ReasoningPart(props: { part: ReasoningPart; message: Message }) { return ( @@ -65,17 +54,19 @@ function TextPart(props: { part: TextPart; message: AssistantMessage }) { ) } -function ToolPart(props: { part: ToolPart; message: AssistantMessage }) { - // const sync = useSync() +function TextPart(props: { part: TextPart; message: Message }) { + return ( + + + + ) +} +function ToolPart(props: { part: ToolPart; message: Message; readonly?: boolean }) { const component = createMemo(() => { const render = ToolRegistry.render(props.part.tool) ?? GenericTool - const metadata = props.part.state.status === "pending" ? {} : (props.part.state.metadata ?? {}) const input = props.part.state.status === "completed" ? props.part.state.input : {} - // const permissions = sync.data.permission[props.message.sessionID] ?? [] - // const permissionIndex = permissions.findIndex((x) => x.callID === props.part.callID) - // const permission = permissions[permissionIndex] return ( ) }) @@ -106,7 +97,12 @@ const isTriggerTitle = (val: any): val is TriggerTitle => { return typeof val === "object" && val !== null && "title" in val && !(val instanceof Node) } -function BasicTool(props: { icon: IconProps["name"]; trigger: TriggerTitle | JSX.Element; children?: JSX.Element }) { +function BasicTool(props: { + icon: IconProps["name"] + trigger: TriggerTitle | JSX.Element + children?: JSX.Element + readonly?: boolean +}) { const resolved = children(() => props.children) return ( @@ -161,13 +157,13 @@ function BasicTool(props: { icon: IconProps["name"]; trigger: TriggerTitle | JSX
- +
- - {props.children} + + {resolved()} // <> @@ -177,15 +173,15 @@ function BasicTool(props: { icon: IconProps["name"]; trigger: TriggerTitle | JSX } function GenericTool(props: ToolProps) { - return + return } type ToolProps = { input: Partial> metadata: Partial> - // permission: Record tool: string output?: string + readonly?: boolean } const ToolRegistry = (() => { diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx index c1884b2c0d..800f3651e3 100644 --- a/packages/desktop/src/pages/index.tsx +++ b/packages/desktop/src/pages/index.tsx @@ -33,7 +33,7 @@ import { Code } from "@/components/code" import { useSync } from "@/context/sync" import { useSDK } from "@/context/sdk" import { ProgressCircle } from "@/components/progress-circle" -import { AssistantMessage } from "@/components/assistant-message" +import { AssistantMessage, Part } from "@/components/assistant-message" import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk" import { DiffChanges } from "@/components/diff-changes" @@ -178,6 +178,8 @@ export default function Page() { } const handleDiffTriggerClick = (event: MouseEvent) => { + // disabling scroll to diff for now + return const target = event.currentTarget as HTMLElement queueMicrotask(() => { if (target.getAttribute("aria-expanded") !== "true") return @@ -636,6 +638,7 @@ export default function Page() {
{(message) => { + const [expanded, setExpanded] = createSignal(false) const title = createMemo(() => message.summary?.title) const prompt = createMemo(() => local.session.getMessageText(message)) const summary = createMemo(() => message.summary?.body) @@ -649,15 +652,12 @@ export default function Page() { if (!last) return false return !last.time.completed }) - const lastWithContent = createMemo(() => - assistantMessages().findLast((m) => { - const parts = sync.data.part[m.id] - return parts?.find((p) => p.type === "text" || p.type === "tool") - }), - ) return ( -
+
{/* Title */}

@@ -665,14 +665,19 @@ export default function Page() {

-
{prompt()}
+
{prompt()}
{/* Response */}
- +
-

Show steps

+

+ + Hide steps + Show steps + +

@@ -687,11 +692,63 @@ export default function Page() {
- - {(last) => { - const lastParts = createMemo(() => sync.data.part[last().id]) + + {(_) => { + const lastMessageWithText = createMemo(() => + assistantMessages().findLast((m) => { + const parts = sync.data.part[m.id] + return parts?.find((p) => p.type === "text") + }), + ) + const lastMessageWithReasoning = createMemo(() => + assistantMessages().findLast((m) => { + const parts = sync.data.part[m.id] + return parts?.find((p) => p.type === "reasoning") + }), + ) + const lastMessageWithTool = createMemo(() => + assistantMessages().findLast((m) => { + const parts = sync.data.part[m.id] + return parts?.find( + (p) => p.type === "tool" && p.state.status === "completed", + ) + }), + ) return ( - +
+ + + {(last) => { + const lastTextPart = createMemo(() => + sync.data.part[last().id].findLast((p) => p.type === "text"), + ) + return + }} + + + {(last) => { + const lastReasoningPart = createMemo(() => + sync.data.part[last().id].findLast( + (p) => p.type === "reasoning", + ), + ) + return ( + + ) + }} + + + + {(last) => { + const lastToolPart = createMemo(() => + sync.data.part[last().id].findLast( + (p) => p.type === "tool" && p.state.status === "completed", + ), + ) + return + }} + +
) }}
diff --git a/packages/ui/src/components/diff.css b/packages/ui/src/components/diff.css index c3484e2014..c4e831879a 100644 --- a/packages/ui/src/components/diff.css +++ b/packages/ui/src/components/diff.css @@ -18,6 +18,7 @@ [data-slot="diff-hunk-separator-content"] { position: sticky; background-color: var(--surface-diff-hidden-base); + color: var(--text-base); width: var(--pjs-column-content-width); left: var(--pjs-column-number-width); padding-left: 8px; diff --git a/packages/ui/src/styles/utilities.css b/packages/ui/src/styles/utilities.css index 85b901566a..99b7760a00 100644 --- a/packages/ui/src/styles/utilities.css +++ b/packages/ui/src/styles/utilities.css @@ -48,35 +48,6 @@ border-width: 0; } -.scroller { - --fade-height: 1.5rem; - - --mask-top: linear-gradient(to bottom, transparent, black var(--fade-height)); - --mask-bottom: linear-gradient(to top, transparent, black var(--fade-height)); - - mask-image: var(--mask-top), var(--mask-bottom); - mask-repeat: no-repeat; - - mask-size: 100% var(--fade-height); - - animation: adjust-masks linear; - animation-timeline: scroll(self); -} - -@keyframes adjust-masks { - from { - mask-position: - 0 calc(0% - var(--fade-height)), - 0 100%; - } - - to { - mask-position: - 0 0, - 0 calc(100% + var(--fade-height)); - } -} - .truncate-start { text-overflow: ellipsis; overflow: hidden; From 7baa75135159907d4e28f82e1e9a22fe6ef7e6e1 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 29 Oct 2025 15:16:17 +0000 Subject: [PATCH 063/609] First pass at adding an enterprise page --- packages/console/app/src/component/header.tsx | 6 + .../console/app/src/routes/api/enterprise.ts | 52 ++ .../app/src/routes/enterprise/index.css | 552 ++++++++++++++++++ .../app/src/routes/enterprise/index.tsx | 199 +++++++ packages/console/app/src/routes/index.css | 6 +- packages/web/src/content/docs/enterprise.mdx | 39 ++ 6 files changed, 849 insertions(+), 5 deletions(-) create mode 100644 packages/console/app/src/routes/api/enterprise.ts create mode 100644 packages/console/app/src/routes/enterprise/index.css create mode 100644 packages/console/app/src/routes/enterprise/index.tsx diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx index 29b35bfa44..ea8921f300 100644 --- a/packages/console/app/src/component/header.tsx +++ b/packages/console/app/src/component/header.tsx @@ -36,6 +36,9 @@ export function Header(props: { zen?: boolean }) {
  • Docs
  • +
  • + Enterprise +
  • @@ -107,6 +110,9 @@ export function Header(props: { zen?: boolean }) {
  • Docs
  • +
  • + Enterprise +
  • diff --git a/packages/console/app/src/routes/api/enterprise.ts b/packages/console/app/src/routes/api/enterprise.ts new file mode 100644 index 0000000000..6298ae349c --- /dev/null +++ b/packages/console/app/src/routes/api/enterprise.ts @@ -0,0 +1,52 @@ +import type { APIEvent } from "@solidjs/start/server" +import { AWS } from "@opencode-ai/console-core/aws.js" + +interface EnterpriseFormData { + name: string + company: string + role: string + email: string + message: string +} + +export async function POST(event: APIEvent) { + try { + const body = (await event.request.json()) as EnterpriseFormData + + // Validate required fields + if (!body.name || !body.company || !body.role || !body.email || !body.message) { + return Response.json({ error: "All fields are required" }, { status: 400 }) + } + + // Validate email format + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + if (!emailRegex.test(body.email)) { + return Response.json({ error: "Invalid email format" }, { status: 400 }) + } + + // Create email content + const emailContent = ` +New Enterprise Inquiry + +Name: ${body.name} +Company: ${body.company} +Role: ${body.role} +Email: ${body.email} + +Message: +${body.message} + `.trim() + + // Send email using AWS SES + await AWS.sendEmail({ + to: "enterprise@opencode.ai", + subject: `Enterprise Inquiry from ${body.company}`, + body: emailContent, + }) + + return Response.json({ success: true, message: "Form submitted successfully" }, { status: 200 }) + } catch (error) { + console.error("Error processing enterprise form:", error) + return Response.json({ error: "Internal server error" }, { status: 500 }) + } +} diff --git a/packages/console/app/src/routes/enterprise/index.css b/packages/console/app/src/routes/enterprise/index.css new file mode 100644 index 0000000000..c0cb478c51 --- /dev/null +++ b/packages/console/app/src/routes/enterprise/index.css @@ -0,0 +1,552 @@ +::selection { + background: var(--color-background-interactive); + color: var(--color-text-strong); + + @media (prefers-color-scheme: dark) { + background: var(--color-background-interactive); + color: var(--color-text-inverted); + } +} + + +[data-page="enterprise"] { + --color-background: hsl(0, 20%, 99%); + --color-background-weak: hsl(0, 8%, 97%); + --color-background-weak-hover: hsl(0, 8%, 94%); + --color-background-strong: hsl(0, 5%, 12%); + --color-background-strong-hover: hsl(0, 5%, 18%); + --color-background-interactive: hsl(62, 84%, 88%); + --color-background-interactive-weaker: hsl(64, 74%, 95%); + + --color-text: hsl(0, 1%, 39%); + --color-text-weak: hsl(0, 1%, 60%); + --color-text-weaker: hsl(30, 2%, 81%); + --color-text-strong: hsl(0, 5%, 12%); + --color-text-inverted: hsl(0, 20%, 99%); + + --color-border: hsl(30, 2%, 81%); + --color-border-weak: hsl(0, 1%, 85%); + + --color-icon: hsl(0, 1%, 55%); + --color-success: hsl(142, 76%, 36%); + + background: var(--color-background); + font-family: var(--font-mono); + color: var(--color-text); + padding-bottom: 5rem; + + @media (prefers-color-scheme: dark) { + --color-background: hsl(0, 9%, 7%); + --color-background-weak: hsl(0, 6%, 10%); + --color-background-weak-hover: hsl(0, 6%, 15%); + --color-background-strong: hsl(0, 15%, 94%); + --color-background-strong-hover: hsl(0, 15%, 97%); + --color-background-interactive: hsl(62, 100%, 90%); + --color-background-interactive-weaker: hsl(60, 20%, 8%); + + --color-text: hsl(0, 4%, 71%); + --color-text-weak: hsl(0, 2%, 49%); + --color-text-weaker: hsl(0, 3%, 28%); + --color-text-strong: hsl(0, 15%, 94%); + --color-text-inverted: hsl(0, 9%, 7%); + + --color-border: hsl(0, 3%, 28%); + --color-border-weak: hsl(0, 4%, 23%); + + --color-icon: hsl(10, 3%, 43%); + --color-success: hsl(142, 76%, 46%); + } + + /* Header and Footer styles - copied from index.css */ + [data-component="top"] { + padding: 24px 5rem; + height: 80px; + position: sticky; + top: 0; + display: flex; + justify-content: space-between; + align-items: center; + background: var(--color-background); + border-bottom: 1px solid var(--color-border-weak); + z-index: 10; + + @media (max-width: 60rem) { + padding: 24px 1.5rem; + } + + img { + height: 34px; + width: auto; + } + + [data-component="nav-desktop"] { + ul { + display: flex; + justify-content: space-between; + gap: 48px; + li { + display: inline-block; + a { + text-decoration: none; + span { + color: var(--color-text-weak); + } + } + a:hover { + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + } + } + + @media (max-width: 40rem) { + display: none; + } + } + + [data-component="nav-mobile"] { + button > svg { + color: var(--color-icon); + } + } + + [data-component="nav-mobile-toggle"] { + border: none; + background: none; + outline: none; + height: 40px; + width: 40px; + cursor: pointer; + margin-right: -8px; + } + + [data-component="nav-mobile-toggle"]:hover { + background: var(--color-background-weak); + } + + [data-component="nav-mobile"] { + display: none; + + @media (max-width: 40rem) { + display: block; + + [data-component="nav-mobile-icon"] { + cursor: pointer; + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; + } + + [data-component="nav-mobile-menu-list"] { + position: fixed; + background: var(--color-background); + top: 80px; + left: 0; + right: 0; + height: 100vh; + + ul { + list-style: none; + padding: 20px 0; + + li { + a { + text-decoration: none; + padding: 20px; + display: block; + + span { + color: var(--color-text-weak); + } + } + + a:hover { + background: var(--color-background-weak); + } + } + } + } + } + } + + [data-slot="logo dark"] { + display: none; + } + + @media (prefers-color-scheme: dark) { + [data-slot="logo light"] { + display: none; + } + [data-slot="logo dark"] { + display: block; + } + } + } + + [data-component="footer"] { + border-top: 1px solid var(--color-border-weak); + display: flex; + flex-direction: row; + + @media (max-width: 65rem) { + border-bottom: 1px solid var(--color-border-weak); + } + + [data-slot="cell"] { + flex: 1; + text-align: center; + + a { + text-decoration: none; + padding: 2rem 0; + width: 100%; + display: block; + + span { + color: var(--color-text-weak); + + @media (max-width: 40rem) { + display: none; + } + } + } + + a:hover { + background: var(--color-background-weak); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + } + } + + [data-slot="cell"] + [data-slot="cell"] { + border-left: 1px solid var(--color-border-weak); + + @media (max-width: 40rem) { + border-left: none; + } + } + + /* Mobile: third column on its own row */ + @media (max-width: 25rem) { + flex-wrap: wrap; + + [data-slot="cell"] { + flex: 1 0 100%; + border-left: none; + border-top: 1px solid var(--color-border-weak); + } + + [data-slot="cell"]:nth-child(1) { + border-top: none; + } + } + } + + [data-component="container"] { + max-width: 67.5rem; + margin: 0 auto; + border: 1px solid var(--color-border-weak); + border-top: none; + + @media (max-width: 65rem) { + border: none; + } + } + + [data-component="content"] { + } + + [data-component="enterprise-content"] { + padding: 4rem 0; + + @media (max-width: 60rem) { + padding: 2rem 0; + } + } + + [data-component="enterprise-columns"] { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4rem; + padding: 4rem 5rem; + + @media (max-width: 80rem) { + gap: 3rem; + } + + @media (max-width: 60rem) { + grid-template-columns: 1fr; + gap: 3rem; + padding: 2rem 1.5rem; + } + } + + [data-component="enterprise-column-1"] { + h2 { + font-size: 1.5rem; + font-weight: 500; + color: var(--color-text-strong); + margin-bottom: 1rem; + } + + h3 { + font-size: 1.25rem; + font-weight: 500; + color: var(--color-text-strong); + margin: 2rem 0 1rem 0; + } + + p { + line-height: 1.6; + margin-bottom: 1.5rem; + color: var(--color-text); + } + + ul { + list-style: none; + padding: 0; + margin-bottom: 2rem; + + li { + margin-bottom: 0.75rem; + padding-left: 1.5rem; + position: relative; + line-height: 1.5; + color: var(--color-text); + + &::before { + content: "•"; + position: absolute; + left: 0; + color: var(--color-background-interactive); + font-weight: bold; + } + + strong { + color: var(--color-text-strong); + font-weight: 500; + } + } + } + } + + [data-component="enterprise-column-2"] { + [data-component="enterprise-form"] { + padding: 0; + + h2 { + font-size: 1.5rem; + font-weight: 500; + color: var(--color-text-strong); + margin-bottom: 1.5rem; + } + + [data-component="form-group"] { + margin-bottom: 1.5rem; + + label { + display: block; + font-weight: 500; + color: var(--color-text-weak); + margin-bottom: 0.5rem; + font-size: 0.875rem; + } + + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active { + transition: background-color 5000000s ease-in-out 0s; + } + + input:-webkit-autofill { + -webkit-text-fill-color: var(--color-text-strong) !important; + } + + input:-moz-autofill { + -moz-text-fill-color: var(--color-text-strong) !important; + } + + input, + textarea { + width: 100%; + padding: 0.75rem; + border: 1px solid var(--color-border-weak); + border-radius: 4px; + background: var(--color-background-weak); + color: var(--color-text-strong); + font-family: inherit; + + &::placeholder { + color: var(--color-text-weak); + } + + &:focus { + background: var(--color-background-interactive-weaker); + outline: none; + border: none; + color: var(--color-text-strong); + border: 1px solid var(--color-background-strong); + box-shadow: 0 0 0 3px var(--color-background-interactive); + + @media (prefers-color-scheme: dark) { + box-shadow: none; + border: 1px solid var(--color-background-interactive) + } + } + } + + textarea { + resize: vertical; + min-height: 120px; + } + } + + [data-component="submit-button"] { + padding: 0.5rem 1.5rem; + background: var(--color-background-strong); + color: var(--color-text-inverted); + border: none; + border-radius: 4px; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s ease; + + &:hover:not(:disabled) { + background: var(--color-background-strong-hover); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + } + + [data-component="success-message"] { + margin-top: 1rem; + padding: 1rem; + background: var(--color-success); + color: white; + border-radius: 4px; + font-size: 0.875rem; + text-align: center; + } + } + } + + [data-component="faq"] { + border-top: 1px solid var(--color-border-weak); + padding: 4rem 5rem; + + @media (max-width: 60rem) { + padding: 2rem 1.5rem; + } + + [data-slot="section-title"] { + margin-bottom: 24px; + + h3 { + font-size: 16px; + font-weight: 500; + color: var(--color-text-strong); + margin-bottom: 12px; + } + + p { + margin-bottom: 12px; + color: var(--color-text); + } + } + + ul { + padding: 0; + + li { + list-style: none; + margin-bottom: 24px; + line-height: 200%; + + @media (max-width: 60rem) { + line-height: 180%; + } + } + } + + [data-slot="faq-question"] { + display: flex; + gap: 16px; + margin-bottom: 8px; + color: var(--color-text-strong); + font-weight: 500; + cursor: pointer; + background: none; + border: none; + padding: 0; + + [data-slot="faq-icon-plus"] { + flex-shrink: 0; + color: var(--color-text-weak); + margin-top: 2px; + + [data-closed] & { + display: block; + } + [data-expanded] & { + display: none; + } + } + [data-slot="faq-icon-minus"] { + flex-shrink: 0; + color: var(--color-text-weak); + margin-top: 2px; + + [data-closed] & { + display: none; + } + [data-expanded] & { + display: block; + } + } + [data-slot="faq-question-text"] { + flex-grow: 1; + text-align: left; + } + } + + [data-slot="faq-answer"] { + margin-left: 40px; + margin-bottom: 32px; + color: var(--color-text); + } + } + + [data-component="legal"] { + color: var(--color-text-weak); + text-align: center; + padding: 2rem 5rem; + + @media (max-width: 60rem) { + padding: 2rem 1.5rem; + } + + a { + color: var(--color-text-weak); + text-decoration: none; + } + } + + a { + color: var(--color-text-strong); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-thickness: 1px; + + &:hover { + text-decoration-thickness: 2px; + } + } +} diff --git a/packages/console/app/src/routes/enterprise/index.tsx b/packages/console/app/src/routes/enterprise/index.tsx new file mode 100644 index 0000000000..21c3db74e9 --- /dev/null +++ b/packages/console/app/src/routes/enterprise/index.tsx @@ -0,0 +1,199 @@ +import "./index.css" +import { Title, Meta } from "@solidjs/meta" +import { createSignal } from "solid-js" +import { Header } from "~/component/header" +import { Footer } from "~/component/footer" +import { Legal } from "~/component/legal" +import { Faq } from "~/component/faq" + +export default function Enterprise() { + const [formData, setFormData] = createSignal({ + name: "", + role: "", + email: "", + message: "", + }) + const [isSubmitting, setIsSubmitting] = createSignal(false) + const [showSuccess, setShowSuccess] = createSignal(false) + + const handleInputChange = (field: string) => (e: Event) => { + const target = e.target as HTMLInputElement | HTMLTextAreaElement + setFormData((prev) => ({ ...prev, [field]: target.value })) + } + + const handleSubmit = async (e: Event) => { + e.preventDefault() + setIsSubmitting(true) + + try { + const response = await fetch("/api/enterprise", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData()), + }) + + if (response.ok) { + setShowSuccess(true) + setFormData({ + name: "", + role: "", + email: "", + message: "", + }) + setTimeout(() => setShowSuccess(false), 5000) + } + } catch (error) { + console.error("Failed to submit form:", error) + } finally { + setIsSubmitting(false) + } + } + + return ( +
    + OpenCode Enterprise | How can we help your organisation? + +
    +
    + +
    +
    +
    +
    +

    Your code is yours

    +

    + Run OpenCode securely inside your organization with no data or context stored, and + no licensing restrictions or ownership claims. Start a trial with your team today, + then scale with enterprise features like SSO, private registries, and + self-hosting. +

    +
    + +
    +
    +
    +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + +