Compare commits

...
52 changed files with 2221 additions and 982 deletions
-9
View File
@@ -21,15 +21,6 @@ jobs:
with:
node-version: "24"
# Workaround for Pulumi version conflict:
# GitHub runners have Pulumi 3.212.0+ pre-installed, which removed the -root flag
# from pulumi-language-nodejs (see https://github.com/pulumi/pulumi/pull/21065).
# SST 3.17.x uses Pulumi SDK 3.210.0 which still passes -root, causing a conflict.
# Removing the system language plugin forces SST to use its bundled compatible version.
# TODO: Remove when sst supports Pulumi >3.210.0
- name: Fix Pulumi version conflict
run: sudo rm -f /usr/local/bin/pulumi-language-nodejs
- run: bun sst deploy --stage=${{ github.ref_name }}
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+118 -130
View File
@@ -23,13 +23,13 @@
"oxlint-tsgolint": "0.21.0",
"prettier": "3.6.2",
"semver": "^7.6.0",
"sst": "3.18.10",
"sst": "4.13.1",
"turbo": "2.8.13",
},
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
@@ -84,7 +84,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -119,7 +119,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -146,7 +146,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@ai-sdk/anthropic": "3.0.64",
"@ai-sdk/openai": "3.0.48",
@@ -168,7 +168,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -192,7 +192,7 @@
},
"packages/core": {
"name": "@opencode-ai/core",
"version": "1.15.6",
"version": "1.15.7",
"bin": {
"opencode": "./bin/opencode",
},
@@ -230,7 +230,7 @@
"ai-gateway-provider": "3.1.2",
"cross-spawn": "catalog:",
"effect": "catalog:",
"gitlab-ai-provider": "6.6.0",
"gitlab-ai-provider": "6.7.0",
"glob": "13.0.5",
"google-auth-library": "10.5.0",
"immer": "11.1.4",
@@ -253,7 +253,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@zip.js/zip.js": "2.7.62",
"drizzle-orm": "catalog:",
@@ -308,7 +308,7 @@
},
"packages/effect-drizzle-sqlite": {
"name": "@opencode-ai/effect-drizzle-sqlite",
"version": "1.15.5",
"version": "1.15.7",
"dependencies": {
"drizzle-orm": "catalog:",
"effect": "catalog:",
@@ -322,7 +322,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@opencode-ai/core": "workspace:*",
"@opencode-ai/ui": "workspace:*",
@@ -352,7 +352,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -368,7 +368,7 @@
},
"packages/http-recorder": {
"name": "@opencode-ai/http-recorder",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@effect/platform-node": "catalog:",
"effect": "catalog:",
@@ -381,7 +381,7 @@
},
"packages/llm": {
"name": "@opencode-ai/llm",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@smithy/eventstream-codec": "4.2.14",
"@smithy/util-utf8": "4.2.2",
@@ -399,7 +399,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.15.6",
"version": "1.15.7",
"bin": {
"opencode": "./bin/opencode",
},
@@ -469,7 +469,7 @@
"drizzle-orm": "catalog:",
"effect": "catalog:",
"fuzzysort": "3.1.0",
"gitlab-ai-provider": "6.6.0",
"gitlab-ai-provider": "6.7.0",
"glob": "13.0.5",
"google-auth-library": "10.5.0",
"gray-matter": "4.0.3",
@@ -537,7 +537,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"effect": "catalog:",
@@ -575,7 +575,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"cross-spawn": "catalog:",
},
@@ -590,7 +590,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -625,7 +625,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/core": "workspace:*",
@@ -674,7 +674,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
@@ -907,6 +907,8 @@
"@aws-sdk/client-cognito-identity": ["@aws-sdk/client-cognito-identity@3.993.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.11", "@aws-sdk/credential-provider-node": "^3.972.10", "@aws-sdk/middleware-host-header": "^3.972.3", "@aws-sdk/middleware-logger": "^3.972.3", "@aws-sdk/middleware-recursion-detection": "^3.972.3", "@aws-sdk/middleware-user-agent": "^3.972.11", "@aws-sdk/region-config-resolver": "^3.972.3", "@aws-sdk/types": "^3.973.1", "@aws-sdk/util-endpoints": "3.993.0", "@aws-sdk/util-user-agent-browser": "^3.972.3", "@aws-sdk/util-user-agent-node": "^3.972.9", "@smithy/config-resolver": "^4.4.6", "@smithy/core": "^3.23.2", "@smithy/fetch-http-handler": "^5.3.9", "@smithy/hash-node": "^4.2.8", "@smithy/invalid-dependency": "^4.2.8", "@smithy/middleware-content-length": "^4.2.8", "@smithy/middleware-endpoint": "^4.4.16", "@smithy/middleware-retry": "^4.4.33", "@smithy/middleware-serde": "^4.2.9", "@smithy/middleware-stack": "^4.2.8", "@smithy/node-config-provider": "^4.3.8", "@smithy/node-http-handler": "^4.4.10", "@smithy/protocol-http": "^5.3.8", "@smithy/smithy-client": "^4.11.5", "@smithy/types": "^4.12.0", "@smithy/url-parser": "^4.2.8", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.32", "@smithy/util-defaults-mode-node": "^4.2.35", "@smithy/util-endpoints": "^3.2.8", "@smithy/util-middleware": "^4.2.8", "@smithy/util-retry": "^4.2.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7Ne3Yk/bgQPVebAkv7W+RfhiwTRSbfER9BtbhOa2w/+dIr902LrJf6vrZlxiqaJbGj2ALx8M+ZK1YIHVxSwu9A=="],
"@aws-sdk/client-lambda": ["@aws-sdk/client-lambda@3.1048.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-node": "^3.972.42", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-ryEYNVdilyWkKsOs/7Xy/l7+qjtSz4sll8NpcWD6AtONxjG/5OMaAhxxDkQb4iBoNMKnISxsARzQAp/Wa8pXIg=="],
"@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.933.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/credential-provider-node": "3.933.0", "@aws-sdk/middleware-bucket-endpoint": "3.930.0", "@aws-sdk/middleware-expect-continue": "3.930.0", "@aws-sdk/middleware-flexible-checksums": "3.932.0", "@aws-sdk/middleware-host-header": "3.930.0", "@aws-sdk/middleware-location-constraint": "3.930.0", "@aws-sdk/middleware-logger": "3.930.0", "@aws-sdk/middleware-recursion-detection": "3.933.0", "@aws-sdk/middleware-sdk-s3": "3.932.0", "@aws-sdk/middleware-ssec": "3.930.0", "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/region-config-resolver": "3.930.0", "@aws-sdk/signature-v4-multi-region": "3.932.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@aws-sdk/util-user-agent-browser": "3.930.0", "@aws-sdk/util-user-agent-node": "3.932.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.2", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-blob-browser": "^4.2.6", "@smithy/hash-node": "^4.2.5", "@smithy/hash-stream-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/md5-js": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.9", "@smithy/middleware-retry": "^4.4.9", "@smithy/middleware-serde": "^4.2.5", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.8", "@smithy/util-defaults-mode-node": "^4.2.11", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-KxwZvdxdCeWK6o8mpnb+kk7Kgb8V+8AjTwSXUWH1UAD85B0tjdo1cSfE5zoR5fWGol4Ml5RLez12a6LPhsoTqA=="],
"@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.933.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.932.0", "@aws-sdk/middleware-host-header": "3.930.0", "@aws-sdk/middleware-logger": "3.930.0", "@aws-sdk/middleware-recursion-detection": "3.933.0", "@aws-sdk/middleware-user-agent": "3.932.0", "@aws-sdk/region-config-resolver": "3.930.0", "@aws-sdk/types": "3.930.0", "@aws-sdk/util-endpoints": "3.930.0", "@aws-sdk/util-user-agent-browser": "3.930.0", "@aws-sdk/util-user-agent-node": "3.932.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.2", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.9", "@smithy/middleware-retry": "^4.4.9", "@smithy/middleware-serde": "^4.2.5", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.8", "@smithy/util-defaults-mode-node": "^4.2.11", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zwGLSiK48z3PzKpQiDMKP85+fpIrPMF1qQOQW9OW7BGj5AuBZIisT2O4VzIgYJeh+t47MLU7VgBQL7muc+MJDg=="],
@@ -977,6 +979,8 @@
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="],
"@aws/durable-execution-sdk-js": ["@aws/durable-execution-sdk-js@1.0.2", "", { "dependencies": { "@aws-sdk/client-lambda": "^3.943.0" } }, "sha512-KIYBVqV9gArkWdPEDYOjJqLlO+NecmCXOXadNBlOspJTmqztwuiyb6aZc468bYWSGuL4Me/gyTIK97ubkwFNCw=="],
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="],
"@azure-rest/core-client": ["@azure-rest/core-client@2.6.0", "", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", "@azure/core-rest-pipeline": "^1.22.0", "@azure/core-tracing": "^1.3.0", "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, "sha512-iuFKDm8XPzNxPfRjhyU5/xKZmcRDzSuEghXDHHk4MjBV/wFL34GmYVBZnn9wmuoLBeS1qAw9ceMdaeJBPcB1QQ=="],
@@ -1463,6 +1467,8 @@
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ=="],
"@nodable/entities": ["@nodable/entities@2.1.0", "", {}, "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
@@ -2613,8 +2619,6 @@
"avvio": ["avvio@9.2.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ=="],
"aws-sdk": ["aws-sdk@2.1692.0", "", { "dependencies": { "buffer": "4.9.2", "events": "1.1.1", "ieee754": "1.1.13", "jmespath": "0.16.0", "querystring": "0.2.0", "sax": "1.2.1", "url": "0.10.3", "util": "^0.12.4", "uuid": "8.0.0", "xml2js": "0.6.2" } }, "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw=="],
"aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="],
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
@@ -2699,7 +2703,7 @@
"browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="],
"buffer": ["buffer@4.9.2", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } }, "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg=="],
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
"buffer-crc32": ["buffer-crc32@1.0.0", "", {}, "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w=="],
@@ -3295,7 +3299,7 @@
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
"gitlab-ai-provider": ["gitlab-ai-provider@6.6.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-jUxYnKA4XQaPc3wxACDZ8bPDXO0Mzx7cZaBDxbT2uGgLqtGZmSi+9tVNIg7louSS+s/ioVra3SoUz3iOFVhKPA=="],
"gitlab-ai-provider": ["gitlab-ai-provider@6.7.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-J7apROAmDwDJcLPcbQ9YQiPhyFN1Vvt/f3ugsePaUnzh3sedfHCHGETgG0Mm0dJCB2rC7DYwmV/sgxLQcQ/sjw=="],
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
@@ -3437,7 +3441,7 @@
"iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
"ieee754": ["ieee754@1.1.13", "", {}, "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="],
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
@@ -3569,7 +3573,7 @@
"is64bit": ["is64bit@2.0.0", "", { "dependencies": { "system-architecture": "^0.1.0" } }, "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw=="],
"isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
"isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
"isbinaryfile": ["isbinaryfile@5.0.7", "", {}, "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ=="],
@@ -3587,8 +3591,6 @@
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"jmespath": ["jmespath@0.16.0", "", {}, "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw=="],
"jose": ["jose@6.0.11", "", {}, "sha512-QxG7EaliDARm1O1S8BGakqncGT9s25bKL1WSf6/oa17Tkqwi8D2ZNglqCF+DsYF88/rV66Q/Q2mFAy697E1DUg=="],
"js-base64": ["js-base64@3.7.7", "", {}, "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="],
@@ -4075,8 +4077,6 @@
"opencode-poe-auth": ["opencode-poe-auth@0.0.1", "", { "dependencies": { "open": "^10.0.0", "poe-oauth": "*" }, "peerDependencies": { "@opencode-ai/plugin": "*" } }, "sha512-cXqTlS6AXHzo1oBdosnxbT47ZJEZ9WXn050X8Re6wZ1vaNnTpB/l2fMQt90evT7RBK0fB8UjXQUDMKyd7bbiqg=="],
"opencontrol": ["opencontrol@0.0.6", "", { "dependencies": { "@modelcontextprotocol/sdk": "1.6.1", "@tsconfig/bun": "1.0.7", "hono": "4.7.4", "zod": "3.24.2", "zod-to-json-schema": "3.24.3" }, "bin": { "opencontrol": "bin/index.mjs" } }, "sha512-QeCrpOK5D15QV8kjnGVeD/BHFLwcVr+sn4T6KKmP0WAMs2pww56e4h+eOGHb5iPOufUQXbdbBKi6WV2kk7tefQ=="],
"openid-client": ["openid-client@5.6.4", "", { "dependencies": { "jose": "^4.15.4", "lru-cache": "^6.0.0", "object-hash": "^2.2.0", "oidc-token-hash": "^5.0.3" } }, "sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA=="],
"opentui-spinner": ["opentui-spinner@0.0.6", "", { "dependencies": { "cli-spinners": "^3.3.0" }, "peerDependencies": { "@opentui/core": "^0.1.49", "@opentui/react": "^0.1.49", "@opentui/solid": "^0.1.49", "typescript": "^5" }, "optionalPeers": ["@opentui/react", "@opentui/solid"] }, "sha512-xupLOeVQEAXEvVJCvHkfX6fChDWmJIPHe5jyUrVb8+n4XVTX8mBNhitFfB9v2ZbkC1H2UwPab/ElePHoW37NcA=="],
@@ -4273,7 +4273,7 @@
"pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="],
"punycode": ["punycode@1.3.2", "", {}, "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"pupa": ["pupa@3.3.0", "", { "dependencies": { "escape-goat": "^4.0.0" } }, "sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA=="],
@@ -4283,8 +4283,6 @@
"quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="],
"querystring": ["querystring@0.2.0", "", {}, "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
@@ -4469,7 +4467,7 @@
"sanitize-filename": ["sanitize-filename@1.6.4", "", { "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg=="],
"sax": ["sax@1.2.1", "", {}, "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA=="],
"sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
@@ -4597,23 +4595,23 @@
"ssri": ["ssri@13.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="],
"sst": ["sst@3.18.10", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.18.10", "sst-darwin-x64": "3.18.10", "sst-linux-arm64": "3.18.10", "sst-linux-x64": "3.18.10", "sst-linux-x86": "3.18.10", "sst-win32-arm64": "3.18.10", "sst-win32-x64": "3.18.10", "sst-win32-x86": "3.18.10" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-SY+ldeJ9K5E9q+DhjXA3e2W3BEOzBwkE3IyLSD71uA3/5nRhUAST31iOWEpW36LbIvSQ9uOVDFcebztoLJ8s7w=="],
"sst": ["sst@4.13.1", "", { "dependencies": { "@aws/durable-execution-sdk-js": "1.0.2", "aws4fetch": "1.0.18", "jose": "5.2.3", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "4.13.1", "sst-darwin-x64": "4.13.1", "sst-linux-arm64": "4.13.1", "sst-linux-x64": "4.13.1", "sst-linux-x86": "4.13.1", "sst-win32-arm64": "4.13.1", "sst-win32-x64": "4.13.1", "sst-win32-x86": "4.13.1" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-FKzhWuqV5NPhFWH7b+Ktf5+Mvox6DCMc8iOrjaS3mkjnnmyEcOZq7HNx2/ZlIcBwgOZE9sCPR3ot1zXtXkXzZg=="],
"sst-darwin-arm64": ["sst-darwin-arm64@3.18.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3MwIpMZhhdZKDqLp9ZQNlwkWix5+q+N0PWstuTomYwgZOxCCe6u9IIsoIszSk+GAJJN/jvGZyLiXKeV4iiQvw=="],
"sst-darwin-arm64": ["sst-darwin-arm64@4.13.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gGwfgZGOsulU6iGeZJtxP5BpSZFsRUy1dG/yTqJa++n1P1APWXZC64u2qRHm6rdwLAjEeWaCQ9k7ouKgn0zh5Q=="],
"sst-darwin-x64": ["sst-darwin-x64@3.18.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-nQ0jMKkPOa+kj6Ygz8+kYhBua/vgNTLkd+4r8NSmk7v+Zs78lKnx3T//kEzS0yik6Q6QwGfokwrTcA1Jii2xSw=="],
"sst-darwin-x64": ["sst-darwin-x64@4.13.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-RcKLI2oAY+Wk5fWUF0gJFKvwMSpid3qw9L3OcfgFL2ymZH652ybLpQPBxtoJ95FdyknWIMnYf6ZK9C2jnH5eaw=="],
"sst-linux-arm64": ["sst-linux-arm64@3.18.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-mj9VNj3SvLS+HaXx2PhCX0aTA7CwJNoM6JhRc0s/zCilqchcvqDjbhpYBJO4brEPv6aOaaa7T3WvIQqtYauK4Q=="],
"sst-linux-arm64": ["sst-linux-arm64@4.13.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Lp/8BWhH8KZnb50xPd8A6bkZ7QqCH3Dar9l16TPwuAmPxxRUlkmg42h+ACZ9n02vSJl8y/WLnV4JB6SgJpRFVg=="],
"sst-linux-x64": ["sst-linux-x64@3.18.10", "", { "os": "linux", "cpu": "x64" }, "sha512-7iy1Eq2eqnT9Ag/8OVgC04vRjV7AAQyf/BvzLc+6Sz+GvRiKA8VEuPnbXNYQF+NIvEqsawfcd7MknSTtImpsvQ=="],
"sst-linux-x64": ["sst-linux-x64@4.13.1", "", { "os": "linux", "cpu": "x64" }, "sha512-f4eHOsApoP+CpUzLUGzfoTBYsqqr6nl/M0gjYsVNi1T+6v92lc84AhQ4DoDZx033QggyxkqRezj8jOkjkKxa7w=="],
"sst-linux-x86": ["sst-linux-x86@3.18.10", "", { "os": "linux", "cpu": "none" }, "sha512-77qZSuPZeQ5bdRCiq1pQEdY8EcGNHboKrx4P2yFid2FBDKJsXxOXtIxJdloyx+ljBn0+nxl/g040QBmXxdc9tA=="],
"sst-linux-x86": ["sst-linux-x86@4.13.1", "", { "os": "linux", "cpu": "none" }, "sha512-5OHdtPa0GmozDpBPdsD9Tv+SGnpjJSoTXptgK59ivQg3UYNWBBotidvEyUJs1MU9B/3+I+Fmw32zsF2O+ZtPgg=="],
"sst-win32-arm64": ["sst-win32-arm64@3.18.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-aY+FhMxvYs8crlrKALpLn/kKmud8YQj6LkMHsrOAAIJhfNyxhCja2vrYQaY+bcqdsS5W2LMVcS2hyaMqKXZKcg=="],
"sst-win32-arm64": ["sst-win32-arm64@4.13.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-qAUuCQj6wDdZ84a9W4FhnRTHYlEnYRHGYFqO3cmMImbnAQEoKSQR1XuWqt0Ev4RT3kU4Lz/fgvJjGkR7WUstLg=="],
"sst-win32-x64": ["sst-win32-x64@3.18.10", "", { "os": "win32", "cpu": "x64" }, "sha512-rY+yJXOpG+P5xXnaQRpCvBK2zwwLhjzpYidGkp6F+cGgiVdh2Wre/CIQNRaVHr20ncj8lLe/RsHWa9QCNM48jg=="],
"sst-win32-x64": ["sst-win32-x64@4.13.1", "", { "os": "win32", "cpu": "x64" }, "sha512-r+83NMwpe4MLAvkVoOxi1KNs6nIqilFucsTr+VN1PgknsiVBY1emITjSWS2jDJJMuH8xJXL5xJzF/l5rcKWErg=="],
"sst-win32-x86": ["sst-win32-x86@3.18.10", "", { "os": "win32", "cpu": "none" }, "sha512-pq8SmV0pIjBFMY6DraUZ4akyTxHnfjIKCRbBLdMxFUZK8TzA1NK2YdjRt1AwrgXRYGRyctrz/mt4WyO0SMOVQQ=="],
"sst-win32-x86": ["sst-win32-x86@4.13.1", "", { "os": "win32", "cpu": "none" }, "sha512-YPxBVdac/MsrzwlC6pF0NrrvMcmfdBLYjv7MbzHc5jNh1FQ1WPh6bdWQqgv0KD9EQTNLLEkej0beydgUvcCWJg=="],
"stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
@@ -4893,8 +4891,6 @@
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"url": ["url@0.10.3", "", { "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ=="],
"use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
"use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
@@ -4903,8 +4899,6 @@
"utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="],
"util": ["util@0.12.5", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="],
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
@@ -5031,6 +5025,8 @@
"xdg-basedir": ["xdg-basedir@5.1.0", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="],
"xml-naming": ["xml-naming@0.1.0", "", {}, "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw=="],
"xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="],
"xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="],
@@ -5193,6 +5189,20 @@
"@aws-sdk/client-cognito-identity/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
"@aws-sdk/client-lambda/@aws-sdk/core": ["@aws-sdk/core@3.974.11", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@aws-sdk/xml-builder": "^3.972.24", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.2", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-QpnINq5FZH6EOaDEkmHdT7eUunbvD27pDNQypaWjFyYz7Zl1q3UCMQErBZxpmfGfI7MvI2TlK8KTkgNpv8b1ug=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.42", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.37", "@aws-sdk/credential-provider-http": "^3.972.39", "@aws-sdk/credential-provider-ini": "^3.972.41", "@aws-sdk/credential-provider-process": "^3.972.37", "@aws-sdk/credential-provider-sso": "^3.972.41", "@aws-sdk/credential-provider-web-identity": "^3.972.41", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/credential-provider-imds": "^4.3.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-D4oon2zbqqsWOJUM99Gm3/ZyJ0IJvTXVN3PyloGb3kQEyI36fjCZheZj422lAgTWWd6TSHgiImLt3RIaLdv3dQ=="],
"@aws-sdk/client-lambda/@aws-sdk/types": ["@aws-sdk/types@3.973.8", "", { "dependencies": { "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw=="],
"@aws-sdk/client-lambda/@smithy/core": ["@smithy/core@3.24.3", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-Ep/7tPamGY8mgESE3LyLKtxJyy6U52WWAqr/3wial47Sj4u3PiIF73AOGI27UyLy9duTkhZbgzodOfLV4TduZg=="],
"@aws-sdk/client-lambda/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-F+DRf8IJazRJgYog2A/yJK7eYVc0rqTlRzO+5ZxjJd4WkZoKz0IJRncf7G6t1pdVT3kryJcwuTFhN1c5m6N47A=="],
"@aws-sdk/client-lambda/@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA=="],
"@aws-sdk/client-lambda/@smithy/types": ["@smithy/types@4.14.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg=="],
"@aws-sdk/client-sso/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
"@aws-sdk/client-sts/@aws-sdk/core": ["@aws-sdk/core@3.775.0", "", { "dependencies": { "@aws-sdk/types": "3.775.0", "@smithy/core": "^3.2.0", "@smithy/node-config-provider": "^4.0.2", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/signature-v4": "^5.0.2", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-middleware": "^4.0.2", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" } }, "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA=="],
@@ -5657,28 +5667,18 @@
"astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"aws-sdk/events": ["events@1.1.1", "", {}, "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw=="],
"aws-sdk/uuid": ["uuid@8.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw=="],
"babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
"babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="],
"bl/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
"body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
"body-parser/qs": ["qs@6.14.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q=="],
"buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"builder-util/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"builder-util-runtime/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
"c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"c12/dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
@@ -5735,8 +5735,6 @@
"engine.io-client/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
"es-get-iterator/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
"esbuild-plugin-copy/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"esbuild-plugin-copy/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
@@ -5845,16 +5843,6 @@
"opencode-poe-auth/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="],
"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=="],
"opencontrol/@tsconfig/bun": ["@tsconfig/bun@1.0.7", "", {}, "sha512-udGrGJBNQdXGVulehc1aWT73wkR9wdaGBtB6yL70RJsqwW/yJhIg6ZbRlPOfIUiFNrnBuYLBi9CSmMKfDC7dvA=="],
"opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
"opencontrol/zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
"opencontrol/zod-to-json-schema": ["zod-to-json-schema@3.24.3", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A=="],
"openid-client/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="],
"openid-client/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
@@ -5901,8 +5889,6 @@
"raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
"readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
"readdir-glob/minimatch": ["minimatch@5.1.9", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw=="],
"restore-cursor/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
@@ -5913,10 +5899,6 @@
"router/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="],
"safe-array-concat/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
"safe-push-apply/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
"send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="],
@@ -5929,8 +5911,6 @@
"shiki/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="],
"sitemap/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
"slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@4.0.0", "", {}, "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ=="],
@@ -5973,8 +5953,6 @@
"unused-filename/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="],
"uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"venice-ai-sdk-provider/@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.41", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g=="],
"vite-plugin-icons-spritesheet/glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="],
@@ -5993,8 +5971,6 @@
"vscode-languageserver-protocol/vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="],
"which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
"wrangler/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
@@ -6003,8 +5979,6 @@
"wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"xml2js/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
"yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="],
"yaml-language-server/yaml": ["yaml@2.7.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="],
@@ -6069,6 +6043,36 @@
"@aws-sdk/client-cognito-identity/@aws-sdk/middleware-user-agent/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.6", "", { "dependencies": { "@aws-sdk/types": "^3.973.7", "@smithy/types": "^4.14.0", "@smithy/url-parser": "^4.2.13", "@smithy/util-endpoints": "^3.3.4", "tslib": "^2.6.2" } }, "sha512-2nUQ+2ih7CShuKHpGSIYvvAIOHy52dOZguYG36zptBukhw6iFwcvGfG0tes0oZFWQqEWvgZe9HLWaNlvXGdOrg=="],
"@aws-sdk/client-lambda/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.24", "", { "dependencies": { "@nodable/entities": "2.1.0", "@smithy/types": "^4.14.1", "fast-xml-parser": "5.7.3", "tslib": "^2.6.2" } }, "sha512-V8z5YcDPfsvzrBlj0xR1vhRtocblhYbqdreCJB/voGd4Sr5zjNAeWxexbnqVtskTJe0vFb5KMqbSL++ePl+zRw=="],
"@aws-sdk/client-lambda/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g=="],
"@aws-sdk/client-lambda/@aws-sdk/core/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.37", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-/jpPvEh6f7ntmIzf7dNxoNX6Q8vt8UpesCjbW6mFfk4V1NW6bIy9qxcQ6WbA8As5yQhsZOe+xeNd4xHX8kdY2Q=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.39", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-pIgTpisWyWg7X1bUbzSjuUYosYTD0Ghz2M0hkSTmb3a6i3qV3uU+NYJPI/E2XSC0HcsZh5rsLPzeXrkb2DS0Cg=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.41", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/credential-provider-env": "^3.972.37", "@aws-sdk/credential-provider-http": "^3.972.39", "@aws-sdk/credential-provider-login": "^3.972.41", "@aws-sdk/credential-provider-process": "^3.972.37", "@aws-sdk/credential-provider-sso": "^3.972.41", "@aws-sdk/credential-provider-web-identity": "^3.972.41", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/credential-provider-imds": "^4.3.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-u2tyjaxJJzW8UtW4SM1ZcPMDwO6y+kV+llvou+Adts0FAKyzes5jG4izQN+KX3yE8ZROpS5y1LJ//xL2iSf76w=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.37", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-7nVaHBUaWIddASYfVaA9O4D5ZVjewU3sCol9WqZPGfW0nR+0WqE0xHZnD/U2L33PlOB8KNXGKZ6wOES/QijKzg=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.41", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/token-providers": "3.1048.0", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-IOWAWEHe5LkjSKkkUUX9ciV6Y1scHTsnfEkdt5yyC4Slrc7AGbkLPrpntjqh18ksJAMOaVhoBsO8p2WyTcY2wQ=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.41", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-mbACk9Yypa8nm4iGZLs0PofOXEcTDOUw6wDnsPXNDNSd2WNXs1tSo+6nc/fh0jLYdfVZThhBL98PHW4aXFsG5A=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.3.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-I2Bti0DKFo2IJyN28ijCsx51BAumEYR4/1yZ1FXyBygy9MqbnMqCev4JPth/MbpRfBSRAX35hITSnAdJRo1u5w=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="],
"@aws-sdk/client-lambda/@aws-sdk/types/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="],
"@aws-sdk/client-lambda/@smithy/core/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="],
"@aws-sdk/client-lambda/@smithy/fetch-http-handler/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="],
"@aws-sdk/client-lambda/@smithy/node-http-handler/@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="],
"@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/property-provider": "^4.0.2", "@smithy/types": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw=="],
"@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.775.0", "", { "dependencies": { "@aws-sdk/core": "3.775.0", "@aws-sdk/types": "3.775.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/property-provider": "^4.0.2", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/util-stream": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww=="],
@@ -6239,8 +6243,6 @@
"@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="],
"@azure/core-http/xml2js/sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
"@azure/core-xml/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="],
"@azure/identity/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
@@ -6553,14 +6555,10 @@
"babel-plugin-module-resolver/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"crc/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"dir-compare/minimatch/brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="],
@@ -6603,6 +6601,8 @@
"lazystream/readable-stream/core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
"lazystream/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
"lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
"lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
@@ -6617,18 +6617,6 @@
"opencode-poe-auth/open/wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
"opencontrol/@modelcontextprotocol/sdk/express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.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-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
"opencontrol/@modelcontextprotocol/sdk/express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="],
"opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="],
"opencontrol/@modelcontextprotocol/sdk/raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
"opencontrol/@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
"ora/bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
"ora/bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
@@ -6641,8 +6629,6 @@
"pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="],
"readable-stream/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"readdir-glob/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="],
"restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
@@ -6761,6 +6747,18 @@
"@aws-sdk/client-cognito-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.5.8", "", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="],
"@aws-sdk/client-lambda/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.41", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0LBitxXiAiaE5nlFPfpNIww/8FRY/I7WIndWsc9GmNFOM7cE1wNpVNQEGEk9Outg5l8xl+3vybxFyUy4l9q/LQ=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/signature-v4-multi-region": "^3.996.27", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/signature-v4-multi-region": "^3.996.27", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1048.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.11", "@aws-sdk/nested-clients": "^3.997.9", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.9", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.11", "@aws-sdk/signature-v4-multi-region": "^3.996.27", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ=="],
"@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-QOYC8q7luzHFXrP0xYAqBctoPkynjfV0r9dqntFu4/IWMTyC1vlo1UTxFAjIPyclYw92XJyEkVCVg9v/nQnsUA=="],
"@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.782.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.775.0", "@aws-sdk/middleware-host-header": "3.775.0", "@aws-sdk/middleware-logger": "3.775.0", "@aws-sdk/middleware-recursion-detection": "3.775.0", "@aws-sdk/middleware-user-agent": "3.782.0", "@aws-sdk/region-config-resolver": "3.775.0", "@aws-sdk/types": "3.775.0", "@aws-sdk/util-endpoints": "3.782.0", "@aws-sdk/util-user-agent-browser": "3.775.0", "@aws-sdk/util-user-agent-node": "3.782.0", "@smithy/config-resolver": "^4.1.0", "@smithy/core": "^3.2.0", "@smithy/fetch-http-handler": "^5.0.2", "@smithy/hash-node": "^4.0.2", "@smithy/invalid-dependency": "^4.0.2", "@smithy/middleware-content-length": "^4.0.2", "@smithy/middleware-endpoint": "^4.1.0", "@smithy/middleware-retry": "^4.1.0", "@smithy/middleware-serde": "^4.0.3", "@smithy/middleware-stack": "^4.0.2", "@smithy/node-config-provider": "^4.0.2", "@smithy/node-http-handler": "^4.0.4", "@smithy/protocol-http": "^5.1.0", "@smithy/smithy-client": "^4.2.0", "@smithy/types": "^4.2.0", "@smithy/url-parser": "^4.0.2", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", "@smithy/util-defaults-mode-browser": "^4.0.8", "@smithy/util-defaults-mode-node": "^4.0.8", "@smithy/util-endpoints": "^3.0.2", "@smithy/util-middleware": "^4.0.2", "@smithy/util-retry": "^4.0.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-5GlJBejo8wqMpSSEKb45WE82YxI2k73YuebjLH/eWDNQeE6VI5Bh9lA1YQ7xNkLLH8hIsb0pSfKVuwh0VEzVrg=="],
@@ -6957,30 +6955,6 @@
"js-beautify/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"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.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
"opencontrol/@modelcontextprotocol/sdk/express/content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="],
"opencontrol/@modelcontextprotocol/sdk/express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
"opencontrol/@modelcontextprotocol/sdk/express/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
"opencontrol/@modelcontextprotocol/sdk/express/finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="],
"opencontrol/@modelcontextprotocol/sdk/express/fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
"opencontrol/@modelcontextprotocol/sdk/express/merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
"opencontrol/@modelcontextprotocol/sdk/express/send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
"opencontrol/@modelcontextprotocol/sdk/express/serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="],
"opencontrol/@modelcontextprotocol/sdk/express/type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
"ora/bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
"pkg-up/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="],
@@ -7003,6 +6977,16 @@
"@aws-sdk/client-cognito-identity/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="],
"@aws-sdk/client-lambda/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/fast-xml-builder": ["fast-xml-builder@1.2.0", "", { "dependencies": { "path-expression-matcher": "^1.5.0", "xml-naming": "^0.1.0" } }, "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q=="],
"@aws-sdk/client-lambda/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.27", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.27", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.27", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg=="],
"@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
"@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
@@ -7077,8 +7061,6 @@
"js-beautify/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"opencontrol/@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
"pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
"pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
@@ -7087,6 +7069,12 @@
"tw-to-css/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g=="],
"@aws-sdk/client-lambda/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients/@aws-sdk/signature-v4-multi-region/@smithy/signature-v4": ["@smithy/signature-v4@5.4.3", "", { "dependencies": { "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g=="],
"@aws-sdk/client-sts/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients/@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="],
"@aws-sdk/credential-provider-cognito-identity/@aws-sdk/nested-clients/@aws-sdk/core/@aws-sdk/xml-builder/fast-xml-parser/strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="],
+11 -11
View File
@@ -4,7 +4,7 @@ import { domain } from "./stage"
const description = "Managed by SST (Don't edit in Honeycomb UI)"
const alertsDisabled = $app.stage !== "production"
const webhookRecipient = new honeycomb.WebhookRecipient("DiscordAlerts", {
const webhookRecipient = new honeycombio.WebhookRecipient("DiscordAlerts", {
name: $app.stage === "production" ? "Discord Alerts" : `Discord Alerts (${$app.stage})`,
url: `https://${domain}/honeycomb/webhook`,
secret: SECRET.HoneycombWebhookSecret.result,
@@ -67,7 +67,7 @@ IF(
)`,
})
return honeycomb.getQuerySpecificationOutput({
return honeycombio.getQuerySpecificationOutput({
breakdowns: ["model"],
calculatedFields: [failedHttpStatus],
calculations: [
@@ -99,7 +99,7 @@ const providerHttpErrorsQuery = () => {
expression: `IF(GT($llm.error.code, "400"), 1, 0)`,
})
return honeycomb.getQuerySpecificationOutput({
return honeycombio.getQuerySpecificationOutput({
breakdowns: ["provider"],
calculatedFields: [successHttpStatus, failedProviderHttpStatus],
calculations: [
@@ -140,7 +140,7 @@ const modelLowTpsQuery = (product: "go" | "zen") => {
{ column: "tps.output", op: "exists" },
]
return honeycomb.getQuerySpecificationOutput({
return honeycombio.getQuerySpecificationOutput({
breakdowns: ["model"],
calculations: [
{ op: "COUNT", name: "TOTAL", filterCombination: "AND", filters },
@@ -157,7 +157,7 @@ const modelLowTpsQuery = (product: "go" | "zen") => {
}).json
}
new honeycomb.Trigger("IncreasedModelHttpErrorsGo", {
new honeycombio.Trigger("IncreasedModelHttpErrorsGo", {
name: "Increased Model HTTP Errors [Go]",
description,
disabled: alertsDisabled,
@@ -177,7 +177,7 @@ new honeycomb.Trigger("IncreasedModelHttpErrorsGo", {
],
})
new honeycomb.Trigger("IncreasedModelHttpErrorsZen", {
new honeycombio.Trigger("IncreasedModelHttpErrorsZen", {
name: "Increased Model HTTP Errors [Zen]",
description,
disabled: alertsDisabled,
@@ -197,7 +197,7 @@ new honeycomb.Trigger("IncreasedModelHttpErrorsZen", {
],
})
new honeycomb.Trigger("LowModelTpsGo", {
new honeycombio.Trigger("LowModelTpsGo", {
name: "Low Model TPS [Go]",
description,
disabled: alertsDisabled,
@@ -217,7 +217,7 @@ new honeycomb.Trigger("LowModelTpsGo", {
],
})
new honeycomb.Trigger("LowModelTpsZen", {
new honeycombio.Trigger("LowModelTpsZen", {
name: "Low Model TPS [Zen]",
description,
disabled: alertsDisabled,
@@ -237,7 +237,7 @@ new honeycomb.Trigger("LowModelTpsZen", {
],
})
new honeycomb.Trigger("IncreasedProviderHttpErrors", {
new honeycombio.Trigger("IncreasedProviderHttpErrors", {
name: "Increased Provider HTTP Errors",
description,
disabled: alertsDisabled,
@@ -257,11 +257,11 @@ new honeycomb.Trigger("IncreasedProviderHttpErrors", {
],
})
new honeycomb.Trigger("IncreasedFreeTierRequests", {
new honeycombio.Trigger("IncreasedFreeTierRequests", {
name: "Increased Free Tier Requests",
description,
disabled: alertsDisabled,
queryJson: honeycomb.getQuerySpecificationOutput({
queryJson: honeycombio.getQuerySpecificationOutput({
calculations: [{ op: "COUNT" }],
filters: [
{ column: "event_type", op: "=", value: "completions" },
+4 -4
View File
@@ -1,8 +1,8 @@
{
"nodeModules": {
"x86_64-linux": "sha256-hIarzU3QNIvkwpfnearfsGaBMCSdovkOWAuvX+EBQI8=",
"aarch64-linux": "sha256-qu+86RNsBZhqzE3CEyg4XHD/3Czc/BqHhY3O1vyogtY=",
"aarch64-darwin": "sha256-7sXZdPh/R4fQBBMq36YdpQE6G2ELMZd08BqMhHbhwv4=",
"x86_64-darwin": "sha256-g5QWpX33R143sNR1G9m7UsSA3jygFyJjT7Kjyjo6sCc="
"x86_64-linux": "sha256-1RiaZQHzIhdtcOJUMsLagpP+nBBL/Qu6zQgrAXMHDCI=",
"aarch64-linux": "sha256-5QZhtkWuNpY/qUxlKRHcGbILOAVnuyzu+h8VDIuMQcU=",
"aarch64-darwin": "sha256-9w3QA22XNc1itGLyhikYU90xGH/iLUUM+SSGXla7lhw=",
"x86_64-darwin": "sha256-cSYiyhhSqIYiTeK1uWHDkHbYstQYD5jEB7JaYjWjgi4="
}
}
+1 -1
View File
@@ -98,7 +98,7 @@
"oxlint-tsgolint": "0.21.0",
"prettier": "3.6.2",
"semver": "^7.6.0",
"sst": "3.18.10",
"sst": "4.13.1",
"turbo": "2.8.13"
},
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.15.6",
"version": "1.15.7",
"description": "",
"type": "module",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.15.6",
"version": "1.15.7",
"type": "module",
"license": "MIT",
"scripts": {
+2 -2
View File
@@ -348,8 +348,8 @@ export const dict = {
"Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, and DeepSeek V4 Flash with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).",
"zen.api.error.rateLimitExceeded": "Rate limit exceeded. Please try again later.",
"zen.api.error.modelNotSupported": "Model {{model}} not supported",
"zen.api.error.modelFormatNotSupported": "Model {{model}} not supported for format {{format}}",
"zen.api.error.modelNotSupported": "Model {{model}} is not supported",
"zen.api.error.modelFormatNotSupported": "Model {{model}} is not supported for format {{format}}",
"zen.api.error.noProviderAvailable": "No provider available",
"zen.api.error.providerNotSupported": "Provider {{provider}} not supported",
"zen.api.error.missingApiKey": "Missing API key.",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.15.6",
"version": "1.15.7",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.15.6",
"version": "1.15.7",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.15.6",
"version": "1.15.7",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.15.6",
"version": "1.15.7",
"name": "@opencode-ai/core",
"type": "module",
"license": "MIT",
@@ -59,7 +59,7 @@
"ai-gateway-provider": "3.1.2",
"cross-spawn": "catalog:",
"effect": "catalog:",
"gitlab-ai-provider": "6.6.0",
"gitlab-ai-provider": "6.7.0",
"glob": "13.0.5",
"google-auth-library": "10.5.0",
"immer": "11.1.4",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.15.6",
"version": "1.15.7",
"type": "module",
"license": "MIT",
"homepage": "https://opencode.ai",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.15.5",
"version": "1.15.7",
"name": "@opencode-ai/effect-drizzle-sqlite",
"type": "module",
"license": "MIT",
+10
View File
@@ -0,0 +1,10 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
/* deno-fmt-ignore-file */
/* biome-ignore-all lint: auto-generated */
/// <reference path="../../sst-env.d.ts" />
import "sst"
export {}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.15.6",
"version": "1.15.7",
"private": true,
"type": "module",
"license": "MIT",
+6 -6
View File
@@ -1,7 +1,7 @@
id = "opencode"
name = "OpenCode"
description = "The open source coding agent."
version = "1.15.6"
version = "1.15.7"
schema_version = 1
authors = ["Anomaly"]
repository = "https://github.com/anomalyco/opencode"
@@ -11,26 +11,26 @@ name = "OpenCode"
icon = "./icons/opencode.svg"
[agent_servers.opencode.targets.darwin-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.6/opencode-darwin-arm64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.7/opencode-darwin-arm64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.darwin-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.6/opencode-darwin-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.7/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.6/opencode-linux-arm64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.7/opencode-linux-arm64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.6/opencode-linux-x64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.7/opencode-linux-x64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.windows-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.6/opencode-windows-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.15.7/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.15.6",
"version": "1.15.7",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.15.6",
"version": "1.15.7",
"name": "@opencode-ai/http-recorder",
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.15.6",
"version": "1.15.7",
"name": "@opencode-ai/llm",
"type": "module",
"license": "MIT",
@@ -10,6 +10,7 @@ import {
type CacheHint,
type FinishReason,
type LLMRequest,
type MediaPart,
type ProviderMetadata,
type ToolCallPart,
type ToolDefinition,
@@ -39,6 +40,17 @@ const AnthropicTextBlock = Schema.Struct({
})
type AnthropicTextBlock = Schema.Schema.Type<typeof AnthropicTextBlock>
const AnthropicImageBlock = Schema.Struct({
type: Schema.tag("image"),
source: Schema.Struct({
type: Schema.tag("base64"),
media_type: Schema.String,
data: Schema.String,
}),
cache_control: Schema.optional(AnthropicCacheControl),
})
type AnthropicImageBlock = Schema.Schema.Type<typeof AnthropicImageBlock>
const AnthropicThinkingBlock = Schema.Struct({
type: Schema.tag("thinking"),
thinking: Schema.String,
@@ -92,7 +104,8 @@ const AnthropicToolResultBlock = Schema.Struct({
cache_control: Schema.optional(AnthropicCacheControl),
})
const AnthropicUserBlock = Schema.Union([AnthropicTextBlock, AnthropicToolResultBlock])
const AnthropicUserBlock = Schema.Union([AnthropicTextBlock, AnthropicImageBlock, AnthropicToolResultBlock])
type AnthropicUserBlock = Schema.Schema.Type<typeof AnthropicUserBlock>
const AnthropicAssistantBlock = Schema.Union([
AnthropicTextBlock,
AnthropicThinkingBlock,
@@ -272,6 +285,19 @@ const lowerServerToolResult = Effect.fn("AnthropicMessages.lowerServerToolResult
return { type: wireType, tool_use_id: part.id, content: part.result.value } satisfies AnthropicServerToolResultBlock
})
const lowerImage = Effect.fn("AnthropicMessages.lowerImage")(function* (part: MediaPart) {
if (!part.mediaType.startsWith("image/"))
return yield* invalid(`Anthropic Messages user media content only supports images`)
return {
type: "image" as const,
source: {
type: "base64" as const,
media_type: part.mediaType,
data: ProviderShared.mediaBase64(part),
},
} satisfies AnthropicImageBlock
})
const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (
request: LLMRequest,
breakpoints: Cache.Breakpoints,
@@ -280,11 +306,17 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (
for (const message of request.messages) {
if (message.role === "user") {
const content: AnthropicTextBlock[] = []
const content: AnthropicUserBlock[] = []
for (const part of message.content) {
if (!ProviderShared.supportsContent(part, ["text"]))
return yield* ProviderShared.unsupportedContent("Anthropic Messages", "user", ["text"])
content.push({ type: "text", text: part.text, cache_control: cacheControl(breakpoints, part.cache) })
if (part.type === "text") {
content.push({ type: "text", text: part.text, cache_control: cacheControl(breakpoints, part.cache) })
continue
}
if (part.type === "media") {
content.push(yield* lowerImage(part))
continue
}
return yield* ProviderShared.unsupportedContent("Anthropic Messages", "user", ["text", "media"])
}
messages.push({ role: "user", content })
continue
+79 -20
View File
@@ -6,11 +6,11 @@ import { HttpTransport, WebSocketTransport } from "../route/transport"
import { Protocol } from "../route/protocol"
import {
LLMEvent,
type MediaPart,
Usage,
type FinishReason,
type LLMRequest,
type ProviderMetadata,
type ReasoningPart,
type TextPart,
type ToolCallPart,
type ToolDefinition,
@@ -43,10 +43,23 @@ const OpenAIResponsesOutputText = Schema.Struct({
text: Schema.String,
})
const OpenAIResponsesReasoningSummaryText = Schema.Struct({
type: Schema.tag("summary_text"),
text: Schema.String,
})
const OpenAIResponsesReasoningItem = Schema.Struct({
type: Schema.tag("reasoning"),
id: Schema.String,
summary: Schema.Array(OpenAIResponsesReasoningSummaryText),
encrypted_content: optionalNull(Schema.String),
})
const OpenAIResponsesInputItem = Schema.Union([
Schema.Struct({ role: Schema.tag("system"), content: Schema.String }),
Schema.Struct({ role: Schema.tag("user"), content: Schema.Array(OpenAIResponsesInputContent) }),
Schema.Struct({ role: Schema.tag("assistant"), content: Schema.Array(OpenAIResponsesOutputText) }),
OpenAIResponsesReasoningItem,
Schema.Struct({
type: Schema.tag("function_call"),
call_id: Schema.String,
@@ -149,6 +162,7 @@ const OpenAIResponsesStreamItem = Schema.Struct({
server_label: Schema.optional(Schema.String),
output: Schema.optional(Schema.Unknown),
error: Schema.optional(Schema.Unknown),
encrypted_content: optionalNull(Schema.String),
})
type OpenAIResponsesStreamItem = Schema.Schema.Type<typeof OpenAIResponsesStreamItem>
@@ -206,17 +220,31 @@ const lowerToolCall = (part: ToolCallPart): OpenAIResponsesInputItem => ({
arguments: ProviderShared.encodeJson(part.input),
})
const imageUrl = (part: MediaPart) =>
typeof part.data === "string" && part.data.startsWith("data:")
? part.data
: `data:${part.mediaType};base64,${ProviderShared.mediaBytes(part)}`
const lowerReasoning = (part: ReasoningPart, store: boolean | undefined): OpenAIResponsesInputItem | undefined => {
const openai = part.providerMetadata?.openai
if (!ProviderShared.isRecord(openai) || typeof openai.itemId !== "string") return undefined
// With store:false, OpenAI only accepts previous reasoning items when the
// encrypted state is present. Bare rs_* ids point to non-persisted items.
if (store === false && typeof openai.reasoningEncryptedContent !== "string") return undefined
return {
type: "reasoning",
id: openai.itemId,
summary: part.text.length > 0 ? [{ type: "summary_text", text: part.text }] : [],
encrypted_content:
typeof openai.reasoningEncryptedContent === "string"
? openai.reasoningEncryptedContent
: openai.reasoningEncryptedContent === null
? null
: undefined,
}
}
const lowerUserContent = Effect.fn("OpenAIResponses.lowerUserContent")(function* (
part: LLMRequest["messages"][number]["content"][number],
) {
if (part.type === "text") return { type: "input_text" as const, text: part.text }
if (part.type === "media" && part.mediaType.startsWith("image/")) {
return { type: "input_image" as const, image_url: imageUrl(part) }
return { type: "input_image" as const, image_url: ProviderShared.mediaDataUrl(part) }
}
if (part.type === "media") return yield* invalid("OpenAI Responses user media content only supports images")
return yield* ProviderShared.unsupportedContent("OpenAI Responses", "user", ["text", "media"])
@@ -226,6 +254,7 @@ const lowerMessages = Effect.fn("OpenAIResponses.lowerMessages")(function* (requ
const system: OpenAIResponsesInputItem[] =
request.system.length === 0 ? [] : [{ role: "system", content: ProviderShared.joinText(request.system) }]
const input: OpenAIResponsesInputItem[] = [...system]
const store = OpenAIOptions.store(request)
for (const message of request.messages) {
if (message.role === "user") {
@@ -235,20 +264,34 @@ const lowerMessages = Effect.fn("OpenAIResponses.lowerMessages")(function* (requ
if (message.role === "assistant") {
const content: TextPart[] = []
const flushText = () => {
if (content.length === 0) return
input.push({ role: "assistant", content: content.map((part) => ({ type: "output_text", text: part.text })) })
content.splice(0, content.length)
}
for (const part of message.content) {
if (!ProviderShared.supportsContent(part, ["text", "tool-call"]))
return yield* ProviderShared.unsupportedContent("OpenAI Responses", "assistant", ["text", "tool-call"])
if (part.type === "text") {
content.push(part)
continue
}
if (part.type === "reasoning") {
flushText()
const reasoning = lowerReasoning(part, store)
if (reasoning) input.push(reasoning)
continue
}
if (part.type === "tool-call") {
flushText()
input.push(lowerToolCall(part))
continue
}
return yield* ProviderShared.unsupportedContent("OpenAI Responses", "assistant", [
"text",
"reasoning",
"tool-call",
])
}
if (content.length > 0)
input.push({ role: "assistant", content: content.map((part) => ({ type: "output_text", text: part.text })) })
flushText()
continue
}
@@ -367,6 +410,11 @@ const isHostedToolItem = (
): item is OpenAIResponsesStreamItem & { type: HostedToolType; id: string } =>
item.type in HOSTED_TOOLS && typeof item.id === "string" && item.id.length > 0
const isReasoningItem = (
item: OpenAIResponsesStreamItem,
): item is OpenAIResponsesStreamItem & { type: "reasoning"; id: string } =>
item.type === "reasoning" && typeof item.id === "string" && item.id.length > 0
// Round-trip the full item as the structured result so consumers can extract
// outputs / sources / status without re-decoding.
const hostedToolResult = (item: OpenAIResponsesStreamItem) => {
@@ -428,16 +476,12 @@ const onReasoningDelta = (state: ParserState, event: OpenAIResponsesEvent): Step
]
}
const onReasoningDone = (state: ParserState, event: OpenAIResponsesEvent): StepResult => {
const events: LLMEvent[] = []
return [
{
...state,
lifecycle: Lifecycle.reasoningEnd(state.lifecycle, events, event.item_id ?? "reasoning-0"),
},
events,
]
}
// The summary done event does not carry encrypted continuation state. Finish the
// common reasoning block when the full reasoning item arrives in output_item.done.
const onReasoningDone = (state: ParserState, _event: OpenAIResponsesEvent): StepResult => [state, NO_EVENTS]
const reasoningMetadata = (item: OpenAIResponsesStreamItem & { id: string }) =>
openaiMetadata({ itemId: item.id, reasoningEncryptedContent: item.encrypted_content ?? null })
const onOutputItemAdded = (state: ParserState, event: OpenAIResponsesEvent): StepResult => {
const item = event.item
@@ -518,6 +562,21 @@ const onOutputItemDone = Effect.fn("OpenAIResponses.onOutputItemDone")(function*
return [{ ...state, lifecycle }, events] satisfies StepResult
}
if (isReasoningItem(item)) {
const events: LLMEvent[] = []
const providerMetadata = reasoningMetadata(item)
if (!state.lifecycle.reasoning.has(item.id)) {
const lifecycle = Lifecycle.stepStart(state.lifecycle, events)
events.push(LLMEvent.reasoningStart({ id: item.id, providerMetadata }))
events.push(LLMEvent.reasoningEnd({ id: item.id, providerMetadata }))
return [{ ...state, lifecycle }, events] satisfies StepResult
}
return [
{ ...state, lifecycle: Lifecycle.reasoningEnd(state.lifecycle, events, item.id, providerMetadata) },
events,
] satisfies StepResult
}
return [state, NO_EVENTS] satisfies StepResult
})
+11 -1
View File
@@ -80,7 +80,7 @@ export const subtractTokens = (total: number | undefined, subtrahend: number | u
*/
export const sumTokens = (...values: ReadonlyArray<number | undefined>): number | undefined => {
if (values.every((value) => value === undefined)) return undefined
return values.reduce<number>((acc, value) => acc + (value ?? 0), 0)
return values.reduce((acc: number, value) => acc + (value ?? 0), 0)
}
export const eventError = (route: string, message: string, raw?: string) =>
@@ -122,6 +122,16 @@ export const parseToolInput = (route: string, name: string, raw: string) =>
export const mediaBytes = (part: MediaPart) =>
typeof part.data === "string" ? part.data : Buffer.from(part.data).toString("base64")
export const mediaBase64 = (part: MediaPart) => {
if (typeof part.data !== "string" || !part.data.startsWith("data:")) return mediaBytes(part)
return part.data.slice(part.data.indexOf(",") + 1)
}
export const mediaDataUrl = (part: MediaPart) =>
typeof part.data === "string" && part.data.startsWith("data:")
? part.data
: `data:${part.mediaType};base64,${mediaBytes(part)}`
export const trimBaseUrl = (value: string) => value.replace(/\/+$/, "")
export const toolResultText = (part: ToolResultPart) => {
+104
View File
@@ -0,0 +1,104 @@
import { LLM, Message, ToolCallPart, ToolDefinition, ToolResultPart, type ContentPart, type Model } from "../src"
export const basicContinuation = ["system", "user-text", "assistant-text", "user-follow-up"] as const
export const toolContinuation = ["tool-call", "tool-result"] as const
export const reasoningContinuation = ["assistant-reasoning", "encrypted-reasoning"] as const
export const mediaContinuation = ["user-image"] as const
export const maximalContinuation = [
...basicContinuation,
...toolContinuation,
...reasoningContinuation,
...mediaContinuation,
] as const
export type ContinuationFeature = (typeof maximalContinuation)[number]
export const nativeOpenAIResponsesContinuation = [
...basicContinuation,
...toolContinuation,
"encrypted-reasoning",
...mediaContinuation,
] as const satisfies ReadonlyArray<ContinuationFeature>
export const nativeAnthropicMessagesContinuation = [
...basicContinuation,
...toolContinuation,
"assistant-reasoning",
...mediaContinuation,
] as const satisfies ReadonlyArray<ContinuationFeature>
export const continuationTool = ToolDefinition.make({
name: "get_weather",
description: "Get current weather for a city.",
inputSchema: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"],
additionalProperties: false,
},
})
export function continuationRequest(input: {
readonly id: string
readonly model: Model
readonly features: ReadonlyArray<ContinuationFeature>
readonly image?: string
}) {
const features = new Set(input.features)
const messages = []
const firstUser: ContentPart[] = []
const firstAssistant: ContentPart[] = []
if (features.has("user-text")) firstUser.push({ type: "text", text: "What is shown here?" })
if (features.has("user-image"))
firstUser.push({ type: "media", mediaType: "image/png", data: input.image ?? "AAECAw==" })
if (firstUser.length > 0) messages.push(Message.user(firstUser))
if (features.has("assistant-reasoning"))
firstAssistant.push({
type: "reasoning",
text: "I inspected the previous turn.",
providerMetadata: { anthropic: { signature: "sig_continuation_1" } },
})
if (features.has("encrypted-reasoning"))
firstAssistant.push({
type: "reasoning",
text: "I inspected the previous turn.",
providerMetadata: {
openai: {
itemId: "rs_continuation_1",
reasoningEncryptedContent: "encrypted-continuation-state",
},
},
})
if (features.has("assistant-text")) firstAssistant.push({ type: "text", text: "It shows a small test image." })
if (firstAssistant.length > 0) messages.push(Message.assistant(firstAssistant))
if (features.has("tool-call")) {
messages.push(Message.user("Check the weather in Paris before continuing."))
messages.push(
Message.assistant([ToolCallPart.make({ id: "call_weather_1", name: "get_weather", input: { city: "Paris" } })]),
)
}
if (features.has("tool-result")) {
messages.push(
Message.tool(ToolResultPart.make({ id: "call_weather_1", name: "get_weather", result: { temperature: 22 } })),
)
if (features.has("assistant-text")) messages.push(Message.assistant("Paris is 22 degrees."))
}
if (features.has("user-follow-up"))
messages.push(Message.user("Continue from this conversation in one short sentence."))
return LLM.request({
id: input.id,
model: input.model,
system: features.has("system") ? "You are concise. Continue from the provided history." : undefined,
messages,
tools: features.has("tool-call") ? [continuationTool] : [],
cache: "none",
providerOptions: features.has("encrypted-reasoning")
? { openai: { store: false, includeEncryptedReasoning: true, reasoningSummary: "auto" } }
: undefined,
generation: { maxTokens: 80, temperature: 0 },
})
}
File diff suppressed because one or more lines are too long
@@ -1,10 +1,12 @@
import { describe, expect } from "bun:test"
import { Effect } from "effect"
import { HttpClientRequest } from "effect/unstable/http"
import { CacheHint, LLM, LLMError, Message, ToolCallPart, Usage } from "../../src"
import { Auth, LLMClient } from "../../src/route"
import * as AnthropicMessages from "../../src/protocols/anthropic-messages"
import { continuationRequest, nativeAnthropicMessagesContinuation } from "../continuation-scenarios"
import { it } from "../lib/effect"
import { fixedResponse } from "../lib/http"
import { dynamicResponse, fixedResponse } from "../lib/http"
import { sseEvents } from "../lib/sse"
const model = AnthropicMessages.route
@@ -40,7 +42,7 @@ describe("Anthropic Messages route", () => {
it.effect("prepares tool call and tool result messages", () =>
Effect.gen(function* () {
const prepared = yield* LLMClient.prepare(
const prepared = yield* LLMClient.prepare<AnthropicMessages.AnthropicMessagesBody>(
LLM.request({
id: "req_tool_result",
model,
@@ -69,6 +71,50 @@ describe("Anthropic Messages route", () => {
}),
)
it.effect("prepares the composed native continuation request", () =>
Effect.gen(function* () {
const prepared = yield* LLMClient.prepare<AnthropicMessages.AnthropicMessagesBody>(
continuationRequest({
id: "req_native_continuation_anthropic",
model,
features: nativeAnthropicMessagesContinuation,
}),
)
expect(prepared.body).toMatchObject({
system: [{ type: "text", text: "You are concise. Continue from the provided history." }],
messages: [
{
role: "user",
content: [
{ type: "text", text: "What is shown here?" },
{ type: "image", source: { type: "base64", media_type: "image/png", data: "AAECAw==" } },
],
},
{
role: "assistant",
content: [
{ type: "thinking", thinking: "I inspected the previous turn.", signature: "sig_continuation_1" },
{ type: "text", text: "It shows a small test image." },
],
},
{ role: "user", content: [{ type: "text", text: "Check the weather in Paris before continuing." }] },
{
role: "assistant",
content: [{ type: "tool_use", id: "call_weather_1", name: "get_weather", input: { city: "Paris" } }],
},
{
role: "user",
content: [{ type: "tool_result", tool_use_id: "call_weather_1", content: '{"temperature":22}' }],
},
{ role: "assistant", content: [{ type: "text", text: "Paris is 22 degrees." }] },
{ role: "user", content: [{ type: "text", text: "Continue from this conversation in one short sentence." }] },
],
})
expect(prepared.body.tools).toEqual([expect.objectContaining({ name: "get_weather" })])
}),
)
it.effect("lowers preserved Anthropic reasoning signature metadata", () =>
Effect.gen(function* () {
const prepared = yield* LLMClient.prepare(
@@ -392,17 +438,51 @@ describe("Anthropic Messages route", () => {
}),
)
it.effect("rejects unsupported user media content", () =>
it.effect("continues a conversation with user image content", () =>
Effect.gen(function* () {
const error = yield* LLMClient.prepare(
const response = yield* LLMClient.generate(
LLM.request({
id: "req_media",
model,
messages: [Message.user({ type: "media", mediaType: "image/png", data: "AAECAw==" })],
messages: [
Message.user([
{ type: "text", text: "What is in this image?" },
{ type: "media", mediaType: "image/png", data: "AAECAw==" },
]),
],
}),
).pipe(Effect.flip)
).pipe(
Effect.provide(
dynamicResponse((input) =>
Effect.gen(function* () {
const web = yield* HttpClientRequest.toWeb(input.request).pipe(Effect.orDie)
expect(yield* Effect.promise(() => web.json())).toMatchObject({
messages: [
{
role: "user",
content: [
{ type: "text", text: "What is in this image?" },
{ type: "image", source: { type: "base64", media_type: "image/png", data: "AAECAw==" } },
],
},
],
})
return input.respond(
sseEvents(
{ type: "content_block_start", index: 0, content_block: { type: "text", text: "" } },
{ type: "content_block_delta", index: 0, delta: { type: "text_delta", text: "An image." } },
{ type: "content_block_stop", index: 0 },
{ type: "message_delta", delta: { stop_reason: "end_turn" }, usage: { output_tokens: 3 } },
{ type: "message_stop" },
),
{ headers: { "content-type": "text/event-stream" } },
)
}),
),
),
)
expect(error.message).toContain("Anthropic Messages user messages only support text content for now")
expect(response.text).toBe("An image.")
}),
)
@@ -84,6 +84,7 @@ describeRecordedGoldenScenarios([
scenarios: [
{ id: "text", temperature: false },
{ id: "reasoning", temperature: false },
{ id: "reasoning-continuation", temperature: false },
{ id: "tool-call", temperature: false },
{ id: "tool-loop", temperature: false },
],
@@ -7,6 +7,7 @@ import * as Azure from "../../src/providers/azure"
import * as OpenAI from "../../src/providers/openai"
import * as OpenAIResponses from "../../src/protocols/openai-responses"
import * as ProviderShared from "../../src/protocols/shared"
import { continuationRequest, nativeOpenAIResponsesContinuation } from "../continuation-scenarios"
import { it } from "../lib/effect"
import { dynamicResponse, fixedResponse } from "../lib/http"
import { sseEvents } from "../lib/sse"
@@ -247,6 +248,49 @@ describe("OpenAI Responses route", () => {
}),
)
it.effect("prepares the composed native continuation request", () =>
Effect.gen(function* () {
const prepared = yield* LLMClient.prepare<OpenAIResponses.OpenAIResponsesBody>(
continuationRequest({
id: "req_native_continuation_openai",
model,
features: nativeOpenAIResponsesContinuation,
}),
)
expect(prepared.body).toMatchObject({
input: [
{ role: "system", content: "You are concise. Continue from the provided history." },
{
role: "user",
content: [
{ type: "input_text", text: "What is shown here?" },
{ type: "input_image", image_url: "data:image/png;base64,AAECAw==" },
],
},
{
type: "reasoning",
id: "rs_continuation_1",
encrypted_content: "encrypted-continuation-state",
summary: [{ type: "summary_text", text: "I inspected the previous turn." }],
},
{ role: "assistant", content: [{ type: "output_text", text: "It shows a small test image." }] },
{ role: "user", content: [{ type: "input_text", text: "Check the weather in Paris before continuing." }] },
{ type: "function_call", call_id: "call_weather_1", name: "get_weather", arguments: '{"city":"Paris"}' },
{ type: "function_call_output", call_id: "call_weather_1", output: '{"temperature":22}' },
{ role: "assistant", content: [{ type: "output_text", text: "Paris is 22 degrees." }] },
{
role: "user",
content: [{ type: "input_text", text: "Continue from this conversation in one short sentence." }],
},
],
include: ["reasoning.encrypted_content"],
store: false,
})
expect(prepared.body.tools).toEqual([expect.objectContaining({ type: "function", name: "get_weather" })])
}),
)
it.effect("maps OpenAI provider options to Responses options", () =>
Effect.gen(function* () {
const prepared = yield* LLMClient.prepare<OpenAIResponses.OpenAIResponsesBody>(
@@ -380,6 +424,172 @@ describe("OpenAI Responses route", () => {
}),
)
it.effect("preserves encrypted reasoning metadata for continuation", () =>
Effect.gen(function* () {
const response = yield* LLMClient.generate(request).pipe(
Effect.provide(
fixedResponse(
sseEvents(
{ type: "response.reasoning_summary_text.delta", item_id: "rs_1", delta: "thinking" },
{
type: "response.output_item.done",
item: {
type: "reasoning",
id: "rs_1",
encrypted_content: "encrypted-state",
summary: [{ type: "summary_text", text: "thinking" }],
},
},
{ type: "response.completed", response: { id: "resp_1" } },
),
),
),
)
expect(response.events).toContainEqual(
expect.objectContaining({
type: "reasoning-end",
id: "rs_1",
providerMetadata: { openai: { itemId: "rs_1", reasoningEncryptedContent: "encrypted-state" } },
}),
)
}),
)
it.effect("continues a stateless reasoning conversation", () =>
Effect.gen(function* () {
const response = yield* LLMClient.generate(
LLM.request({
id: "req_reasoning_continue",
model,
messages: [
Message.user("What changed?"),
Message.assistant([
{
type: "reasoning",
text: "Checked the previous diff.",
providerMetadata: {
openai: {
itemId: "rs_1",
reasoningEncryptedContent: "encrypted-state",
},
},
},
{ type: "text", text: "The parser changed." },
]),
Message.user("Summarize it."),
],
}),
).pipe(
Effect.provide(
dynamicResponse((input) =>
Effect.gen(function* () {
const web = yield* HttpClientRequest.toWeb(input.request).pipe(Effect.orDie)
expect(yield* Effect.promise(() => web.json())).toMatchObject({
input: [
{ role: "user", content: [{ type: "input_text", text: "What changed?" }] },
{
type: "reasoning",
id: "rs_1",
encrypted_content: "encrypted-state",
summary: [{ type: "summary_text", text: "Checked the previous diff." }],
},
{ role: "assistant", content: [{ type: "output_text", text: "The parser changed." }] },
{ role: "user", content: [{ type: "input_text", text: "Summarize it." }] },
],
})
return input.respond(
sseEvents(
{ type: "response.output_text.delta", item_id: "msg_1", delta: "Parser now round-trips reasoning." },
{ type: "response.completed", response: { id: "resp_1" } },
),
{ headers: { "content-type": "text/event-stream" } },
)
}),
),
),
)
expect(response.text).toBe("Parser now round-trips reasoning.")
}),
)
it.effect("preserves assistant content order around reasoning items", () =>
Effect.gen(function* () {
const prepared = yield* LLMClient.prepare<OpenAIResponses.OpenAIResponsesBody>(
LLM.request({
id: "req_reasoning_order",
model,
messages: [
Message.assistant([
{ type: "text", text: "Before." },
{
type: "reasoning",
text: "Checked order.",
providerMetadata: {
openai: {
itemId: "rs_1",
reasoningEncryptedContent: "encrypted-state",
},
},
},
{ type: "text", text: "After." },
]),
],
}),
)
expect(prepared.body.input).toEqual([
{ role: "assistant", content: [{ type: "output_text", text: "Before." }] },
{
type: "reasoning",
id: "rs_1",
encrypted_content: "encrypted-state",
summary: [{ type: "summary_text", text: "Checked order." }],
},
{ role: "assistant", content: [{ type: "output_text", text: "After." }] },
])
}),
)
it.effect("skips non-persisted reasoning ids without encrypted state", () =>
Effect.gen(function* () {
const prepared = yield* LLMClient.prepare(
LLM.request({
id: "req_reasoning_without_encrypted_state",
model,
messages: [
Message.user("What changed?"),
Message.assistant([
{
type: "reasoning",
text: "Checked the previous diff.",
providerMetadata: {
openai: {
itemId: "rs_1",
reasoningEncryptedContent: null,
},
},
},
{ type: "text", text: "The parser changed." },
]),
Message.user("Summarize it."),
],
providerOptions: { openai: { store: false } },
}),
)
expect(prepared.body).toMatchObject({
input: [
{ role: "user", content: [{ type: "input_text", text: "What changed?" }] },
{ role: "assistant", content: [{ type: "output_text", text: "The parser changed." }] },
{ role: "user", content: [{ type: "input_text", text: "Summarize it." }] },
],
store: false,
})
}),
)
it.effect("assembles streamed function call input", () =>
Effect.gen(function* () {
const body = sseEvents(
+2 -10
View File
@@ -2,7 +2,7 @@ import type { HttpRecorder } from "@opencode-ai/http-recorder"
import { describe } from "bun:test"
import { Effect } from "effect"
import type { Model } from "../src"
import { goldenScenarioTags, runGoldenScenario, type GoldenScenarioID } from "./recorded-scenarios"
import { goldenScenarioTags, goldenScenarioTitle, runGoldenScenario, type GoldenScenarioID } from "./recorded-scenarios"
import { recordedTests } from "./recorded-test"
import { kebab } from "./recorded-utils"
@@ -35,14 +35,6 @@ type TargetInput = {
const scenarioInput = (input: ScenarioInput) => (typeof input === "string" ? { id: input } : input)
const scenarioTitle = (id: GoldenScenarioID) => {
if (id === "text") return "streams text"
if (id === "tool-call") return "streams tool call"
if (id === "reasoning") return "uses reasoning"
if (id === "image") return "reads image text"
return "drives a tool loop"
}
const defaultPrefix = (target: TargetInput) => {
if (target.prefix) return target.prefix
const transport = target.transport === "websocket" ? "-websocket" : ""
@@ -77,7 +69,7 @@ const runTarget = (target: TargetInput) => {
describe(`${target.name} recorded`, () => {
target.scenarios.forEach((raw) => {
const input = scenarioInput(raw)
const name = input.name ?? scenarioTitle(input.id)
const name = input.name ?? goldenScenarioTitle(input.id)
recorded.effect.with(
name,
{
+209 -147
View File
@@ -1,6 +1,17 @@
import { expect } from "bun:test"
import { Effect, Schema, Stream } from "effect"
import { LLM, LLMEvent, LLMResponse, Message, ToolChoice, ToolDefinition, type LLMRequest, type Model } from "../src"
import {
LLM,
LLMEvent,
LLMResponse,
Message,
ToolChoice,
ToolDefinition,
type ContentPart,
type FinishReason,
type LLMRequest,
type Model,
} from "../src"
import { LLMClient } from "../src/route"
import { tool } from "../src/tool"
@@ -39,47 +50,6 @@ export const weatherRuntimeTool = tool({
),
})
export const textRequest = (input: {
readonly id: string
readonly model: Model
readonly prompt?: string
readonly maxTokens?: number
readonly temperature?: number | false
}) =>
LLM.request({
id: input.id,
model: input.model,
system: "You are concise.",
prompt: input.prompt ?? "Reply with exactly: Hello!",
cache: "none",
providerOptions:
input.model.route.id === "gemini" ? { gemini: { thinkingConfig: { thinkingBudget: 0 } } } : undefined,
generation:
input.temperature === false
? { maxTokens: input.maxTokens ?? 80 }
: { maxTokens: input.maxTokens ?? 80, temperature: input.temperature ?? 0 },
})
export const weatherToolRequest = (input: {
readonly id: string
readonly model: Model
readonly maxTokens?: number
readonly temperature?: number | false
}) =>
LLM.request({
id: input.id,
model: input.model,
system: "Call tools exactly as requested.",
prompt: "Call get_weather with city exactly Paris.",
tools: [weatherTool],
toolChoice: ToolChoice.make(weatherTool),
cache: "none",
generation:
input.temperature === false
? { maxTokens: input.maxTokens ?? 80 }
: { maxTokens: input.maxTokens ?? 80, temperature: input.temperature ?? 0 },
})
export const weatherToolLoopRequest = (input: {
readonly id: string
readonly model: Model
@@ -116,52 +86,6 @@ const restroomImage = () =>
Effect.map((bytes) => Buffer.from(bytes).toString("base64")),
)
export const imageRequest = (input: {
readonly id: string
readonly model: Model
readonly image: string
readonly maxTokens?: number
readonly temperature?: number | false
}) =>
LLM.request({
id: input.id,
model: input.model,
system: "Read images carefully. Reply only with the visible text.",
messages: [
Message.user([
{
type: "text",
text: "The image contains exactly three lowercase English words. Read them left to right and reply with only those words.",
},
{ type: "media", mediaType: "image/png", data: input.image },
]),
],
cache: "none",
generation:
input.temperature === false
? { maxTokens: input.maxTokens ?? 20 }
: { maxTokens: input.maxTokens ?? 20, temperature: input.temperature ?? 0 },
})
export const reasoningRequest = (input: {
readonly id: string
readonly model: Model
readonly maxTokens?: number
readonly temperature?: number | false
}) =>
LLM.request({
id: input.id,
model: input.model,
system: "Show concise reasoning when the provider supports visible reasoning summaries.",
prompt: "Think briefly, then reply exactly with: Hello!",
cache: "none",
providerOptions: { openai: { reasoningEffort: "low", reasoningSummary: "auto" } },
generation:
input.temperature === false
? { maxTokens: input.maxTokens ?? 120 }
: { maxTokens: input.maxTokens ?? 120, temperature: input.temperature ?? 0 },
})
export const runWeatherToolLoop = (request: LLMRequest) =>
LLMClient.stream({
request,
@@ -212,8 +136,6 @@ export const expectGoldenWeatherToolLoop = (events: ReadonlyArray<LLMEvent>) =>
expect(LLMResponse.text({ events }).trim()).toMatch(/^Paris is sunny\.?$/)
}
export type GoldenScenarioID = "text" | "tool-call" | "tool-loop" | "image" | "reasoning"
export interface GoldenScenarioContext {
readonly id: string
readonly model: Model
@@ -223,6 +145,9 @@ export interface GoldenScenarioContext {
const generate = (request: LLMRequest) => LLMClient.generate(request)
const generation = (context: GoldenScenarioContext, maxTokens: number) =>
context.temperature === false ? { maxTokens } : { maxTokens, temperature: context.temperature ?? 0 }
const normalizeImageText = (value: string) =>
value
.toLowerCase()
@@ -230,75 +155,193 @@ const normalizeImageText = (value: string) =>
.replace(/\s+/g, " ")
.trim()
export const goldenScenarioTags = (id: GoldenScenarioID) => {
if (id === "text") return ["text", "golden"]
if (id === "tool-call") return ["tool", "tool-call", "golden"]
if (id === "image") return ["media", "image", "vision", "golden"]
if (id === "reasoning") return ["reasoning", "golden"]
return ["tool", "tool-loop", "golden"]
const encryptedReasoningOptions = {
openai: {
store: false,
includeEncryptedReasoning: true,
reasoningEffort: "low",
reasoningSummary: "auto",
},
} as const
type AssistantTextExpectation = string | RegExp
type UserStep = { readonly type: "user"; readonly content: Message.ContentInput }
type AssistantStep = {
readonly type: "assistant"
readonly text?: AssistantTextExpectation
readonly toolCall?: { readonly name: string; readonly input: unknown }
readonly reasoning?: "openai-encrypted"
readonly id?: string
readonly system?: string
readonly maxTokens?: number
readonly finish?: FinishReason
readonly tools?: LLM.RequestInput["tools"]
readonly toolChoice?: LLM.RequestInput["toolChoice"]
readonly providerOptions?: LLMRequest["providerOptions"]
readonly assert?: (response: LLMResponse) => void
}
type ConversationStep = UserStep | AssistantStep
const user = (content: Message.ContentInput): ConversationStep => ({ type: "user", content })
const assistant = {
expectText: (
text: AssistantTextExpectation,
options?: Omit<AssistantStep, "type" | "text" | "reasoning" | "toolCall">,
): ConversationStep => ({ type: "assistant", text, ...options }),
expectToolCall: (
name: string,
input: unknown,
options?: Omit<AssistantStep, "type" | "text" | "reasoning" | "toolCall" | "finish">,
): ConversationStep => ({ type: "assistant", toolCall: { name, input }, finish: "tool-calls", ...options }),
expectEncryptedReasoningText: (
text: AssistantTextExpectation,
options?: Omit<AssistantStep, "type" | "text" | "reasoning" | "toolCall" | "providerOptions">,
): ConversationStep => ({
type: "assistant",
text,
reasoning: "openai-encrypted",
providerOptions: encryptedReasoningOptions,
...options,
}),
}
export const runGoldenScenario = (id: GoldenScenarioID, context: GoldenScenarioContext) =>
const assertAssistantText = (actual: string, expected: AssistantTextExpectation) => {
if (typeof expected === "string") {
expect(actual.trim()).toBe(expected)
return
}
expect(actual.trim()).toMatch(expected)
}
const assertAssistantToolCall = (response: LLMResponse, expected: NonNullable<AssistantStep["toolCall"]>) => {
expect(response.toolCalls).toMatchObject([
{ type: "tool-call", id: expect.any(String), name: expected.name, input: expected.input },
])
}
// The generated golden scenarios only model one assistant shape at a time:
// encrypted reasoning + text, text, or tool call. Keep mixed interleavings in
// focused protocol tests where event order can be asserted directly.
const assistantMessageFromResponse = (response: LLMResponse, step: AssistantStep) => {
const content: ContentPart[] = []
if (step.reasoning === "openai-encrypted") {
const reasoning = response.events.find(
(event): event is Extract<LLMEvent, { readonly type: "reasoning-end" }> =>
LLMEvent.is.reasoningEnd(event) && typeof event.providerMetadata?.openai?.itemId === "string",
)
if (!reasoning) throw new Error("OpenAI Responses did not return reasoning metadata")
expect(reasoning.providerMetadata?.openai?.reasoningEncryptedContent).toEqual(expect.any(String))
content.push({ type: "reasoning", text: response.reasoning, providerMetadata: reasoning.providerMetadata })
}
if (response.text.length > 0) content.push({ type: "text", text: response.text })
content.push(...response.toolCalls)
return Message.assistant(content)
}
const runGeneratedConversation = (context: GoldenScenarioContext, steps: ReadonlyArray<ConversationStep>) =>
Effect.gen(function* () {
if (id === "text") {
const messages: Message[] = []
let generated = 0
for (const step of steps) {
if (step.type === "user") {
messages.push(Message.user(step.content))
continue
}
generated += 1
const response = yield* generate(
textRequest({
id: context.id,
LLM.request({
id: step.id ? `${context.id}_${step.id}` : `${context.id}_${generated}`,
model: context.model,
prompt: "Reply exactly with: Hello!",
maxTokens: context.maxTokens ?? 40,
temperature: context.temperature,
system: step.system,
cache: "none",
messages,
tools: step.tools,
toolChoice: step.toolChoice,
providerOptions: step.providerOptions,
generation: generation(context, step.maxTokens ?? context.maxTokens ?? 80),
}),
)
expect(response.text.trim()).toMatch(/^Hello!?$/)
expectFinish(response.events, "stop")
return
if (step.text !== undefined) assertAssistantText(response.text, step.text)
if (step.toolCall) assertAssistantToolCall(response, step.toolCall)
step.assert?.(response)
expectFinish(response.events, step.finish ?? "stop")
messages.push(assistantMessageFromResponse(response, step))
}
})
if (id === "tool-call") {
const response = yield* generate(
weatherToolRequest({
id: context.id,
model: context.model,
maxTokens: context.maxTokens ?? 80,
temperature: context.temperature,
}),
)
expectWeatherToolCall(response)
expectFinish(response.events, "tool-calls")
return
}
const runTextScenario = (context: GoldenScenarioContext) =>
runGeneratedConversation(context, [
user("Reply exactly with: Hello!"),
assistant.expectText(/^Hello!?$/, {
system: "You are concise.",
maxTokens: context.maxTokens ?? 40,
providerOptions:
context.model.route.id === "gemini" ? { gemini: { thinkingConfig: { thinkingBudget: 0 } } } : undefined,
}),
])
if (id === "image") {
const response = yield* generate(
imageRequest({
id: context.id,
model: context.model,
image: yield* restroomImage(),
maxTokens: context.maxTokens ?? 20,
temperature: context.temperature,
}),
)
expect(normalizeImageText(response.text)).toBe(RESTROOM_IMAGE_TEXT)
expectFinish(response.events, "stop")
return
}
const runToolCallScenario = (context: GoldenScenarioContext) =>
runGeneratedConversation(context, [
user("Call get_weather with city exactly Paris."),
assistant.expectToolCall(
weatherToolName,
{ city: "Paris" },
{
system: "Call tools exactly as requested.",
tools: [weatherTool],
toolChoice: ToolChoice.make(weatherTool),
maxTokens: context.maxTokens ?? 80,
},
),
])
if (id === "reasoning") {
const response = yield* generate(
reasoningRequest({
id: context.id,
model: context.model,
maxTokens: context.maxTokens ?? 120,
temperature: context.temperature,
}),
)
expect(response.text.trim()).toMatch(/^Hello!?$/)
expect(response.usage?.reasoningTokens ?? 0).toBeGreaterThan(0)
expectFinish(response.events, "stop")
return
}
const runImageScenario = (context: GoldenScenarioContext) =>
Effect.gen(function* () {
yield* runGeneratedConversation(context, [
user([
{
type: "text",
text: "The image contains exactly three lowercase English words. Read them left to right and reply with only those words.",
},
{ type: "media", mediaType: "image/png", data: yield* restroomImage() },
]),
assistant.expectText(/.+/, {
system: "Read images carefully. Reply only with the visible text.",
maxTokens: context.maxTokens ?? 20,
assert: (response) => expect(normalizeImageText(response.text)).toBe(RESTROOM_IMAGE_TEXT),
}),
])
})
const runReasoningScenario = (context: GoldenScenarioContext) =>
runGeneratedConversation(context, [
user("Think briefly, then reply exactly with: Hello!"),
assistant.expectText(/^Hello!?$/, {
system: "Show concise reasoning when the provider supports visible reasoning summaries.",
providerOptions: { openai: { reasoningEffort: "low", reasoningSummary: "auto" } },
maxTokens: context.maxTokens ?? 120,
assert: (response) => expect(response.usage?.reasoningTokens ?? 0).toBeGreaterThan(0),
}),
])
const runReasoningContinuationScenario = (context: GoldenScenarioContext) =>
runGeneratedConversation(context, [
user("Think briefly, then reply exactly with: Hello!"),
assistant.expectEncryptedReasoningText(/^Hello!?$/, {
id: "first",
system: "Show concise reasoning when the provider supports visible reasoning summaries.",
maxTokens: context.maxTokens ?? 120,
}),
user("Now reply exactly with: Done."),
assistant.expectText(/^Done\.?$/, { id: "second", maxTokens: 40, providerOptions: encryptedReasoningOptions }),
])
const runToolLoopScenario = (context: GoldenScenarioContext) =>
Effect.gen(function* () {
expectGoldenWeatherToolLoop(
yield* runWeatherToolLoop(
goldenWeatherToolLoopRequest({
@@ -311,6 +354,25 @@ export const runGoldenScenario = (id: GoldenScenarioID, context: GoldenScenarioC
)
})
const goldenScenarios = {
text: { title: "streams text", tags: ["text", "golden"], run: runTextScenario },
"tool-call": { title: "streams tool call", tags: ["tool", "tool-call", "golden"], run: runToolCallScenario },
"tool-loop": { title: "drives a tool loop", tags: ["tool", "tool-loop", "golden"], run: runToolLoopScenario },
image: { title: "reads image text", tags: ["media", "image", "vision", "golden"], run: runImageScenario },
reasoning: { title: "uses reasoning", tags: ["reasoning", "golden"], run: runReasoningScenario },
"reasoning-continuation": {
title: "continues encrypted reasoning",
tags: ["reasoning", "continuation", "encrypted-reasoning", "golden"],
run: runReasoningContinuationScenario,
},
} as const
export type GoldenScenarioID = keyof typeof goldenScenarios
export const goldenScenarioTitle = (id: GoldenScenarioID) => goldenScenarios[id].title
export const goldenScenarioTags = (id: GoldenScenarioID) => [...goldenScenarios[id].tags]
export const runGoldenScenario = (id: GoldenScenarioID, context: GoldenScenarioContext) =>
goldenScenarios[id].run(context)
const usageSummary = (usage: LLMResponse["usage"] | undefined) => {
if (!usage) return undefined
return Object.fromEntries(
+2 -2
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.15.6",
"version": "1.15.7",
"name": "opencode",
"type": "module",
"license": "MIT",
@@ -135,7 +135,7 @@
"drizzle-orm": "catalog:",
"effect": "catalog:",
"fuzzysort": "3.1.0",
"gitlab-ai-provider": "6.6.0",
"gitlab-ai-provider": "6.7.0",
"glob": "13.0.5",
"google-auth-library": "10.5.0",
"gray-matter": "4.0.3",
@@ -19,7 +19,7 @@ import {
WorkspaceRoutingQuery,
WorkspaceRoutingQueryFields,
} from "../middleware/workspace-routing"
import { ApiNotFoundError } from "../errors"
import { ApiNotFoundError, SessionBusyError } from "../errors"
import { described } from "./metadata"
import { QueryBoolean } from "./query"
@@ -354,7 +354,7 @@ export const SessionApi = HttpApi.make("session")
query: WorkspaceRoutingQuery,
payload: ShellPayload,
success: described(MessageV2.WithParts, "Created message"),
error: [HttpApiError.BadRequest, ApiNotFoundError],
error: [HttpApiError.BadRequest, ApiNotFoundError, SessionBusyError],
}).annotateMerge(
OpenApi.annotations({
identifier: "session.shell",
@@ -367,7 +367,7 @@ export const SessionApi = HttpApi.make("session")
query: WorkspaceRoutingQuery,
payload: RevertPayload,
success: described(Session.Info, "Updated session"),
error: [HttpApiError.BadRequest, ApiNotFoundError],
error: [HttpApiError.BadRequest, ApiNotFoundError, SessionBusyError],
}).annotateMerge(
OpenApi.annotations({
identifier: "session.revert",
@@ -380,7 +380,7 @@ export const SessionApi = HttpApi.make("session")
params: { sessionID: SessionID },
query: WorkspaceRoutingQuery,
success: described(Session.Info, "Updated session"),
error: [HttpApiError.BadRequest, ApiNotFoundError],
error: [HttpApiError.BadRequest, ApiNotFoundError, SessionBusyError],
}).annotateMerge(
OpenApi.annotations({
identifier: "session.unrevert",
@@ -406,7 +406,7 @@ export const SessionApi = HttpApi.make("session")
params: { sessionID: SessionID, messageID: MessageID },
query: WorkspaceRoutingQuery,
success: described(Schema.Boolean, "Successfully deleted message"),
error: [HttpApiError.BadRequest, ApiNotFoundError],
error: [HttpApiError.BadRequest, ApiNotFoundError, SessionBusyError],
}).annotateMerge(
OpenApi.annotations({
identifier: "session.deleteMessage",
@@ -1,7 +1,6 @@
import type { NotFoundError as StorageNotFoundError } from "@/storage/storage"
import type { Session } from "@/session/session"
import { Effect } from "effect"
import { HttpApiError } from "effect/unstable/httpapi"
import * as ApiError from "../errors"
export function mapStorageNotFound<A, R>(self: Effect.Effect<A, StorageNotFoundError, R>) {
@@ -9,5 +8,14 @@ export function mapStorageNotFound<A, R>(self: Effect.Effect<A, StorageNotFoundE
}
export function mapBusy<A, R>(self: Effect.Effect<A, Session.BusyError, R>) {
return self.pipe(Effect.catchTag("SessionBusyError", () => Effect.fail(new HttpApiError.BadRequest({}))))
return self.pipe(
Effect.catchTag("SessionBusyError", (error) =>
Effect.fail(
new ApiError.SessionBusyError({
sessionID: error.sessionID,
message: `Session is busy: ${error.sessionID}`,
}),
),
),
)
}
@@ -42,10 +42,15 @@ const providerMetadata = (value: unknown): ProviderMetadata | undefined => {
return Object.keys(result).length === 0 ? undefined : result
}
// Stored AI SDK parts historically kept provider-owned continuation metadata in
// `providerOptions`; native parts now use `providerMetadata` directly.
const partProviderMetadata = (part: Record<string, unknown>) =>
providerMetadata(part.providerMetadata) ?? providerMetadata(part.providerOptions)
const textPart = (part: Record<string, unknown>) => ({
type: "text" as const,
text: typeof part.text === "string" ? part.text : "",
providerMetadata: providerMetadata(part.providerOptions),
providerMetadata: partProviderMetadata(part),
})
const mediaPart = (part: Record<string, unknown>) => {
@@ -68,7 +73,7 @@ const toolResult = (part: Record<string, unknown>) => {
result: "value" in output ? output.value : output,
resultType: type,
providerExecuted: typeof part.providerExecuted === "boolean" ? part.providerExecuted : undefined,
providerMetadata: providerMetadata(part.providerOptions),
providerMetadata: partProviderMetadata(part),
})
}
@@ -80,7 +85,7 @@ const contentPart = (part: unknown) => {
return {
type: "reasoning" as const,
text: typeof part.text === "string" ? part.text : "",
providerMetadata: providerMetadata(part.providerOptions),
providerMetadata: partProviderMetadata(part),
}
if (part.type === "tool-call")
return ToolCallPart.make({
@@ -88,7 +93,7 @@ const contentPart = (part: unknown) => {
name: typeof part.toolName === "string" ? part.toolName : "",
input: part.input,
providerExecuted: typeof part.providerExecuted === "boolean" ? part.providerExecuted : undefined,
providerMetadata: providerMetadata(part.providerOptions),
providerMetadata: partProviderMetadata(part),
})
if (part.type === "tool-result") return toolResult(part)
throw new Error(`Native LLM request adapter does not support ${String(part.type)} content parts`)
+30
View File
@@ -20,6 +20,7 @@ import * as Log from "@opencode-ai/core/util/log"
import { EffectBridge } from "@/effect/bridge"
const log = Log.create({ service: "session.tools" })
const schemaInternalKeys = new Set(["_def", "def", "_zod", "~standard", "_cached", "typeName"])
export const resolve = Effect.fn("SessionTools.resolve")(function* (input: {
agent: Agent.Info
@@ -78,6 +79,7 @@ export const resolve = Effect.fn("SessionTools.resolve")(function* (input: {
agent: input.agent,
})) {
const schema = ProviderTransform.schema(input.model, ToolJsonSchema.fromTool(item))
assertNoSchemaInternals(item.id, schema)
tools[item.id] = tool({
description: item.description,
inputSchema: jsonSchema(schema),
@@ -121,6 +123,7 @@ export const resolve = Effect.fn("SessionTools.resolve")(function* (input: {
const schema = yield* Effect.promise(() => Promise.resolve(asSchema(item.inputSchema).jsonSchema))
const transformed = ProviderTransform.schema(input.model, schema)
assertNoSchemaInternals(key, transformed)
item.inputSchema = jsonSchema(transformed)
item.execute = (args, opts) =>
run.promise(
@@ -205,4 +208,31 @@ export const resolve = Effect.fn("SessionTools.resolve")(function* (input: {
return tools
})
function assertNoSchemaInternals(toolID: string, schema: unknown) {
const path = schemaInternalPath(schema)
if (!path) return
throw new Error(`Tool ${toolID} input schema contains non-JSON-Schema Zod internals at ${path}`)
}
function schemaInternalPath(value: unknown, path = "$", skipKeys = false): string | undefined {
if (Array.isArray(value)) {
return value
.map((item, index) => schemaInternalPath(item, `${path}[${index}]`))
.find((item): item is string => item !== undefined)
}
if (typeof value !== "object" || value === null) return undefined
for (const [key, item] of Object.entries(value)) {
const nextPath = /^[A-Za-z_$][\w$]*$/.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`
if (!skipKeys && schemaInternalKeys.has(key)) return nextPath
const found = schemaInternalPath(
item,
nextPath,
key === "properties" || key === "$defs" || key === "definitions" || key === "patternProperties",
)
if (found) return found
}
return undefined
}
export * as SessionTools from "./tools"
+22 -7
View File
@@ -55,6 +55,13 @@ import { Reference } from "@/reference/reference"
import { BackgroundJob } from "@/background/job"
import { SessionStatus } from "@/session/status"
import { RuntimeFlags } from "@/effect/runtime-flags"
import {
objectFromShape,
safeParse,
type AnyObjectSchema,
type AnySchema,
} from "@modelcontextprotocol/sdk/server/zod-compat.js"
import { toJsonSchemaCompat } from "@modelcontextprotocol/sdk/server/zod-json-schema-compat.js"
const log = Log.create({ service: "tool.registry" })
@@ -150,10 +157,10 @@ export const layer: Layer.Layer<
const args = def.args ?? {}
const entries = Object.entries(args)
const allZod = entries.every((entry) => isZodType(entry[1]))
const zodParams = allZod ? z.object(args) : undefined
const zodParams = allZod ? objectFromShape(args as Record<string, AnySchema>) : undefined
const jsonSchema = zodParams ? zodJsonSchema(zodParams) : legacyJsonSchema(entries)
const parameters = zodParams
? Schema.declare<unknown>((u): u is unknown => zodParams.safeParse(u).success)
? Schema.declare<unknown>((u): u is unknown => safeParse(zodParams, u).success)
: Schema.Unknown
return {
id,
@@ -402,7 +409,11 @@ export const defaultLayer = Layer.suspend(() =>
.pipe(Layer.provide(RuntimeFlags.defaultLayer)),
)
function isZodType(value: unknown): value is z.ZodType {
function isZodType(value: unknown): value is AnySchema {
return typeof value === "object" && value !== null && ("_zod" in value || "_def" in value)
}
function isZod4Type(value: unknown): value is z.ZodType {
return typeof value === "object" && value !== null && "_zod" in value
}
@@ -425,8 +436,12 @@ function legacyJsonSchema(entries: [string, unknown][]): JSONSchema7 {
}
}
function zodJsonSchema(schema: z.ZodType): JSONSchema7 {
const result = normalizeZodJsonSchema(z.toJSONSchema(schema, { io: "input", metadata: zodMetadataRegistry(schema) }))
function zodJsonSchema(schema: AnyObjectSchema): JSONSchema7 {
const result = normalizeZodJsonSchema(
isZod4Type(schema)
? z.toJSONSchema(schema, { io: "input", metadata: zodMetadataRegistry(schema) })
: toJsonSchemaCompat(schema, { pipeStrategy: "input" }),
)
if (!isJsonSchemaObject(result)) throw new Error("plugin tool Zod schema produced a non-object JSON Schema")
const { $defs, ...rest } = result
return (
@@ -434,7 +449,7 @@ function zodJsonSchema(schema: z.ZodType): JSONSchema7 {
) as JSONSchema7
}
function zodMetadataRegistry(schema: z.ZodType) {
function zodMetadataRegistry(schema: AnyObjectSchema) {
const registry = z.registry<Record<string, unknown>>()
const seen = new WeakSet<object>()
const collect = (value: unknown) => {
@@ -442,7 +457,7 @@ function zodMetadataRegistry(schema: z.ZodType) {
if (seen.has(value)) return
seen.add(value)
if (isZodType(value)) {
if (isZod4Type(value)) {
const metadata = typeof value.meta === "function" ? value.meta() : undefined
const description = typeof value.description === "string" ? value.description : undefined
const merged = {
File diff suppressed because it is too large Load Diff
@@ -207,6 +207,12 @@ export function provideTmpdirInstance<A, E, R>(
export class TestInstance extends Context.Service<TestInstance, { readonly directory: string }>()("@test/Instance") {}
export const requireInstance = Effect.gen(function* () {
const instance = yield* InstanceRef
if (!instance) return yield* Effect.die(new Error("missing test instance"))
return instance
})
export const withTmpdirInstance =
(options?: { git?: boolean; config?: Partial<Config.Info> | (() => Partial<Config.Info>) }) =>
<A, E, R>(self: Effect.Effect<A, E, R>) =>
@@ -142,4 +142,19 @@ describe("PublicApi OpenAPI v2 errors", () => {
)
}
})
test("documents session busy errors", () => {
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
for (const route of [
["post", "/session/{sessionID}/shell"],
["post", "/session/{sessionID}/revert"],
["post", "/session/{sessionID}/unrevert"],
["delete", "/session/{sessionID}/message/{messageID}"],
] as const) {
expect(componentName(responseRef(spec.paths[route[1]]?.[route[0]]?.responses?.["409"]) ?? "")).toBe(
"SessionBusyError",
)
}
})
})
@@ -1,7 +1,7 @@
import { afterEach, describe, expect } from "bun:test"
import { mkdir } from "node:fs/promises"
import path from "node:path"
import { Effect, Layer } from "effect"
import { Cause, Effect, Exit, Layer } from "effect"
import { Flag } from "@opencode-ai/core/flag/flag"
import { registerAdapter } from "../../src/control-plane/adapters"
import type { WorkspaceAdapter } from "../../src/control-plane/types"
@@ -13,6 +13,7 @@ import { InstanceBootstrap as InstanceBootstrapService } from "../../src/project
import { InstanceStore } from "../../src/project/instance-store"
import { Project } from "../../src/project/project"
import { Server } from "../../src/server/server"
import * as HttpSessionError from "../../src/server/routes/instance/httpapi/handlers/session-errors"
import { SessionPaths } from "../../src/server/routes/instance/httpapi/groups/session"
import { Session } from "@/session/session"
import { MessageID, PartID, SessionID, type SessionID as SessionIDType } from "../../src/session/schema"
@@ -215,6 +216,22 @@ afterEach(async () => {
})
describe("session HttpApi", () => {
it.effect("maps busy sessions to public session busy errors", () =>
Effect.gen(function* () {
const sessionID = SessionID.descending()
const exit = yield* HttpSessionError.mapBusy(Effect.fail(new Session.BusyError({ sessionID }))).pipe(Effect.exit)
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isFailure(exit)) {
expect(Cause.squash(exit.cause)).toMatchObject({
_tag: "SessionBusyError",
sessionID,
message: `Session is busy: ${sessionID}`,
})
}
}),
)
it.instance(
"returns declared not found errors for read routes",
() =>
+255 -107
View File
@@ -1,13 +1,14 @@
import { describe, expect, test } from "bun:test"
import { ToolFailure } from "@opencode-ai/llm"
import { LLMClient, RequestExecutor, WebSocketExecutor } from "@opencode-ai/llm/route"
import { jsonSchema, tool, type ModelMessage } from "ai"
import { jsonSchema, tool, type ModelMessage, type Tool } from "ai"
import { Effect, Layer, Stream } from "effect"
import { LLMNative } from "@/session/llm/native-request"
import { LLMNativeRuntime } from "@/session/llm/native-runtime"
import type { Provider } from "@/provider/provider"
import { ModelID, ProviderID } from "@/provider/schema"
import { OAUTH_DUMMY_KEY } from "@/auth"
import { testEffect } from "../lib/effect"
const baseModel: Provider.Model = {
id: ModelID.make("gpt-5-mini"),
@@ -69,6 +70,10 @@ const providerInfo: Provider.Info = {
models: {},
}
const it = testEffect(
LLMClient.layer.pipe(Layer.provide(Layer.mergeAll(RequestExecutor.defaultLayer, WebSocketExecutor.layer))),
)
function responsesStream(chunks: unknown[]) {
return new Response(chunks.map((chunk) => `data: ${JSON.stringify(chunk)}`).join("\n\n") + "\n\n", {
status: 200,
@@ -76,6 +81,72 @@ function responsesStream(chunks: unknown[]) {
})
}
type NativeRequestInput = Parameters<typeof LLMNative.request>[0]
const sessionText = (text: string) => ({ type: "text" as const, text })
const sessionOpenAIReasoning = (
text: string,
options: {
readonly storedAs: "providerMetadata" | "providerOptions"
readonly itemId: string
readonly encryptedContent: string | null
},
) => {
const metadata = {
openai: { itemId: options.itemId, reasoningEncryptedContent: options.encryptedContent },
}
if (options.storedAs === "providerMetadata")
return Object.assign({ type: "reasoning" as const, text }, { providerMetadata: metadata })
return Object.assign({ type: "reasoning" as const, text }, { providerOptions: metadata })
}
type SessionAssistantPart = ReturnType<typeof sessionText> | ReturnType<typeof sessionOpenAIReasoning>
const storedSession = {
user: (content: string): ModelMessage => ({ role: "user", content }),
assistant: (content: SessionAssistantPart[]): ModelMessage => ({ role: "assistant", content }),
text: sessionText,
openaiReasoning: sessionOpenAIReasoning,
}
const openAIResponses = {
user: (text: string) => ({ role: "user", content: [{ type: "input_text", text }] }),
assistant: (text: string) => ({ role: "assistant", content: [{ type: "output_text", text }] }),
openaiReasoning: (text: string, options: { readonly itemId: string; readonly encryptedContent: string }) => ({
type: "reasoning",
id: options.itemId,
encrypted_content: options.encryptedContent,
summary: [{ type: "summary_text", text }],
}),
}
const prepareNativeRequest = (input: NativeRequestInput) => LLMClient.prepare(LLMNative.request(input))
const expectOpenAIResponsesRequest = (input: {
readonly history: NativeRequestInput["messages"]
readonly providerOptions?: NativeRequestInput["providerOptions"]
readonly maxOutputTokens?: NativeRequestInput["maxOutputTokens"]
readonly headers?: NativeRequestInput["headers"]
readonly expectedBody: unknown
}) =>
Effect.gen(function* () {
expect(
yield* prepareNativeRequest({
model: baseModel,
apiKey: "test-openai-key",
messages: input.history,
providerOptions: input.providerOptions,
maxOutputTokens: input.maxOutputTokens,
headers: input.headers,
}),
).toMatchObject({
route: "openai-responses",
protocol: "openai-responses",
body: input.expectedBody,
})
})
describe("session.llm-native.request", () => {
test("maps normalized stream inputs to a native LLM request", () => {
const messages: ModelMessage[] = [
@@ -219,6 +290,42 @@ describe("session.llm-native.request", () => {
])
})
test("maps stored provider metadata to native content metadata", () => {
const reasoning = Object.assign(
{ type: "reasoning" as const, text: "thinking" },
{
providerMetadata: {
openai: {
itemId: "rs_1",
reasoningEncryptedContent: "encrypted-state",
},
},
},
)
const request = LLMNative.request({
model: baseModel,
messages: [
{
role: "assistant",
content: [reasoning],
},
],
})
expect(request.messages).toMatchObject([
{
role: "assistant",
content: [
{
type: "reasoning",
text: "thinking",
providerMetadata: { openai: { itemId: "rs_1", reasoningEncryptedContent: "encrypted-state" } },
},
],
},
])
})
test("selects native request routes for provider packages", () => {
const openai = LLMNative.model({
model: { ...baseModel, api: { ...baseModel.api, url: "", npm: "@ai-sdk/openai" } },
@@ -390,122 +497,163 @@ describe("session.llm-native.request", () => {
})
})
test("native tool wrapper converts thrown errors into typed ToolFailure", async () => {
const wrapped = LLMNativeRuntime.nativeTools(
{
explode: {
description: "always throws",
inputSchema: jsonSchema({ type: "object" }),
execute: async () => {
throw new Error("boom")
},
} as any,
},
{ messages: [] as ModelMessage[], abort: new AbortController().signal },
)
it.effect("native tool wrapper converts thrown errors into typed ToolFailure", () =>
Effect.gen(function* () {
const wrapped = LLMNativeRuntime.nativeTools(
{
explode: {
description: "always throws",
inputSchema: jsonSchema({ type: "object" }),
execute: async () => {
throw new Error("boom")
},
} satisfies Tool,
},
{ messages: [] as ModelMessage[], abort: new AbortController().signal },
)
const failure = await Effect.runPromise(
Effect.flip(wrapped.explode!.execute!({}, { id: "call-1", name: "explode" })),
)
expect(failure).toBeInstanceOf(ToolFailure)
expect((failure as ToolFailure).message).toBe("boom")
})
const failure = yield* Effect.flip(wrapped.explode.execute({}, { id: "call-1", name: "explode" }))
expect(failure).toBeInstanceOf(ToolFailure)
expect(failure.message).toBe("boom")
}),
)
test("native tool wrapper raises ToolFailure when the source tool has no execute handler", async () => {
// The AI SDK Tool shape allows execute to be omitted (e.g., client-side / MCP tools).
// The native runtime owns execution, so encountering such a tool here means upstream
// wiring is wrong; we want a typed failure, not a silent skip or unhandled exception.
const wrapped = LLMNativeRuntime.nativeTools(
{ incomplete: { description: "no execute", inputSchema: jsonSchema({ type: "object" }) } as any },
{ messages: [] as ModelMessage[], abort: new AbortController().signal },
)
it.effect("native tool wrapper raises ToolFailure when the source tool has no execute handler", () =>
Effect.gen(function* () {
// The AI SDK Tool shape allows execute to be omitted (e.g., client-side / MCP tools).
// The native runtime owns execution, so encountering such a tool here means upstream
// wiring is wrong; we want a typed failure, not a silent skip or unhandled exception.
const wrapped = LLMNativeRuntime.nativeTools(
{ incomplete: { description: "no execute", inputSchema: jsonSchema({ type: "object" }) } satisfies Tool },
{ messages: [] as ModelMessage[], abort: new AbortController().signal },
)
const failure = await Effect.runPromise(
Effect.flip(wrapped.incomplete!.execute!({}, { id: "call-1", name: "incomplete" })),
)
expect(failure).toBeInstanceOf(ToolFailure)
expect((failure as ToolFailure).message).toContain("incomplete")
})
const failure = yield* Effect.flip(wrapped.incomplete.execute({}, { id: "call-1", name: "incomplete" }))
expect(failure).toBeInstanceOf(ToolFailure)
expect(failure.message).toContain("incomplete")
}),
)
test("compiles through the native OpenAI Responses route", async () => {
const prepared = await Effect.runPromise(
LLMClient.prepare(
LLMNative.request({
model: baseModel,
apiKey: "test-openai-key",
messages: [{ role: "user", content: "hello" }],
providerOptions: { openai: { store: false, instructions: "You are concise." } },
maxOutputTokens: 512,
headers: { "x-request": "request-header" },
}),
).pipe(
Effect.provide(LLMClient.layer),
Effect.provide(Layer.mergeAll(RequestExecutor.defaultLayer, WebSocketExecutor.layer)),
),
)
expect(prepared).toMatchObject({
route: "openai-responses",
protocol: "openai-responses",
body: {
it.effect("compiles through the native OpenAI Responses route", () =>
expectOpenAIResponsesRequest({
history: [storedSession.user("hello")],
providerOptions: { openai: { store: false, instructions: "You are concise." } },
maxOutputTokens: 512,
headers: { "x-request": "request-header" },
expectedBody: {
model: "gpt-5-mini",
instructions: "You are concise.",
input: [{ role: "user", content: [{ type: "input_text", text: "hello" }] }],
input: [openAIResponses.user("hello")],
max_output_tokens: 512,
store: false,
stream: true,
},
})
})
}),
)
test("uses provider fetch override for native OpenAI OAuth requests", async () => {
const captures: Array<{ url: string; body: unknown }> = []
const customFetch = (async (input, init) => {
const request = input instanceof Request ? input : new Request(input, init)
captures.push({ url: request.url, body: await request.clone().json() })
return responsesStream([
{ type: "response.output_text.delta", item_id: "msg_1", delta: "Hello" },
{ type: "response.completed", response: { usage: { input_tokens: 1, output_tokens: 1 } } },
])
}) as typeof fetch
const events = await Effect.runPromise(
Effect.gen(function* () {
const llmClient = yield* LLMClient.Service
const native = LLMNativeRuntime.stream({
model: baseModel,
provider: { ...providerInfo, options: { apiKey: OAUTH_DUMMY_KEY, fetch: customFetch } },
auth: { type: "oauth", refresh: "refresh", access: "access", expires: Date.now() + 60_000 },
llmClient,
messages: [{ role: "user", content: "hello" }],
tools: {},
providerOptions: { instructions: "You are concise." },
headers: {},
abort: new AbortController().signal,
})
expect(native.type).toBe("supported")
if (native.type === "unsupported") return []
return yield* native.stream.pipe(Stream.runCollect)
}).pipe(
Effect.provide(LLMClient.layer),
Effect.provide(Layer.mergeAll(RequestExecutor.defaultLayer, WebSocketExecutor.layer)),
),
)
expect(captures).toHaveLength(1)
expect(captures[0]).toMatchObject({
url: "https://api.openai.com/v1/responses",
body: {
model: "gpt-5-mini",
instructions: "You are concise.",
input: [{ role: "user", content: [{ type: "input_text", text: "hello" }] }],
it.effect("omits non-persisted OpenAI reasoning ids without encrypted state", () =>
expectOpenAIResponsesRequest({
history: [
storedSession.user("What changed?"),
storedSession.assistant([
storedSession.openaiReasoning("Checked the previous diff.", {
storedAs: "providerOptions",
itemId: "rs_1",
encryptedContent: null,
}),
storedSession.text("The parser changed."),
]),
storedSession.user("Summarize it."),
],
providerOptions: { openai: { store: false } },
expectedBody: {
input: [
openAIResponses.user("What changed?"),
openAIResponses.assistant("The parser changed."),
openAIResponses.user("Summarize it."),
],
store: false,
},
})
expect(events).toEqual(
expect.arrayContaining([
expect.objectContaining({ type: "text-delta", text: "Hello" }),
expect.objectContaining({ type: "finish" }),
]),
)
})
}),
)
it.effect("preserves encrypted OpenAI reasoning state through native request lowering", () =>
expectOpenAIResponsesRequest({
history: [
storedSession.user("What changed?"),
storedSession.assistant([
storedSession.openaiReasoning("Checked the previous diff.", {
storedAs: "providerMetadata",
itemId: "rs_1",
encryptedContent: "encrypted-state",
}),
storedSession.text("The parser changed."),
]),
storedSession.user("Summarize it."),
],
providerOptions: { openai: { store: false, includeEncryptedReasoning: true } },
expectedBody: {
input: [
openAIResponses.user("What changed?"),
openAIResponses.openaiReasoning("Checked the previous diff.", {
itemId: "rs_1",
encryptedContent: "encrypted-state",
}),
openAIResponses.assistant("The parser changed."),
openAIResponses.user("Summarize it."),
],
include: ["reasoning.encrypted_content"],
store: false,
},
}),
)
it.effect("uses provider fetch override for native OpenAI OAuth requests", () =>
Effect.gen(function* () {
const captures: Array<{ url: string; body: unknown }> = []
const customFetch = Object.assign(
async (input: Parameters<typeof fetch>[0], init: Parameters<typeof fetch>[1]) => {
const request = input instanceof Request ? input : new Request(input, init)
captures.push({ url: request.url, body: await request.clone().json() })
return responsesStream([
{ type: "response.output_text.delta", item_id: "msg_1", delta: "Hello" },
{ type: "response.completed", response: { usage: { input_tokens: 1, output_tokens: 1 } } },
])
},
{ preconnect: () => undefined },
) satisfies typeof fetch
const llmClient = yield* LLMClient.Service
const native = LLMNativeRuntime.stream({
model: baseModel,
provider: { ...providerInfo, options: { apiKey: OAUTH_DUMMY_KEY, fetch: customFetch } },
auth: { type: "oauth", refresh: "refresh", access: "access", expires: Date.now() + 60_000 },
llmClient,
messages: [{ role: "user", content: "hello" }],
tools: {},
providerOptions: { instructions: "You are concise." },
headers: {},
abort: new AbortController().signal,
})
expect(native.type).toBe("supported")
if (native.type === "unsupported") throw new Error(native.reason)
const events = Array.from(yield* native.stream.pipe(Stream.runCollect))
expect(captures).toHaveLength(1)
expect(captures[0]).toMatchObject({
url: "https://api.openai.com/v1/responses",
body: {
model: "gpt-5-mini",
instructions: "You are concise.",
input: [{ role: "user", content: [{ type: "input_text", text: "hello" }] }],
},
})
expect(events).toEqual(
expect.arrayContaining([
expect.objectContaining({ type: "text-delta", text: "Hello" }),
expect.objectContaining({ type: "finish" }),
]),
)
}),
)
})
@@ -0,0 +1,201 @@
import { describe, expect } from "bun:test"
import { jsonSchema } from "ai"
import { Effect, Exit, Layer } from "effect"
import { Agent } from "@/agent/agent"
import { MCP } from "@/mcp"
import { Permission } from "@/permission"
import { ProjectID } from "@/project/schema"
import { ModelID, ProviderID } from "@/provider/schema"
import type { Provider } from "@/provider/provider"
import { SessionTools } from "@/session/tools"
import { MessageV2 } from "@/session/message-v2"
import { MessageID, SessionID } from "@/session/schema"
import { ToolRegistry } from "@/tool/registry"
import { Truncate } from "@/tool/truncate"
import { Plugin } from "@/plugin"
import { testEffect } from "../lib/effect"
const it = testEffect(
Layer.mergeAll(
Layer.succeed(
ToolRegistry.Service,
ToolRegistry.Service.of({
ids: () => Effect.succeed([]),
all: () => Effect.succeed([]),
named: () => Effect.die("unexpected named tool lookup"),
tools: () => Effect.succeed([]),
}),
),
Layer.succeed(
MCP.Service,
MCP.Service.of({
status: () => Effect.succeed({}),
clients: () => Effect.succeed({}),
tools: () =>
Effect.succeed({
ctx_batch_execute: {
description: "context tool",
inputSchema: jsonSchema({
type: "object",
properties: {
batch: {
type: "array",
items: schemaWithZodInternals(),
},
},
}),
execute: () => Promise.resolve({ content: [{ type: "text" as const, text: "ok" }] }),
},
}),
prompts: () => Effect.succeed({}),
resources: () => Effect.succeed({}),
add: () => Effect.succeed({ status: { status: "disabled" as const } }),
connect: () => Effect.void,
disconnect: () => Effect.void,
getPrompt: () => Effect.succeed(undefined),
readResource: () => Effect.succeed(undefined),
startAuth: () => Effect.die("unexpected MCP auth"),
authenticate: () => Effect.die("unexpected MCP auth"),
finishAuth: () => Effect.die("unexpected MCP auth"),
removeAuth: () => Effect.void,
supportsOAuth: () => Effect.succeed(false),
hasStoredTokens: () => Effect.succeed(false),
getAuthStatus: () => Effect.succeed("not_authenticated" as const),
}),
),
Layer.succeed(
Plugin.Service,
Plugin.Service.of({
trigger: (_name, _input, output) => Effect.succeed(output),
list: () => Effect.succeed([]),
init: () => Effect.void,
}),
),
Layer.succeed(
Permission.Service,
Permission.Service.of({
ask: () => Effect.void,
reply: () => Effect.void,
list: () => Effect.succeed([]),
}),
),
Layer.succeed(
Truncate.Service,
Truncate.Service.of({
cleanup: () => Effect.void,
write: () => Effect.succeed("/tmp/tool-output"),
output: (text) => Effect.succeed({ content: text, truncated: false as const }),
limits: () => Effect.succeed({ maxLines: 2000, maxBytes: 50 * 1024 }),
}),
),
),
)
describe("SessionTools.resolve", () => {
it.effect("fails locally when MCP schemas contain Zod internals", () =>
Effect.gen(function* () {
const exit = yield* SessionTools.resolve({
agent: agentInfo(),
model: kimiModel(),
session: sessionInfo(),
processor: processor(),
bypassAgentCheck: false,
messages: [],
promptOps: promptOps(),
}).pipe(Effect.exit)
expect(Exit.isFailure(exit)).toBe(true)
if (!Exit.isFailure(exit)) return
expect(String(exit.cause)).toContain("ctx_batch_execute")
expect(String(exit.cause)).toContain("non-JSON-Schema Zod internals")
expect(String(exit.cause)).toContain("$.properties.batch.items._zod")
}),
)
})
function agentInfo(): Agent.Info {
return {
name: "build",
mode: "primary",
permission: [],
options: {},
}
}
function schemaWithZodInternals() {
return JSON.parse(
JSON.stringify({
_zod: { def: { type: "object" } },
def: { type: "object" },
typeName: "ZodObject",
"~standard": { vendor: "zod" },
}),
)
}
function kimiModel(): Provider.Model {
return {
id: ModelID.make("kimi-k2.6"),
providerID: ProviderID.make("moonshotai"),
name: "Kimi K2.6",
limit: { context: 128_000, output: 32_000 },
cost: { input: 0, output: 0, cache: { read: 0, write: 0 } },
capabilities: {
toolcall: true,
attachment: false,
reasoning: false,
temperature: true,
input: { text: true, image: false, audio: false, video: false, pdf: false },
output: { text: true, image: false, audio: false, video: false, pdf: false },
interleaved: false,
},
api: { id: "kimi-k2.6", url: "https://api.moonshot.example/v1", npm: "@ai-sdk/openai-compatible" },
options: {},
headers: {},
release_date: "2026-01-01",
status: "active",
}
}
function sessionInfo() {
return {
id: SessionID.descending(),
slug: "test",
projectID: ProjectID.global,
directory: "/tmp/test",
title: "test",
version: "test",
time: { created: Date.now(), updated: Date.now() },
}
}
function processor() {
return {
message: {
id: MessageID.ascending(),
sessionID: SessionID.descending(),
role: "assistant",
parentID: MessageID.ascending(),
modelID: ModelID.make("kimi-k2.6"),
providerID: ProviderID.make("moonshotai"),
mode: "build",
agent: "build",
path: { cwd: "/tmp/test", root: "/tmp/test" },
cost: 0,
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
time: { created: Date.now() },
} satisfies MessageV2.Assistant,
updateToolCall: () => Effect.succeed(undefined),
completeToolCall: () => Effect.void,
}
}
function promptOps() {
return {
cancel: () => Effect.void,
resolvePromptParts: (template: string) => Effect.succeed([{ type: "text" as const, text: template }]),
prompt: () => Effect.die("unexpected prompt call"),
loop: () => Effect.die("unexpected loop call"),
}
}
+84 -2
View File
@@ -34,6 +34,7 @@ import { ProviderID, ModelID } from "@/provider/schema"
import { ToolJsonSchema } from "@/tool/json-schema"
import { MessageID, SessionID } from "@/session/schema"
import { RuntimeFlags } from "@/effect/runtime-flags"
import z3 from "zod/v3"
const node = CrossSpawnSpawner.defaultLayer
const configLayer = TestConfig.layer({
@@ -80,7 +81,7 @@ const brokenPluginLayer = Layer.succeed(
init: () => Effect.void,
trigger: ((_name: unknown, _input: unknown, output: unknown) =>
Effect.succeed(output)) as Plugin.Interface["trigger"],
list: () =>
list: (() =>
Effect.succeed([
{
tool: {
@@ -91,7 +92,41 @@ const brokenPluginLayer = Layer.succeed(
},
},
},
]),
])) as unknown as Plugin.Interface["list"],
}),
)
const zod3PluginLayer = Layer.succeed(
Plugin.Service,
Plugin.Service.of({
init: () => Effect.void,
trigger: ((_name: unknown, _input: unknown, output: unknown) =>
Effect.succeed(output)) as Plugin.Interface["trigger"],
list: (() =>
Effect.succeed([
{
tool: {
ctx_batch_execute: {
description: "context-mode batch executor",
args: {
batch: z3
.preprocess(
(value) => (typeof value === "string" ? JSON.parse(value) : value),
z3
.array(
z3.object({
command: z3.string().describe("Command to execute"),
}),
)
.min(1),
)
.describe("Commands to execute as a batch"),
},
execute: async () => "ok",
},
},
},
])) as unknown as Plugin.Interface["list"],
}),
)
@@ -105,6 +140,7 @@ const background = testEffect(
const withBrokenPlugin = testEffect(
Layer.mergeAll(registryLayer({ plugin: brokenPluginLayer }), node, Agent.defaultLayer),
)
const withZod3Plugin = testEffect(Layer.mergeAll(registryLayer({ plugin: zod3PluginLayer }), node, Agent.defaultLayer))
afterEach(async () => {
await disposeAllInstances()
@@ -349,6 +385,52 @@ describe("tool.registry", () => {
}),
)
withZod3Plugin.instance("loads plugin tools with Zod 3 args as JSON Schema", () =>
Effect.gen(function* () {
const registry = yield* ToolRegistry.Service
const loaded = (yield* registry.all()).find((tool) => tool.id === "ctx_batch_execute")
if (!loaded) throw new Error("ctx_batch_execute tool was not loaded")
expect(loaded.jsonSchema).toMatchObject({
type: "object",
properties: {
batch: {
type: "array",
description: "Commands to execute as a batch",
items: {
type: "object",
properties: {
command: { type: "string", description: "Command to execute" },
},
},
minItems: 1,
},
},
required: ["batch"],
})
expect(JSON.stringify(loaded.jsonSchema)).not.toContain("_def")
expect(JSON.stringify(loaded.jsonSchema)).not.toContain("_zod")
expect(Result.isSuccess(Schema.decodeUnknownResult(loaded.parameters)({ batch: [{ command: "pwd" }] }))).toBe(
true,
)
expect(Result.isSuccess(Schema.decodeUnknownResult(loaded.parameters)({}))).toBe(false)
}),
)
withZod3Plugin.instance("validates plugin tools with Zod 3 preprocessors", () =>
Effect.gen(function* () {
const registry = yield* ToolRegistry.Service
const loaded = (yield* registry.all()).find((tool) => tool.id === "ctx_batch_execute")
if (!loaded) throw new Error("ctx_batch_execute tool was not loaded")
expect(
Result.isSuccess(
Schema.decodeUnknownResult(loaded.parameters)({ batch: JSON.stringify([{ command: "pwd" }]) }),
),
).toBe(true)
}),
)
it.instance(
"preserves Zod arg descriptions from older config-scoped plugin packages",
() =>
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.15.6",
"version": "1.15.7",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.15.6",
"version": "1.15.7",
"type": "module",
"license": "MIT",
"scripts": {
+22
View File
@@ -1806,6 +1806,12 @@ export type SubtaskPartInput = {
command?: string
}
export type SessionBusyError = {
_tag: "SessionBusyError"
sessionID: string
message: string
}
export type V2SessionsResponse = {
items: Array<SessionInfo>
cursor: {
@@ -6387,6 +6393,10 @@ export type SessionDeleteMessageErrors = {
* NotFoundError
*/
404: NotFoundError
/**
* SessionBusyError
*/
409: SessionBusyError
}
export type SessionDeleteMessageError = SessionDeleteMessageErrors[keyof SessionDeleteMessageErrors]
@@ -6786,6 +6796,10 @@ export type SessionShellErrors = {
* NotFoundError
*/
404: NotFoundError
/**
* SessionBusyError
*/
409: SessionBusyError
}
export type SessionShellError = SessionShellErrors[keyof SessionShellErrors]
@@ -6826,6 +6840,10 @@ export type SessionRevertErrors = {
* NotFoundError
*/
404: NotFoundError
/**
* SessionBusyError
*/
409: SessionBusyError
}
export type SessionRevertError = SessionRevertErrors[keyof SessionRevertErrors]
@@ -6860,6 +6878,10 @@ export type SessionUnrevertErrors = {
* NotFoundError
*/
404: NotFoundError
/**
* SessionBusyError
*/
409: SessionBusyError
}
export type SessionUnrevertError = SessionUnrevertErrors[keyof SessionUnrevertErrors]
+57
View File
@@ -6194,6 +6194,16 @@
}
}
}
},
"409": {
"description": "SessionBusyError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SessionBusyError"
}
}
}
}
},
"description": "Permanently delete a specific message and all of its parts from a session without reverting file changes.",
@@ -7123,6 +7133,16 @@
}
}
}
},
"409": {
"description": "SessionBusyError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SessionBusyError"
}
}
}
}
},
"description": "Execute a shell command within the session context and return the AI's response.",
@@ -7239,6 +7259,16 @@
}
}
}
},
"409": {
"description": "SessionBusyError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SessionBusyError"
}
}
}
}
},
"description": "Revert a specific message in a session, undoing its effects and restoring the previous state.",
@@ -7340,6 +7370,16 @@
}
}
}
},
"409": {
"description": "SessionBusyError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SessionBusyError"
}
}
}
}
},
"description": "Restore all previously reverted messages in a session.",
@@ -15668,6 +15708,23 @@
"required": ["type", "prompt", "description", "agent"],
"additionalProperties": false
},
"SessionBusyError": {
"type": "object",
"properties": {
"_tag": {
"type": "string",
"enum": ["SessionBusyError"]
},
"sessionID": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": ["_tag", "sessionID", "message"],
"additionalProperties": false
},
"V2SessionsResponse": {
"type": "object",
"properties": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.15.6",
"version": "1.15.7",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.15.6",
"version": "1.15.7",
"type": "module",
"license": "MIT",
"exports": {
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "@opencode-ai/web",
"type": "module",
"license": "MIT",
"version": "1.15.6",
"version": "1.15.7",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "1.15.6",
"version": "1.15.7",
"publisher": "sst-dev",
"repository": {
"type": "git",
+1
View File
@@ -9,6 +9,7 @@ export default $config({
home: "cloudflare",
providers: {
stripe: {
version: "0.0.28",
apiKey: process.env.STRIPE_SECRET_KEY!,
},
random: "4.19.2",