Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f1030db291 |
+3
-1
@@ -17,4 +17,6 @@ if (process.versions.bun !== expectedBunVersion) {
|
||||
console.warn(`Warning: Bun version ${process.versions.bun} differs from expected ${expectedBunVersion}`);
|
||||
}
|
||||
'
|
||||
bun typecheck
|
||||
# Only typecheck packages affected since the merge base with origin/dev,
|
||||
# plus their dependents. Override the base with TURBO_SCM_BASE if needed.
|
||||
TURBO_SCM_BASE="${TURBO_SCM_BASE:-origin/dev}" bun turbo typecheck --affected
|
||||
|
||||
+1
-1
@@ -125,4 +125,4 @@ OpenCode 内置两种 Agent,可用 `Tab` 键快速切换:
|
||||
|
||||
---
|
||||
|
||||
**加入我们的社区** [飞书](https://applink.feishu.cn/client/chat/chatter/add_by_link?link_token=52ao9352-5623-4fa0-b7dd-3407c392c1af&qr_code=true) | [X.com](https://x.com/opencode)
|
||||
**加入我们的社区** [飞书](https://applink.feishu.cn/client/chat/chatter/add_by_link?link_token=738j8655-cd59-4633-a30a-1124e0096789&qr_code=true) | [X.com](https://x.com/opencode)
|
||||
|
||||
+1
-1
@@ -125,4 +125,4 @@ OpenCode 內建了兩種 Agent,您可以使用 `Tab` 鍵快速切換。
|
||||
|
||||
---
|
||||
|
||||
**加入我們的社群** [飞书](https://applink.feishu.cn/client/chat/chatter/add_by_link?link_token=52ao9352-5623-4fa0-b7dd-3407c392c1af&qr_code=true) | [X.com](https://x.com/opencode)
|
||||
**加入我們的社群** [飞书](https://applink.feishu.cn/client/chat/chatter/add_by_link?link_token=738j8655-cd59-4633-a30a-1124e0096789&qr_code=true) | [X.com](https://x.com/opencode)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
node_modules
|
||||
.remotion
|
||||
out/frame-*.png
|
||||
@@ -1,483 +0,0 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "glm52-rise-video",
|
||||
"dependencies": {
|
||||
"@remotion/cli": "^4.0.384",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"remotion": "^4.0.384",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.8",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"typescript": "^5.8.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="],
|
||||
|
||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="],
|
||||
|
||||
"@babel/parser": ["@babel/parser@7.24.1", "", { "bin": "./bin/babel-parser.js" }, "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg=="],
|
||||
|
||||
"@babel/types": ["@babel/types@7.24.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w=="],
|
||||
|
||||
"@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="],
|
||||
|
||||
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.28.1", "", { "os": "android", "cpu": "arm" }, "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.1", "", { "os": "android", "cpu": "arm64" }, "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.28.1", "", { "os": "android", "cpu": "x64" }, "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.1", "", { "os": "linux", "cpu": "arm" }, "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.1", "", { "os": "linux", "cpu": "x64" }, "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA=="],
|
||||
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.1", "", { "os": "none", "cpu": "x64" }, "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg=="],
|
||||
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw=="],
|
||||
|
||||
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.1", "", { "os": "win32", "cpu": "x64" }, "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
|
||||
"@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@mediabunny/aac-encoder": ["@mediabunny/aac-encoder@1.47.0", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-JNzgdJoHMFFnv5imi1+dmjZMudsJ1zNCUCEkKjBh90cqGhAFg8xu4V2gsyxE2i6oq/YpWx23P+OvoANLSMcDzA=="],
|
||||
|
||||
"@mediabunny/flac-encoder": ["@mediabunny/flac-encoder@1.47.0", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-VpKmJO0xlYcFCRD6JvJlMbNQ6d/6YMHdO1gFIqWlZABHjSSL6BquNNEgWSCv5vdF8ELDBwIYBVZEslakIB/7GA=="],
|
||||
|
||||
"@mediabunny/mp3-encoder": ["@mediabunny/mp3-encoder@1.47.0", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-JyzZyGeGRm2HVUQaGJ/VZT9OG+kG00mA8SLP/f3CO7+qWAmBncKc16WYXWHbZEo8Jn/ZGA6De32S5R2bTQbDqA=="],
|
||||
|
||||
"@module-federation/error-codes": ["@module-federation/error-codes@0.22.0", "", {}, "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug=="],
|
||||
|
||||
"@module-federation/runtime": ["@module-federation/runtime@0.22.0", "", { "dependencies": { "@module-federation/error-codes": "0.22.0", "@module-federation/runtime-core": "0.22.0", "@module-federation/sdk": "0.22.0" } }, "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA=="],
|
||||
|
||||
"@module-federation/runtime-core": ["@module-federation/runtime-core@0.22.0", "", { "dependencies": { "@module-federation/error-codes": "0.22.0", "@module-federation/sdk": "0.22.0" } }, "sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA=="],
|
||||
|
||||
"@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.22.0", "", { "dependencies": { "@module-federation/runtime": "0.22.0", "@module-federation/webpack-bundler-runtime": "0.22.0" } }, "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA=="],
|
||||
|
||||
"@module-federation/sdk": ["@module-federation/sdk@0.22.0", "", {}, "sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g=="],
|
||||
|
||||
"@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.22.0", "", { "dependencies": { "@module-federation/runtime": "0.22.0", "@module-federation/sdk": "0.22.0" } }, "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA=="],
|
||||
|
||||
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="],
|
||||
|
||||
"@remotion/bundler": ["@remotion/bundler@4.0.483", "", { "dependencies": { "@remotion/media-parser": "4.0.483", "@remotion/studio": "4.0.483", "@remotion/studio-shared": "4.0.483", "@remotion/timeline-utils": "4.0.483", "@rspack/core": "1.7.11", "@rspack/plugin-react-refresh": "1.6.1", "css-loader": "7.1.4", "esbuild": "0.28.1", "react-refresh": "0.18.0", "remotion": "4.0.483", "style-loader": "4.0.0", "webpack": "5.105.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-5fQRMYgr2sxZPBOThnIVuFwHBq/FhusJ+Ke6xopga8io8ecK/mj9GaRXC3tgfMa+YWuu8ZSXZ0U9EsMZjjP5YQ=="],
|
||||
|
||||
"@remotion/canvas-capture": ["@remotion/canvas-capture@4.0.483", "", { "dependencies": { "mediabunny": "1.47.0", "remotion": "4.0.483" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-JABgbfvXwjFp1E61tlDN9gVAH8OoeF4kUUELNwG9kcNOE4ex8+vCYEO6VKIaXZ4l8A1PEAQ5EK//NheTJ80gfw=="],
|
||||
|
||||
"@remotion/cli": ["@remotion/cli@4.0.483", "", { "dependencies": { "@remotion/bundler": "4.0.483", "@remotion/media-utils": "4.0.483", "@remotion/player": "4.0.483", "@remotion/renderer": "4.0.483", "@remotion/studio": "4.0.483", "@remotion/studio-server": "4.0.483", "@remotion/studio-shared": "4.0.483", "dotenv": "17.3.1", "minimist": "1.2.6", "prompts": "2.4.2", "remotion": "4.0.483" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" }, "bin": { "remotion": "remotion-cli.js", "remotionb": "remotionb-cli.js", "remotiond": "remotiond-cli.js" } }, "sha512-z4TQcgTfQbSIV4GQpCvIihDL77M+leQelbxv962PmfSKTT7z3XnNN732PcZ4sei2+Xg+d2SD95K4tI5XBYs5Gw=="],
|
||||
|
||||
"@remotion/compositor-darwin-arm64": ["@remotion/compositor-darwin-arm64@4.0.483", "", { "os": "darwin", "cpu": "arm64" }, "sha512-CkEJXouGEoCs5PX3KOufkXrlT/Kgn0ZF7SEQ4meCYGYMZD+QPVtsmS1MXH8pQ4RHlFO6Tk7g0CIHMT3Y4yzpuA=="],
|
||||
|
||||
"@remotion/compositor-darwin-x64": ["@remotion/compositor-darwin-x64@4.0.483", "", { "os": "darwin", "cpu": "x64" }, "sha512-vDZK5U8FYbHGMjFC2lUgJRBz8KXwbwFSvEQi8FATD0roNg75SoaEJWrqAOIVv8v5eBjPvo18znDc36NLRYn1Eg=="],
|
||||
|
||||
"@remotion/compositor-linux-arm64-gnu": ["@remotion/compositor-linux-arm64-gnu@4.0.483", "", { "os": "linux", "cpu": "arm64" }, "sha512-1LzfYDY/DQxy3MIc9pCbTn1ObcBDcyI6MzODOwe1bTZl8TZxdUUt1M3hDrQ60AB6iHwruBAnzT9dnogiMIdSew=="],
|
||||
|
||||
"@remotion/compositor-linux-arm64-musl": ["@remotion/compositor-linux-arm64-musl@4.0.483", "", { "os": "linux", "cpu": "arm64" }, "sha512-nG1btxg0HXuLzulIqAg9NnxWyewZNrA0iLe82HdniaJjeWLORreGo4cEEJz1SjbDpQuPEY562XGkTO2DLKK5mA=="],
|
||||
|
||||
"@remotion/compositor-linux-x64-gnu": ["@remotion/compositor-linux-x64-gnu@4.0.483", "", { "os": "linux", "cpu": "x64" }, "sha512-CV4h6r2rNYh4P8utUzP6RM2vW2vq43nA3IvVOwRSuh9LwJh/7rwG53Oco4HanY/sstaNuymGpT57wdXwONU5CQ=="],
|
||||
|
||||
"@remotion/compositor-linux-x64-musl": ["@remotion/compositor-linux-x64-musl@4.0.483", "", { "os": "linux", "cpu": "x64" }, "sha512-moKvavbkoz5nteJZA4K6LMgTTlewhwIbtO7DYARZ3LK3ClGUKnYfFcmaPS15hMun02JPTOMIWbrlaszdR75mxA=="],
|
||||
|
||||
"@remotion/compositor-win32-x64-msvc": ["@remotion/compositor-win32-x64-msvc@4.0.483", "", { "os": "win32", "cpu": "x64" }, "sha512-eDpWe6Vy7ySHugwxlgaeohqdBwR1etxiymXzT13cgbPw2+p6d55z1tJ7VPTXyfu0o+UdyRTauWqD4msoxN0wow=="],
|
||||
|
||||
"@remotion/licensing": ["@remotion/licensing@4.0.483", "", {}, "sha512-GRtjykrxMmB5Cjpq1oVqeYIRXI95vid6afX0LTLfp1shD6MR4lTZRoRuopxrrZp1E4XFGXoY64b6dlIudgTyBQ=="],
|
||||
|
||||
"@remotion/media-parser": ["@remotion/media-parser@4.0.483", "", {}, "sha512-iva9Eof7QQX+3hGxH/N8pGi80wgdGuzOr825Zn7IuEe7IWdtRYWlFpCEghmyfhrwgaWa7RY51wg77ycR3c3nRg=="],
|
||||
|
||||
"@remotion/media-utils": ["@remotion/media-utils@4.0.483", "", { "dependencies": { "mediabunny": "1.47.0", "remotion": "4.0.483" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-4T4WQh/U95kCBzgmz/EL/HL8Zeox/AKAL5ufsehrZFgwlcvH1EsKNJH/RWaAtNPRLF+pskEOgFzPYaczHeI8hg=="],
|
||||
|
||||
"@remotion/player": ["@remotion/player@4.0.483", "", { "dependencies": { "remotion": "4.0.483" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-yyIQ9vinUqqS0fQeL52bPCWQIr8qDXCqQ4iys8P7dSZncdu8V29p4W2a0/4eKV8bv5+mjnJQ/U6nl9NxBF1hdA=="],
|
||||
|
||||
"@remotion/renderer": ["@remotion/renderer@4.0.483", "", { "dependencies": { "@remotion/licensing": "4.0.483", "@remotion/streaming": "4.0.483", "execa": "5.1.1", "remotion": "4.0.483", "source-map": "0.8.0-beta.0", "ws": "8.21.0" }, "optionalDependencies": { "@remotion/compositor-darwin-arm64": "4.0.483", "@remotion/compositor-darwin-x64": "4.0.483", "@remotion/compositor-linux-arm64-gnu": "4.0.483", "@remotion/compositor-linux-arm64-musl": "4.0.483", "@remotion/compositor-linux-x64-gnu": "4.0.483", "@remotion/compositor-linux-x64-musl": "4.0.483", "@remotion/compositor-win32-x64-msvc": "4.0.483" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-eSKdQqm8rcl+GNyOhFsBgcPYWMcxTJWHL5xaNrd037piCaL3sdJ57OEO/AbfEvvOO14zwUvlsONKjlkLlEVyKg=="],
|
||||
|
||||
"@remotion/streaming": ["@remotion/streaming@4.0.483", "", {}, "sha512-96rqrk+l5AfriHOqmqxMn8rI6UJfFY7r5UMDZoSKqXWzTOwj+0VWHTRl9ilZQMXhYACaMSA/5yrL9jgQEK8Yuw=="],
|
||||
|
||||
"@remotion/studio": ["@remotion/studio@4.0.483", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.31", "@remotion/canvas-capture": "4.0.483", "@remotion/media-utils": "4.0.483", "@remotion/player": "4.0.483", "@remotion/renderer": "4.0.483", "@remotion/studio-shared": "4.0.483", "@remotion/timeline-utils": "4.0.483", "@remotion/web-renderer": "4.0.483", "@remotion/zod-types": "4.0.483", "mediabunny": "1.47.0", "memfs": "3.4.3", "open": "8.4.2", "remotion": "4.0.483", "semver": "7.5.3", "zod": "4.3.6" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-gNa1Lw8NmHl0jwFb5fk7rzA+WFTJQpGDT/49A38t9jpEwoF+h1mKTgY8gA202apzjBHrEECdFE450npnBOUpUw=="],
|
||||
|
||||
"@remotion/studio-server": ["@remotion/studio-server@4.0.483", "", { "dependencies": { "@babel/parser": "7.24.1", "@babel/types": "7.24.0", "@remotion/bundler": "4.0.483", "@remotion/renderer": "4.0.483", "@remotion/studio-shared": "4.0.483", "memfs": "3.4.3", "open": "8.4.2", "prettier": "3.8.1", "recast": "0.23.11", "remotion": "4.0.483", "semver": "7.5.3" } }, "sha512-2FSLbVN5N8bgtQPX+RQRbis557tJJnVTOZuEBZndfC9NOoPdARlSgEnwVer9tBNczUlc6B3KrPxyPSlS3UjL+Q=="],
|
||||
|
||||
"@remotion/studio-shared": ["@remotion/studio-shared@4.0.483", "", { "dependencies": { "remotion": "4.0.483" } }, "sha512-aXxBYUgsWgphHVq7T7bz+ICMGzfii7pcX1IxS5hbLMLJHqlDtk9g+qcxm4kJ2Fjj/Gb5gERKiNzYym8WZTIM2Q=="],
|
||||
|
||||
"@remotion/timeline-utils": ["@remotion/timeline-utils@4.0.483", "", { "dependencies": { "mediabunny": "1.47.0" } }, "sha512-KTTMdpNA5uRLX+iisAITO+V9cJBk17F8EWvuUnAEVmAFOQTbGIyPI9HNw5pZmL7SlzOJdFjAtksTjipeYGkEug=="],
|
||||
|
||||
"@remotion/web-renderer": ["@remotion/web-renderer@4.0.483", "", { "dependencies": { "@mediabunny/aac-encoder": "1.47.0", "@mediabunny/flac-encoder": "1.47.0", "@mediabunny/mp3-encoder": "1.47.0", "@remotion/licensing": "4.0.483", "mediabunny": "1.47.0", "remotion": "4.0.483" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-14iURfVWA/hcF/rJvkid1ZR5nmnVhkTIf071FabCFi6kdViOSVBugSglJ8tUPvWVbWmxlXGDGQD9CSU18IATww=="],
|
||||
|
||||
"@remotion/zod-types": ["@remotion/zod-types@4.0.483", "", { "dependencies": { "remotion": "4.0.483" }, "peerDependencies": { "zod": "4.3.6" } }, "sha512-KIVYIzFpZBDB0wxGGQu5tDBr4XOYRzvrPXjmo6O/FI5Xx7O8hgvJmBs9VDkEwonAOft86sg79hI19F1DTX1p4w=="],
|
||||
|
||||
"@rspack/binding": ["@rspack/binding@1.7.11", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.7.11", "@rspack/binding-darwin-x64": "1.7.11", "@rspack/binding-linux-arm64-gnu": "1.7.11", "@rspack/binding-linux-arm64-musl": "1.7.11", "@rspack/binding-linux-x64-gnu": "1.7.11", "@rspack/binding-linux-x64-musl": "1.7.11", "@rspack/binding-wasm32-wasi": "1.7.11", "@rspack/binding-win32-arm64-msvc": "1.7.11", "@rspack/binding-win32-ia32-msvc": "1.7.11", "@rspack/binding-win32-x64-msvc": "1.7.11" } }, "sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q=="],
|
||||
|
||||
"@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@1.7.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig=="],
|
||||
|
||||
"@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@1.7.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA=="],
|
||||
|
||||
"@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@1.7.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA=="],
|
||||
|
||||
"@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@1.7.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw=="],
|
||||
|
||||
"@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@1.7.11", "", { "os": "linux", "cpu": "x64" }, "sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ=="],
|
||||
|
||||
"@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@1.7.11", "", { "os": "linux", "cpu": "x64" }, "sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg=="],
|
||||
|
||||
"@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@1.7.11", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.0.7" }, "cpu": "none" }, "sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ=="],
|
||||
|
||||
"@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@1.7.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA=="],
|
||||
|
||||
"@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@1.7.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw=="],
|
||||
|
||||
"@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@1.7.11", "", { "os": "win32", "cpu": "x64" }, "sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q=="],
|
||||
|
||||
"@rspack/core": ["@rspack/core@1.7.11", "", { "dependencies": { "@module-federation/runtime-tools": "0.22.0", "@rspack/binding": "1.7.11", "@rspack/lite-tapable": "1.1.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" }, "optionalPeers": ["@swc/helpers"] }, "sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew=="],
|
||||
|
||||
"@rspack/lite-tapable": ["@rspack/lite-tapable@1.1.0", "", {}, "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw=="],
|
||||
|
||||
"@rspack/plugin-react-refresh": ["@rspack/plugin-react-refresh@1.6.1", "", { "dependencies": { "error-stack-parser": "^2.1.4", "html-entities": "^2.6.0" }, "peerDependencies": { "react-refresh": ">=0.10.0 <1.0.0", "webpack-hot-middleware": "2.x" }, "optionalPeers": ["webpack-hot-middleware"] }, "sha512-eqqW5645VG3CzGzFgNg5HqNdHVXY+567PGjtDhhrM8t67caxmsSzRmT5qfoEIfBcGgFkH9vEg7kzXwmCYQdQDw=="],
|
||||
|
||||
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="],
|
||||
|
||||
"@types/dom-mediacapture-transform": ["@types/dom-mediacapture-transform@0.1.11", "", { "dependencies": { "@types/dom-webcodecs": "*" } }, "sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ=="],
|
||||
|
||||
"@types/dom-webcodecs": ["@types/dom-webcodecs@0.1.13", "", {}, "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ=="],
|
||||
|
||||
"@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="],
|
||||
|
||||
"@types/eslint-scope": ["@types/eslint-scope@3.7.7", "", { "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="],
|
||||
|
||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||
|
||||
"@types/node": ["@types/node@26.0.1", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw=="],
|
||||
|
||||
"@types/react": ["@types/react@19.2.17", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw=="],
|
||||
|
||||
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
||||
|
||||
"@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="],
|
||||
|
||||
"@webassemblyjs/floating-point-hex-parser": ["@webassemblyjs/floating-point-hex-parser@1.13.2", "", {}, "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA=="],
|
||||
|
||||
"@webassemblyjs/helper-api-error": ["@webassemblyjs/helper-api-error@1.13.2", "", {}, "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ=="],
|
||||
|
||||
"@webassemblyjs/helper-buffer": ["@webassemblyjs/helper-buffer@1.14.1", "", {}, "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA=="],
|
||||
|
||||
"@webassemblyjs/helper-numbers": ["@webassemblyjs/helper-numbers@1.13.2", "", { "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA=="],
|
||||
|
||||
"@webassemblyjs/helper-wasm-bytecode": ["@webassemblyjs/helper-wasm-bytecode@1.13.2", "", {}, "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA=="],
|
||||
|
||||
"@webassemblyjs/helper-wasm-section": ["@webassemblyjs/helper-wasm-section@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/wasm-gen": "1.14.1" } }, "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw=="],
|
||||
|
||||
"@webassemblyjs/ieee754": ["@webassemblyjs/ieee754@1.13.2", "", { "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw=="],
|
||||
|
||||
"@webassemblyjs/leb128": ["@webassemblyjs/leb128@1.13.2", "", { "dependencies": { "@xtuc/long": "4.2.2" } }, "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw=="],
|
||||
|
||||
"@webassemblyjs/utf8": ["@webassemblyjs/utf8@1.13.2", "", {}, "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ=="],
|
||||
|
||||
"@webassemblyjs/wasm-edit": ["@webassemblyjs/wasm-edit@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/helper-wasm-section": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-opt": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1", "@webassemblyjs/wast-printer": "1.14.1" } }, "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ=="],
|
||||
|
||||
"@webassemblyjs/wasm-gen": ["@webassemblyjs/wasm-gen@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg=="],
|
||||
|
||||
"@webassemblyjs/wasm-opt": ["@webassemblyjs/wasm-opt@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1" } }, "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw=="],
|
||||
|
||||
"@webassemblyjs/wasm-parser": ["@webassemblyjs/wasm-parser@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ=="],
|
||||
|
||||
"@webassemblyjs/wast-printer": ["@webassemblyjs/wast-printer@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw=="],
|
||||
|
||||
"@xtuc/ieee754": ["@xtuc/ieee754@1.2.0", "", {}, "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="],
|
||||
|
||||
"@xtuc/long": ["@xtuc/long@4.2.2", "", {}, "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="],
|
||||
|
||||
"acorn": ["acorn@8.17.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg=="],
|
||||
|
||||
"acorn-import-phases": ["acorn-import-phases@1.0.4", "", { "peerDependencies": { "acorn": "^8.14.0" } }, "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ=="],
|
||||
|
||||
"ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
||||
|
||||
"ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="],
|
||||
|
||||
"ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="],
|
||||
|
||||
"ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="],
|
||||
|
||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.40", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw=="],
|
||||
|
||||
"browserslist": ["browserslist@4.28.4", "", { "dependencies": { "baseline-browser-mapping": "^2.10.38", "caniuse-lite": "^1.0.30001799", "electron-to-chromium": "^1.5.376", "node-releases": "^2.0.48", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw=="],
|
||||
|
||||
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001799", "", {}, "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw=="],
|
||||
|
||||
"chrome-trace-event": ["chrome-trace-event@1.0.4", "", {}, "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ=="],
|
||||
|
||||
"commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"css-loader": ["css-loader@7.1.4", "", { "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.40", "postcss-modules-extract-imports": "^3.1.0", "postcss-modules-local-by-default": "^4.0.5", "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", "semver": "^7.6.3" }, "peerDependencies": { "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", "webpack": "^5.27.0" }, "optionalPeers": ["@rspack/core", "webpack"] }, "sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw=="],
|
||||
|
||||
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
|
||||
|
||||
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||
|
||||
"define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="],
|
||||
|
||||
"dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.379", "", {}, "sha512-v/qV5aV5EUA2pGilzUCq5/eyOloZAqDZBu9UMBIzgPpLlprjSR6zswsWBTv0KpqxLGUAZEwhO95ZCt7srymNVA=="],
|
||||
|
||||
"enhanced-resolve": ["enhanced-resolve@5.24.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-7DdUaTjmNwMcH2gLr1qycesKII3BK4RLy/mdAb7x10Lq7bR4aNKHt1BR1ZALSv0rPM/hF5wYF0PhGop/rJm8vw=="],
|
||||
|
||||
"error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="],
|
||||
|
||||
"es-module-lexer": ["es-module-lexer@2.1.0", "", {}, "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ=="],
|
||||
|
||||
"esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="],
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
"eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="],
|
||||
|
||||
"esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
|
||||
|
||||
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
|
||||
|
||||
"estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="],
|
||||
|
||||
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
|
||||
|
||||
"execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="],
|
||||
|
||||
"fs-monkey": ["fs-monkey@1.0.3", "", {}, "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q=="],
|
||||
|
||||
"get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
|
||||
|
||||
"glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||
|
||||
"html-entities": ["html-entities@2.6.0", "", {}, "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ=="],
|
||||
|
||||
"human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
|
||||
|
||||
"icss-utils": ["icss-utils@5.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA=="],
|
||||
|
||||
"is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],
|
||||
|
||||
"is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
||||
|
||||
"is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"jest-worker": ["jest-worker@27.5.1", "", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="],
|
||||
|
||||
"json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
|
||||
|
||||
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||
|
||||
"loader-runner": ["loader-runner@4.3.2", "", {}, "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w=="],
|
||||
|
||||
"lodash.sortby": ["lodash.sortby@4.7.0", "", {}, "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="],
|
||||
|
||||
"lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
|
||||
|
||||
"mediabunny": ["mediabunny@1.47.0", "", { "dependencies": { "@types/dom-mediacapture-transform": "^0.1.11", "@types/dom-webcodecs": "0.1.13" } }, "sha512-XQMZAcaKPkJ7hQ/Q2fvBdl3ZazQl2WVxDysUbJWh4PuAnLoerdsQBdPTDWdUdK6hh26LQ8Ue94MLLnmpWvlUYg=="],
|
||||
|
||||
"memfs": ["memfs@3.4.3", "", { "dependencies": { "fs-monkey": "1.0.3" } }, "sha512-eivjfi7Ahr6eQTn44nvTnR60e4a1Fs1Via2kCR5lHo/kyNoiMWaXCNJ/GpSd0ilXas2JSOl9B5FTIhflXu0hlg=="],
|
||||
|
||||
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
|
||||
|
||||
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||
|
||||
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||
|
||||
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"minimist": ["minimist@1.2.6", "", {}, "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.15", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA=="],
|
||||
|
||||
"neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.50", "", {}, "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg=="],
|
||||
|
||||
"npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
||||
|
||||
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="],
|
||||
|
||||
"postcss-modules-extract-imports": ["postcss-modules-extract-imports@3.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q=="],
|
||||
|
||||
"postcss-modules-local-by-default": ["postcss-modules-local-by-default@4.2.0", "", { "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.1.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw=="],
|
||||
|
||||
"postcss-modules-scope": ["postcss-modules-scope@3.2.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA=="],
|
||||
|
||||
"postcss-modules-values": ["postcss-modules-values@4.0.0", "", { "dependencies": { "icss-utils": "^5.0.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ=="],
|
||||
|
||||
"postcss-selector-parser": ["postcss-selector-parser@7.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg=="],
|
||||
|
||||
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
||||
|
||||
"prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="],
|
||||
|
||||
"prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"react": ["react@19.2.7", "", {}, "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ=="],
|
||||
|
||||
"react-dom": ["react-dom@19.2.7", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.7" } }, "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ=="],
|
||||
|
||||
"react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="],
|
||||
|
||||
"recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="],
|
||||
|
||||
"remotion": ["remotion@4.0.483", "", { "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-lf4xq4Twn75TQeTavFLrTE4zdck7EKBSx07ZrPv4om40Sist+3G0kq7NNzSjMeJ6G2Wx6vI+0oICD/vv4sGWtg=="],
|
||||
|
||||
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||
|
||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
||||
"schema-utils": ["schema-utils@4.3.3", "", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.1.0" } }, "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA=="],
|
||||
|
||||
"semver": ["semver@7.5.3", "", { "dependencies": { "lru-cache": "^6.0.0" }, "bin": { "semver": "bin/semver.js" } }, "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
|
||||
|
||||
"source-map": ["source-map@0.8.0-beta.0", "", { "dependencies": { "whatwg-url": "^7.0.0" } }, "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
|
||||
|
||||
"stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="],
|
||||
|
||||
"strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
|
||||
|
||||
"style-loader": ["style-loader@4.0.0", "", { "peerDependencies": { "webpack": "^5.27.0" } }, "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA=="],
|
||||
|
||||
"supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
|
||||
|
||||
"tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
|
||||
|
||||
"terser": ["terser@5.48.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q=="],
|
||||
|
||||
"terser-webpack-plugin": ["terser-webpack-plugin@5.6.1", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ=="],
|
||||
|
||||
"tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
|
||||
|
||||
"to-fast-properties": ["to-fast-properties@2.0.0", "", {}, "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog=="],
|
||||
|
||||
"tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
|
||||
|
||||
"update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"watchpack": ["watchpack@2.5.2", "", { "dependencies": { "graceful-fs": "^4.1.2" } }, "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg=="],
|
||||
|
||||
"webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="],
|
||||
|
||||
"webpack": ["webpack@5.105.0", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.19.0", "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "terser-webpack-plugin": "^5.3.16", "watchpack": "^2.5.1", "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw=="],
|
||||
|
||||
"webpack-sources": ["webpack-sources@3.5.0", "", {}, "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ=="],
|
||||
|
||||
"whatwg-url": ["whatwg-url@7.1.0", "", { "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", "webidl-conversions": "^4.0.2" } }, "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="],
|
||||
|
||||
"yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||
|
||||
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||
|
||||
"css-loader/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||
|
||||
"esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
|
||||
|
||||
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "glm52-rise-video",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"render": "remotion render src/index.tsx GLM52Rise out/glm-52-broke-out.mp4 --codec h264 --pixel-format yuv420p",
|
||||
"render:sheep": "remotion render src/index.tsx NZSheep out/nz-sheep.mp4 --codec h264 --pixel-format yuv420p",
|
||||
"render:novel": "remotion render src/index.tsx NovelTokens out/novel-1984.mp4 --codec h264 --pixel-format yuv420p",
|
||||
"render:flash": "remotion render src/index.tsx FlashShare out/flash-share.mp4 --codec h264 --pixel-format yuv420p",
|
||||
"render:minimax": "remotion render src/index.tsx MiniMaxClimb out/minimax-climb.mp4 --codec h264 --pixel-format yuv420p",
|
||||
"still:june": "remotion still src/index.tsx JuneTotals out/june-totals.png --frame=0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@remotion/cli": "^4.0.384",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"remotion": "^4.0.384"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.8",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 159 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 172 KiB |
@@ -1,156 +0,0 @@
|
||||
// Verified against the production opencode-stats PlanetScale DB.
|
||||
// Scope: tier='Go' (OpenCode Go), dataset='zen', client='all', source='all', grain='day'.
|
||||
// metric = total_tokens. Daily token volume per model; GLM-5.2 (zhipu) launched Jun 17.
|
||||
// Segments per day (tokens): glm-5.2, deepseek-v4-flash, deepseek-v4-pro, minimax-m3, all others.
|
||||
|
||||
export type Day = {
|
||||
date: string
|
||||
total: number
|
||||
glm: number
|
||||
dsf: number
|
||||
dsp: number
|
||||
mm: number
|
||||
others: number
|
||||
}
|
||||
|
||||
export const days: Day[] = [
|
||||
{
|
||||
date: "Jun 12",
|
||||
total: 2_283_799_449_383,
|
||||
glm: 0,
|
||||
dsf: 1_176_701_653_509,
|
||||
dsp: 569_527_034_307,
|
||||
mm: 159_016_250_684,
|
||||
others: 378_554_510_883,
|
||||
},
|
||||
{
|
||||
date: "Jun 13",
|
||||
total: 2_008_462_388_420,
|
||||
glm: 0,
|
||||
dsf: 995_338_131_997,
|
||||
dsp: 445_817_536_548,
|
||||
mm: 211_743_241_967,
|
||||
others: 355_563_477_908,
|
||||
},
|
||||
{
|
||||
date: "Jun 14",
|
||||
total: 2_007_785_405_251,
|
||||
glm: 0,
|
||||
dsf: 983_954_176_228,
|
||||
dsp: 428_151_999_341,
|
||||
mm: 262_476_527_930,
|
||||
others: 333_202_701_752,
|
||||
},
|
||||
{
|
||||
date: "Jun 15",
|
||||
total: 2_694_736_103_062,
|
||||
glm: 0,
|
||||
dsf: 1_255_893_953_859,
|
||||
dsp: 632_223_338_376,
|
||||
mm: 352_507_442_991,
|
||||
others: 454_111_367_836,
|
||||
},
|
||||
{
|
||||
date: "Jun 16",
|
||||
total: 2_838_153_758_908,
|
||||
glm: 0,
|
||||
dsf: 1_336_625_283_800,
|
||||
dsp: 676_480_415_730,
|
||||
mm: 305_268_829_013,
|
||||
others: 519_779_230_365,
|
||||
},
|
||||
{
|
||||
date: "Jun 17",
|
||||
total: 2_778_964_711_109,
|
||||
glm: 70_095_977_043,
|
||||
dsf: 1_339_831_523_555,
|
||||
dsp: 660_414_395_220,
|
||||
mm: 251_302_096_157,
|
||||
others: 457_320_719_134,
|
||||
},
|
||||
{
|
||||
date: "Jun 18",
|
||||
total: 2_806_992_430_656,
|
||||
glm: 201_130_231_172,
|
||||
dsf: 1_295_599_996_869,
|
||||
dsp: 595_665_008_776,
|
||||
mm: 322_205_104_324,
|
||||
others: 392_392_089_515,
|
||||
},
|
||||
{
|
||||
date: "Jun 19",
|
||||
total: 2_419_611_630_232,
|
||||
glm: 199_086_413_910,
|
||||
dsf: 1_115_750_468_802,
|
||||
dsp: 475_965_869_304,
|
||||
mm: 303_586_698_735,
|
||||
others: 325_222_179_481,
|
||||
},
|
||||
{
|
||||
date: "Jun 20",
|
||||
total: 2_188_278_916_865,
|
||||
glm: 193_931_516_396,
|
||||
dsf: 1_050_194_681_012,
|
||||
dsp: 395_303_435_278,
|
||||
mm: 281_998_000_337,
|
||||
others: 266_851_283_842,
|
||||
},
|
||||
{
|
||||
date: "Jun 21",
|
||||
total: 2_042_309_961_344,
|
||||
glm: 181_894_043_118,
|
||||
dsf: 985_164_570_580,
|
||||
dsp: 368_194_079_542,
|
||||
mm: 259_812_551_324,
|
||||
others: 247_244_716_780,
|
||||
},
|
||||
{
|
||||
date: "Jun 22",
|
||||
total: 2_893_934_325_663,
|
||||
glm: 301_759_048_475,
|
||||
dsf: 1_298_124_282_989,
|
||||
dsp: 581_012_596_194,
|
||||
mm: 371_581_117_839,
|
||||
others: 341_457_280_166,
|
||||
},
|
||||
{
|
||||
date: "Jun 23",
|
||||
total: 3_109_009_321_480,
|
||||
glm: 282_277_235_158,
|
||||
dsf: 1_423_571_678_821,
|
||||
dsp: 627_374_654_587,
|
||||
mm: 429_416_300_508,
|
||||
others: 346_369_452_406,
|
||||
},
|
||||
{
|
||||
date: "Jun 24",
|
||||
total: 2_939_149_971_595,
|
||||
glm: 256_497_442_533,
|
||||
dsf: 1_373_583_023_234,
|
||||
dsp: 601_270_997_775,
|
||||
mm: 391_586_493_231,
|
||||
others: 316_212_014_822,
|
||||
},
|
||||
{
|
||||
date: "Jun 25",
|
||||
total: 3_029_641_552_948,
|
||||
glm: 256_279_657_734,
|
||||
dsf: 1_481_084_002_776,
|
||||
dsp: 602_077_167_287,
|
||||
mm: 375_985_302_874,
|
||||
others: 314_215_422_277,
|
||||
},
|
||||
]
|
||||
|
||||
export const launchIndex = 5 // Jun 17, first day of GLM-5.2 usage
|
||||
// GLM-5.2 weekly token volume, Jun 19-25 (sum of glm): 1,671,725,357,324 = 1.67T
|
||||
export const glmWeekTokensT = 1.672
|
||||
|
||||
// stacked segments, bottom -> top. GLM-5.2 is the hero (blue); the rest are the field it cut into.
|
||||
export const segments = [
|
||||
{ key: "glm", label: "GLM-5.2", color: "#3b5cf6", hero: true },
|
||||
{ key: "dsf", label: "deepseek-v4-flash", color: "#9ca3ad" },
|
||||
{ key: "dsp", label: "deepseek-v4-pro", color: "#b3b9c1" },
|
||||
{ key: "mm", label: "minimax-m3", color: "#c8cdd3" },
|
||||
{ key: "others", label: "other models", color: "#dde0e4" },
|
||||
] as const
|
||||
@@ -1,185 +0,0 @@
|
||||
import React from "react"
|
||||
import { AbsoluteFill, Easing, interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion"
|
||||
|
||||
// stats.opencode.ai design tokens (light theme)
|
||||
const c = {
|
||||
bg: "#ffffff",
|
||||
ink: "#161616",
|
||||
muted: "#5c5c5c",
|
||||
faint: "#808080",
|
||||
line: "#e6e6e6",
|
||||
dot: "#e4e4e4",
|
||||
gray: "#aab0b8",
|
||||
accent: "#3b5cf6",
|
||||
accentHi: "#5b78ff",
|
||||
}
|
||||
const MONO = '"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
|
||||
|
||||
const DOT_MASK =
|
||||
"url(\"data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E\")"
|
||||
|
||||
// verified: OpenCode Go, week of Jun 22-28, 2026 (2026-W26). share = % of 19.64T total Go tokens.
|
||||
const bars = [
|
||||
{ label: "deepseek-v4-flash", share: 48.3, hero: true },
|
||||
{ label: "deepseek-v4-pro", share: 19.4 },
|
||||
{ label: "minimax-m3", share: 13.0 },
|
||||
{ label: "glm-5.2", share: 8.3 },
|
||||
{ label: "mimo-v2.5", share: 4.3 },
|
||||
{ label: "kimi-k2.7-code", share: 2.6 },
|
||||
{ label: "other models", share: 4.1 },
|
||||
]
|
||||
|
||||
function DataWordmark({ height = 30 }: { height?: number }) {
|
||||
return (
|
||||
<svg width={(height * 66) / 20} height={height} viewBox="0 0 66 20" fill="none" style={{ color: c.ink }}>
|
||||
<path opacity="0.2" d="M12 16H4V8H12V16Z" fill="currentColor" />
|
||||
<path d="M12 4H4V16H12V4ZM16 20H0V0H16V20Z" fill="currentColor" />
|
||||
<path
|
||||
d="M63.3543 16L62.5119 12.8711H58.6437L57.8013 16H55.7383L59.2454 4H61.9618L65.4689 16H63.3543ZM61.0678 7.851L60.6896 5.94269H60.4489L60.0707 7.851L59.1595 11.1347H61.9962L61.0678 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path d="M52.5951 5.87392V16H50.4461V5.87392H47.4375V4H55.6209V5.87392H52.5951Z" fill="currentColor" />
|
||||
<path
|
||||
d="M45.2059 16L44.3635 12.8711H40.4953L39.6529 16H37.5898L41.097 4H43.8133L47.3205 16H45.2059ZM42.9194 7.851L42.5411 5.94269H42.3004L41.9222 7.851L41.011 11.1347H43.8477L42.9194 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M28 4H32.0917C32.8138 4 33.4556 4.11461 34.0172 4.34384C34.5903 4.5616 35.0716 4.9169 35.4613 5.40974C35.8625 5.89112 36.1662 6.51003 36.3725 7.26648C36.5788 8.02292 36.6819 8.9341 36.6819 10C36.6819 11.0659 36.5788 11.9771 36.3725 12.7335C36.1662 13.49 35.8625 14.1146 35.4613 14.6075C35.0716 15.0888 34.5903 15.4441 34.0172 15.6734C33.4556 15.8911 32.8138 16 32.0917 16H28V4ZM32.0917 14.1261C32.8252 14.1261 33.3926 13.9026 33.7937 13.4556C34.1948 12.9971 34.3954 12.3152 34.3954 11.4097V8.59026C34.3954 7.68481 34.1948 7.0086 33.7937 6.5616C33.3926 6.10315 32.8252 5.87392 32.0917 5.87392H30.149V14.1261H32.0917Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function FlashShare() {
|
||||
const frame = useCurrentFrame()
|
||||
const { fps } = useVideoConfig()
|
||||
|
||||
const grow = (i: number) =>
|
||||
Math.min(
|
||||
1,
|
||||
Math.max(0, spring({ frame: frame - 18 - i * 7, fps, config: { damping: 18, stiffness: 120, mass: 0.6 } })),
|
||||
)
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ background: c.bg, color: c.ink, fontFamily: MONO, padding: 72, boxSizing: "border-box" }}>
|
||||
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
||||
{/* header */}
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<DataWordmark height={30} />
|
||||
<div style={{ fontSize: 20, fontWeight: 500, color: c.faint, letterSpacing: 1 }}>JUN 22–28, 2026</div>
|
||||
</div>
|
||||
|
||||
{/* headline (static) */}
|
||||
<div style={{ marginTop: 50 }}>
|
||||
<div style={{ fontSize: 23, fontWeight: 600, color: c.muted, letterSpacing: 2 }}>
|
||||
OPENCODE GO · SHARE OF TOKENS
|
||||
</div>
|
||||
<div
|
||||
style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 24, marginTop: 14 }}
|
||||
>
|
||||
<div style={{ fontSize: 62, fontWeight: 600, letterSpacing: -2, lineHeight: 1 }}>DeepSeek V4 Flash</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 88,
|
||||
fontWeight: 600,
|
||||
letterSpacing: -2,
|
||||
lineHeight: 1,
|
||||
color: c.accent,
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
}}
|
||||
>
|
||||
48%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* bar chart */}
|
||||
<div style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "center", gap: 16 }}>
|
||||
{bars.map((b, i) => {
|
||||
const g = grow(i)
|
||||
const pct = b.share * g
|
||||
return (
|
||||
<div key={b.label} style={{ display: "flex", alignItems: "center", gap: 18 }}>
|
||||
<div
|
||||
style={{
|
||||
width: 268,
|
||||
fontSize: 23,
|
||||
fontWeight: b.hero ? 600 : 500,
|
||||
color: b.hero ? c.ink : c.muted,
|
||||
textAlign: "right",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{b.label}
|
||||
</div>
|
||||
<div style={{ position: "relative", flex: 1, height: 48 }}>
|
||||
{/* dotted 100% track — height is a multiple of the 12px tile, anchored bottom, so dots never clip */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
background: c.dot,
|
||||
WebkitMaskImage: DOT_MASK,
|
||||
maskImage: DOT_MASK,
|
||||
WebkitMaskSize: "12px 12px",
|
||||
maskSize: "12px 12px",
|
||||
WebkitMaskRepeat: "repeat",
|
||||
maskRepeat: "repeat",
|
||||
WebkitMaskPosition: "left bottom",
|
||||
maskPosition: "left bottom",
|
||||
}}
|
||||
/>
|
||||
{/* fill */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: `${pct}%`,
|
||||
background: b.hero ? c.accent : c.gray,
|
||||
borderRight: b.hero ? `2px solid ${c.accentHi}` : "none",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: 84,
|
||||
fontSize: 24,
|
||||
fontWeight: b.hero ? 600 : 500,
|
||||
color: b.hero ? c.accent : c.muted,
|
||||
textAlign: "right",
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
}}
|
||||
>
|
||||
{Math.round(pct)}%
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* footer */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginTop: 24,
|
||||
paddingTop: 22,
|
||||
borderTop: `1px solid ${c.line}`,
|
||||
fontSize: 20,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "inline-flex", alignItems: "center", gap: 9, color: c.muted }}>
|
||||
<span style={{ width: 13, height: 13, background: c.accent, display: "inline-block" }} />
|
||||
DeepSeek V4 Flash · 9.48T tokens · 83.6M requests
|
||||
</div>
|
||||
<div style={{ color: c.ink }}>opencode.ai/data</div>
|
||||
</div>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Composition, registerRoot } from "remotion"
|
||||
import { GLM52Rise } from "./video"
|
||||
import { NZSheep } from "./sheep"
|
||||
import { NovelTokens } from "./novel"
|
||||
import { FlashShare } from "./flash"
|
||||
import { MiniMaxClimb } from "./minimax"
|
||||
import { JuneTotals } from "./june"
|
||||
|
||||
function Root() {
|
||||
return (
|
||||
<>
|
||||
<Composition id="GLM52Rise" component={GLM52Rise} durationInFrames={240} fps={30} width={1080} height={1080} />
|
||||
<Composition id="NZSheep" component={NZSheep} durationInFrames={150} fps={30} width={1080} height={1080} />
|
||||
<Composition
|
||||
id="NovelTokens"
|
||||
component={NovelTokens}
|
||||
durationInFrames={150}
|
||||
fps={30}
|
||||
width={1080}
|
||||
height={1080}
|
||||
/>
|
||||
<Composition id="FlashShare" component={FlashShare} durationInFrames={165} fps={30} width={1080} height={1080} />
|
||||
<Composition
|
||||
id="MiniMaxClimb"
|
||||
component={MiniMaxClimb}
|
||||
durationInFrames={165}
|
||||
fps={30}
|
||||
width={1080}
|
||||
height={1080}
|
||||
/>
|
||||
<Composition id="JuneTotals" component={JuneTotals} durationInFrames={1} fps={30} width={1080} height={1080} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
registerRoot(Root)
|
||||
@@ -1,144 +0,0 @@
|
||||
import React from "react"
|
||||
import { AbsoluteFill } from "remotion"
|
||||
|
||||
const c = {
|
||||
bg: "#ffffff",
|
||||
ink: "#161616",
|
||||
muted: "#5c5c5c",
|
||||
faint: "#808080",
|
||||
line: "#e6e6e6",
|
||||
dot: "#dcdcdc",
|
||||
accent: "#3b5cf6",
|
||||
}
|
||||
const MONO = '"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
|
||||
|
||||
const DOT_MASK =
|
||||
"url(\"data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E\")"
|
||||
|
||||
// verified: OpenCode Go (tier=Go, dataset=zen), June 1-30, 2026.
|
||||
// 72.78T tokens · 651.4M requests · 11.42M sessions -> rounded headline figures.
|
||||
|
||||
function DataWordmark({ height = 30 }: { height?: number }) {
|
||||
return (
|
||||
<svg width={(height * 66) / 20} height={height} viewBox="0 0 66 20" fill="none" style={{ color: c.ink }}>
|
||||
<path opacity="0.2" d="M12 16H4V8H12V16Z" fill="currentColor" />
|
||||
<path d="M12 4H4V16H12V4ZM16 20H0V0H16V20Z" fill="currentColor" />
|
||||
<path
|
||||
d="M63.3543 16L62.5119 12.8711H58.6437L57.8013 16H55.7383L59.2454 4H61.9618L65.4689 16H63.3543ZM61.0678 7.851L60.6896 5.94269H60.4489L60.0707 7.851L59.1595 11.1347H61.9962L61.0678 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path d="M52.5951 5.87392V16H50.4461V5.87392H47.4375V4H55.6209V5.87392H52.5951Z" fill="currentColor" />
|
||||
<path
|
||||
d="M45.2059 16L44.3635 12.8711H40.4953L39.6529 16H37.5898L41.097 4H43.8133L47.3205 16H45.2059ZM42.9194 7.851L42.5411 5.94269H42.3004L41.9222 7.851L41.011 11.1347H43.8477L42.9194 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M28 4H32.0917C32.8138 4 33.4556 4.11461 34.0172 4.34384C34.5903 4.5616 35.0716 4.9169 35.4613 5.40974C35.8625 5.89112 36.1662 6.51003 36.3725 7.26648C36.5788 8.02292 36.6819 8.9341 36.6819 10C36.6819 11.0659 36.5788 11.9771 36.3725 12.7335C36.1662 13.49 35.8625 14.1146 35.4613 14.6075C35.0716 15.0888 34.5903 15.4441 34.0172 15.6734C33.4556 15.8911 32.8138 16 32.0917 16H28V4ZM32.0917 14.1261C32.8252 14.1261 33.3926 13.9026 33.7937 13.4556C34.1948 12.9971 34.3954 12.3152 34.3954 11.4097V8.59026C34.3954 7.68481 34.1948 7.0086 33.7937 6.5616C33.3926 6.10315 32.8252 5.87392 32.0917 5.87392H30.149V14.1261H32.0917Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function DotBand() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: 12,
|
||||
background: c.dot,
|
||||
WebkitMaskImage: DOT_MASK,
|
||||
maskImage: DOT_MASK,
|
||||
WebkitMaskSize: "12px 12px",
|
||||
maskSize: "12px 12px",
|
||||
WebkitMaskRepeat: "repeat",
|
||||
maskRepeat: "repeat",
|
||||
WebkitMaskPosition: "left top",
|
||||
maskPosition: "left top",
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function Metric({ value, label }: { value: string; label: string }) {
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 92,
|
||||
fontWeight: 600,
|
||||
letterSpacing: -3,
|
||||
lineHeight: 1,
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
marginLeft: -8, // align the glyph's visual left edge to the column
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</div>
|
||||
<div style={{ marginTop: 16, fontSize: 24, fontWeight: 500, color: c.muted, letterSpacing: 1 }}>{label}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function JuneTotals() {
|
||||
return (
|
||||
<AbsoluteFill style={{ background: c.bg, color: c.ink, fontFamily: MONO, padding: 72, boxSizing: "border-box" }}>
|
||||
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
||||
{/* header */}
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 22 }}>
|
||||
<DataWordmark height={30} />
|
||||
<div style={{ fontSize: 20, fontWeight: 500, color: c.faint, letterSpacing: 1 }}>MONTHLY RECAP</div>
|
||||
</div>
|
||||
<DotBand />
|
||||
|
||||
{/* hero */}
|
||||
<div style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "center" }}>
|
||||
<div style={{ fontSize: 25, fontWeight: 600, color: c.muted, letterSpacing: 3 }}>OPENCODE GO · JUNE 2026</div>
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 300,
|
||||
fontWeight: 600,
|
||||
letterSpacing: -10,
|
||||
lineHeight: 0.82,
|
||||
color: c.accent,
|
||||
marginLeft: -22,
|
||||
}}
|
||||
>
|
||||
73T
|
||||
</div>
|
||||
<div style={{ fontSize: 50, fontWeight: 600, color: c.ink, marginTop: 10 }}>tokens processed</div>
|
||||
</div>
|
||||
|
||||
{/* supporting metrics */}
|
||||
<div
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
marginTop: 60,
|
||||
paddingTop: 40,
|
||||
borderTop: `1px solid ${c.line}`,
|
||||
}}
|
||||
>
|
||||
<Metric value="650M" label="requests" />
|
||||
<Metric value="11M" label="sessions" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* footer */}
|
||||
<DotBand />
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
alignItems: "center",
|
||||
marginTop: 22,
|
||||
fontSize: 20,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<div style={{ color: c.ink }}>opencode.ai/data</div>
|
||||
</div>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
)
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
import React from "react"
|
||||
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion"
|
||||
|
||||
const c = {
|
||||
bg: "#ffffff",
|
||||
ink: "#161616",
|
||||
muted: "#5c5c5c",
|
||||
faint: "#808080",
|
||||
line: "#e6e6e6",
|
||||
dot: "#e4e4e4",
|
||||
accent: "#3b5cf6",
|
||||
accentHi: "#5b78ff",
|
||||
accentDim: "#aebcf3",
|
||||
}
|
||||
const MONO = '"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
|
||||
|
||||
const DOT_MASK =
|
||||
"url(\"data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E\")"
|
||||
|
||||
// verified: minimax-m3, OpenCode Go (tier=Go, dataset=zen), weekly total_tokens.
|
||||
// W26 2.559T is +23.2% / +482.3B vs W25 2.077T.
|
||||
const weeks = [
|
||||
{ label: "May 25", t: 0.008 },
|
||||
{ label: "Jun 1", t: 0.429 },
|
||||
{ label: "Jun 8", t: 1.192 },
|
||||
{ label: "Jun 15", t: 2.077 },
|
||||
{ label: "Jun 22", t: 2.559, latest: true },
|
||||
]
|
||||
const AXIS_MAX = 3.0
|
||||
|
||||
function DataWordmark({ height = 30 }: { height?: number }) {
|
||||
return (
|
||||
<svg width={(height * 66) / 20} height={height} viewBox="0 0 66 20" fill="none" style={{ color: c.ink }}>
|
||||
<path opacity="0.2" d="M12 16H4V8H12V16Z" fill="currentColor" />
|
||||
<path d="M12 4H4V16H12V4ZM16 20H0V0H16V20Z" fill="currentColor" />
|
||||
<path
|
||||
d="M63.3543 16L62.5119 12.8711H58.6437L57.8013 16H55.7383L59.2454 4H61.9618L65.4689 16H63.3543ZM61.0678 7.851L60.6896 5.94269H60.4489L60.0707 7.851L59.1595 11.1347H61.9962L61.0678 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path d="M52.5951 5.87392V16H50.4461V5.87392H47.4375V4H55.6209V5.87392H52.5951Z" fill="currentColor" />
|
||||
<path
|
||||
d="M45.2059 16L44.3635 12.8711H40.4953L39.6529 16H37.5898L41.097 4H43.8133L47.3205 16H45.2059ZM42.9194 7.851L42.5411 5.94269H42.3004L41.9222 7.851L41.011 11.1347H43.8477L42.9194 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M28 4H32.0917C32.8138 4 33.4556 4.11461 34.0172 4.34384C34.5903 4.5616 35.0716 4.9169 35.4613 5.40974C35.8625 5.89112 36.1662 6.51003 36.3725 7.26648C36.5788 8.02292 36.6819 8.9341 36.6819 10C36.6819 11.0659 36.5788 11.9771 36.3725 12.7335C36.1662 13.49 35.8625 14.1146 35.4613 14.6075C35.0716 15.0888 34.5903 15.4441 34.0172 15.6734C33.4556 15.8911 32.8138 16 32.0917 16H28V4ZM32.0917 14.1261C32.8252 14.1261 33.3926 13.9026 33.7937 13.4556C34.1948 12.9971 34.3954 12.3152 34.3954 11.4097V8.59026C34.3954 7.68481 34.1948 7.0086 33.7937 6.5616C33.3926 6.10315 32.8252 5.87392 32.0917 5.87392H30.149V14.1261H32.0917Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
const CHART_H = 420 // multiple of 12 so the dotted tracks never clip
|
||||
|
||||
export function MiniMaxClimb() {
|
||||
const frame = useCurrentFrame()
|
||||
const { fps } = useVideoConfig()
|
||||
|
||||
const grow = (i: number) =>
|
||||
Math.min(
|
||||
1,
|
||||
Math.max(0, spring({ frame: frame - 22 - i * 9, fps, config: { damping: 18, stiffness: 110, mass: 0.6 } })),
|
||||
)
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ background: c.bg, color: c.ink, fontFamily: MONO, padding: 72, boxSizing: "border-box" }}>
|
||||
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
||||
{/* header */}
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<DataWordmark height={30} />
|
||||
<div style={{ fontSize: 20, fontWeight: 500, color: c.faint, letterSpacing: 1 }}>JUN 22–28, 2026</div>
|
||||
</div>
|
||||
|
||||
{/* headline (static) */}
|
||||
<div style={{ marginTop: 50 }}>
|
||||
<div style={{ fontSize: 23, fontWeight: 600, color: c.muted, letterSpacing: 2 }}>
|
||||
OPENCODE GO · WEEKLY TOKENS
|
||||
</div>
|
||||
<div
|
||||
style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 24, marginTop: 14 }}
|
||||
>
|
||||
<div style={{ fontSize: 62, fontWeight: 600, letterSpacing: -2, lineHeight: 1 }}>MiniMax M3</div>
|
||||
<div style={{ textAlign: "right", flexShrink: 0 }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 84,
|
||||
fontWeight: 600,
|
||||
letterSpacing: -2,
|
||||
lineHeight: 1,
|
||||
color: c.accent,
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
}}
|
||||
>
|
||||
+23.2%
|
||||
</div>
|
||||
<div style={{ fontSize: 19, fontWeight: 500, color: c.muted, letterSpacing: 1, marginTop: 6 }}>
|
||||
WEEK OVER WEEK
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* column chart */}
|
||||
<div style={{ flex: 1, display: "flex", alignItems: "flex-end", marginTop: 30 }}>
|
||||
<div style={{ width: "100%", display: "flex", alignItems: "flex-end", gap: 30 }}>
|
||||
{weeks.map((w, i) => {
|
||||
const g = grow(i)
|
||||
const h = Math.round((w.t / AXIS_MAX) * CHART_H * g)
|
||||
return (
|
||||
<div key={w.label} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center" }}>
|
||||
{/* value + bar */}
|
||||
<div style={{ position: "relative", width: "100%", height: CHART_H }}>
|
||||
{/* dotted track */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
background: c.dot,
|
||||
WebkitMaskImage: DOT_MASK,
|
||||
maskImage: DOT_MASK,
|
||||
WebkitMaskSize: "12px 12px",
|
||||
maskSize: "12px 12px",
|
||||
WebkitMaskRepeat: "repeat",
|
||||
maskRepeat: "repeat",
|
||||
WebkitMaskPosition: "left bottom",
|
||||
maskPosition: "left bottom",
|
||||
}}
|
||||
/>
|
||||
{/* fill */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
height: h,
|
||||
background: w.latest ? c.accent : c.accentDim,
|
||||
borderTop: w.latest ? `3px solid ${c.accentHi}` : "none",
|
||||
}}
|
||||
/>
|
||||
{/* value label */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: h + 10,
|
||||
textAlign: "center",
|
||||
fontSize: 26,
|
||||
fontWeight: w.latest ? 600 : 500,
|
||||
color: w.latest ? c.accent : c.muted,
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
opacity: interpolate(g, [0.5, 1], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
}),
|
||||
}}
|
||||
>
|
||||
{w.t.toFixed(2)}T
|
||||
</div>
|
||||
</div>
|
||||
{/* week label */}
|
||||
<div
|
||||
style={{
|
||||
marginTop: 14,
|
||||
fontSize: 18,
|
||||
fontWeight: 500,
|
||||
color: w.latest ? c.ink : c.faint,
|
||||
}}
|
||||
>
|
||||
{w.label}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* footer */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginTop: 22,
|
||||
paddingTop: 22,
|
||||
borderTop: `1px solid ${c.line}`,
|
||||
fontSize: 20,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "inline-flex", alignItems: "center", gap: 9, color: c.muted }}>
|
||||
<span style={{ width: 13, height: 13, background: c.accent, display: "inline-block" }} />
|
||||
2.56T tokens last week · +482.3B added
|
||||
</div>
|
||||
<div style={{ color: c.ink }}>opencode.ai/data</div>
|
||||
</div>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
)
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
import React from "react"
|
||||
import { AbsoluteFill, Easing, Img, interpolate, staticFile, useCurrentFrame } from "remotion"
|
||||
|
||||
const c = {
|
||||
white: "#ffffff",
|
||||
dim: "rgba(255,255,255,0.74)",
|
||||
}
|
||||
const MONO = '"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
|
||||
|
||||
// verified: OpenCode Go, week of Jun 22-28, 2026 (2026-W26)
|
||||
// 19,642,742,937,105 tokens / 173,651,197 requests = 113,116 tokens/request
|
||||
const AVG = 113116
|
||||
const K = Math.round(AVG / 1000) // 113
|
||||
|
||||
const nf = new Intl.NumberFormat("en-US")
|
||||
|
||||
function DataWordmark({ height = 30 }: { height?: number }) {
|
||||
return (
|
||||
<svg width={(height * 66) / 20} height={height} viewBox="0 0 66 20" fill="none" style={{ color: c.white }}>
|
||||
<path opacity="0.35" d="M12 16H4V8H12V16Z" fill="currentColor" />
|
||||
<path d="M12 4H4V16H12V4ZM16 20H0V0H16V20Z" fill="currentColor" />
|
||||
<path
|
||||
d="M63.3543 16L62.5119 12.8711H58.6437L57.8013 16H55.7383L59.2454 4H61.9618L65.4689 16H63.3543ZM61.0678 7.851L60.6896 5.94269H60.4489L60.0707 7.851L59.1595 11.1347H61.9962L61.0678 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path d="M52.5951 5.87392V16H50.4461V5.87392H47.4375V4H55.6209V5.87392H52.5951Z" fill="currentColor" />
|
||||
<path
|
||||
d="M45.2059 16L44.3635 12.8711H40.4953L39.6529 16H37.5898L41.097 4H43.8133L47.3205 16H45.2059ZM42.9194 7.851L42.5411 5.94269H42.3004L41.9222 7.851L41.011 11.1347H43.8477L42.9194 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M28 4H32.0917C32.8138 4 33.4556 4.11461 34.0172 4.34384C34.5903 4.5616 35.0716 4.9169 35.4613 5.40974C35.8625 5.89112 36.1662 6.51003 36.3725 7.26648C36.5788 8.02292 36.6819 8.9341 36.6819 10C36.6819 11.0659 36.5788 11.9771 36.3725 12.7335C36.1662 13.49 35.8625 14.1146 35.4613 14.6075C35.0716 15.0888 34.5903 15.4441 34.0172 15.6734C33.4556 15.8911 32.8138 16 32.0917 16H28V4ZM32.0917 14.1261C32.8252 14.1261 33.3926 13.9026 33.7937 13.4556C34.1948 12.9971 34.3954 12.3152 34.3954 11.4097V8.59026C34.3954 7.68481 34.1948 7.0086 33.7937 6.5616C33.3926 6.10315 32.8252 5.87392 32.0917 5.87392H30.149V14.1261H32.0917Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function NovelTokens() {
|
||||
const frame = useCurrentFrame()
|
||||
|
||||
const k = Math.round(
|
||||
K *
|
||||
interpolate(frame, [18, 92], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
easing: Easing.out(Easing.cubic),
|
||||
}),
|
||||
)
|
||||
|
||||
const zoom = interpolate(frame, [0, 150], [1.06, 1.12], {
|
||||
extrapolateRight: "clamp",
|
||||
easing: Easing.inOut(Easing.quad),
|
||||
})
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ background: "#0c0c0c", overflow: "hidden" }}>
|
||||
<Img
|
||||
src={staticFile("book.jpg")}
|
||||
style={{
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "cover",
|
||||
objectPosition: "center 34%",
|
||||
transform: `scale(${zoom})`,
|
||||
transformOrigin: "center 30%",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* legibility scrims */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
background:
|
||||
"linear-gradient(to bottom, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0) 20%, rgba(0,0,0,0.1) 44%, rgba(0,0,0,0.86) 100%)",
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
boxSizing: "border-box",
|
||||
padding: 64,
|
||||
color: c.white,
|
||||
fontFamily: MONO,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
{/* header */}
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<DataWordmark height={30} />
|
||||
<div style={{ fontSize: 20, fontWeight: 500, color: c.dim, letterSpacing: 1 }}>JUN 22–28, 2026</div>
|
||||
</div>
|
||||
|
||||
{/* bottom block */}
|
||||
<div>
|
||||
<div style={{ fontSize: 23, fontWeight: 600, color: c.dim, letterSpacing: 2, marginBottom: 8 }}>
|
||||
OPENCODE GO · LAST WEEK
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 168,
|
||||
fontWeight: 600,
|
||||
lineHeight: 0.92,
|
||||
letterSpacing: -5,
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
}}
|
||||
>
|
||||
{k}K
|
||||
</div>
|
||||
<div style={{ fontSize: 50, fontWeight: 600, letterSpacing: -1, marginTop: 4 }}>tokens per request</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginTop: 30,
|
||||
fontSize: 20,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<div style={{ color: c.dim }}>{nf.format(AVG)} tokens / request · last week</div>
|
||||
<div style={{ color: c.white }}>opencode.ai/data</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
)
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
import React from "react"
|
||||
import { AbsoluteFill, Easing, Img, interpolate, staticFile, useCurrentFrame } from "remotion"
|
||||
|
||||
const c = {
|
||||
white: "#ffffff",
|
||||
dim: "rgba(255,255,255,0.72)",
|
||||
faint: "rgba(255,255,255,0.55)",
|
||||
}
|
||||
const MONO = '"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
|
||||
|
||||
// verified: NZ OpenCode Go, week of Jun 22-28, 2026 (2026-W26)
|
||||
const TOKENS = 40_915_594_381 // 40.9B
|
||||
const SHEEP = 23_600_000 // 23.6M
|
||||
const PER_SHEEP = Math.round(TOKENS / SHEEP) // 1,734
|
||||
const nf = new Intl.NumberFormat("en-US")
|
||||
|
||||
// the correct opencode "DATA" wordmark (white, over photo)
|
||||
function DataWordmark({ height = 30 }: { height?: number }) {
|
||||
return (
|
||||
<svg width={(height * 66) / 20} height={height} viewBox="0 0 66 20" fill="none" style={{ color: c.white }}>
|
||||
<path opacity="0.35" d="M12 16H4V8H12V16Z" fill="currentColor" />
|
||||
<path d="M12 4H4V16H12V4ZM16 20H0V0H16V20Z" fill="currentColor" />
|
||||
<path
|
||||
d="M63.3543 16L62.5119 12.8711H58.6437L57.8013 16H55.7383L59.2454 4H61.9618L65.4689 16H63.3543ZM61.0678 7.851L60.6896 5.94269H60.4489L60.0707 7.851L59.1595 11.1347H61.9962L61.0678 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path d="M52.5951 5.87392V16H50.4461V5.87392H47.4375V4H55.6209V5.87392H52.5951Z" fill="currentColor" />
|
||||
<path
|
||||
d="M45.2059 16L44.3635 12.8711H40.4953L39.6529 16H37.5898L41.097 4H43.8133L47.3205 16H45.2059ZM42.9194 7.851L42.5411 5.94269H42.3004L41.9222 7.851L41.011 11.1347H43.8477L42.9194 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M28 4H32.0917C32.8138 4 33.4556 4.11461 34.0172 4.34384C34.5903 4.5616 35.0716 4.9169 35.4613 5.40974C35.8625 5.89112 36.1662 6.51003 36.3725 7.26648C36.5788 8.02292 36.6819 8.9341 36.6819 10C36.6819 11.0659 36.5788 11.9771 36.3725 12.7335C36.1662 13.49 35.8625 14.1146 35.4613 14.6075C35.0716 15.0888 34.5903 15.4441 34.0172 15.6734C33.4556 15.8911 32.8138 16 32.0917 16H28V4ZM32.0917 14.1261C32.8252 14.1261 33.3926 13.9026 33.7937 13.4556C34.1948 12.9971 34.3954 12.3152 34.3954 11.4097V8.59026C34.3954 7.68481 34.1948 7.0086 33.7937 6.5616C33.3926 6.10315 32.8252 5.87392 32.0917 5.87392H30.149V14.1261H32.0917Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function NZSheep() {
|
||||
const frame = useCurrentFrame()
|
||||
|
||||
const count = Math.round(
|
||||
PER_SHEEP *
|
||||
interpolate(frame, [18, 90], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
easing: Easing.out(Easing.cubic),
|
||||
}),
|
||||
)
|
||||
|
||||
// slow Ken Burns push-in (scale up only — never reveals an edge)
|
||||
const zoom = interpolate(frame, [0, 150], [1.06, 1.12], {
|
||||
extrapolateRight: "clamp",
|
||||
easing: Easing.inOut(Easing.quad),
|
||||
})
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ background: "#0c0c0c", overflow: "hidden" }}>
|
||||
{/* the sheep, staring */}
|
||||
<Img
|
||||
src={staticFile("sheep.jpg")}
|
||||
style={{
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "cover",
|
||||
objectPosition: "center 38%",
|
||||
transform: `scale(${zoom})`,
|
||||
transformOrigin: "center 35%",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* legibility scrims */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
background:
|
||||
"linear-gradient(to bottom, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0) 22%, rgba(0,0,0,0) 48%, rgba(0,0,0,0.78) 100%)",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* content */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
boxSizing: "border-box",
|
||||
padding: 64,
|
||||
color: c.white,
|
||||
fontFamily: MONO,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
{/* header */}
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<DataWordmark height={30} />
|
||||
<div style={{ fontSize: 20, fontWeight: 500, color: c.dim, letterSpacing: 1 }}>JUN 22–28, 2026</div>
|
||||
</div>
|
||||
|
||||
{/* bottom block */}
|
||||
<div>
|
||||
<div style={{ fontSize: 23, fontWeight: 600, color: c.dim, letterSpacing: 2, marginBottom: 8 }}>
|
||||
OPENCODE GO · NEW ZEALAND
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 168,
|
||||
fontWeight: 600,
|
||||
lineHeight: 0.92,
|
||||
letterSpacing: -5,
|
||||
fontVariantNumeric: "tabular-nums",
|
||||
}}
|
||||
>
|
||||
{nf.format(count)}
|
||||
</div>
|
||||
<div style={{ fontSize: 50, fontWeight: 600, letterSpacing: -1, marginTop: 4 }}>tokens per sheep</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginTop: 34,
|
||||
fontSize: 20,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<div style={{ color: c.dim }}>40.9B tokens ÷ 23.6M sheep · last week</div>
|
||||
<div style={{ color: c.white }}>opencode.ai/data</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
)
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
import React from "react"
|
||||
import { AbsoluteFill, Easing, interpolate, useCurrentFrame, useVideoConfig } from "remotion"
|
||||
import { days, launchIndex, glmWeekTokensT, segments } from "./data"
|
||||
|
||||
// stats.opencode.ai design tokens (light theme)
|
||||
const c = {
|
||||
bg: "#ffffff",
|
||||
ink: "#161616",
|
||||
muted: "#5c5c5c",
|
||||
faint: "#808080",
|
||||
line: "#e6e6e6",
|
||||
dot: "#ededed",
|
||||
accent: "#3b5cf6",
|
||||
accentHi: "#5b78ff",
|
||||
}
|
||||
|
||||
const MONO = '"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
|
||||
const W = 1080
|
||||
|
||||
const DOT_MASK =
|
||||
"url(\"data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E\")"
|
||||
|
||||
const field = segments.filter((s) => !s.hero)
|
||||
const glmColor = segments.find((s) => s.hero)!.color
|
||||
|
||||
const clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v))
|
||||
|
||||
// the correct opencode "DATA" wordmark (from stats.opencode.ai header)
|
||||
function DataWordmark({ height = 30, color = c.ink }: { height?: number; color?: string }) {
|
||||
return (
|
||||
<svg width={(height * 66) / 20} height={height} viewBox="0 0 66 20" fill="none" style={{ color }}>
|
||||
<path opacity="0.2" d="M12 16H4V8H12V16Z" fill="currentColor" />
|
||||
<path d="M12 4H4V16H12V4ZM16 20H0V0H16V20Z" fill="currentColor" />
|
||||
<path
|
||||
d="M63.3543 16L62.5119 12.8711H58.6437L57.8013 16H55.7383L59.2454 4H61.9618L65.4689 16H63.3543ZM61.0678 7.851L60.6896 5.94269H60.4489L60.0707 7.851L59.1595 11.1347H61.9962L61.0678 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path d="M52.5951 5.87392V16H50.4461V5.87392H47.4375V4H55.6209V5.87392H52.5951Z" fill="currentColor" />
|
||||
<path
|
||||
d="M45.2059 16L44.3635 12.8711H40.4953L39.6529 16H37.5898L41.097 4H43.8133L47.3205 16H45.2059ZM42.9194 7.851L42.5411 5.94269H42.3004L41.9222 7.851L41.011 11.1347H43.8477L42.9194 7.851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M28 4H32.0917C32.8138 4 33.4556 4.11461 34.0172 4.34384C34.5903 4.5616 35.0716 4.9169 35.4613 5.40974C35.8625 5.89112 36.1662 6.51003 36.3725 7.26648C36.5788 8.02292 36.6819 8.9341 36.6819 10C36.6819 11.0659 36.5788 11.9771 36.3725 12.7335C36.1662 13.49 35.8625 14.1146 35.4613 14.6075C35.0716 15.0888 34.5903 15.4441 34.0172 15.6734C33.4556 15.8911 32.8138 16 32.0917 16H28V4ZM32.0917 14.1261C32.8252 14.1261 33.3926 13.9026 33.7937 13.4556C34.1948 12.9971 34.3954 12.3152 34.3954 11.4097V8.59026C34.3954 7.68481 34.1948 7.0086 33.7937 6.5616C33.3926 6.10315 32.8252 5.87392 32.0917 5.87392H30.149V14.1261H32.0917Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function GLM52Rise() {
|
||||
const frame = useCurrentFrame()
|
||||
const { fps } = useVideoConfig()
|
||||
|
||||
// ---------- virtual camera ----------
|
||||
// open zoomed-in on the field, pan right while the blue fills, then pull back to reveal.
|
||||
const K = [0, 32, 150, 206, 240]
|
||||
const ease = Easing.inOut(Easing.cubic)
|
||||
const opt = { extrapolateLeft: "clamp" as const, extrapolateRight: "clamp" as const, easing: ease }
|
||||
const s = interpolate(frame, K, [1.82, 1.72, 1.72, 1.0, 1.0], opt)
|
||||
let fx = interpolate(frame, K, [420, 438, 760, 540, 540], opt)
|
||||
let fy = interpolate(frame, K, [664, 664, 664, 540, 540], opt)
|
||||
// keep the framing inside the 1080 canvas so edges never reveal black
|
||||
fx = clamp(fx, 540 / s, W - 540 / s)
|
||||
fy = clamp(fy, 540 / s, W - 540 / s)
|
||||
const camera = `translate(${540 - fx * s}px, ${540 - fy * s}px) scale(${s})`
|
||||
|
||||
// ---------- blue sweep (synced to the pan) ----------
|
||||
const p = interpolate(frame, [32, 150], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: ease })
|
||||
const revealAmount = p * (days.length - launchIndex) + 0.35
|
||||
const fillOf = (i: number) => clamp(revealAmount - (i - launchIndex), 0, 1)
|
||||
|
||||
// token number climbs as the camera pulls back and the headline re-enters frame
|
||||
const tokensT =
|
||||
glmWeekTokensT *
|
||||
interpolate(frame, [150, 202], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
easing: Easing.out(Easing.cubic),
|
||||
})
|
||||
|
||||
// chart geometry
|
||||
const chartH = 440
|
||||
const chartW = 936
|
||||
const gap = 14
|
||||
const EXAGGERATE = 2.876 // broken y-axis: GLM-5.2 magnified ~2.9x for emphasis
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ background: c.bg, overflow: "hidden" }}>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
width: W,
|
||||
height: W,
|
||||
background: c.bg,
|
||||
transformOrigin: "0 0",
|
||||
transform: camera,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: W,
|
||||
height: W,
|
||||
boxSizing: "border-box",
|
||||
padding: 72,
|
||||
color: c.ink,
|
||||
fontFamily: MONO,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
{/* header */}
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<DataWordmark height={30} />
|
||||
<div style={{ fontSize: 20, fontWeight: 500, color: c.faint, letterSpacing: 1 }}>JUN 12–25, 2026</div>
|
||||
</div>
|
||||
|
||||
{/* headline (static) */}
|
||||
<div style={{ marginTop: 52 }}>
|
||||
<div style={{ fontSize: 92, fontWeight: 600, lineHeight: 0.98, letterSpacing: -2 }}>
|
||||
GLM-5.2 <span style={{ color: c.accent }}>broke out</span>
|
||||
</div>
|
||||
<div style={{ marginTop: 22, fontSize: 30, fontWeight: 500, color: c.muted }}>
|
||||
From 0 to <span style={{ color: c.ink }}>{tokensT.toFixed(2)}T tokens</span> in a week.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* stacked chart */}
|
||||
<div style={{ flex: 1, display: "flex", alignItems: "flex-end", marginTop: 40 }}>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
width: chartW,
|
||||
height: chartH,
|
||||
margin: "0 auto",
|
||||
borderBottom: `2px solid ${c.ink}`,
|
||||
boxSizing: "border-box",
|
||||
}}
|
||||
>
|
||||
{/* faint dotted backdrop */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: -8,
|
||||
right: -8,
|
||||
top: -8,
|
||||
bottom: 0,
|
||||
background: c.dot,
|
||||
WebkitMaskImage: DOT_MASK,
|
||||
maskImage: DOT_MASK,
|
||||
WebkitMaskSize: "12px 12px",
|
||||
maskSize: "12px 12px",
|
||||
WebkitMaskRepeat: "repeat",
|
||||
maskRepeat: "repeat",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* columns */}
|
||||
<div style={{ position: "absolute", inset: 0, display: "flex", gap, alignItems: "flex-end" }}>
|
||||
{days.map((d, i) => {
|
||||
const glmShare = d.glm / d.total
|
||||
const blueH = Math.round(glmShare * EXAGGERATE * chartH)
|
||||
const filled = Math.round(blueH * fillOf(i))
|
||||
const slotGap = filled > 2 ? 5 : 0
|
||||
const fieldH = chartH - filled - slotGap
|
||||
const fieldTotal = d.dsf + d.dsp + d.mm + d.others
|
||||
return (
|
||||
<div key={i} style={{ position: "relative", flex: 1, height: chartH }}>
|
||||
{/* gray field of other models (already in place) */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: fieldH,
|
||||
display: "flex",
|
||||
flexDirection: "column-reverse",
|
||||
}}
|
||||
>
|
||||
{field.map((seg) => (
|
||||
<div
|
||||
key={seg.key}
|
||||
style={{
|
||||
height: Math.round(((d[seg.key as keyof typeof d] as number) / fieldTotal) * fieldH),
|
||||
background: seg.color,
|
||||
borderTop: `2px solid ${c.bg}`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{/* GLM-5.2, animates in */}
|
||||
{filled > 2 && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
height: filled,
|
||||
background: glmColor,
|
||||
borderTop: `2px solid ${c.accentHi}`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* day axis */}
|
||||
<div style={{ display: "flex", gap, width: chartW, margin: "14px auto 0" }}>
|
||||
{days.map((d, i) => (
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
flex: 1,
|
||||
textAlign: "center",
|
||||
fontSize: 15,
|
||||
fontWeight: 500,
|
||||
color: i === days.length - 1 ? c.ink : c.faint,
|
||||
}}
|
||||
>
|
||||
{i === 0 || i === launchIndex || i === days.length - 1 ? d.date : ""}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* footer */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginTop: 28,
|
||||
paddingTop: 22,
|
||||
borderTop: `1px solid ${c.line}`,
|
||||
fontSize: 20,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "inline-flex", alignItems: "center", gap: 9, color: c.muted }}>
|
||||
<span style={{ width: 13, height: 13, background: c.accent, display: "inline-block" }} />
|
||||
GLM-5.2
|
||||
</div>
|
||||
<div style={{ color: c.ink }}>opencode.ai/data</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
)
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
"prettier": "3.6.2",
|
||||
"semver": "^7.6.0",
|
||||
"sst": "catalog:",
|
||||
"turbo": "2.10.2",
|
||||
"turbo": "2.8.13",
|
||||
},
|
||||
},
|
||||
"packages/app": {
|
||||
@@ -2791,18 +2791,6 @@
|
||||
|
||||
"@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="],
|
||||
|
||||
"@turbo/darwin-64": ["@turbo/darwin-64@2.10.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-wBM3ObqOWnKUDmg7QfUFDkDHPFUAJmrYlYqmEM8jMPAPA/I6wRJIbWimeQUqhOiQ8xPKhzyWM+xaiUP0wz8FEQ=="],
|
||||
|
||||
"@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.10.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/Cq0joWnuMjDPfhjbFP4sv+C/7gkQ415zlaO4XUzD5EZxbtrKgXKvuuydMvogG8GeUnN1aDltW71RlmEfpjbyw=="],
|
||||
|
||||
"@turbo/linux-64": ["@turbo/linux-64@2.10.2", "", { "os": "linux", "cpu": "x64" }, "sha512-mMsf5IIhiKuceEXNstd25IbadjBXZ0amxzFOqliEzJX6HyeeHdBQPVSY583PWqYDyqM/FB8d5ZjkthfBSeuH3Q=="],
|
||||
|
||||
"@turbo/linux-arm64": ["@turbo/linux-arm64@2.10.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Wcng1i2kaKmXutmwxT9MUoYZvdaIekXAdlGr4+0TpgbhGLw7nDuEcRBFrxb5BbRoX1d1q8SpdRxLc45TvDZIdQ=="],
|
||||
|
||||
"@turbo/windows-64": ["@turbo/windows-64@2.10.2", "", { "os": "win32", "cpu": "x64" }, "sha512-SsNhM7Ho7EpAdwtrJKBOic9Hso23vu6Dp0gAfLOvUFjPzurr/sGQlXZEvr6z89ne4RDOypTwz5CBDrixpMKtXw=="],
|
||||
|
||||
"@turbo/windows-arm64": ["@turbo/windows-arm64@2.10.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Gf+S7ICAdimT/n02bOuVWKvhHnct/HYjZg3oBNIz5hZ9ZyWHbQim9J3P5Qip8WpX0ksxF7eaBVziJCuLnjhqDg=="],
|
||||
|
||||
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="],
|
||||
|
||||
"@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="],
|
||||
@@ -5333,7 +5321,19 @@
|
||||
|
||||
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],
|
||||
|
||||
"turbo": ["turbo@2.10.2", "", { "optionalDependencies": { "@turbo/darwin-64": "2.10.2", "@turbo/darwin-arm64": "2.10.2", "@turbo/linux-64": "2.10.2", "@turbo/linux-arm64": "2.10.2", "@turbo/windows-64": "2.10.2", "@turbo/windows-arm64": "2.10.2" }, "bin": { "turbo": "bin/turbo" } }, "sha512-wTExrNrRjB8qzIcg+ZLm0A3GFNLDsWNwdS/RBXB0FPrBDyzk3i96Yx+TxWZC7a0k1SIreFB8ciUbxjmEqTH8IQ=="],
|
||||
"turbo": ["turbo@2.8.13", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.13", "turbo-darwin-arm64": "2.8.13", "turbo-linux-64": "2.8.13", "turbo-linux-arm64": "2.8.13", "turbo-windows-64": "2.8.13", "turbo-windows-arm64": "2.8.13" }, "bin": { "turbo": "bin/turbo" } }, "sha512-nyM99hwFB9/DHaFyKEqatdayGjsMNYsQ/XBNO6MITc7roncZetKb97MpHxWf3uiU+LB9c9HUlU3Jp2Ixei2k1A=="],
|
||||
|
||||
"turbo-darwin-64": ["turbo-darwin-64@2.8.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-PmOvodQNiOj77+Zwoqku70vwVjKzL34RTNxxoARjp5RU5FOj/CGiC6vcDQhNtFPUOWSAaogHF5qIka9TBhX4XA=="],
|
||||
|
||||
"turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kI+anKcLIM4L8h+NsM7mtAUpElkCOxv5LgiQVQR8BASyDFfc8Efj5kCk3cqxuxOvIqx0sLfCX7atrHQ2kwuNJQ=="],
|
||||
|
||||
"turbo-linux-64": ["turbo-linux-64@2.8.13", "", { "os": "linux", "cpu": "x64" }, "sha512-j29KnQhHyzdzgCykBFeBqUPS4Wj7lWMnZ8CHqytlYDap4Jy70l4RNG46pOL9+lGu6DepK2s1rE86zQfo0IOdPw=="],
|
||||
|
||||
"turbo-linux-arm64": ["turbo-linux-arm64@2.8.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-OEl1YocXGZDRDh28doOUn49QwNe82kXljO1HXApjU0LapkDiGpfl3jkAlPKxEkGDSYWc8MH5Ll8S16Rf5tEBYg=="],
|
||||
|
||||
"turbo-windows-64": ["turbo-windows-64@2.8.13", "", { "os": "win32", "cpu": "x64" }, "sha512-717bVk1+Pn2Jody7OmWludhEirEe0okoj1NpRbSm5kVZz/yNN/jfjbxWC6ilimXMz7xoMT3IDfQFJsFR3PMANA=="],
|
||||
|
||||
"turbo-windows-arm64": ["turbo-windows-arm64@2.8.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-R819HShLIT0Wj6zWVnIsYvSNtRNj1q9VIyaUz0P24SMcLCbQZIm1sV09F4SDbg+KCCumqD2lcaR2UViQ8SnUJA=="],
|
||||
|
||||
"turndown": ["turndown@7.2.0", "", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A=="],
|
||||
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@
|
||||
"prettier": "3.6.2",
|
||||
"semver": "^7.6.0",
|
||||
"sst": "catalog:",
|
||||
"turbo": "2.10.2"
|
||||
"turbo": "2.8.13"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.933.0",
|
||||
|
||||
@@ -48,40 +48,6 @@ test("does not reverse visible rows when the user wheels during shell remeasurem
|
||||
await reportVisualStability(testInfo, "wheel-during-resize", trace, rowPairPlan(regions, 1))
|
||||
})
|
||||
|
||||
test("keeps moving upward while drag-selecting above the timeline", async ({ page }) => {
|
||||
await setupTimeline(page, {
|
||||
messages: history(80),
|
||||
viewport: { width: 1400, height: 700 },
|
||||
reducedMotion: true,
|
||||
})
|
||||
const scroller = page.locator(".scroll-view__viewport", { has: page.locator("[data-timeline-row]") })
|
||||
const text = page.getByText("History 79.", { exact: false })
|
||||
await expect(text).toBeVisible()
|
||||
await scroller.evaluate((element) => {
|
||||
element.dataset.selectionLength = "0"
|
||||
document.addEventListener("selectionchange", () => {
|
||||
element.dataset.selectionLength = String(
|
||||
Math.max(Number(element.dataset.selectionLength), window.getSelection()?.toString().length ?? 0),
|
||||
)
|
||||
})
|
||||
})
|
||||
const textBox = await text.boundingBox()
|
||||
const scrollBox = await scroller.boundingBox()
|
||||
expect(textBox).not.toBeNull()
|
||||
expect(scrollBox).not.toBeNull()
|
||||
if (!textBox || !scrollBox) return
|
||||
|
||||
await page.mouse.move(textBox.x + textBox.width - 10, textBox.y + textBox.height / 2)
|
||||
await page.mouse.down()
|
||||
await page.mouse.move(textBox.x + 20, scrollBox.y - 120, { steps: 30 })
|
||||
|
||||
await expect.poll(() => scroller.evaluate((element) => Number(element.dataset.selectionLength))).toBeGreaterThan(0)
|
||||
await expect
|
||||
.poll(() => scroller.evaluate((element) => element.scrollHeight - element.clientHeight - element.scrollTop))
|
||||
.toBeGreaterThan(500)
|
||||
await page.mouse.up()
|
||||
})
|
||||
|
||||
test("does not pull a keyboard-scrolled user during shell remeasurement", async ({ page }, testInfo) => {
|
||||
const shellID = "prt_keyboard_01_shell"
|
||||
const followingID = "prt_keyboard_02_following"
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
import type { Page } from "@playwright/test"
|
||||
import { expectSessionTitle } from "../../utils/waits"
|
||||
import { mockOpenCodeServer } from "../../utils/mock-server"
|
||||
import { benchmark, expect, withBenchmarkPage } from "../benchmark"
|
||||
import { fixture } from "./session-timeline-stress.fixture"
|
||||
import { installStressSessionTabs, stressSessionHref } from "./timeline-test-helpers"
|
||||
import { measureSessionSwitch, waitForStableTimeline } from "./session-tab-switch-probe"
|
||||
|
||||
type ParentHydrationBenchmarkMode = "natural" | "candidate"
|
||||
|
||||
const mode = process.env.SESSION_PARENT_HYDRATION_BENCHMARK_MODE ?? "natural"
|
||||
if (mode !== "natural" && mode !== "candidate") throw new Error(`Unknown parent hydration benchmark mode: ${mode}`)
|
||||
const userID = "msg_parent_hydration_user"
|
||||
const user = {
|
||||
...fixture.messages[fixture.targetID][0]!,
|
||||
info: { ...fixture.messages[fixture.targetID][0]!.info, id: userID, time: { created: 1700001000000 } },
|
||||
parts: fixture.messages[fixture.targetID][0]!.parts.map((part, index) => ({
|
||||
...part,
|
||||
id: `prt_parent_hydration_user_${index}`,
|
||||
messageID: userID,
|
||||
})),
|
||||
}
|
||||
const assistantSeed = fixture.messages[fixture.targetID][3]!
|
||||
const assistants = Array.from({ length: 14 }, (_, index) => {
|
||||
const messageID = `msg_parent_hydration_${String(index).padStart(2, "0")}`
|
||||
return {
|
||||
...assistantSeed,
|
||||
info: {
|
||||
...assistantSeed.info,
|
||||
id: messageID,
|
||||
parentID: userID,
|
||||
time: { created: 1700001001000 + index * 1_000, completed: 1700001001500 + index * 1_000 },
|
||||
},
|
||||
parts: assistantSeed.parts.map((part, partIndex) => ({
|
||||
...part,
|
||||
id: `prt_parent_hydration_${String(index).padStart(2, "0")}_${partIndex}`,
|
||||
messageID,
|
||||
})),
|
||||
}
|
||||
})
|
||||
const messages = [user, ...assistants]
|
||||
const target = fixture.sessions.find((session) => session.id === fixture.targetID)!
|
||||
const lastID = userID
|
||||
const lastPartID = assistants.at(-1)!.parts.at(-1)!.id
|
||||
|
||||
benchmark("hydrates an orphaned latest turn after a cold session click", async ({ browser, report }, testInfo) => {
|
||||
benchmark.setTimeout(180_000)
|
||||
const results = [] as Awaited<ReturnType<typeof trial>>[]
|
||||
for (let run = 0; run < 5; run++) {
|
||||
results.push(
|
||||
await withBenchmarkPage(
|
||||
browser,
|
||||
`session-parent-hydration-${mode}-${run}`,
|
||||
(page) => trial(page, mode),
|
||||
testInfo,
|
||||
),
|
||||
)
|
||||
}
|
||||
const timing = results.map((result) => result.metrics.firstCorrectObservedMs!).sort((a, b) => a - b)
|
||||
report(
|
||||
{
|
||||
results: results.map((result) => ({ ...result.metrics, historyGateCount: result.historyGateCount })),
|
||||
summary: {
|
||||
firstCorrectObservedMs: { min: timing[0], median: timing[2], max: timing.at(-1) },
|
||||
blankSamples: results.map((result) => result.metrics.blankSamples),
|
||||
requestCounts: {
|
||||
list: results.map((result) => result.requestCounts.list),
|
||||
parent: results.map((result) => result.requestCounts.parent),
|
||||
},
|
||||
historyGateCount: results.map((result) => result.historyGateCount),
|
||||
},
|
||||
},
|
||||
{ mode },
|
||||
)
|
||||
})
|
||||
|
||||
async function trial(page: Page, mode: ParentHydrationBenchmarkMode) {
|
||||
const requests: { type: "list" | "parent"; before?: string }[] = []
|
||||
const history = mode === "candidate" ? Promise.withResolvers<void>() : undefined
|
||||
let historyGates = 0
|
||||
await mockOpenCodeServer(page, {
|
||||
sessions: fixture.sessions.filter((session) => session.id === fixture.sourceID),
|
||||
provider: fixture.provider,
|
||||
directory: fixture.directory,
|
||||
project: fixture.project,
|
||||
messageDelay: 50,
|
||||
onMessages: (request) => {
|
||||
if (request.sessionID === fixture.targetID && request.phase === "start")
|
||||
requests.push({ type: "list", before: request.before })
|
||||
},
|
||||
beforeMessagesResponse: (request) => {
|
||||
if (mode !== "candidate" || request.sessionID !== fixture.targetID || !request.before) return Promise.resolve()
|
||||
historyGates++
|
||||
return history!.promise
|
||||
},
|
||||
onMessage: (request) => {
|
||||
if (request.sessionID === fixture.targetID && request.messageID === userID) requests.push({ type: "parent" })
|
||||
},
|
||||
message: (sessionID, messageID) => {
|
||||
if (sessionID !== fixture.targetID || messageID !== userID) return
|
||||
return user
|
||||
},
|
||||
pageMessages: (sessionID, limit, before) => {
|
||||
const items = sessionID === fixture.targetID ? messages : fixture.messages[fixture.sourceID]
|
||||
const end = before ? items.findIndex((message) => message.info.id === before) : items.length
|
||||
const start = Math.max(0, end - limit)
|
||||
return { items: items.slice(start, end), cursor: start > 0 ? items[start]!.info.id : undefined }
|
||||
},
|
||||
})
|
||||
await page.route(`**/session/${fixture.targetID}`, (route) =>
|
||||
route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify(target) }),
|
||||
)
|
||||
await installStressSessionTabs(page, { sessionIDs: [fixture.sourceID] })
|
||||
await page.goto(stressSessionHref(fixture.sourceID))
|
||||
await expectSessionTitle(page, fixture.expected.sourceTitle)
|
||||
await waitForStableTimeline(page, fixture.expected.sourceMessageIDs.at(-1)!)
|
||||
|
||||
const href = stressSessionHref(fixture.targetID)
|
||||
await page.evaluate(
|
||||
({ href, title }) => {
|
||||
const link = document.createElement("a")
|
||||
link.id = "parent-hydration-target"
|
||||
link.href = href
|
||||
link.textContent = title
|
||||
document.body.append(link)
|
||||
},
|
||||
{ href, title: target.title },
|
||||
)
|
||||
const metrics = await measureSessionSwitch(page, {
|
||||
destinationIDs: messages.map((message) => message.info.id),
|
||||
sourceIDs: fixture.messages[fixture.sourceID].map((message) => message.info.id),
|
||||
lastID,
|
||||
requiredPartID: lastPartID,
|
||||
requireBottomAnchor: false,
|
||||
href,
|
||||
switch: async () => {
|
||||
await page.locator("#parent-hydration-target").click()
|
||||
await expectSessionTitle(page, target.title)
|
||||
},
|
||||
}).finally(() => history?.resolve())
|
||||
expect(metrics.firstCorrectObservedMs).not.toBeNull()
|
||||
const requestCounts = {
|
||||
list: requests.filter((request) => request.type === "list").length,
|
||||
parent: requests.filter((request) => request.type === "parent").length,
|
||||
}
|
||||
if (mode === "candidate") {
|
||||
expect(requestCounts.parent).toBe(1)
|
||||
expect(historyGates).toBe(1)
|
||||
}
|
||||
return { metrics, requestCounts, historyGateCount: historyGates }
|
||||
}
|
||||
@@ -4,8 +4,6 @@ export type SessionSwitchSample = {
|
||||
source: string[]
|
||||
hasVisibleRows: boolean
|
||||
last: boolean
|
||||
requiredPartVisible?: boolean
|
||||
bottomAnchorRequired?: boolean
|
||||
bottomErrorPx?: number
|
||||
review?: {
|
||||
fileHost: boolean
|
||||
@@ -43,8 +41,7 @@ export function isCorrectDestination(sample: SessionSwitchSample) {
|
||||
sample.destination.length > 0 &&
|
||||
sample.source.length === 0 &&
|
||||
sample.last &&
|
||||
sample.requiredPartVisible !== false &&
|
||||
(sample.bottomAnchorRequired === false || Math.abs(sample.bottomErrorPx ?? Infinity) <= 1)
|
||||
Math.abs(sample.bottomErrorPx ?? Infinity) <= 1
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,16 +8,9 @@ type SessionSwitchProbe = {
|
||||
|
||||
async function installSessionSwitchProbe(
|
||||
page: Page,
|
||||
input: {
|
||||
destinationIDs: string[]
|
||||
sourceIDs: string[]
|
||||
lastID: string
|
||||
requiredPartID?: string
|
||||
requireBottomAnchor?: boolean
|
||||
href: string
|
||||
},
|
||||
input: { destinationIDs: string[]; sourceIDs: string[]; lastID: string; href: string },
|
||||
) {
|
||||
await page.evaluate(({ destinationIDs, sourceIDs, lastID, requiredPartID, requireBottomAnchor, href }) => {
|
||||
await page.evaluate(({ destinationIDs, sourceIDs, lastID, href }) => {
|
||||
const destination = new Set(destinationIDs)
|
||||
const source = new Set(sourceIDs)
|
||||
const samples: SessionSwitchSample[] = []
|
||||
@@ -73,13 +66,6 @@ async function installSessionSwitchProbe(
|
||||
const rect = element.getBoundingClientRect()
|
||||
return rect.bottom > view.top && rect.top < view.bottom
|
||||
})
|
||||
const requiredPartVisible = requiredPartID
|
||||
? [...root.querySelectorAll<HTMLElement>("[data-timeline-part-id]")].some((element) => {
|
||||
if (element.dataset.timelinePartId !== requiredPartID) return false
|
||||
const rect = element.getBoundingClientRect()
|
||||
return rect.width > 0 && rect.height > 0 && rect.bottom > view.top && rect.top < view.bottom
|
||||
})
|
||||
: undefined
|
||||
const spacer = root.querySelector<HTMLElement>('[data-timeline-row="bottom-spacer"]')?.getBoundingClientRect()
|
||||
samples.push({
|
||||
observedAtMs,
|
||||
@@ -87,22 +73,11 @@ async function installSessionSwitchProbe(
|
||||
source: visible.filter((id) => source.has(id)),
|
||||
hasVisibleRows,
|
||||
last: visible.includes(lastID),
|
||||
requiredPartVisible,
|
||||
bottomAnchorRequired: requireBottomAnchor !== false,
|
||||
bottomErrorPx: spacer ? spacer.bottom - view.bottom : undefined,
|
||||
review,
|
||||
})
|
||||
} else {
|
||||
samples.push({
|
||||
observedAtMs,
|
||||
destination: [],
|
||||
source: [],
|
||||
hasVisibleRows: false,
|
||||
last: false,
|
||||
requiredPartVisible: requiredPartID ? false : undefined,
|
||||
bottomAnchorRequired: requireBottomAnchor !== false,
|
||||
review,
|
||||
})
|
||||
samples.push({ observedAtMs, destination: [], source: [], hasVisibleRows: false, last: false, review })
|
||||
}
|
||||
requestAnimationFrame(sample)
|
||||
}, 0)
|
||||
@@ -142,8 +117,7 @@ async function waitForStableSessionSwitch(page: Page) {
|
||||
sample.destination.length > 0 &&
|
||||
sample.source.length === 0 &&
|
||||
sample.last &&
|
||||
sample.requiredPartVisible !== false &&
|
||||
(sample.bottomAnchorRequired === false || Math.abs(sample.bottomErrorPx ?? Infinity) <= 1),
|
||||
Math.abs(sample.bottomErrorPx ?? Infinity) <= 1,
|
||||
)
|
||||
)
|
||||
})
|
||||
@@ -161,27 +135,13 @@ async function collectSessionSwitchResult(page: Page) {
|
||||
|
||||
export async function measureSessionSwitch(
|
||||
page: Page,
|
||||
input: {
|
||||
destinationIDs: string[]
|
||||
sourceIDs: string[]
|
||||
lastID: string
|
||||
requiredPartID?: string
|
||||
requireBottomAnchor?: boolean
|
||||
href: string
|
||||
switch: () => Promise<void>
|
||||
},
|
||||
input: { destinationIDs: string[]; sourceIDs: string[]; lastID: string; href: string; switch: () => Promise<void> },
|
||||
) {
|
||||
const { switch: run, ...probe } = input
|
||||
await installSessionSwitchProbe(page, probe)
|
||||
try {
|
||||
await run()
|
||||
await waitForStableSessionSwitch(page)
|
||||
return await collectSessionSwitchResult(page)
|
||||
} finally {
|
||||
await page.evaluate(() => {
|
||||
;(window as Window & { __sessionSwitchProbe?: SessionSwitchProbe }).__sessionSwitchProbe?.stop()
|
||||
})
|
||||
}
|
||||
await run()
|
||||
await waitForStableSessionSwitch(page)
|
||||
return collectSessionSwitchResult(page)
|
||||
}
|
||||
|
||||
export async function waitForStableTimeline(page: Page, lastID: string) {
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { expect, test } from "bun:test"
|
||||
import type { Page, Route } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../../utils/mock-server"
|
||||
|
||||
test("applies message latency after a list response gate is released", async () => {
|
||||
const events: string[] = []
|
||||
const gate = Promise.withResolvers<void>()
|
||||
let handler: ((route: Route) => Promise<void>) | undefined
|
||||
const page = {
|
||||
route: (_url: string, callback: (route: Route) => Promise<void>) => {
|
||||
handler = callback
|
||||
return Promise.resolve()
|
||||
},
|
||||
} as unknown as Page
|
||||
await mockOpenCodeServer(page, {
|
||||
provider: {},
|
||||
directory: "C:/OpenCode",
|
||||
project: {},
|
||||
sessions: [{ id: "session" }],
|
||||
messageDelay: 25,
|
||||
beforeMessagesResponse: () => {
|
||||
events.push("before")
|
||||
return gate.promise
|
||||
},
|
||||
onMessages: (request) => events.push(request.phase),
|
||||
pageMessages: () => {
|
||||
events.push("page")
|
||||
return { items: [] }
|
||||
},
|
||||
})
|
||||
|
||||
const response = handler!({
|
||||
request: () => ({ url: () => "http://127.0.0.1:4096/session/session/message" }),
|
||||
fulfill: () => {
|
||||
events.push("fulfill")
|
||||
return Promise.resolve()
|
||||
},
|
||||
} as unknown as Route)
|
||||
expect(events).toEqual(["start", "before"])
|
||||
|
||||
const released = performance.now()
|
||||
gate.resolve()
|
||||
await response
|
||||
expect(performance.now() - released).toBeGreaterThanOrEqual(20)
|
||||
expect(events).toEqual(["start", "before", "page", "end", "fulfill"])
|
||||
})
|
||||
@@ -52,35 +52,3 @@ test("reports missing correctness without throwing", () => {
|
||||
expect(result.firstCorrectObservedMs).toBeNull()
|
||||
expect(result.stableObservedMs).toBeNull()
|
||||
})
|
||||
|
||||
test("requires an explicitly tracked part to be visible", () => {
|
||||
const result = classifySessionSwitch([
|
||||
{
|
||||
observedAtMs: 16,
|
||||
destination: ["destination"],
|
||||
source: [],
|
||||
hasVisibleRows: true,
|
||||
last: true,
|
||||
requiredPartVisible: false,
|
||||
bottomErrorPx: 0,
|
||||
},
|
||||
])
|
||||
|
||||
expect(result.firstCorrectObservedMs).toBeNull()
|
||||
})
|
||||
|
||||
test("can measure content correctness without requiring a bottom anchor", () => {
|
||||
const result = classifySessionSwitch([
|
||||
{
|
||||
observedAtMs: 16,
|
||||
destination: ["destination"],
|
||||
source: [],
|
||||
hasVisibleRows: true,
|
||||
last: true,
|
||||
requiredPartVisible: true,
|
||||
bottomAnchorRequired: false,
|
||||
},
|
||||
])
|
||||
|
||||
expect(result.firstCorrectObservedMs).toBe(16)
|
||||
})
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import { expect, test } from "bun:test"
|
||||
import type { Page } from "@playwright/test"
|
||||
import { measureSessionSwitch } from "../timeline/session-tab-switch-probe"
|
||||
|
||||
function testPage(waitFailure?: Error) {
|
||||
const stops: unknown[] = []
|
||||
const page = {
|
||||
evaluate: async (_callback: unknown, input?: unknown) => {
|
||||
if (input) return
|
||||
stops.push(undefined)
|
||||
},
|
||||
waitForFunction: async () => {
|
||||
if (waitFailure) throw waitFailure
|
||||
},
|
||||
} as unknown as Page
|
||||
return { page, stops }
|
||||
}
|
||||
|
||||
function input(run: () => Promise<void>) {
|
||||
return {
|
||||
destinationIDs: ["destination"],
|
||||
sourceIDs: ["source"],
|
||||
lastID: "destination",
|
||||
href: "/session/destination",
|
||||
switch: run,
|
||||
}
|
||||
}
|
||||
|
||||
test("stops sampling when the session switch fails", async () => {
|
||||
const failure = new Error("switch failed")
|
||||
const context = testPage()
|
||||
|
||||
await expect(
|
||||
measureSessionSwitch(
|
||||
context.page,
|
||||
input(async () => Promise.reject(failure)),
|
||||
),
|
||||
).rejects.toBe(failure)
|
||||
|
||||
expect(context.stops).toHaveLength(1)
|
||||
})
|
||||
|
||||
test("stops sampling when the stable wait fails", async () => {
|
||||
const failure = new Error("stable wait failed")
|
||||
const context = testPage(failure)
|
||||
|
||||
await expect(
|
||||
measureSessionSwitch(
|
||||
context.page,
|
||||
input(async () => {}),
|
||||
),
|
||||
).rejects.toBe(failure)
|
||||
|
||||
expect(context.stops).toHaveLength(1)
|
||||
})
|
||||
@@ -1,83 +0,0 @@
|
||||
import { expect, test } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectAppVisible } from "../utils/waits"
|
||||
|
||||
const draftID = "draft_new_session_panel_corner"
|
||||
const directory = "C:/OpenCode/NewSessionPanelCorner"
|
||||
const server = `http://${process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"}:${process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"}`
|
||||
|
||||
test.use({
|
||||
viewport: { width: 935, height: 522 },
|
||||
deviceScaleFactor: 1,
|
||||
})
|
||||
|
||||
test("matches the rounded panel corners to the dark new-session background", async ({ page }, testInfo) => {
|
||||
await mockOpenCodeServer(page, {
|
||||
directory,
|
||||
project: {
|
||||
id: "proj_new_session_panel_corner",
|
||||
worktree: directory,
|
||||
vcs: "git",
|
||||
name: "new-session-panel-corner",
|
||||
time: { created: 1700000000000, updated: 1700000000000 },
|
||||
sandboxes: [],
|
||||
},
|
||||
provider: { all: [], connected: [], default: {} },
|
||||
sessions: [],
|
||||
pageMessages: () => ({ items: [] }),
|
||||
})
|
||||
await page.addInitScript(
|
||||
({ directory, draftID, server }) => {
|
||||
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
|
||||
localStorage.setItem("opencode-theme-id", "oc-2")
|
||||
localStorage.setItem("opencode-color-scheme", "dark")
|
||||
localStorage.setItem(
|
||||
"opencode.global.dat:server",
|
||||
JSON.stringify({
|
||||
projects: { local: [{ worktree: directory, expanded: true }] },
|
||||
lastProject: { local: directory },
|
||||
}),
|
||||
)
|
||||
localStorage.setItem(
|
||||
"opencode.window.browser.dat:tabs",
|
||||
JSON.stringify([{ type: "draft", draftID, server, directory }]),
|
||||
)
|
||||
},
|
||||
{ directory, draftID, server },
|
||||
)
|
||||
|
||||
await page.goto(`/new-session?draftId=${draftID}`)
|
||||
await expectAppVisible(page.locator('[data-component="prompt-input"]'))
|
||||
await expect(page.locator("html")).toHaveAttribute("data-color-scheme", "dark")
|
||||
const panel = page.locator('main div[class*="rounded-[10px]"][class*="overflow-hidden"]')
|
||||
await expect(panel).toHaveCount(1)
|
||||
const box = await panel.boundingBox()
|
||||
if (!box) throw new Error("New-session panel bounds are unavailable")
|
||||
|
||||
const screenshot = await page.screenshot({ path: testInfo.outputPath("new-session-dark.png") })
|
||||
const corners = await page.evaluate(
|
||||
async ({ source, points }) => {
|
||||
const image = new Image()
|
||||
image.src = source
|
||||
await image.decode()
|
||||
const canvas = document.createElement("canvas")
|
||||
canvas.width = image.naturalWidth
|
||||
canvas.height = image.naturalHeight
|
||||
const context = canvas.getContext("2d")
|
||||
if (!context) throw new Error("2D canvas is unavailable")
|
||||
context.drawImage(image, 0, 0)
|
||||
return points.map((point) => Array.from(context.getImageData(point.x, point.y, 1, 1).data))
|
||||
},
|
||||
{
|
||||
source: `data:image/png;base64,${screenshot.toString("base64")}`,
|
||||
points: [
|
||||
{ x: Math.floor(box.x), y: Math.floor(box.y) },
|
||||
{ x: Math.ceil(box.x + box.width) - 1, y: Math.floor(box.y) },
|
||||
{ x: Math.floor(box.x), y: Math.ceil(box.y + box.height) - 1 },
|
||||
{ x: Math.ceil(box.x + box.width) - 1, y: Math.ceil(box.y + box.height) - 1 },
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
expect(corners.every(([red, green, blue, alpha]) => red <= 8 && green <= 8 && blue <= 8 && alpha === 255)).toBe(true)
|
||||
})
|
||||
@@ -1,220 +0,0 @@
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import {
|
||||
assistantMessage,
|
||||
directory,
|
||||
messageUpdated,
|
||||
project,
|
||||
session,
|
||||
sessionID,
|
||||
status,
|
||||
textPart,
|
||||
title,
|
||||
userID,
|
||||
userMessage,
|
||||
} from "../performance/timeline-stability/fixture"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { installSseTransport } from "../utils/sse-transport"
|
||||
import { expectSessionTitle } from "../utils/waits"
|
||||
|
||||
const assistants = Array.from({ length: 14 }, (_, index) =>
|
||||
assistantMessage([textPart(`prt_history_root_${index}`, `Assistant response ${index}`)], {
|
||||
id: `msg_${String(index + 1001).padStart(4, "0")}_history_root_assistant`,
|
||||
parentID: userID,
|
||||
created: 1700000001000 + index * 1_000,
|
||||
completed: index < 13,
|
||||
}),
|
||||
)
|
||||
const messages = [userMessage(), ...assistants]
|
||||
const lastAssistant = assistants.at(-1)!
|
||||
const lastPartID = assistants.at(-1)!.parts[0]!.id
|
||||
const userPartID = `prt_${userID}_text`
|
||||
const completed = {
|
||||
...lastAssistant.info,
|
||||
time: { ...lastAssistant.info.time, completed: lastAssistant.info.time.created + 15_000 },
|
||||
}
|
||||
const scenarios = [
|
||||
{ name: "completion", info: completed, idleFirst: false, interrupted: false },
|
||||
{
|
||||
name: "interruption",
|
||||
info: { ...completed, error: { name: "MessageAbortedError", data: { message: "Stopped" } } },
|
||||
idleFirst: true,
|
||||
interrupted: true,
|
||||
},
|
||||
] as const
|
||||
|
||||
test.use({ viewport: { width: 646, height: 1385 } })
|
||||
|
||||
for (const scenario of scenarios) {
|
||||
test(`keeps the latest user turn visible through ${scenario.name}`, async ({ page }) => {
|
||||
const requests: { before?: string; phase: "start" | "end" }[] = []
|
||||
const pages: { before?: string; limit: number }[] = []
|
||||
const roots: { sessionID: string; messageID: string }[] = []
|
||||
const sequence: string[] = []
|
||||
const history = Promise.withResolvers<void>()
|
||||
const transport = await installSseTransport<{ directory: string; payload: Record<string, unknown> }>(page, {
|
||||
server: `http://${process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"}:${process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"}`,
|
||||
retry: 20,
|
||||
})
|
||||
await mockOpenCodeServer(page, {
|
||||
directory,
|
||||
project: project(),
|
||||
provider: {
|
||||
all: [
|
||||
{
|
||||
id: "opencode",
|
||||
name: "OpenCode",
|
||||
models: {
|
||||
"claude-opus-4-6": {
|
||||
id: "claude-opus-4-6",
|
||||
name: "Claude Opus 4.6",
|
||||
limit: { context: 200_000 },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
connected: ["opencode"],
|
||||
default: { providerID: "opencode", modelID: "claude-opus-4-6" },
|
||||
},
|
||||
sessions: [session()],
|
||||
sessionStatus: { [sessionID]: { type: "busy" } },
|
||||
beforeMessagesResponse: (request) => (request.before ? history.promise : Promise.resolve()),
|
||||
onMessages: (request) => {
|
||||
requests.push(request)
|
||||
sequence.push(`messages:${request.phase}:${request.before ?? "latest"}`)
|
||||
},
|
||||
onMessage: (request) => {
|
||||
roots.push(request)
|
||||
sequence.push(`message:${request.messageID}`)
|
||||
},
|
||||
message: (requestedSessionID, messageID) => {
|
||||
if (requestedSessionID !== sessionID) return
|
||||
return messages.find((item) => item.info.id === messageID)
|
||||
},
|
||||
pageMessages: (_, limit, before) => {
|
||||
pages.push({ before, limit })
|
||||
const end = before ? messages.findIndex((message) => message.info.id === before) : messages.length
|
||||
const start = Math.max(0, end - limit)
|
||||
return {
|
||||
items: messages.slice(start, end),
|
||||
cursor: start > 0 ? messages[start]!.info.id : undefined,
|
||||
}
|
||||
},
|
||||
})
|
||||
await page.addInitScript(
|
||||
({ userPartID, lastPartID }) => {
|
||||
const state = { armed: false, hidden: false, samples: 0, stop: false }
|
||||
;(window as Window & { __historyRootProbe?: typeof state }).__historyRootProbe = state
|
||||
const sample = () => {
|
||||
if (state.armed) {
|
||||
const virtual = document.querySelector<HTMLElement>("[data-timeline-virtual-content]")
|
||||
const viewport = virtual?.closest<HTMLElement>(".scroll-view__viewport")
|
||||
const view = viewport?.getBoundingClientRect()
|
||||
const visible = (partID: string) => {
|
||||
const part = viewport?.querySelector<HTMLElement>(`[data-timeline-part-id="${partID}"]`)
|
||||
const rect = part?.getBoundingClientRect()
|
||||
return (
|
||||
!!rect &&
|
||||
!!view &&
|
||||
rect.width > 0 &&
|
||||
rect.height > 0 &&
|
||||
rect.bottom > view.top &&
|
||||
rect.top < view.bottom
|
||||
)
|
||||
}
|
||||
if (!virtual || !visible(userPartID) || !visible(lastPartID)) state.hidden = true
|
||||
state.samples++
|
||||
}
|
||||
if (!state.stop) requestAnimationFrame(() => setTimeout(sample, 0))
|
||||
}
|
||||
requestAnimationFrame(() => setTimeout(sample, 0))
|
||||
},
|
||||
{ userPartID, lastPartID },
|
||||
)
|
||||
|
||||
await page.goto(`/${base64Encode(directory)}/session/${sessionID}`)
|
||||
await transport.waitForConnection()
|
||||
await expectSessionTitle(page, title)
|
||||
await expect(page.locator(`[data-timeline-part-id="${lastPartID}"]`)).toBeVisible()
|
||||
await expect(page.locator(`[data-timeline-part-id="${userPartID}"]`)).toBeVisible()
|
||||
await expect.poll(() => requests.filter((request) => request.phase === "start").length).toBe(2)
|
||||
expect(requests.filter((request) => request.phase === "end")).toHaveLength(1)
|
||||
expect(sequence.slice(0, 4)).toEqual([
|
||||
"messages:start:latest",
|
||||
"messages:end:latest",
|
||||
`message:${userID}`,
|
||||
`messages:start:${messages.at(-2)!.info.id}`,
|
||||
])
|
||||
await page.evaluate(() => {
|
||||
;(
|
||||
window as Window & {
|
||||
__historyRootProbe?: { armed: boolean }
|
||||
}
|
||||
).__historyRootProbe!.armed = true
|
||||
})
|
||||
await waitForProbeSamples(page, 0)
|
||||
expect(await historyRootHidden(page)).toBe(false)
|
||||
const beforeHistory = await probeSamples(page)
|
||||
history.resolve()
|
||||
await expect(page.locator('[data-timeline-part-id^="prt_history_root_"]')).toHaveCount(14)
|
||||
await expect(page.getByRole("button", { name: "Stop" })).toBeVisible()
|
||||
await waitForProbeSamples(page, beforeHistory)
|
||||
expect(pages[0]).toEqual({ before: undefined, limit: 2 })
|
||||
expect(roots).toEqual([{ sessionID, messageID: userID }])
|
||||
|
||||
const message = messageUpdated(scenario.info)
|
||||
const idle = status("idle")
|
||||
for (const event of scenario.idleFirst ? [idle, message] : [message, idle]) {
|
||||
const beforeEvent = await probeSamples(page)
|
||||
await transport.send(event)
|
||||
if (event === idle) await expect(page.getByRole("button", { name: "Stop" })).toHaveCount(0)
|
||||
if (event === message && scenario.interrupted)
|
||||
await expect(page.getByText("Interrupted", { exact: true })).toBeVisible()
|
||||
await waitForProbeSamples(page, beforeEvent)
|
||||
const current = await timelineState(page)
|
||||
expect(current, JSON.stringify(current)).toMatchObject({ virtual: true })
|
||||
expect(current.rows, JSON.stringify(current)).toBeGreaterThan(0)
|
||||
}
|
||||
|
||||
expect(requests[0]).toEqual({ before: undefined, phase: "start", sessionID })
|
||||
expect(requests[1]).toEqual({ before: undefined, phase: "end", sessionID })
|
||||
await expect(page.getByRole("button", { name: "Stop" })).toHaveCount(0)
|
||||
await expect(page.locator('[data-timeline-row="bottom-spacer"]')).toBeVisible()
|
||||
if (scenario.interrupted) await expect(page.getByText("Interrupted", { exact: true })).toBeVisible()
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const state = (window as Window & { __historyRootProbe?: { hidden: boolean; stop: boolean } })
|
||||
.__historyRootProbe!
|
||||
state.stop = true
|
||||
return state.hidden
|
||||
}),
|
||||
).toBe(false)
|
||||
})
|
||||
}
|
||||
|
||||
function timelineState(page: Page) {
|
||||
return page.evaluate(() => ({
|
||||
virtual: !!document.querySelector("[data-timeline-virtual-content]"),
|
||||
rows: document.querySelectorAll("[data-timeline-key]").length,
|
||||
}))
|
||||
}
|
||||
|
||||
function probeSamples(page: Page) {
|
||||
return page.evaluate(
|
||||
() => (window as Window & { __historyRootProbe?: { samples: number } }).__historyRootProbe!.samples,
|
||||
)
|
||||
}
|
||||
|
||||
async function waitForProbeSamples(page: Page, after: number) {
|
||||
await page.waitForFunction(
|
||||
(after) =>
|
||||
(window as Window & { __historyRootProbe?: { samples: number } }).__historyRootProbe!.samples >= after + 3,
|
||||
after,
|
||||
)
|
||||
}
|
||||
|
||||
function historyRootHidden(page: Page) {
|
||||
return page.evaluate(
|
||||
() => (window as Window & { __historyRootProbe?: { hidden: boolean } }).__historyRootProbe!.hidden,
|
||||
)
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { expect, test } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
import { expectSessionTitle } from "../utils/waits"
|
||||
|
||||
const directory = "C:/OpenCode/TerminalComposerFocus"
|
||||
const projectID = "proj_terminal_composer_focus"
|
||||
const sessionID = "ses_terminal_composer_focus"
|
||||
const ptyID = "pty_terminal_composer_focus"
|
||||
|
||||
test.use({ viewport: { width: 1440, height: 900 } })
|
||||
|
||||
test("routes typing to the composer unless the open terminal is focused", async ({ page }) => {
|
||||
await mockOpenCodeServer(page, {
|
||||
directory,
|
||||
project: {
|
||||
id: projectID,
|
||||
worktree: directory,
|
||||
vcs: "git",
|
||||
name: "terminal-composer-focus",
|
||||
time: { created: 1700000000000, updated: 1700000000000 },
|
||||
sandboxes: [],
|
||||
},
|
||||
provider: {
|
||||
all: [
|
||||
{
|
||||
id: "opencode",
|
||||
name: "OpenCode",
|
||||
models: { test: { id: "test", name: "Test", limit: { context: 200_000 } } },
|
||||
},
|
||||
],
|
||||
connected: ["opencode"],
|
||||
default: { providerID: "opencode", modelID: "test" },
|
||||
},
|
||||
sessions: [
|
||||
{
|
||||
id: sessionID,
|
||||
slug: "terminal-composer-focus",
|
||||
projectID,
|
||||
directory,
|
||||
title: "Terminal composer focus",
|
||||
version: "dev",
|
||||
time: { created: 1700000000000, updated: 1700000000000 },
|
||||
},
|
||||
],
|
||||
pageMessages: () => ({ items: [] }),
|
||||
})
|
||||
await page.route("**/pty", (route) =>
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ id: ptyID, title: "Terminal 1" }),
|
||||
}),
|
||||
)
|
||||
await page.route(`**/pty/${ptyID}`, (route) =>
|
||||
route.fulfill({ status: 200, contentType: "application/json", body: "{}" }),
|
||||
)
|
||||
await page.route(`**/pty/${ptyID}/connect-token*`, (route) =>
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
headers: { "access-control-allow-origin": "*" },
|
||||
body: JSON.stringify({ ticket: "e2e-ticket" }),
|
||||
}),
|
||||
)
|
||||
await page.routeWebSocket(new RegExp(`/pty/${ptyID}/connect`), () => undefined)
|
||||
await page.addInitScript(() => {
|
||||
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
|
||||
})
|
||||
|
||||
await page.goto(`/${base64Encode(directory)}/session/${sessionID}`)
|
||||
await expectSessionTitle(page, "Terminal composer focus")
|
||||
|
||||
const composer = page.locator('[data-component="prompt-input"]')
|
||||
const terminal = page.locator('[data-component="terminal"]')
|
||||
await page.keyboard.press("Control+Backquote")
|
||||
await expect(terminal).toBeVisible()
|
||||
await expect.poll(() => terminal.evaluate((element) => element.contains(document.activeElement))).toBe(true)
|
||||
|
||||
await page.keyboard.type("x")
|
||||
await expect(composer).toHaveText("")
|
||||
|
||||
await page.waitForTimeout(300)
|
||||
await page.evaluate(() => (document.activeElement as HTMLElement | null)?.blur())
|
||||
await page.keyboard.type("a")
|
||||
|
||||
await expect(composer).toBeFocused()
|
||||
await expect(composer).toHaveText("a")
|
||||
})
|
||||
@@ -7,7 +7,7 @@ const projectID = "proj_hidden_terminal_regression"
|
||||
const sessionID = "ses_hidden_terminal_regression"
|
||||
const title = "Hidden terminal regression"
|
||||
|
||||
test("unmounts the terminal panel while it is hidden", async ({ page }) => {
|
||||
test("unmounts the terminal renderer while the pane is hidden", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 1400, height: 900 })
|
||||
await mockOpenCodeServer(page, {
|
||||
directory,
|
||||
@@ -64,14 +64,13 @@ test("unmounts the terminal panel while it is hidden", async ({ page }) => {
|
||||
await expect(page.locator('[data-component="terminal"]')).toBeVisible()
|
||||
|
||||
await page.keyboard.press("Control+Backquote")
|
||||
await expect(panel).toHaveCount(0)
|
||||
await expect(panel).toHaveAttribute("aria-hidden", "true")
|
||||
await expect(page.locator('[data-component="terminal"]')).toHaveCount(0)
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 700 })
|
||||
await expect(page.locator('[data-component="terminal"]')).toHaveCount(0)
|
||||
|
||||
await page.keyboard.press("Control+Backquote")
|
||||
await expect(panel).toBeVisible()
|
||||
await expect(page.locator('[data-component="terminal"]')).toBeVisible()
|
||||
})
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
"./performance/timeline-stability/fixture.test.ts",
|
||||
"./performance/timeline-stability/fixture.ts",
|
||||
"./performance/unit/visual-stability.test.ts",
|
||||
"./regression/new-session-panel-corner.spec.ts",
|
||||
"./regression/session-timeline-context-resize.spec.ts",
|
||||
"./utils/**/*.ts"
|
||||
]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Page, Route } from "@playwright/test"
|
||||
|
||||
const emptyList = new Set(["/skill", "/command", "/lsp", "/formatter", "/vcs/status", "/vcs/diff"])
|
||||
const emptyObject = new Set(["/global/config", "/config", "/provider/auth", "/mcp", "/experimental/resource"])
|
||||
const emptyObject = new Set(["/global/config", "/config", "/provider/auth", "/mcp"])
|
||||
|
||||
export interface MockServerConfig {
|
||||
provider: unknown
|
||||
@@ -11,10 +11,7 @@ export interface MockServerConfig {
|
||||
pageMessages: (sessionId: string, limit: number, before?: string) => { items: unknown[]; cursor?: string }
|
||||
vcsDiff?: unknown[]
|
||||
messageDelay?: number
|
||||
beforeMessagesResponse?: (input: { sessionID: string; before?: string }) => Promise<void>
|
||||
onMessages?: (input: { sessionID: string; before?: string; phase: "start" | "end" }) => void
|
||||
message?: (sessionID: string, messageID: string) => unknown
|
||||
onMessage?: (input: { sessionID: string; messageID: string }) => void
|
||||
events?: () => unknown[]
|
||||
eventRetry?: number
|
||||
todos?: (sessionID: string) => unknown[]
|
||||
@@ -55,7 +52,6 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) {
|
||||
const path = url.pathname
|
||||
if (path === "/global/event" || path === "/event") return sse(route, config.events?.(), config.eventRetry)
|
||||
if (path === "/global/health") return json(route, { healthy: true })
|
||||
if (path === "/experimental/capabilities") return json(route, { backgroundSubagents: false })
|
||||
if (path === "/permission")
|
||||
return json(route, typeof config.permissions === "function" ? config.permissions() : (config.permissions ?? []))
|
||||
if (path === "/question")
|
||||
@@ -66,14 +62,6 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) {
|
||||
return json(route, await config.fileList(url.searchParams.get("path") ?? ""))
|
||||
if (path === "/file/content" && config.fileContent)
|
||||
return json(route, await config.fileContent(url.searchParams.get("path") ?? ""))
|
||||
if (path === "/api/reference")
|
||||
return json(route, {
|
||||
location: {
|
||||
directory: config.directory,
|
||||
project: { id: (config.project as { id?: string }).id, directory: config.directory },
|
||||
},
|
||||
data: [],
|
||||
})
|
||||
if (emptyObject.has(path)) return json(route, {})
|
||||
if (emptyList.has(path)) return json(route, [])
|
||||
if (path in staticRoutes) return json(route, staticRoutes[path])
|
||||
@@ -84,18 +72,6 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) {
|
||||
return json(route, session ?? {})
|
||||
}
|
||||
|
||||
const projectMatch = path.match(/^\/project\/([^/]+)$/)
|
||||
if (projectMatch) return json(route, config.project)
|
||||
|
||||
const messageMatch = path.match(/^\/session\/([^/]+)\/message\/([^/]+)$/)
|
||||
if (messageMatch) {
|
||||
config.onMessage?.({ sessionID: messageMatch[1]!, messageID: messageMatch[2]! })
|
||||
if (config.messageDelay !== undefined) await new Promise((resolve) => setTimeout(resolve, config.messageDelay))
|
||||
const message = config.message?.(messageMatch[1]!, messageMatch[2]!)
|
||||
if (message === undefined) return json(route, { error: "Message not found" }, undefined, 404)
|
||||
return json(route, message)
|
||||
}
|
||||
|
||||
const todoMatch = path.match(/^\/session\/([^/]+)\/todo$/)
|
||||
if (todoMatch) return json(route, config.todos?.(todoMatch[1]!) ?? [])
|
||||
if (/^\/session\/[^/]+\/(children|diff)$/.test(path)) return json(route, [])
|
||||
@@ -106,8 +82,7 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) {
|
||||
const before = token ? cursors.get(token) : undefined
|
||||
if (token && !before) return json(route, { error: "Invalid cursor" }, undefined, 400)
|
||||
config.onMessages?.({ sessionID: messagesMatch[1], before, phase: "start" })
|
||||
await config.beforeMessagesResponse?.({ sessionID: messagesMatch[1]!, before })
|
||||
if (config.messageDelay !== undefined) await new Promise((resolve) => setTimeout(resolve, config.messageDelay))
|
||||
if (config.messageDelay) await new Promise((resolve) => setTimeout(resolve, config.messageDelay))
|
||||
const limit = Number(url.searchParams.get("limit") ?? 80)
|
||||
const pageData = config.pageMessages(messagesMatch[1], limit, before)
|
||||
config.onMessages?.({ sessionID: messagesMatch[1], before, phase: "end" })
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, For, Show } from "solid-js"
|
||||
import { FileIcon } from "@opencode-ai/ui/file-icon"
|
||||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
|
||||
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||
import { getDirectory, getFilename, getFilenameTruncated } from "@opencode-ai/core/util/path"
|
||||
import type { ContextItem } from "@/context/prompt"
|
||||
|
||||
@@ -27,7 +27,7 @@ export const PromptContextItems: Component<ContextItemsProps> = (props) => {
|
||||
const selected = props.active(item)
|
||||
|
||||
return (
|
||||
<TooltipV2
|
||||
<Tooltip
|
||||
value={
|
||||
<span class="flex max-w-[300px]">
|
||||
<span class="text-text-invert-base truncate-start [unicode-bidi:plaintext] min-w-0">
|
||||
@@ -78,7 +78,7 @@ export const PromptContextItems: Component<ContextItemsProps> = (props) => {
|
||||
{(comment) => <div class="text-12-regular text-text-strong ml-5 pr-1 truncate">{comment()}</div>}
|
||||
</Show>
|
||||
</div>
|
||||
</TooltipV2>
|
||||
</Tooltip>
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
|
||||
@@ -1,271 +0,0 @@
|
||||
import type { JSX } from "solid-js"
|
||||
import { Show, createEffect, onCleanup } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useSortable } from "@dnd-kit/solid/sortable"
|
||||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||
import { Tabs } from "@opencode-ai/ui/tabs"
|
||||
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
|
||||
import { Icon } from "@opencode-ai/ui/icon"
|
||||
import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2"
|
||||
import { isDefaultTitle as isDefaultTerminalTitle } from "@/context/terminal-title"
|
||||
import { useTerminal, type LocalPTY } from "@/context/terminal"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { focusTerminalById } from "@/pages/session/helpers"
|
||||
|
||||
export function SortableTerminalTabV2(props: {
|
||||
terminal: LocalPTY
|
||||
index: () => number
|
||||
newLayout: boolean
|
||||
onClose?: () => void
|
||||
}): JSX.Element {
|
||||
const terminal = useTerminal()
|
||||
const language = useLanguage()
|
||||
const sortable = useSortable({
|
||||
get id() {
|
||||
return props.terminal.id
|
||||
},
|
||||
get index() {
|
||||
return props.index()
|
||||
},
|
||||
})
|
||||
const [store, setStore] = createStore({
|
||||
editing: false,
|
||||
title: props.terminal.title,
|
||||
menuOpen: false,
|
||||
menuPosition: { x: 0, y: 0 },
|
||||
blurEnabled: false,
|
||||
})
|
||||
let input: HTMLInputElement | undefined
|
||||
let blurFrame: number | undefined
|
||||
let editRequested = false
|
||||
|
||||
const isDefaultTitle = () => {
|
||||
const number = props.terminal.titleNumber
|
||||
if (!Number.isFinite(number) || number <= 0) return false
|
||||
return isDefaultTerminalTitle(props.terminal.title, number)
|
||||
}
|
||||
|
||||
const label = () => {
|
||||
language.locale()
|
||||
if (props.terminal.title && !isDefaultTitle()) return props.terminal.title
|
||||
|
||||
const number = props.terminal.titleNumber
|
||||
if (Number.isFinite(number) && number > 0) return language.t("terminal.title.numbered", { number })
|
||||
if (props.terminal.title) return props.terminal.title
|
||||
return language.t("terminal.title")
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
const count = terminal.all().length
|
||||
void terminal.close(props.terminal.id)
|
||||
if (count === 1) {
|
||||
props.onClose?.()
|
||||
}
|
||||
}
|
||||
|
||||
const focus = () => {
|
||||
if (store.editing) return
|
||||
terminal.open(props.terminal.id)
|
||||
if (document.activeElement instanceof HTMLElement) document.activeElement.blur()
|
||||
focusTerminalById(props.terminal.id)
|
||||
}
|
||||
|
||||
const edit = (e?: Event) => {
|
||||
if (e) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
setStore("blurEnabled", false)
|
||||
setStore("title", props.terminal.title)
|
||||
setStore("editing", true)
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
if (!store.blurEnabled) return
|
||||
|
||||
const value = store.title.trim()
|
||||
if (value && value !== props.terminal.title) {
|
||||
terminal.update({ id: props.terminal.id, title: value })
|
||||
}
|
||||
setStore("editing", false)
|
||||
}
|
||||
|
||||
const keydown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault()
|
||||
save()
|
||||
return
|
||||
}
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault()
|
||||
setStore("editing", false)
|
||||
}
|
||||
}
|
||||
|
||||
const menu = (e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
setStore("menuPosition", { x: e.clientX, y: e.clientY })
|
||||
setStore("menuOpen", true)
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
if (!store.editing) return
|
||||
if (!input) return
|
||||
input.focus()
|
||||
input.select()
|
||||
if (blurFrame !== undefined) cancelAnimationFrame(blurFrame)
|
||||
blurFrame = requestAnimationFrame(() => {
|
||||
blurFrame = undefined
|
||||
setStore("blurEnabled", true)
|
||||
})
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
if (blurFrame === undefined) return
|
||||
cancelAnimationFrame(blurFrame)
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={sortable.ref}
|
||||
class="outline-none focus:outline-none focus-visible:outline-none"
|
||||
classList={{
|
||||
"h-full flex items-center": props.newLayout,
|
||||
"h-full": !props.newLayout,
|
||||
}}
|
||||
>
|
||||
<Show
|
||||
when={props.newLayout}
|
||||
fallback={
|
||||
<div class="relative h-full">
|
||||
<Tabs.Trigger
|
||||
value={props.terminal.id}
|
||||
onClick={focus}
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onContextMenu={menu}
|
||||
class="!shadow-none"
|
||||
classes={{
|
||||
button: "border-0 outline-none focus:outline-none focus-visible:outline-none !shadow-none !ring-0",
|
||||
}}
|
||||
closeButton={
|
||||
<IconButton
|
||||
icon="close"
|
||||
variant="ghost"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
close()
|
||||
}}
|
||||
aria-label={language.t("terminal.close")}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<span onDblClick={edit} classList={{ invisible: store.editing }}>
|
||||
{label()}
|
||||
</span>
|
||||
</Tabs.Trigger>
|
||||
<Show when={store.editing}>
|
||||
<div class="absolute inset-0 flex items-center px-3 bg-muted z-10 pointer-events-auto">
|
||||
<input
|
||||
ref={input}
|
||||
type="text"
|
||||
value={store.title}
|
||||
onInput={(e) => setStore("title", e.currentTarget.value)}
|
||||
onBlur={save}
|
||||
onKeyDown={keydown}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
class="bg-transparent border-none outline-none text-sm min-w-0 flex-1"
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
<DropdownMenu open={store.menuOpen} onOpenChange={(open) => setStore("menuOpen", open)}>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
class="fixed"
|
||||
style={{
|
||||
left: `${store.menuPosition.x}px`,
|
||||
top: `${store.menuPosition.y}px`,
|
||||
}}
|
||||
onCloseAutoFocus={(e) => {
|
||||
if (!editRequested) return
|
||||
e.preventDefault()
|
||||
editRequested = false
|
||||
requestAnimationFrame(() => edit())
|
||||
}}
|
||||
>
|
||||
<DropdownMenu.Item onSelect={() => (editRequested = true)}>
|
||||
<Icon name="edit" class="w-4 h-4 mr-2" />
|
||||
{language.t("common.rename")}
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onSelect={close}>
|
||||
<Icon name="close" class="w-4 h-4 mr-2" />
|
||||
{language.t("common.close")}
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<MenuV2.Context>
|
||||
<MenuV2.Context.Trigger class="relative" as="div">
|
||||
<Tabs.Trigger
|
||||
value={props.terminal.id}
|
||||
onClick={focus}
|
||||
closeButton={
|
||||
<IconButton
|
||||
icon="close-small"
|
||||
variant="ghost"
|
||||
class="h-5 w-5"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
close()
|
||||
}}
|
||||
aria-label={language.t("terminal.close")}
|
||||
/>
|
||||
}
|
||||
hideCloseButton
|
||||
onMiddleClick={close}
|
||||
>
|
||||
<span
|
||||
class="truncate"
|
||||
data-slot="terminal-tab-title"
|
||||
onDblClick={edit}
|
||||
classList={{ invisible: store.editing }}
|
||||
>
|
||||
{label()}
|
||||
</span>
|
||||
</Tabs.Trigger>
|
||||
<Show when={store.editing}>
|
||||
<div class="absolute inset-0 flex items-center bg-v2-background-bg-layer-01 z-10 pointer-events-auto rounded-[6px] shadow-[inset_0_0_0_0.5px_var(--v2-border-border-muted)] px-2">
|
||||
<input
|
||||
ref={input}
|
||||
type="text"
|
||||
value={store.title}
|
||||
onInput={(e) => setStore("title", e.currentTarget.value)}
|
||||
onBlur={save}
|
||||
onKeyDown={keydown}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
class="bg-transparent border-none outline-none min-w-0 flex-1 p-0 text-[13px] leading-4 tracking-[-0.04px] text-v2-text-text-base [font-weight:440] [font-variation-settings:'slnt'_0] [font-variant-numeric:tabular-nums]"
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
</MenuV2.Context.Trigger>
|
||||
<MenuV2.Context.Portal>
|
||||
<MenuV2.Context.Content
|
||||
onCloseAutoFocus={(e) => {
|
||||
if (!editRequested) return
|
||||
e.preventDefault()
|
||||
editRequested = false
|
||||
requestAnimationFrame(() => edit())
|
||||
}}
|
||||
>
|
||||
<MenuV2.Item onSelect={() => (editRequested = true)}>{language.t("common.rename")}</MenuV2.Item>
|
||||
<MenuV2.Item onSelect={close}>{language.t("common.close")}</MenuV2.Item>
|
||||
</MenuV2.Context.Content>
|
||||
</MenuV2.Context.Portal>
|
||||
</MenuV2.Context>
|
||||
</Show>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { createSignal, Show, type JSXElement } from "solid-js"
|
||||
import "./titlebar-tab-popover.css"
|
||||
|
||||
// Initial hover delay before the preview appears, per design.
|
||||
const OPEN_DELAY = 2_000
|
||||
const OPEN_DELAY = 400
|
||||
// Mouse-out delay: begin closing immediately (a brief exit animation plays).
|
||||
const CLOSE_DELAY = 0
|
||||
// After a preview closes, hovering a neighbouring tab within this window skips
|
||||
|
||||
@@ -17,6 +17,8 @@ import { createTabPromptState } from "@/context/prompt"
|
||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||
import { canStartTabDrag, isTabCloseTarget } from "./titlebar-tab-gesture"
|
||||
|
||||
const sortableTransition = { duration: 0 }
|
||||
|
||||
function SessionTabSlot(props: {
|
||||
tab: SessionTab
|
||||
id: string
|
||||
|
||||
@@ -374,16 +374,9 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
|
||||
keybind: "mod+w",
|
||||
hidden: true,
|
||||
onSelect: () => {
|
||||
tabsStoreActions.closeTab(tabsStore.findIndex((tab) => current === tab))
|
||||
tabsStoreActions.removeTab(tabsStore.findIndex((tab) => current === tab))
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "tab.reopenClosed",
|
||||
category: language.t("command.category.file"),
|
||||
title: language.t("command.tab.reopenClosed"),
|
||||
keybind: "mod+shift+t",
|
||||
onSelect: () => tabsStoreActions.reopenClosedTab(),
|
||||
},
|
||||
{
|
||||
id: `tab.prev`,
|
||||
category: "tab",
|
||||
@@ -471,7 +464,7 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
|
||||
}}
|
||||
onClose={(tab) => {
|
||||
const index = tabsStore.findIndex((item) => tabKey(item) === tabKey(tab))
|
||||
if (index !== -1) tabsStoreActions.closeTab(index)
|
||||
if (index !== -1) tabsStoreActions.removeTab(index)
|
||||
}}
|
||||
onReorder={(keys) => tabsStoreActions.reorder(keys)}
|
||||
/>
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import type { SessionTab, Tab } from "./tabs"
|
||||
|
||||
export type ClosedTab = {
|
||||
tab: SessionTab
|
||||
index: number
|
||||
}
|
||||
|
||||
const CLOSED_TAB_LIMIT = 25
|
||||
|
||||
// Only session tabs are recorded; closing a draft tab deletes its persisted
|
||||
// state, so a reopened draft would come back empty anyway.
|
||||
export function pushClosedTab(stack: ClosedTab[], tab: Tab, index: number): ClosedTab[] {
|
||||
if (tab.type !== "session") return stack
|
||||
return [...stack, { tab: { ...tab }, index }].slice(-CLOSED_TAB_LIMIT)
|
||||
}
|
||||
|
||||
// Pops the most recently closed tab that is not open again,
|
||||
// discarding stale entries along the way.
|
||||
export function takeClosedTab(stack: ClosedTab[], tabs: Tab[]): { entry?: ClosedTab; stack: ClosedTab[] } {
|
||||
const remaining = [...stack]
|
||||
while (remaining.length) {
|
||||
const entry = remaining.pop()
|
||||
if (entry && !isOpen(tabs, entry.tab)) return { entry, stack: remaining }
|
||||
}
|
||||
return { stack: remaining }
|
||||
}
|
||||
|
||||
export function removeClosedTabs(stack: ClosedTab[], server: SessionTab["server"], sessionIDs: string[]) {
|
||||
const removed = new Set(sessionIDs)
|
||||
return stack.filter((entry) => entry.tab.server !== server || !removed.has(entry.tab.sessionId))
|
||||
}
|
||||
|
||||
export function nextTabAfterClose(tabs: Tab[], index: number, active: boolean) {
|
||||
if (!active) return undefined
|
||||
return tabs[index + 1] ?? tabs[index - 1] ?? null
|
||||
}
|
||||
|
||||
function isOpen(tabs: Tab[], tab: SessionTab) {
|
||||
return tabs.some((item) => item.type === "session" && item.server === tab.server && item.sessionId === tab.sessionId)
|
||||
}
|
||||
@@ -15,13 +15,11 @@ const session = (id: string, parentID?: string): Session => ({
|
||||
})
|
||||
|
||||
type UserMessage = Extract<Message, { role: "user" }>
|
||||
type AssistantMessage = Extract<Message, { role: "assistant" }>
|
||||
type TextPart = Extract<Part, { type: "text" }>
|
||||
type MessageResponse = {
|
||||
data: { info: Message; parts: Part[] }[]
|
||||
response: { headers: Headers }
|
||||
}
|
||||
type SingleMessageResponse = { data: MessageResponse["data"][number] }
|
||||
|
||||
const userMessage = (id: string, input: Partial<UserMessage> = {}): UserMessage => ({
|
||||
id,
|
||||
@@ -33,22 +31,6 @@ const userMessage = (id: string, input: Partial<UserMessage> = {}): UserMessage
|
||||
...input,
|
||||
})
|
||||
|
||||
const assistantMessage = (id: string, parentID: string, input: Partial<AssistantMessage> = {}): AssistantMessage => ({
|
||||
id,
|
||||
sessionID: "child",
|
||||
role: "assistant",
|
||||
time: { created: Number(id.at(-1)), completed: Number(id.at(-1)) },
|
||||
parentID,
|
||||
modelID: "model",
|
||||
providerID: "provider",
|
||||
mode: "build",
|
||||
agent: "build",
|
||||
path: { cwd: "/repo", root: "/repo" },
|
||||
cost: 0,
|
||||
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
||||
...input,
|
||||
})
|
||||
|
||||
const textPart = (messageID: string, input: Partial<TextPart> = {}): TextPart => ({
|
||||
id: "part",
|
||||
sessionID: "child",
|
||||
@@ -63,8 +45,6 @@ const response = (data: MessageResponse["data"] = [], cursor?: string): MessageR
|
||||
response: { headers: new Headers(cursor ? { "x-next-cursor": cursor } : undefined) },
|
||||
})
|
||||
|
||||
const singleResponse = (info: Message, parts: Part[] = []): SingleMessageResponse => ({ data: { info, parts } })
|
||||
|
||||
const deferredResponse = () => Promise.withResolvers<MessageResponse>()
|
||||
|
||||
function messageClient(...responses: Array<MessageResponse | Promise<MessageResponse>>) {
|
||||
@@ -91,40 +71,6 @@ function messageClient(...responses: Array<MessageResponse | Promise<MessageResp
|
||||
})
|
||||
}
|
||||
|
||||
function rootMessageClient(
|
||||
pages: Array<MessageResponse | Promise<MessageResponse>>,
|
||||
roots: Array<SingleMessageResponse | Promise<SingleMessageResponse>>,
|
||||
) {
|
||||
let pageIndex = 0
|
||||
let rootIndex = 0
|
||||
const requests: unknown[] = []
|
||||
const rootRequests: unknown[] = []
|
||||
const rootWaiting = new Map<number, () => void>()
|
||||
const client = {
|
||||
session: {
|
||||
get: async () => ({ data: session("child", "root") }),
|
||||
messages: (input: unknown) => {
|
||||
requests.push(input)
|
||||
return pages[pageIndex++]
|
||||
},
|
||||
message: (input: unknown) => {
|
||||
rootRequests.push(input)
|
||||
rootWaiting.get(rootRequests.length)?.()
|
||||
rootWaiting.delete(rootRequests.length)
|
||||
return roots[rootIndex++]
|
||||
},
|
||||
},
|
||||
} as unknown as OpencodeClient
|
||||
return Object.assign(client, {
|
||||
requests,
|
||||
rootRequests,
|
||||
rootRequested(count: number) {
|
||||
if (rootRequests.length >= count) return Promise.resolve()
|
||||
return new Promise<void>((resolve) => rootWaiting.set(count, resolve))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const retryImmediately: typeof retry = async (task, options = {}) => {
|
||||
const attempts = options.attempts ?? 3
|
||||
for (let attempt = 0; ; attempt++) {
|
||||
@@ -178,238 +124,6 @@ describe("server session", () => {
|
||||
expect(ctx.store.data.message.root).toEqual([])
|
||||
})
|
||||
|
||||
test("backfills an assistant-only initial page through its user root", async () => {
|
||||
const user = userMessage("message-1")
|
||||
const assistants = [assistantMessage("message-2", user.id), assistantMessage("message-3", user.id)]
|
||||
const client = rootMessageClient(
|
||||
[
|
||||
response(
|
||||
assistants.map((info) => ({ info, parts: [] })),
|
||||
"older",
|
||||
),
|
||||
],
|
||||
[singleResponse(user)],
|
||||
)
|
||||
const store = createServerSession(client)
|
||||
|
||||
await store.sync("child")
|
||||
|
||||
expect(client.requests).toEqual([{ sessionID: "child", limit: 2, before: undefined }])
|
||||
expect(client.rootRequests).toEqual([{ sessionID: "child", messageID: user.id }])
|
||||
expect(store.data.message.child).toEqual([user, ...assistants])
|
||||
expect(store.history.more("child")).toBe(true)
|
||||
})
|
||||
|
||||
test("does not let an optimistic user suppress initial root backfill", async () => {
|
||||
const user = userMessage("message-1")
|
||||
const part = textPart(user.id)
|
||||
const assistants = [assistantMessage("message-2", user.id), assistantMessage("message-3", user.id)]
|
||||
const client = rootMessageClient(
|
||||
[
|
||||
response(
|
||||
assistants.map((info) => ({ info, parts: [] })),
|
||||
"older",
|
||||
),
|
||||
],
|
||||
[singleResponse(user)],
|
||||
)
|
||||
const store = createServerSession(client)
|
||||
store.optimistic.add({ sessionID: "child", message: user, parts: [part] })
|
||||
|
||||
await store.sync("child")
|
||||
store.optimistic.remove({ sessionID: "child", messageID: user.id })
|
||||
|
||||
expect(client.requests).toHaveLength(1)
|
||||
expect(client.rootRequests).toHaveLength(1)
|
||||
expect(store.data.message.child).toEqual([user, ...assistants])
|
||||
})
|
||||
|
||||
test("backfills the parent of fetched assistants when another user is cached", async () => {
|
||||
const unrelated = userMessage("message-0", { time: { created: 0 } })
|
||||
const user = userMessage("message-1")
|
||||
const assistants = [assistantMessage("message-2", user.id), assistantMessage("message-3", user.id)]
|
||||
const client = rootMessageClient(
|
||||
[
|
||||
response([{ info: unrelated, parts: [] }]),
|
||||
response(
|
||||
assistants.map((info) => ({ info, parts: [] })),
|
||||
"older",
|
||||
),
|
||||
],
|
||||
[singleResponse(user)],
|
||||
)
|
||||
const store = createServerSession(client)
|
||||
await store.sync("child")
|
||||
|
||||
await store.sync("child", { force: true })
|
||||
|
||||
expect(client.requests).toHaveLength(2)
|
||||
expect(client.rootRequests).toHaveLength(1)
|
||||
expect(store.data.message.child).toEqual([unrelated, user, ...assistants])
|
||||
})
|
||||
|
||||
test("preserves cached history between an injected parent and the page boundary", async () => {
|
||||
const user = userMessage("message-1")
|
||||
const cached = userMessage("message-3", { time: { created: 3 } })
|
||||
const assistant = assistantMessage("message-4", user.id)
|
||||
const client = rootMessageClient(
|
||||
[response([{ info: cached, parts: [] }]), response([{ info: assistant, parts: [] }], "older")],
|
||||
[singleResponse(user)],
|
||||
)
|
||||
const store = createServerSession(client)
|
||||
await store.sync("child")
|
||||
|
||||
await store.sync("child", { force: true })
|
||||
|
||||
expect(store.data.message.child).toEqual([user, cached, assistant])
|
||||
})
|
||||
|
||||
test("refreshes a cached parent omitted by an assistant-only replacement page", async () => {
|
||||
const stale = userMessage("message-1", { summary: { title: "stale", diffs: [] } })
|
||||
const fresh = { ...stale, summary: { title: "fresh", diffs: [] } }
|
||||
const stalePart = textPart(stale.id, { text: "stale" })
|
||||
const freshPart = { ...stalePart, text: "fresh" }
|
||||
const assistant = assistantMessage("message-2", stale.id)
|
||||
const client = rootMessageClient(
|
||||
[response([{ info: stale, parts: [stalePart] }]), response([{ info: assistant, parts: [] }], "older")],
|
||||
[singleResponse(fresh, [freshPart])],
|
||||
)
|
||||
const store = createServerSession(client)
|
||||
await store.sync("child")
|
||||
|
||||
await store.sync("child", { force: true })
|
||||
|
||||
expect(client.rootRequests).toEqual([{ sessionID: "child", messageID: stale.id }])
|
||||
expect(store.data.message.child).toEqual([fresh, assistant])
|
||||
expect(store.data.part[stale.id]).toEqual([freshPart])
|
||||
})
|
||||
|
||||
test("refreshes a confirmed optimistic parent while preserving pending parts", async () => {
|
||||
const stale = userMessage("message-1", { summary: { title: "stale", diffs: [] } })
|
||||
const fresh = { ...stale, summary: { title: "fresh", diffs: [] } }
|
||||
const confirmed = textPart(stale.id, { id: "confirmed", text: "stale" })
|
||||
const refreshed = { ...confirmed, text: "fresh" }
|
||||
const pending = textPart(stale.id, { id: "pending", text: "pending" })
|
||||
const assistant = assistantMessage("message-2", stale.id)
|
||||
const client = rootMessageClient(
|
||||
[response([{ info: stale, parts: [confirmed] }]), response([{ info: assistant, parts: [] }], "older")],
|
||||
[singleResponse(fresh, [refreshed])],
|
||||
)
|
||||
const store = createServerSession(client)
|
||||
store.optimistic.add({ sessionID: "child", message: stale, parts: [confirmed, pending] })
|
||||
await store.sync("child")
|
||||
|
||||
await store.sync("child", { force: true })
|
||||
|
||||
expect(client.rootRequests).toEqual([{ sessionID: "child", messageID: stale.id }])
|
||||
expect(store.data.message.child).toEqual([fresh, assistant])
|
||||
expect(store.data.part[stale.id]).toEqual([refreshed, pending])
|
||||
})
|
||||
|
||||
test("uses a parent received by SSE during the replacement load", async () => {
|
||||
const pending = deferredResponse()
|
||||
const user = userMessage("message-1")
|
||||
const assistant = assistantMessage("message-2", user.id)
|
||||
const client = rootMessageClient([pending.promise], [])
|
||||
const store = createServerSession(client)
|
||||
const loading = store.sync("child")
|
||||
|
||||
store.apply({ type: "message.updated", properties: { info: user } })
|
||||
pending.resolve(response([{ info: assistant, parts: [] }], "older"))
|
||||
await loading
|
||||
|
||||
expect(client.rootRequests).toEqual([])
|
||||
expect(store.data.message.child).toEqual([user, assistant])
|
||||
})
|
||||
|
||||
test("uses a successful retry over events received by a failed backfill attempt", async () => {
|
||||
const failed = deferredResponse()
|
||||
const user = userMessage("message-1")
|
||||
const live = { ...user, agent: "stale" }
|
||||
const assistants = [assistantMessage("message-2", user.id), assistantMessage("message-3", user.id)]
|
||||
const client = rootMessageClient(
|
||||
[
|
||||
response(
|
||||
assistants.map((info) => ({ info, parts: [] })),
|
||||
"older",
|
||||
),
|
||||
],
|
||||
[failed.promise.then((result) => ({ data: result.data[0]! })), singleResponse(user)],
|
||||
)
|
||||
const store = createServerSession(client, { retry: retryImmediately })
|
||||
const loading = store.sync("child")
|
||||
await client.rootRequested(1)
|
||||
|
||||
store.apply({ type: "message.updated", properties: { info: live } })
|
||||
failed.reject(new Error("retry"))
|
||||
await loading
|
||||
|
||||
expect(client.requests).toHaveLength(1)
|
||||
expect(client.rootRequests).toHaveLength(2)
|
||||
expect(store.data.message.child).toEqual([user, ...assistants])
|
||||
})
|
||||
|
||||
test("preserves newer-page events across a failed parent retry", async () => {
|
||||
const failed = deferredResponse()
|
||||
const user = userMessage("message-1")
|
||||
const assistant = assistantMessage("message-2", user.id)
|
||||
const live = { ...assistant, cost: 1 }
|
||||
const client = rootMessageClient(
|
||||
[response([{ info: assistant, parts: [] }], "older")],
|
||||
[failed.promise.then((result) => ({ data: result.data[0]! })), singleResponse(user)],
|
||||
)
|
||||
const store = createServerSession(client, { retry: retryImmediately })
|
||||
const loading = store.sync("child")
|
||||
await client.rootRequested(1)
|
||||
|
||||
store.apply({ type: "message.updated", properties: { info: live } })
|
||||
failed.reject(new Error("retry"))
|
||||
await loading
|
||||
|
||||
expect(store.data.message.child).toEqual([user, live])
|
||||
})
|
||||
|
||||
test("preserves unrelated message events across a failed parent retry", async () => {
|
||||
const failed = deferredResponse()
|
||||
const user = userMessage("message-1")
|
||||
const assistant = assistantMessage("message-2", user.id)
|
||||
const live = userMessage("message-4", { time: { created: 4 } })
|
||||
const client = rootMessageClient(
|
||||
[response([{ info: assistant, parts: [] }], "older")],
|
||||
[failed.promise.then((result) => ({ data: result.data[0]! })), singleResponse(user)],
|
||||
)
|
||||
const store = createServerSession(client, { retry: retryImmediately })
|
||||
const loading = store.sync("child")
|
||||
await client.rootRequested(1)
|
||||
|
||||
store.apply({ type: "message.updated", properties: { info: live } })
|
||||
failed.reject(new Error("retry"))
|
||||
await loading
|
||||
|
||||
expect(store.data.message.child).toEqual([user, assistant, live])
|
||||
})
|
||||
|
||||
test("preserves newer-page part events across a failed parent retry", async () => {
|
||||
const failed = deferredResponse()
|
||||
const user = userMessage("message-1")
|
||||
const assistant = assistantMessage("message-2", user.id)
|
||||
const stale = textPart(assistant.id, { text: "stale" })
|
||||
const live = { ...stale, text: "live" }
|
||||
const client = rootMessageClient(
|
||||
[response([{ info: assistant, parts: [stale] }], "older")],
|
||||
[failed.promise.then((result) => ({ data: result.data[0]! })), singleResponse(user)],
|
||||
)
|
||||
const store = createServerSession(client, { retry: retryImmediately })
|
||||
const loading = store.sync("child")
|
||||
await client.rootRequested(1)
|
||||
|
||||
store.apply({ type: "message.part.updated", properties: { sessionID: "child", part: live, time: 2 } })
|
||||
failed.reject(new Error("retry"))
|
||||
await loading
|
||||
|
||||
expect(store.data.part[assistant.id]).toEqual([live])
|
||||
})
|
||||
|
||||
test("merges live events into the initial page", async () => {
|
||||
const pending = deferredResponse()
|
||||
const user = userMessage("message-1")
|
||||
@@ -1191,26 +905,6 @@ describe("server session", () => {
|
||||
expect(store.data.message.child).toEqual([latest])
|
||||
})
|
||||
|
||||
test("does not scan cached messages for user roots during history prepend", async () => {
|
||||
const guard = { active: false }
|
||||
const latest = new Proxy(userMessage("message-2", { time: { created: 2 } }), {
|
||||
get(target, property, receiver) {
|
||||
if (guard.active && property === "role") throw new Error("cached role accessed")
|
||||
return Reflect.get(target, property, receiver)
|
||||
},
|
||||
})
|
||||
const older = userMessage("message-1")
|
||||
const store = createServerSession(
|
||||
messageClient(response([{ info: latest, parts: [] }], "older"), response([{ info: older, parts: [] }])),
|
||||
)
|
||||
await store.sync("child")
|
||||
guard.active = true
|
||||
|
||||
await store.history.loadMore("child")
|
||||
|
||||
expect(store.data.message.child).toEqual([older, latest])
|
||||
})
|
||||
|
||||
test("preserves loaded history during an incomplete refresh", async () => {
|
||||
const older = userMessage("message-1")
|
||||
const latest = userMessage("message-2", { time: { created: 2 } })
|
||||
|
||||
@@ -54,11 +54,6 @@ type MessageLoadState = {
|
||||
clearedMessageParts: Set<string>
|
||||
}
|
||||
|
||||
type MessageLoadBaseline = Pick<
|
||||
MessageLoadState,
|
||||
"touchedMessages" | "retainedMessages" | "touchedParts" | "clearedMessageParts"
|
||||
>
|
||||
|
||||
function mergeOptimisticPage(page: MessagePage, items: OptimisticItem[]) {
|
||||
if (items.length === 0) return { ...page, observed: [] as { messageID: string; parts: Part[] }[] }
|
||||
const session = [...page.session]
|
||||
@@ -352,7 +347,7 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
|
||||
load.touchedParts.set(messageID, new Set([partID]))
|
||||
}
|
||||
|
||||
const resetMessageLoad = (sessionID: string, load: MessageLoadState, baseline?: MessageLoadBaseline) => {
|
||||
const resetMessageLoad = (sessionID: string, load: MessageLoadState) => {
|
||||
load.touchedMessages.clear()
|
||||
load.retainedMessages.clear()
|
||||
load.touchedParts.clear()
|
||||
@@ -385,27 +380,8 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
|
||||
parts.forEach((partID) => touched.add(partID))
|
||||
load.touchedParts.set(messageID, touched)
|
||||
}
|
||||
baseline?.touchedMessages.forEach((messageID) => load.touchedMessages.add(messageID))
|
||||
baseline?.retainedMessages.forEach((messageID) => load.retainedMessages.add(messageID))
|
||||
baseline?.clearedMessageParts.forEach((messageID) => load.clearedMessageParts.add(messageID))
|
||||
baseline?.touchedParts.forEach((parts, messageID) => {
|
||||
const touched = load.touchedParts.get(messageID) ?? new Set<string>()
|
||||
parts.forEach((partID) => touched.add(partID))
|
||||
load.touchedParts.set(messageID, touched)
|
||||
})
|
||||
}
|
||||
|
||||
const messageLoadBaseline = (load: MessageLoadState, exclude: string): MessageLoadBaseline => ({
|
||||
touchedMessages: new Set([...load.touchedMessages].filter((messageID) => messageID !== exclude)),
|
||||
retainedMessages: new Set([...load.retainedMessages].filter((messageID) => messageID !== exclude)),
|
||||
touchedParts: new Map(
|
||||
[...load.touchedParts]
|
||||
.filter(([messageID]) => messageID !== exclude)
|
||||
.map(([messageID, parts]) => [messageID, new Set(parts)]),
|
||||
),
|
||||
clearedMessageParts: new Set([...load.clearedMessageParts].filter((messageID) => messageID !== exclude)),
|
||||
})
|
||||
|
||||
const evict = (sessionIDs: string[]) => {
|
||||
if (sessionIDs.length === 0) return
|
||||
const evicted = new Set(sessionIDs)
|
||||
@@ -484,18 +460,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
|
||||
}
|
||||
}
|
||||
|
||||
const fetchMessage = async (sessionID: string, messageID: string, onAttempt?: () => void) => {
|
||||
const response = await (options?.retry ?? retry)(() => {
|
||||
onAttempt?.()
|
||||
return client.session.message({ sessionID, messageID })
|
||||
})
|
||||
if (!response.data?.info?.id) throw new Error(`Message not found: ${messageID}`)
|
||||
return {
|
||||
message: cleanMessage(response.data.info),
|
||||
parts: response.data.parts.filter((part) => !!part?.id).sort((a, b) => cmp(a.id, b.id)),
|
||||
}
|
||||
}
|
||||
|
||||
const replaceMessages = (sessionID: string, messages: Message[]) => {
|
||||
const messageIDs = new Set(messages.map((message) => message.id))
|
||||
const dropped = (data.message[sessionID] ?? []).filter((message) => !messageIDs.has(message.id))
|
||||
@@ -614,79 +578,36 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
|
||||
messageLoads.set(sessionID, load)
|
||||
setMeta("loading", sessionID, true)
|
||||
let applied = false
|
||||
try {
|
||||
const page = await fetchMessages(sessionID, limit, before, () => resetMessageLoad(sessionID, load))
|
||||
const first = page.session.reduce<Message | undefined>(
|
||||
(oldest, message) => (!oldest || cmpMessage(message, oldest) < 0 ? message : oldest),
|
||||
undefined,
|
||||
)
|
||||
if (generations.get(sessionID) !== active) return
|
||||
|
||||
const parents = [] as Awaited<ReturnType<typeof fetchMessage>>[]
|
||||
if (mode !== "prepend") {
|
||||
const users = new Set([
|
||||
...page.session.filter((message) => message.role === "user").map((message) => message.id),
|
||||
...(data.message[sessionID] ?? [])
|
||||
.filter((message) => {
|
||||
if (message.role !== "user") return false
|
||||
const item = optimistic.get(sessionID)?.get(message.id)
|
||||
return load.touchedMessages.has(message.id) && (!item || item.confirmedMessage === true)
|
||||
})
|
||||
.map((message) => message.id),
|
||||
])
|
||||
const parentIDs = [
|
||||
...new Set(
|
||||
page.session.flatMap((message) =>
|
||||
message.role === "assistant" && !users.has(message.parentID) ? [message.parentID] : [],
|
||||
),
|
||||
),
|
||||
]
|
||||
for (const parentID of parentIDs) {
|
||||
if (generations.get(sessionID) !== active) break
|
||||
const parent = await fetchMessage(sessionID, parentID, () =>
|
||||
resetMessageLoad(sessionID, load, messageLoadBaseline(load, parentID)),
|
||||
)
|
||||
if (parent.message.role !== "user") throw new Error(`Assistant parent is not a user message: ${parentID}`)
|
||||
parents.push(parent)
|
||||
await fetchMessages(sessionID, limit, before, () => resetMessageLoad(sessionID, load))
|
||||
.then((page) => {
|
||||
if (generations.get(sessionID) !== active) return
|
||||
const first = page.session.reduce<Message | undefined>(
|
||||
(oldest, message) => (!oldest || cmpMessage(message, oldest) < 0 ? message : oldest),
|
||||
undefined,
|
||||
)
|
||||
const preserveUnfetched =
|
||||
mode === "prepend" || (!page.complete && (!first || ((message: Message) => cmpMessage(message, first) < 0)))
|
||||
applyMessagePage(
|
||||
sessionID,
|
||||
page,
|
||||
messageLoads.get(sessionID) === load ? load : undefined,
|
||||
preserveUnfetched,
|
||||
mode !== "prepend",
|
||||
)
|
||||
applied = true
|
||||
})
|
||||
.finally(() => {
|
||||
if (!applied && generations.get(sessionID) === active && messageLoads.get(sessionID) === load) {
|
||||
for (const messageID of load.orphanParents) {
|
||||
if (!orphanParts.get(sessionID)?.has(messageID)) continue
|
||||
setData(produce((draft) => deleteMessageParts(draft, messageID)))
|
||||
orphanParts.get(sessionID)?.delete(messageID)
|
||||
}
|
||||
if (orphanParts.get(sessionID)?.size === 0) orphanParts.delete(sessionID)
|
||||
}
|
||||
}
|
||||
if (generations.get(sessionID) !== active) return
|
||||
const result =
|
||||
mode === "prepend"
|
||||
? page
|
||||
: {
|
||||
...page,
|
||||
session: merge(
|
||||
page.session,
|
||||
parents.map((parent) => parent.message),
|
||||
),
|
||||
part: merge(
|
||||
page.part,
|
||||
parents.map((parent) => ({ id: parent.message.id, part: parent.parts })),
|
||||
),
|
||||
}
|
||||
const preserveUnfetched =
|
||||
mode === "prepend" || (!result.complete && (!first || ((message: Message) => cmpMessage(message, first) < 0)))
|
||||
applyMessagePage(
|
||||
sessionID,
|
||||
result,
|
||||
messageLoads.get(sessionID) === load ? load : undefined,
|
||||
preserveUnfetched,
|
||||
mode !== "prepend",
|
||||
)
|
||||
applied = true
|
||||
} finally {
|
||||
if (!applied && generations.get(sessionID) === active && messageLoads.get(sessionID) === load) {
|
||||
for (const messageID of load.orphanParents) {
|
||||
if (!orphanParts.get(sessionID)?.has(messageID)) continue
|
||||
setData(produce((draft) => deleteMessageParts(draft, messageID)))
|
||||
orphanParts.get(sessionID)?.delete(messageID)
|
||||
}
|
||||
if (orphanParts.get(sessionID)?.size === 0) orphanParts.delete(sessionID)
|
||||
}
|
||||
if (messageLoads.get(sessionID) === load) messageLoads.delete(sessionID)
|
||||
if (generations.get(sessionID) === active) setMeta("loading", sessionID, false)
|
||||
}
|
||||
if (messageLoads.get(sessionID) === load) messageLoads.delete(sessionID)
|
||||
if (generations.get(sessionID) === active) setMeta("loading", sessionID, false)
|
||||
})
|
||||
}
|
||||
|
||||
const sync = (sessionID: string, options?: { force?: boolean; messageLimit?: number }) => {
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { createRoot, getOwner, onCleanup } from "solid-js"
|
||||
import { createTabMemory } from "./tab-memory"
|
||||
import { nextTabAfterClose, pushClosedTab, removeClosedTabs, takeClosedTab, type ClosedTab } from "./closed-tabs"
|
||||
import type { SessionTab, Tab } from "./tabs"
|
||||
import type { ServerConnection } from "./server"
|
||||
|
||||
const server = "local\nhttp://localhost:4096" as ServerConnection.Key
|
||||
|
||||
function sessionTab(sessionId: string): SessionTab {
|
||||
return { type: "session", server, sessionId }
|
||||
}
|
||||
|
||||
describe("tab memory", () => {
|
||||
test("keeps state until its tab is removed", () => {
|
||||
@@ -31,75 +22,3 @@ describe("tab memory", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("closed tab stack", () => {
|
||||
test("records session tabs with their index", () => {
|
||||
const stack = pushClosedTab([], sessionTab("a"), 2)
|
||||
|
||||
expect(stack).toEqual([{ tab: sessionTab("a"), index: 2 }])
|
||||
})
|
||||
|
||||
test("ignores draft tabs", () => {
|
||||
const draft: Tab = { type: "draft", draftID: "d1", server, directory: "/tmp" }
|
||||
|
||||
expect(pushClosedTab([], draft, 0)).toEqual([])
|
||||
})
|
||||
|
||||
test("caps the stack size", () => {
|
||||
const stack = Array.from({ length: 30 }, (_, i) => i).reduce<ClosedTab[]>(
|
||||
(acc, i) => pushClosedTab(acc, sessionTab(`s${i}`), i),
|
||||
[],
|
||||
)
|
||||
|
||||
expect(stack).toHaveLength(25)
|
||||
expect(stack[0]?.tab.sessionId).toBe("s5")
|
||||
expect(stack.at(-1)?.tab.sessionId).toBe("s29")
|
||||
})
|
||||
|
||||
test("pops the most recently closed tab", () => {
|
||||
const stack = [
|
||||
{ tab: sessionTab("a"), index: 0 },
|
||||
{ tab: sessionTab("b"), index: 1 },
|
||||
]
|
||||
const result = takeClosedTab(stack, [])
|
||||
|
||||
expect(result.entry?.tab.sessionId).toBe("b")
|
||||
expect(result.stack).toEqual([{ tab: sessionTab("a"), index: 0 }])
|
||||
})
|
||||
|
||||
test("skips entries whose tab is already open", () => {
|
||||
const stack = [
|
||||
{ tab: sessionTab("a"), index: 0 },
|
||||
{ tab: sessionTab("b"), index: 1 },
|
||||
]
|
||||
const result = takeClosedTab(stack, [sessionTab("b")])
|
||||
|
||||
expect(result.entry?.tab.sessionId).toBe("a")
|
||||
expect(result.stack).toEqual([])
|
||||
})
|
||||
|
||||
test("returns no entry when everything is open or empty", () => {
|
||||
expect(takeClosedTab([], []).entry).toBeUndefined()
|
||||
|
||||
const result = takeClosedTab([{ tab: sessionTab("a"), index: 0 }], [sessionTab("a")])
|
||||
expect(result.entry).toBeUndefined()
|
||||
expect(result.stack).toEqual([])
|
||||
})
|
||||
|
||||
test("purges removed sessions", () => {
|
||||
const stack = [
|
||||
{ tab: sessionTab("a"), index: 0 },
|
||||
{ tab: sessionTab("b"), index: 1 },
|
||||
]
|
||||
|
||||
expect(removeClosedTabs(stack, server, ["a"])).toEqual([{ tab: sessionTab("b"), index: 1 }])
|
||||
})
|
||||
|
||||
test("does not navigate when a background tab closes", () => {
|
||||
const tabs = [sessionTab("a"), sessionTab("b"), sessionTab("c")]
|
||||
|
||||
expect(nextTabAfterClose(tabs, 1, false)).toBeUndefined()
|
||||
expect(nextTabAfterClose(tabs, 1, true)).toEqual(sessionTab("c"))
|
||||
expect(nextTabAfterClose([sessionTab("a")], 0, true)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -10,7 +10,6 @@ import { uuid } from "@/utils/uuid"
|
||||
import { SessionTabsRemovedDetail } from "@/components/titlebar-session-events"
|
||||
import { sessionHref } from "@/utils/session-route"
|
||||
import { createTabMemory } from "./tab-memory"
|
||||
import { nextTabAfterClose, pushClosedTab, removeClosedTabs, takeClosedTab, type ClosedTab } from "./closed-tabs"
|
||||
|
||||
export type SessionTab = {
|
||||
type: "session"
|
||||
@@ -64,7 +63,6 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||
createStore<Tab[]>([]),
|
||||
)
|
||||
const [recent, setRecent, , recentReady] = persisted(Persist.window("tabs.recent"), createStore<RecentTab>({}))
|
||||
const [closed, setClosed, , closedReady] = persisted(Persist.window("tabs.closed"), createStore<ClosedTab[]>([]))
|
||||
|
||||
const params = useParams()
|
||||
const navigate = useNavigate()
|
||||
@@ -89,15 +87,6 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||
})
|
||||
}
|
||||
|
||||
const updateClosed = (update: (stack: ClosedTab[]) => ClosedTab[]) => {
|
||||
const apply = () => setClosed((stack) => update(stack))
|
||||
if (closedReady()) {
|
||||
apply()
|
||||
return
|
||||
}
|
||||
void closedReady.promise?.then(apply)
|
||||
}
|
||||
|
||||
const removeDraftPersisted = (draftID: string) => {
|
||||
for (const key of draftPersistedKeys()) removePersisted(Persist.draft(draftID, key), platform)
|
||||
}
|
||||
@@ -117,13 +106,6 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||
if (recent.key && !next.some((tab) => tabKey(tab) === recent.key)) setRecentKey(undefined)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!closedReady()) return
|
||||
const servers = new Set(server.list.map(ServerConnection.key))
|
||||
const next = closed.filter((entry) => servers.has(entry.tab.server))
|
||||
if (next.length !== closed.length) setClosed(() => next)
|
||||
})
|
||||
|
||||
const navigateTab = (tab: Tab) => {
|
||||
const href = tabHref(tab)
|
||||
setRecentKey(tabKey(tab))
|
||||
@@ -135,7 +117,7 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||
if (!tab) return
|
||||
const key = tabKey(tab)
|
||||
const draftID = tab.type === "draft" ? tab.draftID : undefined
|
||||
const nextTab = nextTabAfterClose(store, index, recentKey() === key && location.pathname !== "/")
|
||||
const nextTab = store[index + 1] ?? store[index - 1]
|
||||
closing.add(key)
|
||||
void startTransition(() => {
|
||||
setStore(
|
||||
@@ -143,11 +125,9 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||
tabs.splice(index, 1)
|
||||
}),
|
||||
)
|
||||
if (nextTab === null) {
|
||||
setRecentKey(undefined)
|
||||
navigate("/")
|
||||
}
|
||||
if (recent.key === key) setRecentKey(nextTab && tabKey(nextTab))
|
||||
if (nextTab) navigateTab(nextTab)
|
||||
else navigate("/")
|
||||
}).finally(() => closing.delete(key))
|
||||
memory.remove(key)
|
||||
if (draftID) removeDraftPersisted(draftID)
|
||||
@@ -221,45 +201,13 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||
removeDraftPersisted(draftID)
|
||||
},
|
||||
removeTab,
|
||||
// User-initiated close: records the tab so it can be reopened.
|
||||
// Cleanup paths (missing sessions, archive, server removal) go through
|
||||
// removeTab and friends directly and are not recorded.
|
||||
closeTab(index: number) {
|
||||
const tab = store[index]
|
||||
if (!tab) return
|
||||
if (tab.type === "session") updateClosed((stack) => pushClosedTab(stack, tab, index))
|
||||
removeTab(index)
|
||||
},
|
||||
reopenClosedTab() {
|
||||
if (!closedReady()) {
|
||||
void closedReady.promise?.then(() => actions.reopenClosedTab())
|
||||
return
|
||||
}
|
||||
const result = takeClosedTab(closed, store)
|
||||
if (result.stack.length === closed.length) return
|
||||
setClosed(() => result.stack)
|
||||
const entry = result.entry
|
||||
if (!entry) return
|
||||
const index = Math.min(entry.index, store.length)
|
||||
void startTransition(() => {
|
||||
setStore(
|
||||
produce((tabs) => {
|
||||
if (tabs.some((item) => tabKey(item) === tabKey(entry.tab))) return
|
||||
tabs.splice(index, 0, entry.tab)
|
||||
}),
|
||||
)
|
||||
navigateTab(entry.tab)
|
||||
})
|
||||
},
|
||||
removeSessionTab(input: Omit<SessionTab, "type">) {
|
||||
updateClosed((stack) => removeClosedTabs(stack, input.server, [input.sessionId]))
|
||||
const index = store.findIndex(
|
||||
(tab) => tab.type === "session" && tab.server === input.server && tab.sessionId === input.sessionId,
|
||||
)
|
||||
if (index !== -1) removeTab(index)
|
||||
},
|
||||
removeServer(key: ServerConnection.Key) {
|
||||
updateClosed((stack) => stack.filter((entry) => entry.tab.server !== key))
|
||||
const drafts = store.flatMap((tab) => (tab.type === "draft" && tab.server === key ? [tab.draftID] : []))
|
||||
const removed = store.filter((tab) => tab.server === key).map(tabKey)
|
||||
setStore((tabs) => tabs.filter((tab) => tab.server !== key))
|
||||
@@ -270,7 +218,6 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||
},
|
||||
removeSessions: (input: SessionTabsRemovedDetail) => {
|
||||
const targetServer = input.server ?? server.key
|
||||
updateClosed((stack) => removeClosedTabs(stack, targetServer, input.sessionIDs))
|
||||
const removed = store
|
||||
.filter(
|
||||
(tab) => tab.type === "session" && tab.server === targetServer && input.sessionIDs.includes(tab.sessionId),
|
||||
|
||||
@@ -48,7 +48,6 @@ export const dict = {
|
||||
"command.session.new": "New session",
|
||||
"command.file.open": "Open file",
|
||||
"command.tab.close": "Close tab",
|
||||
"command.tab.reopenClosed": "Reopen closed tab",
|
||||
"command.context.addSelection": "Add selection to context",
|
||||
"command.context.addSelection.description": "Add selected lines from the current file",
|
||||
"command.input.focus": "Focus input",
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { shouldOpenSessionInBackground } from "./home-session-open"
|
||||
|
||||
describe("shouldOpenSessionInBackground", () => {
|
||||
test("requires only the platform primary modifier", () => {
|
||||
expect(shouldOpenSessionInBackground({ mac: true, meta: true, ctrl: false, shift: false, alt: false })).toBe(true)
|
||||
expect(shouldOpenSessionInBackground({ mac: false, meta: false, ctrl: true, shift: false, alt: false })).toBe(true)
|
||||
expect(shouldOpenSessionInBackground({ mac: true, meta: true, ctrl: false, shift: true, alt: false })).toBe(false)
|
||||
expect(shouldOpenSessionInBackground({ mac: false, meta: false, ctrl: true, shift: false, alt: true })).toBe(false)
|
||||
expect(shouldOpenSessionInBackground({ mac: false, meta: true, ctrl: false, shift: false, alt: false })).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -1,11 +0,0 @@
|
||||
export function shouldOpenSessionInBackground(input: {
|
||||
mac: boolean
|
||||
meta: boolean
|
||||
ctrl: boolean
|
||||
shift: boolean
|
||||
alt: boolean
|
||||
}) {
|
||||
if (input.shift || input.alt) return false
|
||||
if (input.mac) return input.meta && !input.ctrl
|
||||
return input.ctrl && !input.meta
|
||||
}
|
||||
@@ -66,7 +66,6 @@ import { Persist, persisted } from "@/utils/persist"
|
||||
import { useMarked } from "@opencode-ai/ui/context/marked"
|
||||
import { preloadMarkdown } from "@opencode-ai/session-ui/markdown-cache"
|
||||
import { archiveHomeSession } from "./home-session-archive"
|
||||
import { shouldOpenSessionInBackground } from "./home-session-open"
|
||||
import { showToast } from "@/utils/toast"
|
||||
|
||||
const HOME_SESSION_LIMIT = 64
|
||||
@@ -239,20 +238,6 @@ function useHomeSessionHeaderOpacity(groups: () => HomeSessionGroup[]) {
|
||||
return { setViewport, setContentRef, setHeaderRef, update, titleOpacity }
|
||||
}
|
||||
|
||||
// Cmd+click on macOS (Ctrl+click elsewhere) opens a session tab in the
|
||||
// background without navigating, matching browser conventions.
|
||||
function isBackgroundOpen(event: MouseEvent) {
|
||||
return shouldOpenSessionInBackground({
|
||||
mac: typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform),
|
||||
meta: event.metaKey,
|
||||
ctrl: event.ctrlKey,
|
||||
shift: event.shiftKey,
|
||||
alt: event.altKey,
|
||||
})
|
||||
}
|
||||
|
||||
type OpenSessionOptions = { background?: boolean }
|
||||
|
||||
export function NewHome() {
|
||||
const sync = useServerSync()
|
||||
const layout = useLayout()
|
||||
@@ -392,11 +377,9 @@ export function NewHome() {
|
||||
setState("searchFocused", false)
|
||||
}
|
||||
|
||||
function selectSearchSession(session: Session, options?: OpenSessionOptions) {
|
||||
openSession(session, options)
|
||||
// Background opens keep the search visible so several results can be
|
||||
// opened in a row.
|
||||
if (!options?.background) closeSearch()
|
||||
function selectSearchSession(session: Session) {
|
||||
openSession(session)
|
||||
closeSearch()
|
||||
}
|
||||
|
||||
command.register("home", () => [
|
||||
@@ -481,17 +464,13 @@ export function NewHome() {
|
||||
.forEach((directory) => state.project.markViewed(directory))
|
||||
}
|
||||
|
||||
function openSession(session: Session, options?: OpenSessionOptions) {
|
||||
function openSession(session: Session) {
|
||||
const project = projectForSession(session, projects(), projectByID())
|
||||
const conn = focusedServer()
|
||||
if (!conn) return
|
||||
const directory = project?.worktree ?? session.directory
|
||||
const ctx = global.ensureServerCtx(conn)
|
||||
ctx.projects.open(directory)
|
||||
if (options?.background) {
|
||||
tabs.addSessionTab({ server: ServerConnection.key(conn), sessionId: session.id })
|
||||
return
|
||||
}
|
||||
ctx.projects.touch(directory)
|
||||
startTransition(() => {
|
||||
const tab = tabs.addSessionTab({ server: ServerConnection.key(conn), sessionId: session.id })
|
||||
@@ -1151,7 +1130,7 @@ function HomeSessionSearch(props: {
|
||||
onInput: (value: string) => void
|
||||
onFocus: () => void
|
||||
onClose: () => void
|
||||
onSelect: (session: Session, options?: OpenSessionOptions) => void
|
||||
onSelect: (session: Session) => void
|
||||
}) {
|
||||
const language = useLanguage()
|
||||
const [store, setStore] = createStore({ active: "" })
|
||||
@@ -1265,7 +1244,7 @@ function HomeSessionSearch(props: {
|
||||
server={props.server}
|
||||
selected={store.active === homeSessionSearchKey(record)}
|
||||
onHighlight={() => setStore("active", homeSessionSearchKey(record))}
|
||||
onSelect={(session, options) => props.onSelect(session, options)}
|
||||
onSelect={(session) => props.onSelect(session)}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
@@ -1345,7 +1324,7 @@ function HomeSessionSearchResultRow(props: {
|
||||
server: ServerConnection.Key
|
||||
selected: boolean
|
||||
onHighlight: () => void
|
||||
onSelect: (session: Session, options?: OpenSessionOptions) => void
|
||||
onSelect: (session: Session) => void
|
||||
}) {
|
||||
const title = createMemo(() => sessionTitle(props.record.session.title) || props.record.session.id)
|
||||
const showProjectName = () => props.showProjectName && props.record.projectName
|
||||
@@ -1366,7 +1345,7 @@ function HomeSessionSearchResultRow(props: {
|
||||
group: !!showProjectName(),
|
||||
}}
|
||||
onMouseEnter={() => props.onHighlight()}
|
||||
onClick={(event) => props.onSelect(props.record.session, { background: isBackgroundOpen(event) })}
|
||||
onClick={() => props.onSelect(props.record.session)}
|
||||
>
|
||||
<HomeSessionLeading
|
||||
project={props.record.project}
|
||||
@@ -1410,7 +1389,7 @@ function HomeSessionRow(props: {
|
||||
record: HomeSessionRecord
|
||||
showProjectName: boolean
|
||||
server: ServerConnection.Key
|
||||
openSession: (session: Session, options?: OpenSessionOptions) => void
|
||||
openSession: (session: Session) => void
|
||||
archiveSession: (session: Session) => Promise<void>
|
||||
}) {
|
||||
const language = useLanguage()
|
||||
@@ -1426,7 +1405,7 @@ function HomeSessionRow(props: {
|
||||
type="button"
|
||||
data-component="home-session-row"
|
||||
class={`${HOME_ROW} h-10 min-w-0 flex-1 gap-2 py-3 pl-3 pr-10`}
|
||||
onClick={(event) => props.openSession(props.record.session, { background: isBackgroundOpen(event) })}
|
||||
onClick={() => props.openSession(props.record.session)}
|
||||
>
|
||||
<HomeSessionLeading
|
||||
project={props.record.project}
|
||||
|
||||
@@ -93,7 +93,7 @@ export default function NewSessionPage() {
|
||||
return (
|
||||
<div class="relative size-full overflow-hidden flex flex-col">
|
||||
<div class="flex-1 min-h-0 flex flex-col gap-2 p-2">
|
||||
<div class="@container relative flex flex-col min-h-0 h-full flex-1">
|
||||
<div class="@container relative flex flex-col min-h-0 h-full bg-background-stronger flex-1">
|
||||
<div class="flex-1 min-h-0 overflow-hidden rounded-[10px]">
|
||||
<NewSessionDesignView>
|
||||
<div class={NEW_SESSION_CONTENT_WIDTH}>
|
||||
|
||||
@@ -64,20 +64,25 @@ import {
|
||||
createSessionComposerRegionController,
|
||||
SessionComposerRegion,
|
||||
} from "@/pages/session/composer"
|
||||
import { createOpenReviewFile, createSessionTabs, createSizing, shouldShowFileTree } from "@/pages/session/helpers"
|
||||
import {
|
||||
createOpenReviewFile,
|
||||
createSessionTabs,
|
||||
createSizing,
|
||||
focusTerminalById,
|
||||
shouldFocusTerminalOnKeyDown,
|
||||
shouldShowFileTree,
|
||||
} from "@/pages/session/helpers"
|
||||
import { MessageTimeline } from "@/pages/session/timeline/message-timeline"
|
||||
import { createTimelineModel } from "@/pages/session/timeline/model"
|
||||
import { type DiffStyle, SessionReviewTab, type SessionReviewTabProps } from "@/pages/session/review-tab"
|
||||
import { useSessionLayout } from "@/pages/session/session-layout"
|
||||
import { syncSessionModel } from "@/pages/session/session-model-helpers"
|
||||
import { SessionSidePanel } from "@/pages/session/session-side-panel"
|
||||
import { sessionPanelLayout } from "@/pages/session/session-panel-layout"
|
||||
import { SessionReviewEmptyChangesV2 } from "@opencode-ai/session-ui/v2/session-review-empty-changes-v2"
|
||||
import { SessionReviewEmptyNoGitV2 } from "@opencode-ai/session-ui/v2/session-review-empty-no-git-v2"
|
||||
import { ReviewPanelV2 } from "@/pages/session/v2/review-panel-v2"
|
||||
import { createReviewPanelV2State } from "@/pages/session/v2/review-panel-v2-state"
|
||||
import { TerminalPanel } from "@/pages/session/terminal-panel"
|
||||
import { TerminalPanelV2 } from "@/pages/session/terminal-panel-v2"
|
||||
import { useComposerCommands } from "@/pages/session/use-composer-commands"
|
||||
import { useSessionCommands } from "@/pages/session/use-session-commands"
|
||||
import { useSessionHashScroll } from "@/pages/session/use-session-hash-scroll"
|
||||
@@ -429,12 +434,6 @@ export default function Page() {
|
||||
const isDesktop = createMediaQuery("(min-width: 768px)")
|
||||
const size = createSizing()
|
||||
const desktopReviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened())
|
||||
const desktopV2ReviewOpen = createMemo(() => newSessionDesign() && desktopReviewOpen() && !!params.id)
|
||||
const terminalOpen = createMemo(() => view().terminal.opened())
|
||||
const desktopTerminalOpen = createMemo(() => isDesktop() && terminalOpen())
|
||||
const desktopInlineTerminalOnlyOpen = createMemo(
|
||||
() => newSessionDesign() && desktopTerminalOpen() && !desktopV2ReviewOpen(),
|
||||
)
|
||||
const desktopFileTreeOpen = createMemo(
|
||||
() =>
|
||||
isDesktop() &&
|
||||
@@ -443,23 +442,13 @@ export default function Page() {
|
||||
opened: layout.fileTree.opened(),
|
||||
}),
|
||||
)
|
||||
const desktopSessionResizeOpen = createMemo(() =>
|
||||
newSessionDesign() ? desktopV2ReviewOpen() || desktopTerminalOpen() : desktopReviewOpen(),
|
||||
)
|
||||
const desktopSidePanelOpen = createMemo(() => desktopSessionResizeOpen() || desktopFileTreeOpen())
|
||||
const desktopSidePanelOpen = createMemo(() => desktopReviewOpen() || desktopFileTreeOpen())
|
||||
const sessionPanelWidth = createMemo(() => {
|
||||
if (!desktopSidePanelOpen()) return "100%"
|
||||
if (desktopSessionResizeOpen()) return `${layout.session.width()}px`
|
||||
if (desktopReviewOpen()) return `${layout.session.width()}px`
|
||||
return `calc(100% - ${layout.fileTree.width()}px)`
|
||||
})
|
||||
const centered = createMemo(() => isDesktop() && !desktopReviewOpen())
|
||||
const desktopV2PanelLayout = createMemo(() =>
|
||||
sessionPanelLayout({
|
||||
review: desktopV2ReviewOpen(),
|
||||
terminal: desktopTerminalOpen(),
|
||||
files: desktopFileTreeOpen(),
|
||||
}),
|
||||
)
|
||||
|
||||
function normalizeTab(tab: string) {
|
||||
if (!tab.startsWith("file://")) return tab
|
||||
@@ -953,6 +942,12 @@ export default function Page() {
|
||||
return
|
||||
}
|
||||
|
||||
// Prefer the open terminal over the composer when it can take focus
|
||||
if (view().terminal.opened()) {
|
||||
const id = terminal.active()
|
||||
if (id && shouldFocusTerminalOnKeyDown(event) && focusTerminalById(id)) return
|
||||
}
|
||||
|
||||
const key = scrollKey(event)
|
||||
if (key) {
|
||||
if (!scroller || !isScrollKeyTarget(target ?? null, key)) return
|
||||
@@ -2111,7 +2106,7 @@ export default function Page() {
|
||||
classList={{
|
||||
"@container relative shrink-0 flex flex-col min-h-0 h-full flex-1 md:flex-none transition-[width]": true,
|
||||
"duration-[240ms] ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none":
|
||||
!size.active() && !ui.reviewSnap && !desktopInlineTerminalOnlyOpen(),
|
||||
!size.active() && !ui.reviewSnap,
|
||||
}}
|
||||
style={{
|
||||
width: sessionPanelWidth(),
|
||||
@@ -2131,7 +2126,7 @@ export default function Page() {
|
||||
</SessionPanelFrame>
|
||||
)}
|
||||
|
||||
<Show when={desktopSessionResizeOpen()}>
|
||||
<Show when={desktopReviewOpen()}>
|
||||
<div onPointerDown={() => size.start()}>
|
||||
<ResizeHandle
|
||||
classList={{
|
||||
@@ -2150,72 +2145,22 @@ export default function Page() {
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<Show when={!newSessionDesign()}>
|
||||
<SessionSidePanel
|
||||
canReview={canReview}
|
||||
diffs={reviewDiffs}
|
||||
diffsReady={reviewReady}
|
||||
empty={reviewEmptyText}
|
||||
hasReview={hasReview}
|
||||
reviewCount={reviewCount}
|
||||
reviewPanel={reviewPanel}
|
||||
activeDiff={tree.activeDiff}
|
||||
focusReviewDiff={focusReviewDiff}
|
||||
reviewSnap={ui.reviewSnap}
|
||||
size={size}
|
||||
/>
|
||||
</Show>
|
||||
<Show when={newSessionDesign()}>
|
||||
<Show when={isDesktop() ? desktopV2PanelLayout().visible : terminalOpen()}>
|
||||
<div class="min-w-0 h-full flex flex-1 flex-col">
|
||||
<Show when={isDesktop() && (desktopV2ReviewOpen() || desktopFileTreeOpen())}>
|
||||
<div class="min-h-0 flex-1">
|
||||
<SessionSidePanel
|
||||
canReview={canReview}
|
||||
diffs={reviewDiffs}
|
||||
diffsReady={reviewReady}
|
||||
empty={reviewEmptyText}
|
||||
hasReview={hasReview}
|
||||
reviewCount={reviewCount}
|
||||
reviewPanel={reviewPanelV2}
|
||||
activeDiff={tree.activeDiff}
|
||||
focusReviewDiff={focusReviewDiff}
|
||||
reviewSnap={ui.reviewSnap}
|
||||
size={size}
|
||||
stacked={desktopV2PanelLayout().stacked}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={desktopV2PanelLayout().stacked}>
|
||||
<div class="relative h-2 shrink-0" onPointerDown={() => size.start()}>
|
||||
<ResizeHandle
|
||||
class="!relative !inset-auto !h-full !w-full !transform-none"
|
||||
direction="vertical"
|
||||
size={layout.terminal.height()}
|
||||
min={100}
|
||||
max={typeof window === "undefined" ? 600 : window.innerHeight * 0.6}
|
||||
collapseThreshold={50}
|
||||
onResize={(height) => {
|
||||
size.touch()
|
||||
layout.terminal.resize(height)
|
||||
}}
|
||||
onCollapse={() => view().terminal.close()}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={terminalOpen()}>
|
||||
<div class="min-h-0 flex-1">
|
||||
<TerminalPanelV2 stacked={desktopV2PanelLayout().stacked} />
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
</Show>
|
||||
<SessionSidePanel
|
||||
canReview={canReview}
|
||||
diffs={reviewDiffs}
|
||||
diffsReady={reviewReady}
|
||||
empty={reviewEmptyText}
|
||||
hasReview={hasReview}
|
||||
reviewCount={reviewCount}
|
||||
reviewPanel={() => (newSessionDesign() ? reviewPanelV2() : reviewPanel())}
|
||||
activeDiff={tree.activeDiff}
|
||||
focusReviewDiff={focusReviewDiff}
|
||||
reviewSnap={ui.reviewSnap}
|
||||
size={size}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Show when={!newSessionDesign()}>
|
||||
<TerminalPanel />
|
||||
</Show>
|
||||
<TerminalPanel />
|
||||
</SessionRouteFrame>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
createSessionTabs,
|
||||
focusTerminalById,
|
||||
getTabReorderIndex,
|
||||
shouldFocusTerminalOnKeyDown,
|
||||
shouldShowFileTree,
|
||||
} from "./helpers"
|
||||
|
||||
@@ -94,6 +95,26 @@ describe("focusTerminalById", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("shouldFocusTerminalOnKeyDown", () => {
|
||||
test("skips pure modifier keys", () => {
|
||||
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "Meta", metaKey: true }))).toBe(false)
|
||||
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "Control", ctrlKey: true }))).toBe(false)
|
||||
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "Alt", altKey: true }))).toBe(false)
|
||||
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "Shift", shiftKey: true }))).toBe(false)
|
||||
})
|
||||
|
||||
test("skips shortcut key combos", () => {
|
||||
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "c", metaKey: true }))).toBe(false)
|
||||
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "c", ctrlKey: true }))).toBe(false)
|
||||
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "ArrowLeft", altKey: true }))).toBe(false)
|
||||
})
|
||||
|
||||
test("keeps plain typing focused on terminal", () => {
|
||||
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "a" }))).toBe(true)
|
||||
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "A", shiftKey: true }))).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("getTabReorderIndex", () => {
|
||||
test("returns target index for valid drag reorder", () => {
|
||||
expect(getTabReorderIndex(["a", "b", "c"], "a", "c")).toBe(2)
|
||||
|
||||
@@ -98,6 +98,13 @@ export const focusTerminalById = (id: string) => {
|
||||
return true
|
||||
}
|
||||
|
||||
const skip = new Set(["Alt", "Control", "Meta", "Shift"])
|
||||
|
||||
export const shouldFocusTerminalOnKeyDown = (event: Pick<KeyboardEvent, "key" | "ctrlKey" | "metaKey" | "altKey">) => {
|
||||
if (skip.has(event.key)) return false
|
||||
return !(event.ctrlKey || event.metaKey || event.altKey)
|
||||
}
|
||||
|
||||
export const createOpenReviewFile = (input: {
|
||||
showAllFiles: () => void
|
||||
tabForPath: (path: string) => string
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { sessionPanelLayout } from "./session-panel-layout"
|
||||
|
||||
describe("sessionPanelLayout", () => {
|
||||
test("keeps one V2 owner while changing panel geometry", () => {
|
||||
expect(sessionPanelLayout({ review: false, terminal: false, files: false })).toEqual({
|
||||
visible: false,
|
||||
stacked: false,
|
||||
})
|
||||
expect(sessionPanelLayout({ review: false, terminal: true, files: false })).toEqual({
|
||||
visible: true,
|
||||
stacked: false,
|
||||
})
|
||||
expect(sessionPanelLayout({ review: true, terminal: true, files: false })).toEqual({
|
||||
visible: true,
|
||||
stacked: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,6 +0,0 @@
|
||||
export function sessionPanelLayout(input: { review: boolean; terminal: boolean; files: boolean }) {
|
||||
return {
|
||||
visible: input.review || input.terminal || input.files,
|
||||
stacked: input.review && input.terminal,
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ export function SessionSidePanel(props: {
|
||||
focusReviewDiff: (path: string) => void
|
||||
reviewSnap: boolean
|
||||
size: Sizing
|
||||
stacked?: boolean
|
||||
}) {
|
||||
const layout = useLayout()
|
||||
const settings = useSettings()
|
||||
@@ -220,10 +219,8 @@ export function SessionSidePanel(props: {
|
||||
aria-label={language.t("session.panel.reviewAndFiles")}
|
||||
aria-hidden={!open()}
|
||||
inert={!open()}
|
||||
class="relative min-w-0 flex overflow-hidden bg-background-base"
|
||||
class="relative min-w-0 h-full flex shrink-0 overflow-hidden bg-background-base"
|
||||
classList={{
|
||||
"h-full shrink-0": !props.stacked,
|
||||
"min-h-0 flex-1": props.stacked,
|
||||
"pointer-events-none": !open(),
|
||||
"transition-[width] duration-[240ms] ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none":
|
||||
!props.size.active() && !props.reviewSnap,
|
||||
|
||||
@@ -1,366 +0,0 @@
|
||||
import { For, Show, createEffect, createMemo, on, onCleanup, onMount } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { makeEventListener } from "@solid-primitives/event-listener"
|
||||
import { createMediaQuery } from "@solid-primitives/media"
|
||||
import { DragDropProvider, PointerSensor } from "@dnd-kit/solid"
|
||||
import { isSortable } from "@dnd-kit/solid/sortable"
|
||||
import { Accessibility, AutoScroller, Feedback, PointerActivationConstraints } from "@dnd-kit/dom"
|
||||
import { RestrictToHorizontalAxis } from "@dnd-kit/abstract/modifiers"
|
||||
import { RestrictToElement } from "@dnd-kit/dom/modifiers"
|
||||
import { Tabs } from "@opencode-ai/ui/tabs"
|
||||
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
|
||||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||
import { TooltipKeybind } from "@opencode-ai/ui/tooltip"
|
||||
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
|
||||
import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2"
|
||||
|
||||
import { SortableTerminalTabV2 } from "@/components/session/session-sortable-terminal-tab-v2"
|
||||
import { Terminal } from "@/components/terminal"
|
||||
import { useCommand } from "@/context/command"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { useLayout } from "@/context/layout"
|
||||
import { useSettings } from "@/context/settings"
|
||||
import { useTerminal } from "@/context/terminal"
|
||||
import { useSDK } from "@/context/sdk"
|
||||
import { terminalTabLabel } from "@/pages/session/terminal-label"
|
||||
import { createSizing, focusTerminalById } from "@/pages/session/helpers"
|
||||
import { getTerminalHandoff, setTerminalHandoff } from "@/pages/session/handoff"
|
||||
import { useSessionLayout } from "@/pages/session/session-layout"
|
||||
|
||||
export function TerminalPanelV2(props: { stacked?: boolean } = {}) {
|
||||
const delays = [120, 240]
|
||||
const layout = useLayout()
|
||||
const terminal = useTerminal()
|
||||
const sdk = useSDK()
|
||||
const language = useLanguage()
|
||||
const command = useCommand()
|
||||
const settings = useSettings()
|
||||
const { workspaceKey, view } = useSessionLayout()
|
||||
|
||||
const isDesktop = createMediaQuery("(min-width: 768px)")
|
||||
const newLayout = createMemo(() => settings.general.newLayoutDesigns())
|
||||
const opened = createMemo(() => view().terminal.opened())
|
||||
const size = createSizing()
|
||||
const height = createMemo(() => layout.terminal.height())
|
||||
const close = () => view().terminal.close()
|
||||
let root: HTMLDivElement | undefined
|
||||
let tabList: HTMLDivElement | undefined
|
||||
|
||||
const [store, setStore] = createStore({
|
||||
autoCreated: false,
|
||||
recovered: {} as Record<string, boolean>,
|
||||
view: typeof window === "undefined" ? 1000 : (window.visualViewport?.height ?? window.innerHeight),
|
||||
})
|
||||
|
||||
const max = () => store.view * 0.6
|
||||
const pane = () => Math.min(height(), max())
|
||||
const stacked = createMemo(() => isDesktop() && props.stacked)
|
||||
const panelHeight = createMemo(() =>
|
||||
isDesktop() ? (stacked() ? `${pane()}px` : "100%") : opened() ? `${pane()}px` : "0px",
|
||||
)
|
||||
const contentHeight = createMemo(() => (isDesktop() ? (stacked() ? `${pane()}px` : "100%") : `${pane()}px`))
|
||||
const newTerminalKeybind = createMemo(() => command.keybindParts("terminal.new"))
|
||||
|
||||
onMount(() => {
|
||||
if (typeof window === "undefined") return
|
||||
|
||||
const sync = () => setStore("view", window.visualViewport?.height ?? window.innerHeight)
|
||||
const port = window.visualViewport
|
||||
|
||||
sync()
|
||||
makeEventListener(window, "resize", sync)
|
||||
if (port) makeEventListener(port, "resize", sync)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!opened()) {
|
||||
setStore("autoCreated", false)
|
||||
return
|
||||
}
|
||||
|
||||
if (!terminal.ready() || terminal.all().length !== 0 || store.autoCreated) return
|
||||
terminal.new()
|
||||
setStore("autoCreated", true)
|
||||
})
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => terminal.all().length,
|
||||
(count, prevCount) => {
|
||||
if (prevCount === undefined || prevCount <= 0 || count !== 0) return
|
||||
if (!opened()) return
|
||||
close()
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
const focus = (id: string) => {
|
||||
focusTerminalById(id)
|
||||
|
||||
const frame = requestAnimationFrame(() => {
|
||||
if (!opened()) return
|
||||
if (terminal.active() !== id) return
|
||||
focusTerminalById(id)
|
||||
})
|
||||
|
||||
const timers = delays.map((ms) =>
|
||||
window.setTimeout(() => {
|
||||
if (!opened()) return
|
||||
if (terminal.active() !== id) return
|
||||
focusTerminalById(id)
|
||||
}, ms),
|
||||
)
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(frame)
|
||||
for (const timer of timers) clearTimeout(timer)
|
||||
}
|
||||
}
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => [opened(), terminal.active()] as const,
|
||||
([next, id]) => {
|
||||
if (!next || !id) return
|
||||
const stop = focus(id)
|
||||
onCleanup(stop)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
createEffect(() => {
|
||||
if (opened()) return
|
||||
const active = document.activeElement
|
||||
if (!(active instanceof HTMLElement)) return
|
||||
if (!root?.contains(active)) return
|
||||
active.blur()
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const dir = sdk().directory
|
||||
if (!dir) return
|
||||
if (!terminal.ready()) return
|
||||
language.locale()
|
||||
|
||||
setTerminalHandoff(
|
||||
workspaceKey(),
|
||||
terminal.all().map((pty) =>
|
||||
terminalTabLabel({
|
||||
title: pty.title,
|
||||
titleNumber: pty.titleNumber,
|
||||
t: language.t as (key: string, vars?: Record<string, string | number | boolean>) => string,
|
||||
}),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
const handoff = createMemo(() => {
|
||||
const dir = sdk().directory
|
||||
if (!dir) return []
|
||||
return getTerminalHandoff(workspaceKey()) ?? []
|
||||
})
|
||||
|
||||
const all = terminal.all
|
||||
const ids = createMemo(() => all().map((pty) => pty.id))
|
||||
|
||||
const recoverTerminal = (key: string, id: string, clone: (id: string) => Promise<void>) => {
|
||||
if (store.recovered[key]) return
|
||||
setStore("recovered", key, true)
|
||||
void clone(id)
|
||||
}
|
||||
|
||||
const terminalRecoveryKey = (pty: { id: string; title: string; titleNumber: number }) => {
|
||||
return String(pty.titleNumber || pty.title || pty.id)
|
||||
}
|
||||
|
||||
const markTerminalConnected = (key: string, id: string, trim: (id: string) => void) => {
|
||||
setStore("recovered", key, false)
|
||||
trim(id)
|
||||
}
|
||||
|
||||
const handleTerminalDragEnd = () => {
|
||||
const activeId = terminal.active()
|
||||
if (!activeId) return
|
||||
requestAnimationFrame(() => {
|
||||
if (terminal.active() !== activeId) return
|
||||
focusTerminalById(activeId)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<aside
|
||||
ref={root}
|
||||
id="terminal-panel"
|
||||
role="region"
|
||||
aria-label={language.t("terminal.title")}
|
||||
aria-hidden={!opened()}
|
||||
inert={!opened()}
|
||||
class="relative shrink-0 overflow-hidden bg-background-stronger"
|
||||
classList={{
|
||||
"w-full": !isDesktop() || stacked(),
|
||||
"min-w-0 h-full flex-1": isDesktop() && opened() && !stacked(),
|
||||
"w-0 h-full pointer-events-none": isDesktop() && !opened(),
|
||||
"rounded-[10px] shadow-[var(--v2-elevation-raised)]": isDesktop() && newLayout(),
|
||||
"transition-[height] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[height] motion-reduce:transition-none":
|
||||
!isDesktop() && !size.active(),
|
||||
}}
|
||||
style={{ height: panelHeight() }}
|
||||
>
|
||||
<div classList={{ "md:hidden": !stacked(), hidden: stacked() }} onPointerDown={() => size.start()}>
|
||||
<ResizeHandle
|
||||
classList={{
|
||||
"-top-1": newLayout(),
|
||||
}}
|
||||
direction="vertical"
|
||||
size={pane()}
|
||||
min={100}
|
||||
max={max()}
|
||||
collapseThreshold={50}
|
||||
onResize={(next) => {
|
||||
size.touch()
|
||||
layout.terminal.resize(next)
|
||||
}}
|
||||
onCollapse={close}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="absolute inset-0 flex flex-col overflow-hidden"
|
||||
classList={{
|
||||
"border-t border-border-weak-base": opened() && !isDesktop(),
|
||||
"border-t border-border-weaker-base": opened() && stacked() && !newLayout(),
|
||||
"border-l border-border-weaker-base": opened() && isDesktop() && !newLayout(),
|
||||
"pointer-events-none": !opened(),
|
||||
}}
|
||||
style={{ height: contentHeight() }}
|
||||
>
|
||||
<Show
|
||||
when={terminal.ready()}
|
||||
fallback={
|
||||
<div class="flex flex-col h-full pointer-events-none">
|
||||
<div class="h-10 flex items-center gap-2 px-2 border-b border-border-weaker-base bg-background-stronger overflow-hidden">
|
||||
<For each={handoff()}>
|
||||
{(title) => (
|
||||
<div class="px-2 py-1 rounded-md bg-surface-base text-14-regular text-text-weak truncate max-w-40">
|
||||
{title}
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
<div class="flex-1" />
|
||||
<div class="text-text-weak pr-2">
|
||||
{language.t("common.loading")}
|
||||
{language.t("common.loading.ellipsis")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex items-center justify-center text-text-weak">{language.t("terminal.loading")}</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<DragDropProvider
|
||||
sensors={[
|
||||
PointerSensor.configure({
|
||||
activationConstraints: [new PointerActivationConstraints.Distance({ value: 4 })],
|
||||
preventActivation: (event) =>
|
||||
event.target instanceof Element &&
|
||||
!!event.target.closest('[data-slot="tabs-trigger-close-button"], input, [contenteditable="true"]'),
|
||||
}),
|
||||
]}
|
||||
modifiers={[RestrictToHorizontalAxis, RestrictToElement.configure({ element: () => tabList ?? null })]}
|
||||
plugins={(defaults) => [
|
||||
...defaults.filter((plugin) => plugin !== Accessibility),
|
||||
AutoScroller.configure({ acceleration: 8, threshold: { x: 0.05, y: 0 } }),
|
||||
Feedback.configure({ dropAnimation: null }),
|
||||
]}
|
||||
onDragEnd={(event) => {
|
||||
const source = event.operation.source
|
||||
if (!event.canceled && isSortable(source) && source.initialIndex !== source.index) {
|
||||
terminal.move(source.id.toString(), source.index)
|
||||
}
|
||||
handleTerminalDragEnd()
|
||||
}}
|
||||
>
|
||||
<div class="flex flex-col h-full">
|
||||
<Tabs
|
||||
variant={newLayout() ? "normal" : "alt"}
|
||||
value={terminal.active()}
|
||||
onChange={(id) => terminal.open(id)}
|
||||
class={newLayout() ? "!h-[52px] !flex-none" : "!h-auto !flex-none"}
|
||||
>
|
||||
<Tabs.List ref={tabList} class={newLayout() ? undefined : "h-10 border-b border-border-weaker-base"}>
|
||||
<For each={all()}>
|
||||
{(pty, index) => (
|
||||
<SortableTerminalTabV2 terminal={pty} index={index} newLayout={newLayout()} onClose={close} />
|
||||
)}
|
||||
</For>
|
||||
<div class="h-full flex items-center justify-center">
|
||||
<Show
|
||||
when={newLayout()}
|
||||
fallback={
|
||||
<TooltipKeybind
|
||||
title={language.t("command.terminal.new")}
|
||||
keybind={command.keybind("terminal.new")}
|
||||
class="flex items-center"
|
||||
>
|
||||
<IconButton
|
||||
icon="plus-small"
|
||||
variant="ghost"
|
||||
iconSize="large"
|
||||
onClick={terminal.new}
|
||||
aria-label={language.t("command.terminal.new")}
|
||||
/>
|
||||
</TooltipKeybind>
|
||||
}
|
||||
>
|
||||
<TooltipV2
|
||||
value={
|
||||
<>
|
||||
{language.t("command.terminal.new")}
|
||||
<Show when={newTerminalKeybind().length > 0}>
|
||||
<KeybindV2 keys={newTerminalKeybind()} variant="neutral" />
|
||||
</Show>
|
||||
</>
|
||||
}
|
||||
placement="bottom"
|
||||
class="flex items-center"
|
||||
>
|
||||
<IconButton
|
||||
icon="plus-small"
|
||||
variant="ghost"
|
||||
iconSize="large"
|
||||
onClick={terminal.new}
|
||||
aria-label={language.t("command.terminal.new")}
|
||||
/>
|
||||
</TooltipV2>
|
||||
</Show>
|
||||
</div>
|
||||
</Tabs.List>
|
||||
</Tabs>
|
||||
<div class="flex-1 min-h-0 relative">
|
||||
<Show when={opened() && terminal.active()} keyed>
|
||||
{(id) => {
|
||||
const ops = terminal.bind()
|
||||
return (
|
||||
<Show when={all().find((pty) => pty.id === id)}>
|
||||
{(pty) => (
|
||||
<div id={`terminal-wrapper-${id}`} class="absolute inset-0">
|
||||
<Terminal
|
||||
pty={pty()}
|
||||
autoFocus={opened()}
|
||||
class="!px-[14px]"
|
||||
onConnect={() => markTerminalConnected(terminalRecoveryKey(pty()), id, ops.trim)}
|
||||
onCleanup={ops.update}
|
||||
onConnectError={() => recoverTerminal(terminalRecoveryKey(pty()), id, ops.clone)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Show>
|
||||
)
|
||||
}}
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</DragDropProvider>
|
||||
</Show>
|
||||
</div>
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
@@ -598,12 +598,8 @@ export function MessageTimeline(props: {
|
||||
|
||||
const handleListPointerDown = (event: PointerEvent & { currentTarget: HTMLDivElement }) => {
|
||||
if (!prependLoading) clearPrependAnchor()
|
||||
props.onMarkScrollGesture(event.target)
|
||||
}
|
||||
|
||||
const handleListPointerMove = (event: PointerEvent) => {
|
||||
if (event.buttons !== 1) return
|
||||
props.onMarkScrollGesture(event.target)
|
||||
if (event.target !== event.currentTarget) return
|
||||
props.onMarkScrollGesture(event.currentTarget)
|
||||
}
|
||||
|
||||
const handleListKeyDown = (event: KeyboardEvent & { currentTarget: HTMLDivElement }) => {
|
||||
@@ -1360,7 +1356,6 @@ export function MessageTimeline(props: {
|
||||
onTouchEnd={handleListTouchEnd}
|
||||
onTouchCancel={handleListTouchEnd}
|
||||
onPointerDown={handleListPointerDown}
|
||||
onPointerMove={handleListPointerMove}
|
||||
onKeyDown={handleListKeyDown}
|
||||
onScroll={handleListScroll}
|
||||
onClick={props.onAutoScrollInteraction}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import type { AssistantMessage, Message, UserMessage } from "@opencode-ai/sdk/v2"
|
||||
import { isTimelineReady, loadOlderTimeline, selectUserMessages, selectVisibleUserMessages } from "./model"
|
||||
import { loadOlderTimeline, selectUserMessages, selectVisibleUserMessages } from "./model"
|
||||
|
||||
const user = (id: string) => ({ id, role: "user" }) as UserMessage
|
||||
const assistant = (id: string) => ({ id, role: "assistant" }) as AssistantMessage
|
||||
@@ -15,12 +15,6 @@ describe("timeline model", () => {
|
||||
expect(selectVisibleUserMessages(users)).toBe(users)
|
||||
})
|
||||
|
||||
test("waits for an assistant-only load to hydrate its user root", () => {
|
||||
expect(isTimelineReady([assistant("msg_2")], true)).toBe(false)
|
||||
expect(isTimelineReady([user("msg_1"), assistant("msg_2")], true)).toBe(true)
|
||||
expect(isTimelineReady([], false)).toBe(true)
|
||||
})
|
||||
|
||||
test("loads exactly one opaque cursor page", async () => {
|
||||
let calls = 0
|
||||
const anchors: Array<string | boolean> = []
|
||||
|
||||
@@ -45,7 +45,7 @@ export function createTimelineModel(input: {
|
||||
})
|
||||
const ready = createMemo(() => {
|
||||
const id = input.sessionID()
|
||||
return !id || isTimelineReady(sync().data.message[id], serverSync().session.history.loading(id))
|
||||
return !id || sync().data.message[id] !== undefined
|
||||
})
|
||||
const userMessages = createMemo(() => selectUserMessages(messages()), emptyUserMessages, { equals: same })
|
||||
const visibleUserMessages = createMemo(
|
||||
@@ -98,10 +98,6 @@ export function selectUserMessages(messages: Message[]) {
|
||||
return messages.filter((message): message is UserMessage => message.role === "user")
|
||||
}
|
||||
|
||||
export function isTimelineReady(messages: Message[] | undefined, loading: boolean) {
|
||||
return messages !== undefined && (messages.some((message) => message.role === "user") || !loading)
|
||||
}
|
||||
|
||||
export function selectVisibleUserMessages(messages: UserMessage[], revertMessageID?: string) {
|
||||
if (!revertMessageID) return messages
|
||||
return messages.filter((message) => message.id < revertMessageID)
|
||||
|
||||
@@ -5,14 +5,6 @@
|
||||
- Keep Code Mode unaware of host session, channel, and conversation models. The hosting application supplies trusted execution scope around it.
|
||||
- Tool schemas are the model-facing Interface. Keep arguments minimal and natural to the operation; never add unrelated IDs as ambient capability tokens.
|
||||
|
||||
## OpenAPI
|
||||
|
||||
- Generate an operation only when its transport semantics are supported; otherwise return a precise `skipped` reason.
|
||||
- Never guess parameter serialization or malformed security semantics. Unsupported serialization is skipped and malformed security fails closed.
|
||||
- Render unresolved schema constructs as `unknown`, never as invented TypeScript names.
|
||||
- Keep network reads bounded and map expected encoding, transport, and decoding failures to model-safe `ToolError` values.
|
||||
- Test supported behavior directly; do not reproduce adapter algorithms in tests.
|
||||
|
||||
## Future Design Notes
|
||||
|
||||
- If a captured user-visible output channel returns (an earlier `output.text`/`output.file`/`output.image` API was removed from v1), keep `output` as its name, distinct from the program return value: `return` stays the structured result for the model, while `output.*` describes artifacts the host may render into a conversation or UI after execution. Keep this host-neutral and let applications decide how captured output is delivered. In v1, hosts collect media host-side (outside the sandbox) instead.
|
||||
|
||||
@@ -4,7 +4,7 @@ Effect-native confined code execution over explicit, schema-described tools.
|
||||
|
||||
CodeMode lets a model write a small JavaScript program that can call only the tools supplied by the host. The program can sequence calls, transform plain data, branch, loop, and run independent calls in parallel without receiving ambient filesystem, process, network, module, or application authority.
|
||||
|
||||
The package is currently private to this workspace. Its API is designed around one-shot and reusable execution:
|
||||
The package is currently private to this workspace. Its API is designed around three uses:
|
||||
|
||||
```ts
|
||||
// One execution
|
||||
@@ -13,6 +13,9 @@ yield * CodeMode.execute({ tools, code })
|
||||
// A reusable runtime
|
||||
const runtime = CodeMode.make({ tools, limits })
|
||||
yield * runtime.execute(code)
|
||||
|
||||
// One agent-facing code tool
|
||||
const codeTool = runtime.agentTool()
|
||||
```
|
||||
|
||||
## Install
|
||||
@@ -114,9 +117,10 @@ const runtime = CodeMode.make({
|
||||
runtime.catalog() // structured tool descriptions
|
||||
runtime.instructions() // model-facing syntax and tool guide
|
||||
runtime.execute(source) // ExecuteResult
|
||||
runtime.agentTool() // { name, description, input, output, execute }
|
||||
```
|
||||
|
||||
`CodeMode.Input` and `CodeMode.Result` are Effect schemas for the execution request and result. Hosts can combine them with `runtime.instructions()` and `runtime.execute()` when constructing a framework-specific agent tool.
|
||||
`catalog`, `instructions`, and `agentTool` are projections of the same configured tool tree. `agentTool().description` is exactly `instructions()`.
|
||||
|
||||
### Results
|
||||
|
||||
@@ -148,31 +152,6 @@ interface ExecuteFailure {
|
||||
|
||||
`onToolCallEnd` receives `{ index, name, input, durationMs, outcome, message? }` when an admitted call settles. `outcome` is `"success"` or `"failure"`; `message` is the model-safe failure message and is present only on failure. Interrupted calls (for example when the execution timeout fires) do not produce an end event. Both hooks are Effect-returning and must not fail.
|
||||
|
||||
### OpenAPI tools
|
||||
|
||||
`OpenAPI.fromSpec` turns an OpenAPI 3.x document into a tool subtree - one tool per operation. Dotted `operationId` values form namespaces such as `v2.session.get`. Missing IDs receive a flat method/path fallback such as `getUsersById`; names are sanitized and deduplicated. The host places the subtree under a key in its `tools` tree; that key is the model-visible namespace.
|
||||
|
||||
```ts
|
||||
import { CodeMode, OpenAPI } from "@opencode-ai/codemode"
|
||||
import { Effect } from "effect"
|
||||
import { FetchHttpClient } from "effect/unstable/http"
|
||||
|
||||
const api = OpenAPI.fromSpec({
|
||||
spec: await Bun.file("openapi.json").json(), // parsed document (no YAML)
|
||||
auth: {
|
||||
resolve: ({ name, scopes, operation }) =>
|
||||
name === "BearerAuth" ? Effect.succeed({ type: "bearer", token }) : Effect.succeed(undefined),
|
||||
},
|
||||
})
|
||||
|
||||
const runtime = CodeMode.make({ tools: { opencode: api.tools } })
|
||||
const result = await Effect.runPromise(runtime.execute(code).pipe(Effect.provide(FetchHttpClient.layer)))
|
||||
```
|
||||
|
||||
`fromSpec` is synchronous and returns `{ tools, skipped }`. The initial adapter supports query `form`/`deepObject`, path/header `simple`, JSON request bodies, JSON responses, and text responses; unsupported parameter encodings, non-JSON request bodies, binary responses, and streaming operations land in `skipped` instead of producing broken tools. Operation and path servers take precedence over document servers unless `baseUrl` explicitly overrides all of them. Tool inputs flatten path, query, header, and closed object-body fields into one model-facing object while retaining their HTTP locations internally. Cross-location name collisions receive a location prefix such as `path_id` and `query_id`; composed, nullable, dictionary, conditionally-required, and non-object JSON bodies remain under `body`. Auth is never model-visible. Responses are limited to 50 MiB, and non-2xx responses become safe tool failures carrying the status and a size-capped body summary. Deferred capabilities are tracked in `src/openapi/TODO.md`.
|
||||
|
||||
Supported bearer, basic, header, and query authentication follows OpenAPI `security` semantics and is resolved host-side via `auth.resolve` - credential storage, OAuth flows, and token refresh never enter the compiler. Cookie authentication alternatives are discarded; an operation is skipped when it has no supported alternative. See the option docstrings in `src/openapi/types.ts` for the full semantics. Generated tools require `HttpClient.HttpClient` (from `effect/unstable/http`) in the Effect environment - provide `FetchHttpClient.layer` or a custom/test client layer at execution. The supplied client owns redirect policy; credentialed hosts should reject redirects or strip credentials when the origin changes.
|
||||
|
||||
## Discovery
|
||||
|
||||
The agent-tool instructions use a budgeted catalog. Every tool namespace is always listed with its tool count regardless of budget, and as many complete tool signatures (each with a one-line description) as fit an estimated-token budget are inlined. Selection is round-robin across namespaces for fairness: in each round (namespaces alphabetical), every namespace still holding un-inlined tools attempts to place its next-cheapest signature line against the shared budget, and a namespace whose next line does not fit drops out while the others keep going - so every namespace gets some representation before any namespace gets everything. The instructions state exactly how comprehensive the list is, both overall (`COMPLETE list` vs `PARTIAL - N of M shown`) and per namespace (`(3 tools)`, `(3 tools, 1 shown)`, `(3 tools, none shown)`).
|
||||
@@ -329,6 +308,8 @@ A program cannot gain authority through prose or generated code. It can only exe
|
||||
The public contract is guided by these equivalences:
|
||||
|
||||
- `CodeMode.execute({ ...options, code })` is equivalent to `CodeMode.make(options).execute(code)`.
|
||||
- `CodeMode.make(options).agentTool().execute({ code })` is equivalent to `CodeMode.make(options).execute(code)`.
|
||||
- `CodeMode.make(options).agentTool().description` equals `CodeMode.make(options).instructions()`.
|
||||
- A tool implementation is not invoked unless its input has decoded successfully.
|
||||
- A tool result is not visible to the program unless its output has decoded and crossed the plain-data boundary successfully.
|
||||
- Unknown host failures do not become model-visible diagnostics; `ToolError` is the explicit safe-message channel.
|
||||
|
||||
@@ -246,7 +246,7 @@ maxOutputBytes? }` (defaults 10_000 / 100 / 32_000). This wave kept the other kn
|
||||
serialized values become truncated text + ` [result truncated: N bytes exceeds the M-byte
|
||||
output limit; return a smaller value]`; logs keep leading lines within the remaining budget
|
||||
- `[logs truncated: showing K of N lines]`; result gains `truncated: true` (also added to
|
||||
`CodeMode.Result`). UTF-8-safe truncation (no split code points). (The in-sandbox
|
||||
`ExecuteResultSchema`). UTF-8-safe truncation (no split code points). (The in-sandbox
|
||||
`maxDataBytes` check that used to throw first on oversized raw values died in Fix 5 -
|
||||
truncation is now the only result-size mechanism.)
|
||||
- **Search polish**: default limit 12 -> **10** (`defaultSearchLimit`); exact-path lookup - a
|
||||
@@ -575,7 +575,7 @@ configurable knobs; the internal limit system dies):
|
||||
`maxCollectionLength` (every array-length/object-field-count check - this knob was
|
||||
actively harmful: an MCP tool returning 20k rows failed). The `OperationLimitExceeded`
|
||||
and `AuditLimitExceeded` diagnostic kinds are gone from the `DiagnosticKind` union and
|
||||
`CodeMode.Result` (fine - the package is unreleased).
|
||||
`ExecuteResultSchema` (fine - the package is unreleased).
|
||||
- **Fixed constants, not knobs**: `TOOL_CALL_CONCURRENCY = 8` (codemode.ts; the fork
|
||||
semaphore) and `MAX_VALUE_DEPTH = 32` (tool-runtime.ts; the `copyIn` depth check - kept
|
||||
only because it produces a clearer error than a native stack-overflow RangeError; still
|
||||
|
||||
@@ -108,14 +108,14 @@ export type ExecuteFailure = {
|
||||
/** Result of executing a CodeMode program. Program failures are data, not Effect failures. */
|
||||
export type ExecuteResult = ExecuteSuccess | ExecuteFailure
|
||||
|
||||
/** Configuration shared by `CodeMode.make` and `CodeMode.execute`. */
|
||||
/** Reusable CodeMode configuration shared by `execute` and `agentTool`. */
|
||||
export type CodeModeOptions<Tools extends Record<string, unknown> = {}> = Omit<ExecuteOptions<Tools>, "code"> & {
|
||||
/** Progressive-disclosure configuration for the agent-facing tool catalog. */
|
||||
readonly discovery?: DiscoveryOptions
|
||||
}
|
||||
|
||||
/** Schema for a CodeMode execution request. */
|
||||
const Input = Schema.Struct({ code: Schema.String })
|
||||
/** Input schema for the single agent-facing tool produced by `runtime.agentTool()`. */
|
||||
export const ExecuteInputSchema = Schema.Struct({ code: Schema.String })
|
||||
|
||||
const DiagnosticKindSchema = Schema.Literals([
|
||||
"ParseError",
|
||||
@@ -130,8 +130,8 @@ const DiagnosticKindSchema = Schema.Literals([
|
||||
"ExecutionFailure",
|
||||
])
|
||||
|
||||
/** Schema for the structured success or diagnostic returned by CodeMode execution. */
|
||||
const Result = Schema.Union([
|
||||
/** Structured success or diagnostic result schema returned by CodeMode execution. */
|
||||
export const ExecuteResultSchema = Schema.Union([
|
||||
Schema.Struct({
|
||||
ok: Schema.Literal(true),
|
||||
value: Schema.Json,
|
||||
@@ -153,12 +153,23 @@ const Result = Schema.Union([
|
||||
}),
|
||||
])
|
||||
|
||||
/** Agent-facing projection of a configured CodeMode runtime. */
|
||||
export type AgentToolDefinition<R = never> = {
|
||||
readonly name: "code"
|
||||
readonly description: string
|
||||
readonly input: typeof ExecuteInputSchema
|
||||
readonly output: typeof ExecuteResultSchema
|
||||
readonly execute: (input: { readonly code: string }) => Effect.Effect<ExecuteResult, never, R>
|
||||
}
|
||||
|
||||
/** Reusable confined runtime over one explicit tool tree. */
|
||||
export type CodeModeRuntime<R = never> = {
|
||||
/** Lists schema-described tool paths provided by the host. */
|
||||
readonly catalog: () => ReadonlyArray<ToolDescription>
|
||||
/** Builds model-facing syntax guidance and visible tool signatures. */
|
||||
readonly instructions: () => string
|
||||
/** Projects the configured runtime as one agent-facing `code` tool. */
|
||||
readonly agentTool: () => AgentToolDefinition<R>
|
||||
/** Executes a program using this runtime's configured host tools. */
|
||||
readonly execute: (code: string) => Effect.Effect<ExecuteResult, never, R>
|
||||
}
|
||||
@@ -4077,12 +4088,13 @@ export const execute = <const Tools extends Record<string, unknown>>(
|
||||
/**
|
||||
* Creates an Effect-native runtime over explicit, schema-described tools.
|
||||
*
|
||||
* Use `execute` for host-driven execution. Tool requirements remain in the returned Effect environment.
|
||||
* Use `execute` for host-driven execution or `agentTool` to expose one confined code tool to an
|
||||
* agent framework. Tool requirements remain in the returned Effect environment.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const runtime = CodeMode.make({ tools: { orders: { lookup } } })
|
||||
* const result = runtime.execute("return await tools.orders.lookup({ id: 'order_42' })")
|
||||
* const code = runtime.agentTool()
|
||||
* ```
|
||||
*/
|
||||
export const make = <const Tools extends Record<string, unknown> = {}>(
|
||||
@@ -4099,9 +4111,16 @@ export const make = <const Tools extends Record<string, unknown> = {}>(
|
||||
return {
|
||||
catalog: () => catalog,
|
||||
instructions: () => instructions,
|
||||
agentTool: () => ({
|
||||
name: "code",
|
||||
description: instructions,
|
||||
input: ExecuteInputSchema,
|
||||
output: ExecuteResultSchema,
|
||||
execute: ({ code }) => executeProgram(code),
|
||||
}),
|
||||
execute: executeProgram,
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructors for one-shot and reusable CodeMode execution. */
|
||||
export const CodeMode = { Input, Result, make, execute }
|
||||
export const CodeMode = { make, execute }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
export { ToolError, CodeMode, toolError } from "./codemode.js"
|
||||
export { ToolError, CodeMode, ExecuteInputSchema, ExecuteResultSchema, toolError } from "./codemode.js"
|
||||
export { Tool } from "./tool.js"
|
||||
export * as OpenAPI from "./openapi/index.js"
|
||||
export type { Definition as ToolDefinition, JsonSchema, ToolSchema } from "./tool.js"
|
||||
export type { ToolCallEnded, ToolCallHooks } from "./tool-runtime.js"
|
||||
export type {
|
||||
AgentToolDefinition,
|
||||
CodeModeOptions,
|
||||
CodeModeRuntime,
|
||||
DataValue,
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# OpenAPI Follow-ups
|
||||
|
||||
The initial adapter intentionally skips operations it cannot execute correctly. Future work may add:
|
||||
|
||||
- Cookie parameters, authentication, and cookie-header merging.
|
||||
- Matrix, label, space-delimited, pipe-delimited, `allowReserved`, and parameter `content` serialization.
|
||||
- External references and complete nested `$defs` support.
|
||||
- Relative or templated server URLs and server variables.
|
||||
- Base URLs containing query strings or fragments.
|
||||
- Runtime response-schema validation and full content negotiation.
|
||||
- Binary response values and explicit byte-oriented return types.
|
||||
- Request/response projection for `readOnly` and `writeOnly` properties.
|
||||
- SSE, WebSocket, and other streaming transports.
|
||||
- Recovery of responses rejected by a status-filtering `HttpClient`.
|
||||
- Configurable request and response size limits.
|
||||
- Adapter-enforced redirect policy independent of the supplied `HttpClient`.
|
||||
- Strict UTF-8 and empty-body validation for JSON responses.
|
||||
- Compile-time rejection of parameter schemas with nested values unsupported by their serialization style; runtime rejects them before auth resolution.
|
||||
- Complete malformed-security-scheme validation and broader auth-combination coverage.
|
||||
@@ -1,130 +0,0 @@
|
||||
import { HttpClient } from "effect/unstable/http"
|
||||
import { Tool, type Definition } from "../tool.js"
|
||||
import { invoke } from "./runtime.js"
|
||||
import {
|
||||
componentDefinitions,
|
||||
inputSchema,
|
||||
isRecord,
|
||||
methods,
|
||||
nonEmptyString,
|
||||
operationInput,
|
||||
operationOutput,
|
||||
operationPath,
|
||||
operationSecurityRequirements,
|
||||
securityRequirements,
|
||||
securitySchemes,
|
||||
specServerUrl,
|
||||
validateBaseUrl,
|
||||
} from "./spec.js"
|
||||
import type { Operation, Options, Result, Skipped, Tools } from "./types.js"
|
||||
|
||||
export type {
|
||||
AuthResolver,
|
||||
Credential,
|
||||
Document,
|
||||
Operation,
|
||||
Options,
|
||||
Result,
|
||||
SecurityScheme,
|
||||
Skipped,
|
||||
Tools,
|
||||
} from "./types.js"
|
||||
|
||||
/**
|
||||
* Builds a CodeMode tool subtree from an OpenAPI 3.x document, one tool per
|
||||
* operation. Auth is resolved host-side via `auth.resolve` and never
|
||||
* model-visible. Tools require `HttpClient.HttpClient`; unrepresentable
|
||||
* operations land in `skipped`.
|
||||
*/
|
||||
export const fromSpec = (options: Options): Result => {
|
||||
const document = options.spec
|
||||
const schemes = securitySchemes(document)
|
||||
const defaultSecurity = securityRequirements(document.security)
|
||||
const definitions = componentDefinitions(document)
|
||||
const paths = isRecord(document.paths) ? document.paths : {}
|
||||
const used = new Set<string>()
|
||||
const namespaces = new Set<string>()
|
||||
const skipped: Array<Skipped> = []
|
||||
const tools = Object.create(null) as Tools
|
||||
|
||||
for (const [path, pathValue] of Object.entries(paths)) {
|
||||
if (!isRecord(pathValue)) continue
|
||||
for (const [method, operationValue] of Object.entries(pathValue)) {
|
||||
if (!methods.has(method) || !isRecord(operationValue)) continue
|
||||
const segments = operationPath(method, path, operationValue, used, namespaces)
|
||||
const operation: Operation = {
|
||||
operationId: nonEmptyString(operationValue.operationId),
|
||||
method: method.toUpperCase(),
|
||||
path,
|
||||
summary: nonEmptyString(operationValue.summary),
|
||||
description: nonEmptyString(operationValue.description),
|
||||
}
|
||||
const output = operationOutput(document, operationValue, definitions)
|
||||
if (!output.ok) {
|
||||
skipped.push({ method: operation.method, path, reason: output.reason })
|
||||
continue
|
||||
}
|
||||
|
||||
const resolvedBaseUrl = (() => {
|
||||
if (options.baseUrl !== undefined) return validateBaseUrl(options.baseUrl)
|
||||
if (operationValue.servers !== undefined) return specServerUrl(operationValue)
|
||||
if (pathValue.servers !== undefined) return specServerUrl(pathValue)
|
||||
return specServerUrl(document)
|
||||
})()
|
||||
if (!resolvedBaseUrl.ok) {
|
||||
skipped.push({ method: operation.method, path, reason: resolvedBaseUrl.reason })
|
||||
continue
|
||||
}
|
||||
const parsedInput = operationInput(document, pathValue, operationValue)
|
||||
if (!parsedInput.ok) {
|
||||
skipped.push({ method: operation.method, path, reason: parsedInput.reason })
|
||||
continue
|
||||
}
|
||||
const input = parsedInput.value
|
||||
|
||||
const security = operationSecurityRequirements(operationValue.security, defaultSecurity, schemes)
|
||||
if (!security.ok) {
|
||||
skipped.push({ method: operation.method, path, reason: security.reason })
|
||||
continue
|
||||
}
|
||||
const plan = {
|
||||
operation,
|
||||
url: `${resolvedBaseUrl.value.replace(/\/+$/, "")}${path}`,
|
||||
fields: input.fields,
|
||||
body: input.body,
|
||||
security: security.value,
|
||||
schemes,
|
||||
auth: options.auth,
|
||||
headers: options.headers ?? {},
|
||||
}
|
||||
used.add(segments.join("."))
|
||||
for (const index of segments.slice(0, -1).keys()) namespaces.add(segments.slice(0, index + 1).join("."))
|
||||
setTool(
|
||||
tools,
|
||||
segments,
|
||||
Tool.make({
|
||||
description: operation.description ?? operation.summary ?? `${operation.method} ${path}`,
|
||||
input: inputSchema(input.fields, definitions),
|
||||
output: output.value,
|
||||
run: (input) => invoke(plan, input),
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return { tools, skipped }
|
||||
}
|
||||
|
||||
const setTool = (tools: Tools, path: ReadonlyArray<string>, definition: Definition<HttpClient.HttpClient>): void => {
|
||||
const [head, ...rest] = path
|
||||
if (head === undefined) return
|
||||
if (rest.length === 0) {
|
||||
tools[head] = definition
|
||||
return
|
||||
}
|
||||
const child = tools[head]
|
||||
if (child === undefined || !isRecord(child) || child._tag === "CodeModeTool") {
|
||||
tools[head] = Object.create(null) as Tools
|
||||
}
|
||||
setTool(tools[head] as Tools, rest, definition)
|
||||
}
|
||||
@@ -1,326 +0,0 @@
|
||||
import { Effect, Option, Schema, Stream } from "effect"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse, type HttpMethod } from "effect/unstable/http"
|
||||
import { ToolError, toolError } from "../tool-error.js"
|
||||
import { isRecord, own } from "./spec.js"
|
||||
import type { AppliedAuth, Credential, Plan, SecurityScheme } from "./types.js"
|
||||
|
||||
const decodeJson = Schema.decodeUnknownOption(Schema.UnknownFromJsonString)
|
||||
const maxErrorBodyChars = 1_024
|
||||
const maxResponseBodyBytes = 50 * 1024 * 1024
|
||||
|
||||
export const invoke = (plan: Plan, input: unknown): Effect.Effect<unknown, unknown, HttpClient.HttpClient> =>
|
||||
Effect.gen(function* () {
|
||||
const value = isRecord(input) ? input : {}
|
||||
|
||||
let request = yield* buildRequest(plan, value)
|
||||
|
||||
const auth = yield* resolveAuth(plan)
|
||||
for (const [name, item] of Object.entries(auth.query)) {
|
||||
request = HttpClientRequest.setUrlParam(request, name, item)
|
||||
}
|
||||
request = HttpClientRequest.setHeaders(request, auth.headers)
|
||||
|
||||
const client = yield* HttpClient.HttpClient
|
||||
const response = yield* client
|
||||
.execute(request)
|
||||
.pipe(
|
||||
Effect.catch((cause) =>
|
||||
Effect.fail(toolError(`${plan.operation.method} ${plan.operation.path} failed: transport error`, cause)),
|
||||
),
|
||||
)
|
||||
const text = yield* readResponseBody(response, plan)
|
||||
const mediaType = response.headers["content-type"]?.split(";")[0]?.trim().toLowerCase()
|
||||
const json = mediaType === "application/json" || mediaType?.endsWith("+json") === true
|
||||
const decoded = text === "" ? Option.some(null) : json ? decodeJson(text) : Option.none()
|
||||
const parsed = json ? Option.getOrElse(decoded, () => text) : text === "" ? null : text
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
const rendered = typeof parsed === "string" ? parsed : (JSON.stringify(parsed) ?? "")
|
||||
const summary =
|
||||
rendered === "" || rendered === "null"
|
||||
? "no response body"
|
||||
: rendered.length > maxErrorBodyChars
|
||||
? `${rendered.slice(0, maxErrorBodyChars)}...`
|
||||
: rendered
|
||||
return yield* Effect.fail(
|
||||
toolError(`${plan.operation.method} ${plan.operation.path} failed with HTTP ${response.status}: ${summary}`),
|
||||
)
|
||||
}
|
||||
if (json && Option.isNone(decoded)) {
|
||||
return yield* Effect.fail(toolError(`${plan.operation.method} ${plan.operation.path} returned malformed JSON.`))
|
||||
}
|
||||
return parsed
|
||||
})
|
||||
|
||||
const buildRequest = (
|
||||
plan: Plan,
|
||||
input: Readonly<Record<string, unknown>>,
|
||||
): Effect.Effect<HttpClientRequest.HttpClientRequest, ToolError> =>
|
||||
Effect.gen(function* () {
|
||||
// Validate every model-controlled value before auth resolution, which may refresh tokens.
|
||||
const url = buildUrl(plan, input)
|
||||
if (url instanceof ToolError) return yield* Effect.fail(url)
|
||||
const missing = plan.fields.find(
|
||||
(field) => field.required && field.location !== "path" && own(input, field.inputName) === undefined,
|
||||
)
|
||||
if (missing !== undefined) {
|
||||
const label = missing.location === "body" ? "body field" : `${missing.location} parameter`
|
||||
return yield* Effect.fail(toolError(`Missing required ${label} '${missing.inputName}'.`))
|
||||
}
|
||||
|
||||
let request = HttpClientRequest.make(plan.operation.method as HttpMethod.HttpMethod)(url)
|
||||
for (const field of plan.fields) {
|
||||
if (field.location !== "query") continue
|
||||
const item = own(input, field.inputName)
|
||||
if (item === undefined) continue
|
||||
const serialized = serializeQuery(request, field, item)
|
||||
if (serialized instanceof ToolError) return yield* Effect.fail(serialized)
|
||||
request = serialized
|
||||
}
|
||||
|
||||
// Host headers first, then declared header parameters.
|
||||
request = HttpClientRequest.setHeaders(request, plan.headers)
|
||||
for (const field of plan.fields) {
|
||||
if (field.location !== "header") continue
|
||||
const item = own(input, field.inputName)
|
||||
if (item === undefined) continue
|
||||
const serialized = serializeSimple(field, item, String)
|
||||
if (serialized instanceof ToolError) return yield* Effect.fail(serialized)
|
||||
request = HttpClientRequest.setHeader(request, field.name, serialized)
|
||||
}
|
||||
|
||||
const setBody = (value: unknown, mediaType: string) =>
|
||||
HttpClientRequest.bodyJson(request, value).pipe(
|
||||
Effect.map((next) => HttpClientRequest.setHeader(next, "content-type", mediaType)),
|
||||
Effect.mapError((cause) =>
|
||||
toolError(`Invalid JSON body for ${plan.operation.method} ${plan.operation.path}.`, cause),
|
||||
),
|
||||
)
|
||||
if (plan.body?.mode === "value") {
|
||||
const field = plan.fields.find((field) => field.location === "body")
|
||||
const body = field === undefined ? undefined : own(input, field.inputName)
|
||||
if (body !== undefined) request = yield* setBody(body, plan.body.mediaType)
|
||||
}
|
||||
if (plan.body?.mode === "object") {
|
||||
const entries = plan.fields.flatMap((field) => {
|
||||
if (field.location !== "body") return []
|
||||
const item = own(input, field.inputName)
|
||||
return item === undefined ? [] : [[field.name, item] as const]
|
||||
})
|
||||
if (plan.body.required || entries.length > 0) {
|
||||
request = yield* setBody(Object.fromEntries(entries), plan.body.mediaType)
|
||||
}
|
||||
}
|
||||
return request
|
||||
})
|
||||
|
||||
const resolveAuth = (plan: Plan): Effect.Effect<AppliedAuth, unknown> =>
|
||||
Effect.gen(function* () {
|
||||
const none: AppliedAuth = { headers: {}, query: {} }
|
||||
if (plan.security.length === 0) return none
|
||||
|
||||
const unavailable: Array<string> = []
|
||||
alternatives: for (const requirement of plan.security) {
|
||||
const names = Object.keys(requirement)
|
||||
if (names.length === 0) return none
|
||||
const credentials: Array<readonly [string, SecurityScheme, Credential]> = []
|
||||
for (const name of names) {
|
||||
const scheme = own(plan.schemes, name)
|
||||
if (scheme === undefined || plan.auth === undefined) {
|
||||
unavailable.push(name)
|
||||
continue alternatives
|
||||
}
|
||||
const credential = yield* plan.auth.resolve({
|
||||
name,
|
||||
definition: scheme,
|
||||
scopes: requirement[name] ?? [],
|
||||
operation: plan.operation,
|
||||
})
|
||||
if (credential === undefined) {
|
||||
unavailable.push(name)
|
||||
continue alternatives
|
||||
}
|
||||
credentials.push([name, scheme, credential])
|
||||
}
|
||||
const applied = applyCredentials(credentials)
|
||||
return applied instanceof ToolError ? yield* Effect.fail(applied) : applied
|
||||
}
|
||||
|
||||
return yield* Effect.fail(
|
||||
toolError(
|
||||
`${plan.operation.method} ${plan.operation.path} requires authentication; no credential available for: ${[...new Set(unavailable)].join(", ")}.`,
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
const applyCredentials = (
|
||||
credentials: ReadonlyArray<readonly [string, SecurityScheme, Credential]>,
|
||||
): AppliedAuth | ToolError => {
|
||||
const headers = new Map<string, string>()
|
||||
const query = new Map<string, string>()
|
||||
const add = (carrier: "header" | "query", name: string, value: string): ToolError | undefined => {
|
||||
const target = carrier === "header" ? headers : query
|
||||
if (target.has(name)) return toolError(`Authentication resolves multiple credentials for ${carrier} '${name}'.`)
|
||||
target.set(name, value)
|
||||
}
|
||||
for (const [name, definition, credential] of credentials) {
|
||||
if (credential.type === "bearer") {
|
||||
const duplicate = add("header", "authorization", `Bearer ${credential.token}`)
|
||||
if (duplicate !== undefined) return duplicate
|
||||
continue
|
||||
}
|
||||
if (credential.type === "basic") {
|
||||
// Buffer instead of btoa: btoa throws on non-Latin-1 credentials.
|
||||
const duplicate = add(
|
||||
"header",
|
||||
"authorization",
|
||||
`Basic ${Buffer.from(`${credential.username}:${credential.password}`, "utf8").toString("base64")}`,
|
||||
)
|
||||
if (duplicate !== undefined) return duplicate
|
||||
continue
|
||||
}
|
||||
if (credential.type === "header") {
|
||||
const duplicate = add("header", credential.name.toLowerCase(), credential.value)
|
||||
if (duplicate !== undefined) return duplicate
|
||||
continue
|
||||
}
|
||||
// apiKey: the carrier comes from the scheme declaration.
|
||||
if (definition.type !== "apiKey") {
|
||||
return toolError(
|
||||
`Security scheme '${name}' is not an apiKey scheme; resolve a bearer, basic, or header credential for it.`,
|
||||
)
|
||||
}
|
||||
if (definition.in === "cookie") return toolError(`Cookie authentication '${name}' is not supported.`)
|
||||
const parameter = definition.in === "header" ? definition.name.toLowerCase() : definition.name
|
||||
const duplicate = add(definition.in, parameter, credential.value)
|
||||
if (duplicate !== undefined) return duplicate
|
||||
}
|
||||
return { headers: Object.fromEntries(headers), query: Object.fromEntries(query) }
|
||||
}
|
||||
|
||||
const buildUrl = (plan: Plan, input: Readonly<Record<string, unknown>>): string | ToolError => {
|
||||
let url = plan.url
|
||||
for (const field of plan.fields) {
|
||||
if (field.location !== "path") continue
|
||||
const item = own(input, field.inputName)
|
||||
if (item === undefined) {
|
||||
return toolError(`Missing required path parameter '${field.inputName}'.`)
|
||||
}
|
||||
const fieldValue = serializeSimple(field, item, (value) =>
|
||||
encodeURIComponent(value).replace(
|
||||
/[!'()*]/g,
|
||||
(character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`,
|
||||
),
|
||||
)
|
||||
if (fieldValue instanceof ToolError) return fieldValue
|
||||
// '.'/'..' survive encoding and URL normalization collapses them, letting a
|
||||
// model-supplied value retarget the request to a different endpoint.
|
||||
if (fieldValue === "" || fieldValue === "." || fieldValue === "..") {
|
||||
return toolError(`Invalid path parameter '${field.inputName}'.`)
|
||||
}
|
||||
url = url.replaceAll(`{${field.name}}`, fieldValue)
|
||||
}
|
||||
const unresolved = url.match(/\{[^{}]+\}/)
|
||||
if (unresolved !== null) return toolError(`Unresolved path parameter ${unresolved[0]}.`)
|
||||
return url
|
||||
}
|
||||
|
||||
const serializeSimple = (
|
||||
field: Plan["fields"][number],
|
||||
value: unknown,
|
||||
encode: (value: string) => string,
|
||||
): string | ToolError => {
|
||||
const scalar = (item: unknown): string | ToolError =>
|
||||
item !== null && typeof item !== "string" && typeof item !== "number" && typeof item !== "boolean"
|
||||
? toolError(`Parameter '${field.inputName}' contains an unsupported nested value.`)
|
||||
: encode(String(item))
|
||||
if (Array.isArray(value)) {
|
||||
const items = value.map(scalar)
|
||||
const invalid = items.find((item): item is ToolError => item instanceof ToolError)
|
||||
return invalid ?? items.join(",")
|
||||
}
|
||||
if (!isRecord(value)) return scalar(value)
|
||||
const entries = Object.entries(value).flatMap<string | ToolError>(([name, item]) => {
|
||||
const rendered = scalar(item)
|
||||
if (rendered instanceof ToolError) return [rendered]
|
||||
return field.explode ? [`${encode(name)}=${rendered}`] : [encode(name), rendered]
|
||||
})
|
||||
const invalid = entries.find((item): item is ToolError => item instanceof ToolError)
|
||||
return invalid ?? entries.join(",")
|
||||
}
|
||||
|
||||
const serializeQuery = (
|
||||
request: HttpClientRequest.HttpClientRequest,
|
||||
field: Plan["fields"][number],
|
||||
value: unknown,
|
||||
): HttpClientRequest.HttpClientRequest | ToolError => {
|
||||
if (field.style === "deepObject") {
|
||||
if (!isRecord(value)) return toolError(`Deep-object parameter '${field.inputName}' must be an object.`)
|
||||
return Object.entries(value).reduce<HttpClientRequest.HttpClientRequest | ToolError>((current, [name, item]) => {
|
||||
if (current instanceof ToolError) return current
|
||||
if (item === undefined || (item !== null && typeof item === "object")) {
|
||||
return toolError(`Deep-object parameter '${field.inputName}' contains an unsupported nested value.`)
|
||||
}
|
||||
return HttpClientRequest.appendUrlParam(current, `${field.name}[${name}]`, String(item))
|
||||
}, request)
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
const rendered = serializeSimple(field, value, String)
|
||||
if (rendered instanceof ToolError) return rendered
|
||||
if (!field.explode) return HttpClientRequest.appendUrlParam(request, field.name, rendered)
|
||||
if (value.some((item) => item === undefined || (item !== null && typeof item === "object"))) {
|
||||
return toolError(`Query parameter '${field.inputName}' contains an unsupported nested value.`)
|
||||
}
|
||||
return value.reduce((current, item) => HttpClientRequest.appendUrlParam(current, field.name, String(item)), request)
|
||||
}
|
||||
if (isRecord(value) && field.explode) {
|
||||
return Object.entries(value).reduce<HttpClientRequest.HttpClientRequest | ToolError>((current, [name, item]) => {
|
||||
if (current instanceof ToolError) return current
|
||||
if (item === undefined || (item !== null && typeof item === "object")) {
|
||||
return toolError(`Query parameter '${field.inputName}' contains an unsupported nested value.`)
|
||||
}
|
||||
return HttpClientRequest.appendUrlParam(current, name, String(item))
|
||||
}, request)
|
||||
}
|
||||
const rendered = serializeSimple(field, value, String)
|
||||
return rendered instanceof ToolError ? rendered : HttpClientRequest.appendUrlParam(request, field.name, rendered)
|
||||
}
|
||||
|
||||
const readResponseBody = (
|
||||
response: HttpClientResponse.HttpClientResponse,
|
||||
plan: Plan,
|
||||
): Effect.Effect<string, ToolError> =>
|
||||
Effect.gen(function* () {
|
||||
const contentLength = response.headers["content-length"]
|
||||
const parsedSize = contentLength === undefined ? undefined : Number.parseInt(contentLength, 10)
|
||||
const declaredSize =
|
||||
parsedSize !== undefined && Number.isSafeInteger(parsedSize) && parsedSize >= 0 ? parsedSize : undefined
|
||||
if (declaredSize !== undefined && declaredSize > maxResponseBodyBytes) {
|
||||
return yield* Effect.fail(toolError(`${plan.operation.method} ${plan.operation.path} response exceeds 50 MiB.`))
|
||||
}
|
||||
let body = Buffer.allocUnsafe(Math.min(maxResponseBodyBytes, declaredSize ?? 64 * 1024))
|
||||
let size = 0
|
||||
yield* Stream.runForEach(response.stream, (chunk) => {
|
||||
if (size + chunk.byteLength > maxResponseBodyBytes) {
|
||||
return Effect.fail(toolError(`${plan.operation.method} ${plan.operation.path} response exceeds 50 MiB.`))
|
||||
}
|
||||
if (size + chunk.byteLength > body.byteLength) {
|
||||
const grown = Buffer.allocUnsafe(
|
||||
Math.min(maxResponseBodyBytes, Math.max(size + chunk.byteLength, body.byteLength * 2)),
|
||||
)
|
||||
body.copy(grown, 0, 0, size)
|
||||
body = grown
|
||||
}
|
||||
body.set(chunk, size)
|
||||
size += chunk.byteLength
|
||||
return Effect.void
|
||||
}).pipe(
|
||||
Effect.catch((cause) => {
|
||||
if (cause instanceof ToolError) return Effect.fail(cause)
|
||||
if (cause.reason._tag === "EmptyBodyError") return Effect.void
|
||||
return Effect.fail(
|
||||
toolError(`${plan.operation.method} ${plan.operation.path} failed while reading the response body.`, cause),
|
||||
)
|
||||
}),
|
||||
)
|
||||
return new TextDecoder().decode(body.subarray(0, size))
|
||||
})
|
||||
@@ -1,511 +0,0 @@
|
||||
import { fromSchemaOpenApi3_0, fromSchemaOpenApi3_1 } from "effect/JsonSchema"
|
||||
import type { JsonSchema } from "../tool.js"
|
||||
import { isBlockedMember } from "../tool-runtime.js"
|
||||
import type {
|
||||
Body,
|
||||
Document,
|
||||
InputField,
|
||||
OperationInput,
|
||||
Parsed,
|
||||
SecurityRequirement,
|
||||
SecurityScheme,
|
||||
} from "./types.js"
|
||||
|
||||
export const methods = new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"])
|
||||
const parameterLocations = ["path", "query", "header"] as const
|
||||
const ignoredHeaderParameters = new Set(["accept", "content-type", "authorization"])
|
||||
|
||||
export const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
typeof value === "object" && value !== null && !Array.isArray(value)
|
||||
|
||||
const asArray = (value: unknown): ReadonlyArray<unknown> => (Array.isArray(value) ? value : [])
|
||||
|
||||
export const nonEmptyString = (value: unknown): string | undefined =>
|
||||
typeof value === "string" && value !== "" ? value : undefined
|
||||
|
||||
// Guards record lookups keyed by spec- or model-controlled names against
|
||||
// prototype-inherited values (e.g. a parameter named `toString`).
|
||||
export const own = <T>(record: Readonly<Record<string, T>>, key: string): T | undefined =>
|
||||
Object.hasOwn(record, key) ? record[key] : undefined
|
||||
|
||||
export const resolve = (document: Document, value: unknown): unknown => {
|
||||
const next = (current: unknown, seen: ReadonlySet<string>): unknown => {
|
||||
if (!isRecord(current)) return current
|
||||
const ref = nonEmptyString(current.$ref)
|
||||
if (ref === undefined || !ref.startsWith("#/") || seen.has(ref)) return current
|
||||
const target = ref
|
||||
.slice(2)
|
||||
.split("/")
|
||||
.map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~"))
|
||||
.reduce<unknown>((item, segment) => (isRecord(item) ? own(item, segment) : undefined), document)
|
||||
return target === undefined ? current : next(target, new Set([...seen, ref]))
|
||||
}
|
||||
return next(value, new Set())
|
||||
}
|
||||
|
||||
const projectSchema = (document: Document, value: unknown): JsonSchema => {
|
||||
if (!isRecord(value)) return {}
|
||||
const normalized = nonEmptyString(document.openapi)?.startsWith("3.0")
|
||||
? fromSchemaOpenApi3_0(value)
|
||||
: fromSchemaOpenApi3_1(value)
|
||||
return Object.keys(normalized.definitions).length === 0
|
||||
? normalized.schema
|
||||
: { ...normalized.schema, $defs: normalized.definitions }
|
||||
}
|
||||
|
||||
export const componentDefinitions = (document: Document): Readonly<Record<string, JsonSchema>> => {
|
||||
const components = isRecord(document.components) ? document.components : {}
|
||||
const schemas = isRecord(components.schemas) ? components.schemas : {}
|
||||
return Object.fromEntries(Object.entries(schemas).map(([name, value]) => [name, projectSchema(document, value)]))
|
||||
}
|
||||
|
||||
const withDefinitions = (schema: JsonSchema, definitions: Readonly<Record<string, JsonSchema>>): JsonSchema => {
|
||||
if (Object.keys(definitions).length === 0) return schema
|
||||
const local = isRecord(schema.$defs) ? schema.$defs : {}
|
||||
return { ...schema, $defs: { ...definitions, ...local } }
|
||||
}
|
||||
|
||||
const isJsonMediaType = (mediaType: string): boolean => {
|
||||
const normalized = mediaType.split(";")[0]?.trim().toLowerCase() ?? ""
|
||||
return normalized === "application/json" || normalized.endsWith("+json")
|
||||
}
|
||||
|
||||
const isBinaryMediaType = (document: Document, mediaType: string, value: unknown): boolean => {
|
||||
const normalized = mediaType.split(";")[0]?.trim().toLowerCase() ?? ""
|
||||
if (!isJsonMediaType(normalized) && !normalized.startsWith("text/")) return true
|
||||
if (!isRecord(value)) return false
|
||||
const schema = resolve(document, value.schema)
|
||||
return isRecord(schema) && schema.format === "binary"
|
||||
}
|
||||
|
||||
const jsonContent = (
|
||||
content: Record<string, unknown>,
|
||||
): { readonly mediaType: string; readonly schema: unknown } | undefined => {
|
||||
const entry = Object.entries(content).find(([mediaType]) => isJsonMediaType(mediaType))
|
||||
return entry !== undefined && isRecord(entry[1]) ? { mediaType: entry[0], schema: entry[1].schema } : undefined
|
||||
}
|
||||
|
||||
const isFlattenableObjectBody = (
|
||||
schema: unknown,
|
||||
requestRequired: boolean,
|
||||
): schema is Record<string, unknown> & { readonly properties: Record<string, unknown> } =>
|
||||
isRecord(schema) &&
|
||||
requestRequired &&
|
||||
schema.type === "object" &&
|
||||
isRecord(schema.properties) &&
|
||||
schema.additionalProperties === false &&
|
||||
schema.nullable !== true &&
|
||||
schema.allOf === undefined &&
|
||||
schema.anyOf === undefined &&
|
||||
schema.oneOf === undefined
|
||||
|
||||
type PlannedField = Omit<InputField, "inputName">
|
||||
|
||||
const operationParameters = (
|
||||
document: Document,
|
||||
pathItem: Record<string, unknown>,
|
||||
operation: Record<string, unknown>,
|
||||
): Parsed<ReadonlyArray<PlannedField>> => {
|
||||
// Operation-level parameters override path-level ones sharing (location, name).
|
||||
const declared = new Map<
|
||||
string,
|
||||
{ readonly name: string; readonly location: string; readonly parameter: Record<string, unknown> }
|
||||
>()
|
||||
for (const raw of [...asArray(pathItem.parameters), ...asArray(operation.parameters)]) {
|
||||
const resolved = resolve(document, raw)
|
||||
if (!isRecord(resolved)) return { ok: false, reason: "parameter declaration is invalid or unresolved" }
|
||||
const name = nonEmptyString(resolved.name)
|
||||
const location = nonEmptyString(resolved.in)
|
||||
if (name === undefined || location === undefined)
|
||||
return { ok: false, reason: "parameter declaration is missing name or location" }
|
||||
declared.set(`${location}:${name}`, { name, location, parameter: resolved })
|
||||
}
|
||||
const unordered: Array<PlannedField> = []
|
||||
for (const item of declared.values()) {
|
||||
const name = item.name
|
||||
const location = item.location
|
||||
const resolved = item.parameter
|
||||
if (location === "cookie") return { ok: false, reason: `cookie parameter '${name}' is not supported` }
|
||||
if (location !== "path" && location !== "query" && location !== "header") {
|
||||
return { ok: false, reason: `parameter '${name}' uses unsupported location '${location}'` }
|
||||
}
|
||||
if (location === "header" && ignoredHeaderParameters.has(name.toLowerCase())) continue
|
||||
if (resolved.schema === undefined && resolved.content === undefined) {
|
||||
return { ok: false, reason: `parameter '${name}' declares neither schema nor content` }
|
||||
}
|
||||
if (resolved.content !== undefined)
|
||||
return { ok: false, reason: `parameter '${name}' uses unsupported content encoding` }
|
||||
if (resolved.style !== undefined && nonEmptyString(resolved.style) === undefined) {
|
||||
return { ok: false, reason: `parameter '${name}' has an invalid style` }
|
||||
}
|
||||
if (resolved.explode !== undefined && typeof resolved.explode !== "boolean") {
|
||||
return { ok: false, reason: `parameter '${name}' has an invalid explode value` }
|
||||
}
|
||||
if (resolved.allowReserved !== undefined && typeof resolved.allowReserved !== "boolean") {
|
||||
return { ok: false, reason: `parameter '${name}' has an invalid allowReserved value` }
|
||||
}
|
||||
if (resolved.allowReserved === true)
|
||||
return { ok: false, reason: `parameter '${name}' uses unsupported allowReserved encoding` }
|
||||
const declaredStyle = nonEmptyString(resolved.style) ?? (location === "query" ? "form" : "simple")
|
||||
if (location === "query" && declaredStyle !== "form" && declaredStyle !== "deepObject") {
|
||||
return { ok: false, reason: `query parameter '${name}' uses unsupported style '${declaredStyle}'` }
|
||||
}
|
||||
if (location !== "query" && declaredStyle !== "simple") {
|
||||
return { ok: false, reason: `${location} parameter '${name}' uses unsupported style '${declaredStyle}'` }
|
||||
}
|
||||
const style = declaredStyle === "deepObject" ? "deepObject" : declaredStyle === "form" ? "form" : "simple"
|
||||
const explode = typeof resolved.explode === "boolean" ? resolved.explode : style === "form"
|
||||
if (style === "deepObject" && !explode) {
|
||||
return { ok: false, reason: `query parameter '${name}' uses deepObject with explode=false` }
|
||||
}
|
||||
const base = projectSchema(document, resolved.schema)
|
||||
const description = nonEmptyString(resolved.description)
|
||||
unordered.push({
|
||||
name,
|
||||
location,
|
||||
required: resolved.required === true || location === "path",
|
||||
style,
|
||||
explode,
|
||||
schema: {
|
||||
...base,
|
||||
...(base.description === undefined && description !== undefined ? { description } : {}),
|
||||
},
|
||||
})
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
value: parameterLocations.flatMap((location) => unordered.filter((field) => field.location === location)),
|
||||
}
|
||||
}
|
||||
|
||||
const operationBody = (
|
||||
document: Document,
|
||||
operation: Record<string, unknown>,
|
||||
): Parsed<{ readonly fields: ReadonlyArray<PlannedField>; readonly body: Body | undefined }> => {
|
||||
const resolved = resolve(document, operation.requestBody)
|
||||
if (!isRecord(resolved)) return { ok: true, value: { fields: [], body: undefined } }
|
||||
const content = isRecord(resolved.content) ? resolved.content : {}
|
||||
const selected = jsonContent(content)
|
||||
if (selected === undefined) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: `request body has no JSON content (declared: ${Object.keys(content).join(", ") || "none"})`,
|
||||
}
|
||||
}
|
||||
const schema = resolve(document, selected.schema)
|
||||
const required = resolved.required === true
|
||||
if (!isFlattenableObjectBody(schema, required)) {
|
||||
return {
|
||||
ok: true,
|
||||
value: {
|
||||
fields: [
|
||||
{
|
||||
name: "body",
|
||||
location: "body",
|
||||
required,
|
||||
schema: projectSchema(document, selected.schema),
|
||||
style: undefined,
|
||||
explode: undefined,
|
||||
},
|
||||
],
|
||||
body: { required, mode: "value", mediaType: selected.mediaType },
|
||||
},
|
||||
}
|
||||
}
|
||||
const requiredProperties = new Set(
|
||||
Array.isArray(schema.required) ? schema.required.filter((item): item is string => typeof item === "string") : [],
|
||||
)
|
||||
return {
|
||||
ok: true,
|
||||
value: {
|
||||
fields: Object.entries(schema.properties).map(([name, value]) => ({
|
||||
name,
|
||||
location: "body" as const,
|
||||
required: required && requiredProperties.has(name),
|
||||
schema: projectSchema(document, value),
|
||||
style: undefined,
|
||||
explode: undefined,
|
||||
})),
|
||||
body: { required, mode: "object", mediaType: selected.mediaType },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const operationInput = (
|
||||
document: Document,
|
||||
pathItem: Record<string, unknown>,
|
||||
operation: Record<string, unknown>,
|
||||
): Parsed<OperationInput> => {
|
||||
const parameters = operationParameters(document, pathItem, operation)
|
||||
if (!parameters.ok) return parameters
|
||||
const requestBody = operationBody(document, operation)
|
||||
if (!requestBody.ok) return requestBody
|
||||
const fields = [...parameters.value, ...requestBody.value.fields]
|
||||
|
||||
const conflicts = new Set(
|
||||
[...Map.groupBy(fields, (field) => field.name)]
|
||||
.filter(([, matches]) => new Set(matches.map((field) => field.location)).size > 1)
|
||||
.map(([name]) => name),
|
||||
)
|
||||
const used = new Set<string>()
|
||||
return {
|
||||
ok: true,
|
||||
value: {
|
||||
fields: fields.map((field) => {
|
||||
const visibleName = isBlockedMember(field.name) ? `${field.name}_2` : field.name
|
||||
const base = conflicts.has(field.name) ? `${field.location}_${visibleName}` : visibleName
|
||||
const next = (index: number): string => {
|
||||
const candidate = index === 1 ? base : `${base}_${index}`
|
||||
return used.has(candidate) ? next(index + 1) : candidate
|
||||
}
|
||||
const inputName = next(1)
|
||||
used.add(inputName)
|
||||
return { ...field, inputName }
|
||||
}),
|
||||
body: requestBody.value.body,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const inputSchema = (
|
||||
fields: ReadonlyArray<InputField>,
|
||||
definitions: Readonly<Record<string, JsonSchema>>,
|
||||
): JsonSchema => {
|
||||
const required = fields.filter((field) => field.required).map((field) => field.inputName)
|
||||
return withDefinitions(
|
||||
{
|
||||
type: "object",
|
||||
properties: Object.fromEntries(fields.map((field) => [field.inputName, field.schema])),
|
||||
...(required.length === 0 ? {} : { required }),
|
||||
},
|
||||
definitions,
|
||||
)
|
||||
}
|
||||
|
||||
const successfulResponses = (
|
||||
document: Document,
|
||||
operation: Record<string, unknown>,
|
||||
): Parsed<ReadonlyArray<Record<string, unknown>>> => {
|
||||
if (!isRecord(operation.responses)) return { ok: true, value: [] }
|
||||
const entries = Object.entries(operation.responses)
|
||||
const selected = [
|
||||
...entries.filter(([status]) => /^2\d\d$/.test(status)).sort(([a], [b]) => a.localeCompare(b)),
|
||||
...entries.filter(([status]) => status.toUpperCase() === "2XX"),
|
||||
]
|
||||
const responses: Array<Record<string, unknown>> = []
|
||||
for (const [, value] of selected) {
|
||||
const resolved = resolve(document, value)
|
||||
if (!isRecord(resolved) || nonEmptyString(resolved.$ref) !== undefined) {
|
||||
return { ok: false, reason: "successful response declaration is invalid or unresolved" }
|
||||
}
|
||||
responses.push(resolved)
|
||||
}
|
||||
return { ok: true, value: responses }
|
||||
}
|
||||
|
||||
export const operationOutput = (
|
||||
document: Document,
|
||||
operation: Record<string, unknown>,
|
||||
definitions: Readonly<Record<string, JsonSchema>>,
|
||||
): Parsed<JsonSchema | undefined> => {
|
||||
if (operation["x-websocket"] === true) return { ok: false, reason: "WebSocket operations are not supported" }
|
||||
const responses = successfulResponses(document, operation)
|
||||
if (!responses.ok) return responses
|
||||
const streams = responses.value.some(
|
||||
(response) =>
|
||||
isRecord(response.content) &&
|
||||
Object.keys(response.content).some(
|
||||
(mediaType) => mediaType.split(";")[0]?.trim().toLowerCase() === "text/event-stream",
|
||||
),
|
||||
)
|
||||
if (streams) return { ok: false, reason: "SSE operations are not supported" }
|
||||
const binary = responses.value.some(
|
||||
(response) =>
|
||||
isRecord(response.content) &&
|
||||
Object.entries(response.content).some(([mediaType, value]) => isBinaryMediaType(document, mediaType, value)),
|
||||
)
|
||||
if (binary) return { ok: false, reason: "binary responses are not supported" }
|
||||
|
||||
const outcomes: Array<JsonSchema> = []
|
||||
for (const response of responses.value) {
|
||||
if (response.content !== undefined && !isRecord(response.content)) return { ok: true, value: undefined }
|
||||
const content = isRecord(response.content) ? response.content : {}
|
||||
if (Object.keys(content).length === 0) {
|
||||
outcomes.push({ type: "null" })
|
||||
continue
|
||||
}
|
||||
for (const [mediaType, value] of Object.entries(content)) {
|
||||
if (!isJsonMediaType(mediaType)) {
|
||||
outcomes.push({ type: "string" })
|
||||
continue
|
||||
}
|
||||
if (!isRecord(value) || value.schema === undefined) return { ok: true, value: undefined }
|
||||
outcomes.push(projectSchema(document, value.schema))
|
||||
}
|
||||
}
|
||||
if (outcomes.length === 0) return { ok: true, value: undefined }
|
||||
return {
|
||||
ok: true,
|
||||
value: withDefinitions(outcomes.length === 1 ? (outcomes[0] ?? {}) : { anyOf: outcomes }, definitions),
|
||||
}
|
||||
}
|
||||
|
||||
const sanitizeOperationSegment = (raw: string): string => {
|
||||
const base =
|
||||
raw
|
||||
.replaceAll(/[^A-Za-z0-9_$]+/g, "_")
|
||||
.replace(/^_+|_+$/g, "")
|
||||
.replace(/^([0-9])/, "_$1") || "operation"
|
||||
return isBlockedMember(base) ? `${base}_2` : base
|
||||
}
|
||||
|
||||
const fallbackOperationId = (method: string, path: string): string =>
|
||||
[
|
||||
method,
|
||||
...path
|
||||
.split("/")
|
||||
.filter((part) => part !== "")
|
||||
.flatMap((part) => (part.startsWith("{") && part.endsWith("}") ? ["by", part.slice(1, -1)] : [part]))
|
||||
.flatMap((part) => part.split(/[^A-Za-z0-9]+/).filter((word) => word !== "")),
|
||||
]
|
||||
.map((word, index) => {
|
||||
const lower = word.toLowerCase()
|
||||
return index === 0 ? lower : `${lower.charAt(0).toUpperCase()}${lower.slice(1)}`
|
||||
})
|
||||
.join("")
|
||||
|
||||
export const operationPath = (
|
||||
method: string,
|
||||
path: string,
|
||||
operation: Record<string, unknown>,
|
||||
used: ReadonlySet<string>,
|
||||
namespaces: ReadonlySet<string>,
|
||||
): ReadonlyArray<string> => {
|
||||
const raw = nonEmptyString(operation.operationId)
|
||||
const segments = (raw === undefined ? [fallbackOperationId(method, path)] : raw.split(".")).map(
|
||||
sanitizeOperationSegment,
|
||||
)
|
||||
if (isOperationPathAvailable(segments, used, namespaces)) return segments
|
||||
const conflict = segments.slice(0, -1).findIndex((_, index) => used.has(segments.slice(0, index + 1).join(".")))
|
||||
if (conflict >= 0 && conflict + 1 < segments.length) {
|
||||
const collapsed = segments.flatMap((segment, index) => {
|
||||
if (index === conflict) {
|
||||
const next = segments[index + 1] ?? ""
|
||||
return [`${segment}${next.charAt(0).toUpperCase()}${next.slice(1)}`]
|
||||
}
|
||||
return index === conflict + 1 ? [] : [segment]
|
||||
})
|
||||
if (isOperationPathAvailable(collapsed, used, namespaces)) return collapsed
|
||||
}
|
||||
const fallback = segments.join("_")
|
||||
const next = (index: number): string => {
|
||||
const candidate = `${fallback}_${index}`
|
||||
return isOperationPathAvailable([candidate], used, namespaces) ? candidate : next(index + 1)
|
||||
}
|
||||
return [next(2)]
|
||||
}
|
||||
|
||||
const isOperationPathAvailable = (
|
||||
segments: ReadonlyArray<string>,
|
||||
used: ReadonlySet<string>,
|
||||
namespaces: ReadonlySet<string>,
|
||||
): boolean => {
|
||||
const key = segments.join(".")
|
||||
if (used.has(key) || namespaces.has(key)) return false
|
||||
return segments.slice(0, -1).every((_, index) => !used.has(segments.slice(0, index + 1).join(".")))
|
||||
}
|
||||
|
||||
export const specServerUrl = (source: Record<string, unknown>): Parsed<string> => {
|
||||
const server = asArray(source.servers).find(isRecord)
|
||||
const url = server === undefined ? undefined : nonEmptyString(server.url)
|
||||
if (url === undefined) return { ok: false, reason: "spec declares no servers; pass baseUrl" }
|
||||
if (/\{[^{}]+\}/.test(url)) {
|
||||
return { ok: false, reason: `server URL '${url}' is not an absolute URL; pass baseUrl` }
|
||||
}
|
||||
return validateBaseUrl(url)
|
||||
}
|
||||
|
||||
export const validateBaseUrl = (value: string): Parsed<string> => {
|
||||
if (!/^https?:\/\//i.test(value)) return { ok: false, reason: `server URL '${value}' is not an absolute HTTP(S) URL` }
|
||||
const url = URL.parse(value)
|
||||
if (url === null || (url.protocol !== "http:" && url.protocol !== "https:")) {
|
||||
return { ok: false, reason: `server URL '${value}' is not an absolute HTTP(S) URL` }
|
||||
}
|
||||
if (url.search !== "" || url.hash !== "") {
|
||||
return { ok: false, reason: `server URL '${value}' contains an unsupported query string or fragment` }
|
||||
}
|
||||
return { ok: true, value }
|
||||
}
|
||||
|
||||
export const securityRequirements = (value: unknown): Parsed<ReadonlyArray<SecurityRequirement>> => {
|
||||
if (value === undefined) return { ok: true, value: [] }
|
||||
if (!Array.isArray(value)) return { ok: false, reason: "security declaration is not an array" }
|
||||
const requirements: Array<SecurityRequirement> = []
|
||||
for (const item of value) {
|
||||
if (!isRecord(item)) return { ok: false, reason: "security requirement is not an object" }
|
||||
const requirement = Object.create(null) as Record<string, ReadonlyArray<string>>
|
||||
for (const [name, scopes] of Object.entries(item)) {
|
||||
if (!Array.isArray(scopes)) return { ok: false, reason: "security requirement scopes are not string arrays" }
|
||||
const parsed = scopes.filter((scope): scope is string => typeof scope === "string")
|
||||
if (parsed.length !== scopes.length) {
|
||||
return { ok: false, reason: "security requirement scopes are not string arrays" }
|
||||
}
|
||||
requirement[name] = parsed
|
||||
}
|
||||
requirements.push(requirement)
|
||||
}
|
||||
return { ok: true, value: requirements }
|
||||
}
|
||||
|
||||
export const operationSecurityRequirements = (
|
||||
value: unknown,
|
||||
defaults: Parsed<ReadonlyArray<SecurityRequirement>>,
|
||||
schemes: Readonly<Record<string, SecurityScheme>>,
|
||||
): Parsed<ReadonlyArray<SecurityRequirement>> => {
|
||||
const parsed = value === undefined ? defaults : securityRequirements(value)
|
||||
if (!parsed.ok) return parsed
|
||||
const supported = parsed.value.filter((requirement) =>
|
||||
Object.keys(requirement).every((name) => {
|
||||
const scheme = own(schemes, name)
|
||||
return scheme !== undefined && !(scheme.type === "apiKey" && scheme.in === "cookie")
|
||||
}),
|
||||
)
|
||||
if (parsed.value.length === 0 || supported.length > 0) return { ok: true, value: supported }
|
||||
|
||||
const names = [...new Set(parsed.value.flatMap((requirement) => Object.keys(requirement)))]
|
||||
const cookieScheme = names.find((name) => {
|
||||
const definition = own(schemes, name)
|
||||
return definition?.type === "apiKey" && definition.in === "cookie"
|
||||
})
|
||||
return {
|
||||
ok: false,
|
||||
reason:
|
||||
cookieScheme === undefined
|
||||
? `security requirement references missing or malformed scheme: ${names.join(", ")}`
|
||||
: `cookie authentication '${cookieScheme}' is not supported`,
|
||||
}
|
||||
}
|
||||
|
||||
export const securitySchemes = (document: Document): Readonly<Record<string, SecurityScheme>> => {
|
||||
const components = isRecord(document.components) ? document.components : {}
|
||||
const declared = isRecord(components.securitySchemes) ? components.securitySchemes : {}
|
||||
return Object.fromEntries(
|
||||
Object.entries(declared).flatMap<readonly [string, SecurityScheme]>(([name, value]) => {
|
||||
const resolved = resolve(document, value)
|
||||
if (!isRecord(resolved)) return []
|
||||
const type = nonEmptyString(resolved.type)
|
||||
if (type === "apiKey") {
|
||||
const carrier = nonEmptyString(resolved.in)
|
||||
const parameter = nonEmptyString(resolved.name)
|
||||
if (parameter === undefined || (carrier !== "header" && carrier !== "query" && carrier !== "cookie")) return []
|
||||
return [[name, { type, name: parameter, in: carrier }] as const]
|
||||
}
|
||||
if (type === "http") {
|
||||
const scheme = nonEmptyString(resolved.scheme)?.toLowerCase()
|
||||
return scheme === undefined ? [] : [[name, { type, scheme }] as const]
|
||||
}
|
||||
if (type === "oauth2" || type === "openIdConnect") return [[name, { type }] as const]
|
||||
return []
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
import { Effect } from "effect"
|
||||
import { HttpClient } from "effect/unstable/http"
|
||||
import type { Definition, JsonSchema } from "../tool.js"
|
||||
|
||||
/** A parsed OpenAPI 3.x document. YAML must be parsed by the host. */
|
||||
export type Document = Record<string, unknown>
|
||||
|
||||
/** The operation identity handed to auth resolution and errors. */
|
||||
export type Operation = {
|
||||
readonly operationId: string | undefined
|
||||
readonly method: string
|
||||
readonly path: string
|
||||
readonly summary: string | undefined
|
||||
readonly description: string | undefined
|
||||
}
|
||||
|
||||
/** A resolved OpenAPI security scheme from `components.securitySchemes`. */
|
||||
export type SecurityScheme =
|
||||
| { readonly type: "apiKey"; readonly name: string; readonly in: "header" | "query" | "cookie" }
|
||||
| { readonly type: "http"; readonly scheme: string }
|
||||
| { readonly type: "oauth2" }
|
||||
| { readonly type: "openIdConnect" }
|
||||
|
||||
/**
|
||||
* Credential material returned by a host auth resolver. The carrier for `apiKey`
|
||||
* comes from the scheme definition, not the credential. `header` is the escape
|
||||
* hatch for nonstandard schemes.
|
||||
*/
|
||||
export type Credential =
|
||||
| { readonly type: "bearer"; readonly token: string }
|
||||
| { readonly type: "basic"; readonly username: string; readonly password: string }
|
||||
| { readonly type: "apiKey"; readonly value: string }
|
||||
| { readonly type: "header"; readonly name: string; readonly value: string }
|
||||
|
||||
/**
|
||||
* Resolves credential material for one named security scheme at call time.
|
||||
* `undefined` means unavailable, try the next OR alternative; a failure aborts
|
||||
* the call rather than falling through.
|
||||
*/
|
||||
export type AuthResolver = (context: {
|
||||
readonly name: string
|
||||
readonly definition: SecurityScheme
|
||||
readonly scopes: ReadonlyArray<string>
|
||||
readonly operation: Operation
|
||||
}) => Effect.Effect<Credential | undefined, unknown>
|
||||
|
||||
export type Options = {
|
||||
readonly spec: Document
|
||||
/** Overrides all document, path, and operation `servers`. Required when no applicable absolute server URL exists. */
|
||||
readonly baseUrl?: string | undefined
|
||||
/** Host credential resolution, keyed by security scheme name. */
|
||||
readonly auth?: { readonly resolve: AuthResolver } | undefined
|
||||
/** Static headers on every request. Not model-visible; declared header params may override them, auth always wins. */
|
||||
readonly headers?: Readonly<Record<string, string>> | undefined
|
||||
}
|
||||
|
||||
/** An operation that could not be represented as a tool, and why. */
|
||||
export type Skipped = {
|
||||
readonly method: string
|
||||
readonly path: string
|
||||
readonly reason: string
|
||||
}
|
||||
|
||||
export type Tools = { [name: string]: Definition<HttpClient.HttpClient> | Tools }
|
||||
|
||||
export type Result = {
|
||||
/** Tool subtree; the host places it under a key in its `tools` tree. */
|
||||
readonly tools: Tools
|
||||
readonly skipped: ReadonlyArray<Skipped>
|
||||
}
|
||||
|
||||
export type Parsed<T> = { readonly ok: true; readonly value: T } | { readonly ok: false; readonly reason: string }
|
||||
|
||||
export type InputLocation = "path" | "query" | "header" | "body"
|
||||
|
||||
export type InputField = {
|
||||
/** Model-visible field name after cross-location collision handling. */
|
||||
readonly inputName: string
|
||||
/** Original parameter or body-property name used on the wire. */
|
||||
readonly name: string
|
||||
readonly location: InputLocation
|
||||
readonly required: boolean
|
||||
readonly schema: JsonSchema
|
||||
readonly style: "simple" | "form" | "deepObject" | undefined
|
||||
readonly explode: boolean | undefined
|
||||
}
|
||||
|
||||
export type Body = { readonly required: boolean; readonly mode: "object" | "value"; readonly mediaType: string }
|
||||
|
||||
export type OperationInput = {
|
||||
readonly fields: ReadonlyArray<InputField>
|
||||
readonly body: Body | undefined
|
||||
}
|
||||
|
||||
/** One OR alternative: scheme name -> required scopes. Empty object = unauthenticated is acceptable. */
|
||||
export type SecurityRequirement = Readonly<Record<string, ReadonlyArray<string>>>
|
||||
|
||||
export type Plan = {
|
||||
readonly operation: Operation
|
||||
readonly url: string
|
||||
readonly fields: ReadonlyArray<InputField>
|
||||
readonly body: Body | undefined
|
||||
readonly security: ReadonlyArray<SecurityRequirement>
|
||||
readonly schemes: Readonly<Record<string, SecurityScheme>>
|
||||
readonly auth: { readonly resolve: AuthResolver } | undefined
|
||||
readonly headers: Readonly<Record<string, string>>
|
||||
}
|
||||
|
||||
export type AppliedAuth = {
|
||||
readonly headers: Readonly<Record<string, string>>
|
||||
readonly query: Readonly<Record<string, string>>
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Token estimation for budgeting model-facing text. Copied from
|
||||
* `@opencode-ai/core/util/token` (chars / 4) so this package stays
|
||||
* dependency-free; keep the two in sync if the heuristic ever changes.
|
||||
*/
|
||||
export * as Token from "./token.js"
|
||||
|
||||
const CHARS_PER_TOKEN = 4
|
||||
|
||||
export const estimate = (input: string) => Math.max(0, Math.round(input.length / CHARS_PER_TOKEN))
|
||||
@@ -10,32 +10,27 @@ import {
|
||||
outputTypeScript,
|
||||
type Definition,
|
||||
} from "./tool.js"
|
||||
import { estimate } from "./token.js"
|
||||
import { SandboxDate, SandboxMap, SandboxPromise, SandboxRegExp, SandboxSet } from "./values.js"
|
||||
|
||||
const estimateTokens = (input: string) => Math.max(0, Math.round(input.length / 4))
|
||||
|
||||
export type HostTool<R = never> = (...args: Array<unknown>) => Effect.Effect<unknown, unknown, R>
|
||||
|
||||
export type HostTools<R = never> = {
|
||||
[name: string]: HostTool<R> | Definition<R> | HostTools<R>
|
||||
}
|
||||
|
||||
export type Services<Tools> = ServicesOf<Tools, []>
|
||||
|
||||
type ServicesOf<Tools, Depth extends ReadonlyArray<unknown>> = Depth["length"] extends 8
|
||||
? never
|
||||
: Tools extends (...args: Array<unknown>) => Effect.Effect<unknown, unknown, infer R>
|
||||
export type Services<Tools> = Tools extends (...args: Array<unknown>) => Effect.Effect<unknown, unknown, infer R>
|
||||
? R
|
||||
: Tools extends {
|
||||
readonly _tag: "CodeModeTool"
|
||||
readonly run: (input: unknown) => Effect.Effect<unknown, unknown, infer R>
|
||||
}
|
||||
? R
|
||||
: Tools extends {
|
||||
readonly _tag: "CodeModeTool"
|
||||
readonly run: (input: unknown) => Effect.Effect<unknown, unknown, infer R>
|
||||
}
|
||||
? R
|
||||
: Tools extends object
|
||||
? string extends keyof Tools
|
||||
? ServicesOf<Tools[string], [...Depth, unknown]>
|
||||
: ServicesOf<Tools[keyof Tools], [...Depth, unknown]>
|
||||
: never
|
||||
: Tools extends object
|
||||
? string extends keyof Tools
|
||||
? never
|
||||
: Services<Tools[keyof Tools]>
|
||||
: never
|
||||
|
||||
/** Minimal audit record retained for each admitted tool call. */
|
||||
export type ToolCall = {
|
||||
@@ -295,16 +290,17 @@ const definitions = <R>(
|
||||
return entries
|
||||
}
|
||||
|
||||
const describeDefinition = <R>(path: string, definition: Definition<R>): ToolDescription => ({
|
||||
path,
|
||||
description: definition.description,
|
||||
signature: `${toolExpression(path)}(input: ${inputTypeScript(definition)}): Promise<${outputTypeScript(definition)}>`,
|
||||
})
|
||||
|
||||
const visibleDefinitions = <R>(tools: HostTools<R>) =>
|
||||
definitions(tools).map(({ path, definition }) => ({
|
||||
path,
|
||||
definition,
|
||||
description: {
|
||||
path,
|
||||
description: definition.description,
|
||||
signature: `${toolExpression(path)}(input: ${inputTypeScript(definition)}): Promise<${outputTypeScript(definition)}>`,
|
||||
},
|
||||
}))
|
||||
definitions(tools).flatMap(({ path, definition }) => {
|
||||
const description = describeDefinition(path, definition)
|
||||
return [{ path, definition, description }]
|
||||
})
|
||||
|
||||
export const catalog = <R>(tools: HostTools<R>): ReadonlyArray<ToolDescription> =>
|
||||
visibleDefinitions(tools).map(({ description }) => description)
|
||||
@@ -355,10 +351,16 @@ const termForms = (term: string): Array<string> => {
|
||||
return forms
|
||||
}
|
||||
|
||||
const firstLine = (text: string) => text.split("\n", 1)[0]!.trim()
|
||||
|
||||
/** One-line description used on inline catalog lines; the full text stays in search results. */
|
||||
const brief = (text: string, max = 120) => {
|
||||
const line = firstLine(text)
|
||||
return line.length > max ? line.slice(0, max - 1) + "..." : line
|
||||
}
|
||||
|
||||
const catalogLine = (tool: ToolDescription) => {
|
||||
// Inline catalog lines use only a compact first line; full text stays in search results.
|
||||
const line = tool.description.split("\n", 1)[0]!.trim()
|
||||
const description = line.length > 120 ? line.slice(0, 119) + "..." : line
|
||||
const description = brief(tool.description)
|
||||
return description === "" ? ` - ${tool.signature}` : ` - ${tool.signature} // ${description}`
|
||||
}
|
||||
|
||||
@@ -428,7 +430,7 @@ export const discoveryPlan = <R>(
|
||||
picked: new Set<ToolDescription>(),
|
||||
queue: [...group].sort(
|
||||
(left, right) =>
|
||||
estimateTokens(catalogLine(left)) - estimateTokens(catalogLine(right)) || left.path.localeCompare(right.path),
|
||||
estimate(catalogLine(left)) - estimate(catalogLine(right)) || left.path.localeCompare(right.path),
|
||||
),
|
||||
}))
|
||||
let used = 0
|
||||
@@ -437,7 +439,7 @@ export const discoveryPlan = <R>(
|
||||
const stillActive: typeof active = []
|
||||
for (const selection of active) {
|
||||
const tool = selection.queue[0]!
|
||||
const cost = estimateTokens(catalogLine(tool))
|
||||
const cost = estimate(catalogLine(tool))
|
||||
if (used + cost > maxInlineCatalogTokens) continue
|
||||
selection.queue.shift()
|
||||
selection.picked.add(tool)
|
||||
@@ -456,8 +458,8 @@ export const discoveryPlan = <R>(
|
||||
|
||||
// Section order is deliberate: workflow first (the top is the least likely part of a long
|
||||
// description to be truncated or skimmed away), then rules, then syntax, with the budgeted
|
||||
// catalog at the bottom. Example call forms use placeholders - never a real or fabricated
|
||||
// tool name - and show both dot and bracket notation so non-identifier names are not normalized.
|
||||
// catalog at the bottom. Example call forms use explicit `<namespace>.<tool>` placeholders -
|
||||
// never a real or fabricated tool name.
|
||||
const intro = [
|
||||
"Write a CodeMode program to answer the request. Return code only.",
|
||||
empty
|
||||
@@ -465,9 +467,6 @@ export const discoveryPlan = <R>(
|
||||
: complete
|
||||
? "Execute JavaScript in a confined runtime. Inside this program, `tools` contains only the host-provided tools listed below; surrounding agent tools are not available unless listed here."
|
||||
: "Execute JavaScript in a confined runtime. Inside this program, `tools` contains only the host-provided tools listed or searchable below; surrounding agent tools are not available unless listed here.",
|
||||
...(empty
|
||||
? []
|
||||
: ["Do not infer or normalize tool names; use only exact signatures shown below or returned by search."]),
|
||||
]
|
||||
|
||||
// The search step exists only when search is advertised (PARTIAL catalog); a COMPLETE
|
||||
@@ -481,14 +480,14 @@ export const discoveryPlan = <R>(
|
||||
...(complete
|
||||
? [
|
||||
"1. Pick a tool from the list under `## Available tools` - each line is the exact call signature; use it as-is rather than guessing segments.",
|
||||
"2. Call it using the exact signature shown; bracket notation and quotes are part of the path.",
|
||||
"2. Call it using the exact signature shown: `const res = await tools.<namespace>.<tool>(input)` - bracket notation may appear for names that are not JavaScript identifiers.",
|
||||
'3. Parse text results: `const data = typeof res === "string" ? JSON.parse(res) : res` - most tools return JSON as a string.',
|
||||
"4. Return only the fields you need: `return { <field>: data.<field> }` - raw payloads get truncated and waste context.",
|
||||
]
|
||||
: [
|
||||
'1. If the exact signature is not listed below, first search: `const { items } = await tools.$codemode.search({ query: "<intent + key nouns>" })`.',
|
||||
'1. Find a tool (skip when it is already listed below): `const { items } = await tools.$codemode.search({ query: "<intent + key nouns>" })` - short phrases like "list issues" work best.',
|
||||
"2. Read the matches: each item is `{ path, description, signature }` - read the description before using an unfamiliar tool.",
|
||||
"3. Call the result's `path` as-is; bracket notation and quotes are part of the path.",
|
||||
"3. Call it with the result's `path` as-is (never guess segments): `const res = await tools.<namespace>.<tool>(input)` - bracket notation may appear for names that are not JavaScript identifiers.",
|
||||
'4. Parse text results: `const data = typeof res === "string" ? JSON.parse(res) : res` - most tools return JSON as a string.',
|
||||
"5. Return only the fields you need: `return { <field>: data.<field> }` - raw payloads get truncated and waste context.",
|
||||
]),
|
||||
@@ -505,7 +504,7 @@ export const discoveryPlan = <R>(
|
||||
: "- Only tools listed here or returned by `tools.$codemode.search` are available inside `tools`; tools from the surrounding agent/runtime are not implicitly exposed.",
|
||||
"- Filter, aggregate, and transform collections in code - never return them raw or call a tool per item across messages.",
|
||||
"- A result typed `Promise<unknown>` has no guaranteed shape - verify what actually came back before relying on its fields.",
|
||||
'- Run independent calls in parallel: `await Promise.all(items.map((item) => tools.<namespace>.<tool>(item)))`, or use `tools.<namespace>["tool-name"](item)` when the listed signature uses bracket notation.',
|
||||
"- Run independent calls in parallel: `await Promise.all(items.map((item) => tools.<namespace>.<tool>(item)))`.",
|
||||
"- `Object.keys(tools)` lists namespaces; `Object.keys(tools.<namespace>)` lists its tools; `for...in` works on both.",
|
||||
...(complete
|
||||
? []
|
||||
@@ -636,6 +635,9 @@ export type ToolRuntime<R = never> = {
|
||||
readonly keys: (path: ReadonlyArray<string>) => ReadonlyArray<string>
|
||||
}
|
||||
|
||||
const failureMessage = (error: unknown): string =>
|
||||
error instanceof ToolError || error instanceof ToolRuntimeError ? error.message : "Tool execution failed"
|
||||
|
||||
export const make = <R>(
|
||||
tools: HostTools<R>,
|
||||
/** Undefined means unlimited tool calls. */
|
||||
@@ -654,16 +656,9 @@ export const make = <R>(
|
||||
const startedAt = Date.now()
|
||||
return effect.pipe(
|
||||
Effect.tap(() => onEnd({ ...call, durationMs: Date.now() - startedAt, outcome: "success" })),
|
||||
Effect.tapError((error) => {
|
||||
const message =
|
||||
error instanceof ToolError || error instanceof ToolRuntimeError ? error.message : "Tool execution failed"
|
||||
return onEnd({
|
||||
...call,
|
||||
durationMs: Date.now() - startedAt,
|
||||
outcome: "failure",
|
||||
message,
|
||||
})
|
||||
}),
|
||||
Effect.tapError((error) =>
|
||||
onEnd({ ...call, durationMs: Date.now() - startedAt, outcome: "failure", message: failureMessage(error) }),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Effect, JsonPointer, Schema } from "effect"
|
||||
import { Effect, Schema } from "effect"
|
||||
|
||||
/**
|
||||
* JSON Schema subset accepted for render-only tool schemas.
|
||||
@@ -13,7 +13,6 @@ export type JsonSchema = {
|
||||
readonly const?: unknown
|
||||
readonly anyOf?: ReadonlyArray<JsonSchema>
|
||||
readonly oneOf?: ReadonlyArray<JsonSchema>
|
||||
readonly allOf?: ReadonlyArray<JsonSchema>
|
||||
readonly properties?: Readonly<Record<string, JsonSchema>>
|
||||
readonly required?: ReadonlyArray<string>
|
||||
readonly items?: JsonSchema
|
||||
@@ -77,13 +76,6 @@ const effectNumberSentinel = (schema: JsonSchema) =>
|
||||
schema.enum.length === 1 &&
|
||||
(schema.enum[0] === "NaN" || schema.enum[0] === "Infinity" || schema.enum[0] === "-Infinity")
|
||||
|
||||
const intersection = (members: ReadonlyArray<string>): string => {
|
||||
const concrete = members.filter((member) => member !== "unknown")
|
||||
if (concrete.length === 0) return "unknown"
|
||||
if (concrete.length === 1) return concrete[0] ?? "unknown"
|
||||
return concrete.map((member) => (member.includes(" | ") ? `(${member})` : member)).join(" & ")
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursion ceiling for schema rendering. Object, array, and union recursion all increment
|
||||
* depth, so this bounds every recursion path - pathological or structurally cyclic schemas
|
||||
@@ -97,30 +89,6 @@ type RenderContext = {
|
||||
readonly pretty: boolean
|
||||
}
|
||||
|
||||
const hasUnresolvedRef = (
|
||||
schema: JsonSchema,
|
||||
definitions: Readonly<Record<string, JsonSchema>>,
|
||||
seen: ReadonlySet<string> = new Set(),
|
||||
visited: ReadonlySet<JsonSchema> = new Set(),
|
||||
): boolean => {
|
||||
if (visited.has(schema)) return false
|
||||
const nextVisited = new Set([...visited, schema])
|
||||
if (schema.$ref !== undefined) {
|
||||
const segment = schema.$ref.match(/^#\/(?:\$defs|definitions)\/([^/]+)$/)?.[1]
|
||||
const name = segment === undefined ? undefined : JsonPointer.unescapeToken(segment)
|
||||
if (name === undefined || definitions[name] === undefined || seen.has(name)) return true
|
||||
if (hasUnresolvedRef(definitions[name], definitions, new Set([...seen, name]), nextVisited)) return true
|
||||
}
|
||||
return [
|
||||
...(schema.anyOf ?? []),
|
||||
...(schema.oneOf ?? []),
|
||||
...(schema.allOf ?? []),
|
||||
...Object.values(schema.properties ?? {}),
|
||||
...(schema.items === undefined ? [] : [schema.items]),
|
||||
...(typeof schema.additionalProperties === "object" ? [schema.additionalProperties] : []),
|
||||
].some((item) => hasUnresolvedRef(item, definitions, seen, nextVisited))
|
||||
}
|
||||
|
||||
/**
|
||||
* Schema constraints a TypeScript type cannot express natively but a model benefits from,
|
||||
* surfaced as JSDoc tags (`@deprecated`, `@default`, `@format`, `@minItems`, `@maxItems`).
|
||||
@@ -168,18 +136,11 @@ const renderSchema = (
|
||||
seen: ReadonlySet<string> = new Set(),
|
||||
): string => {
|
||||
if (depth > MAX_RENDER_DEPTH) return "unknown"
|
||||
const nested =
|
||||
schema.definitions === undefined && schema.$defs === undefined
|
||||
? ctx
|
||||
: { ...ctx, definitions: { ...ctx.definitions, ...(schema.definitions ?? {}), ...(schema.$defs ?? {}) } }
|
||||
if (schema.$ref) {
|
||||
const segment = schema.$ref.match(/^#\/(?:\$defs|definitions)\/([^/]+)$/)?.[1]
|
||||
const name = segment === undefined ? undefined : JsonPointer.unescapeToken(segment)
|
||||
if (!name || !nested.definitions[name] || seen.has(name)) return "unknown"
|
||||
return intersection([
|
||||
renderSchema(nested.definitions[name], nested, depth, new Set([...seen, name])),
|
||||
renderSchema({ ...schema, $ref: undefined }, nested, depth + 1, seen),
|
||||
])
|
||||
const name = schema.$ref.split("/").pop()
|
||||
if (!name || !ctx.definitions[name]) return name ?? "unknown"
|
||||
if (seen.has(name)) return name // recursive type: reference by name rather than loop
|
||||
return renderSchema(ctx.definitions[name], ctx, depth, new Set([...seen, name]))
|
||||
}
|
||||
if (schema.const !== undefined) return renderLiteral(schema.const)
|
||||
if (schema.enum) return schema.enum.map(renderLiteral).join(" | ")
|
||||
@@ -205,34 +166,24 @@ const renderSchema = (
|
||||
) {
|
||||
return "{}"
|
||||
}
|
||||
const members = alternatives.map((item) => renderSchema(item, nested, depth + 1, seen))
|
||||
if (members.some((member) => member === "unknown")) return "unknown"
|
||||
return intersection([
|
||||
members.join(" | "),
|
||||
renderSchema({ ...schema, anyOf: undefined, oneOf: undefined }, nested, depth + 1, seen),
|
||||
])
|
||||
}
|
||||
if (schema.allOf) {
|
||||
const members = schema.allOf.map((item) => renderSchema(item, nested, depth + 1, seen))
|
||||
if (schema.allOf.some((item) => hasUnresolvedRef(item, nested.definitions))) return "unknown"
|
||||
return intersection([renderSchema({ ...schema, allOf: undefined }, nested, depth + 1, seen), ...members])
|
||||
return alternatives.map((item) => renderSchema(item, ctx, depth + 1, seen)).join(" | ")
|
||||
}
|
||||
if (Array.isArray(schema.type)) {
|
||||
return schema.type.map((item) => renderSchema({ ...schema, type: item }, nested, depth + 1, seen)).join(" | ")
|
||||
return schema.type.map((item) => renderSchema({ type: item }, ctx, depth + 1, seen)).join(" | ")
|
||||
}
|
||||
if (schema.type === "string") return "string"
|
||||
if (schema.type === "number" || schema.type === "integer") return "number"
|
||||
if (schema.type === "boolean") return "boolean"
|
||||
if (schema.type === "null") return "null"
|
||||
if (schema.type === "array") return `Array<${renderSchema(schema.items ?? {}, nested, depth + 1, seen)}>`
|
||||
if (schema.type === "array") return `Array<${renderSchema(schema.items ?? {}, ctx, depth + 1, seen)}>`
|
||||
if (schema.type === "object" || schema.properties) {
|
||||
const required = new Set(schema.required ?? [])
|
||||
const properties = Object.entries(schema.properties ?? {})
|
||||
const additional = schema.additionalProperties
|
||||
const indexType =
|
||||
additional && typeof additional === "object" ? renderSchema(additional, nested, depth + 1, seen) : undefined
|
||||
additional && typeof additional === "object" ? renderSchema(additional, ctx, depth + 1, seen) : undefined
|
||||
const field = ([name, value]: readonly [string, JsonSchema]) =>
|
||||
`${renderKey(name)}${required.has(name) ? "" : "?"}: ${renderSchema(value, nested, depth + 1, seen)}`
|
||||
`${renderKey(name)}${required.has(name) ? "" : "?"}: ${renderSchema(value, ctx, depth + 1, seen)}`
|
||||
|
||||
if (!ctx.pretty) {
|
||||
const fields = properties.map(field)
|
||||
@@ -302,8 +253,7 @@ export const inputProperties = <R>(definition: Definition<R>): Array<InputProper
|
||||
const definitions = document.definitions ?? {}
|
||||
let schema = document.schema
|
||||
if (schema.$ref !== undefined) {
|
||||
const segment = schema.$ref.match(/^#\/(?:\$defs|definitions)\/([^/]+)$/)?.[1]
|
||||
const name = segment === undefined ? undefined : JsonPointer.unescapeToken(segment)
|
||||
const name = schema.$ref.split("/").pop()
|
||||
const resolved = name === undefined ? undefined : definitions[name]
|
||||
if (resolved === undefined) return []
|
||||
schema = resolved
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Cause, Effect, Schema } from "effect"
|
||||
import { CodeMode, Tool, toolError, type ExecutionLimits } from "../src/index.js"
|
||||
import {
|
||||
CodeMode,
|
||||
ExecuteInputSchema,
|
||||
ExecuteResultSchema,
|
||||
Tool,
|
||||
toolError,
|
||||
type ExecutionLimits,
|
||||
} from "../src/index.js"
|
||||
import type { Definition } from "../src/tool.js"
|
||||
|
||||
const run = (tool: Definition<never>) =>
|
||||
@@ -228,7 +235,7 @@ describe("CodeMode console capture", () => {
|
||||
logs: ['Thread info: {"name":"Demo","count":2}', "[warn] careful"],
|
||||
toolCalls: [],
|
||||
})
|
||||
expect(Schema.decodeUnknownSync(CodeMode.Result)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
|
||||
expect(Schema.decodeUnknownSync(ExecuteResultSchema)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
|
||||
})
|
||||
|
||||
test("keeps logs captured before failures", async () => {
|
||||
@@ -364,7 +371,7 @@ describe("CodeMode output budget", () => {
|
||||
expect(result.value).toMatch(
|
||||
/^\{"data":"x+ \[result truncated: \d+ bytes exceeds the 40-byte output limit; return a smaller value\]$/,
|
||||
)
|
||||
expect(Schema.decodeUnknownSync(CodeMode.Result)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
|
||||
expect(Schema.decodeUnknownSync(ExecuteResultSchema)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
|
||||
})
|
||||
|
||||
test("keeps leading logs within the remaining budget and marks the cut", async () => {
|
||||
@@ -494,16 +501,24 @@ describe("CodeMode public contract", () => {
|
||||
const tools = { orders: { lookup } }
|
||||
const source = `return await tools.orders.lookup({ id: "order_42" })`
|
||||
|
||||
test("keeps one-shot and reusable execution equivalent", async () => {
|
||||
test("keeps one-shot, reusable, and agent-tool execution equivalent", async () => {
|
||||
const runtime = CodeMode.make({ tools })
|
||||
const [oneShot, reusable] = await Promise.all([
|
||||
const agentTool = runtime.agentTool()
|
||||
const [oneShot, reusable, projected] = await Promise.all([
|
||||
Effect.runPromise(CodeMode.execute({ tools, code: source })),
|
||||
Effect.runPromise(runtime.execute(source)),
|
||||
Effect.runPromise(agentTool.execute({ code: source })),
|
||||
])
|
||||
|
||||
expect(reusable).toStrictEqual(oneShot)
|
||||
expect(Schema.decodeUnknownSync(CodeMode.Input)({ code: source })).toStrictEqual({ code: source })
|
||||
expect(Schema.decodeUnknownSync(CodeMode.Result)(JSON.parse(JSON.stringify(reusable)))).toStrictEqual(reusable)
|
||||
expect(projected).toStrictEqual(oneShot)
|
||||
expect(agentTool.name).toBe("code")
|
||||
expect(agentTool.input).toBe(ExecuteInputSchema)
|
||||
expect(agentTool.output).toBe(ExecuteResultSchema)
|
||||
expect(agentTool.description).toBe(runtime.instructions())
|
||||
expect(Schema.decodeUnknownSync(ExecuteResultSchema)(JSON.parse(JSON.stringify(projected)))).toStrictEqual(
|
||||
projected,
|
||||
)
|
||||
})
|
||||
|
||||
test("inlines a COMPLETE small catalog and keeps search registered but unadvertised", async () => {
|
||||
@@ -607,12 +622,12 @@ describe("CodeMode public contract", () => {
|
||||
)
|
||||
expect(instructions).toContain("Return only the fields you need")
|
||||
expect(instructions).toContain("raw payloads get truncated and waste context")
|
||||
expect(instructions).toContain("Do not infer or normalize tool names")
|
||||
expect(instructions).toContain("bracket notation and quotes are part of the path")
|
||||
expect(instructions).toContain("`const res = await tools.<namespace>.<tool>(input)`")
|
||||
expect(instructions).toContain("surrounding agent tools are not available unless listed here")
|
||||
expect(instructions).toContain("Only tools listed here are available inside `tools`")
|
||||
// Placeholders use generic namespace/tool/field names only - no fabricated real tools
|
||||
// and no real catalog tools cherry-picked into example lines.
|
||||
expect(instructions).toContain("bracket notation may appear for names that are not JavaScript identifiers")
|
||||
// Placeholders use the <namespace>.<tool>/<field> style ONLY - no fabricated tool
|
||||
// names, and no real catalog tools cherry-picked into example lines.
|
||||
expect(instructions).toContain("`return { <field>: data.<field> }`")
|
||||
expect(instructions).not.toContain("total_count")
|
||||
expect(instructions).not.toContain("list_issues")
|
||||
@@ -625,7 +640,7 @@ describe("CodeMode public contract", () => {
|
||||
// PARTIAL: the workflow starts with search (with query-style guidance that is clearly
|
||||
// a query string, never a tool name) and the browse-namespace rule appears.
|
||||
expect(partial).toContain(
|
||||
'1. If the exact signature is not listed below, first search: `const { items } = await tools.$codemode.search({ query: "<intent + key nouns>" })`.',
|
||||
'1. Find a tool (skip when it is already listed below): `const { items } = await tools.$codemode.search({ query: "<intent + key nouns>" })` - short phrases like "list issues" work best.',
|
||||
)
|
||||
expect(partial).toContain(
|
||||
"Only tools listed here or returned by `tools.$codemode.search` are available inside `tools`",
|
||||
@@ -1020,7 +1035,7 @@ describe("CodeMode public contract", () => {
|
||||
value: { top: null, nested: [1, null] },
|
||||
toolCalls: [],
|
||||
})
|
||||
expect(Schema.decodeUnknownSync(CodeMode.Result)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
|
||||
expect(Schema.decodeUnknownSync(ExecuteResultSchema)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
|
||||
})
|
||||
|
||||
test("rejects invalid configuration and discovery limits", async () => {
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "CodeMode Happy Path",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://api.example.test/v1"
|
||||
}
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/users/{userId}": {
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "#/components/parameters/UserId"
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"operationId": "users.get",
|
||||
"summary": "Get a user",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "include",
|
||||
"in": "query",
|
||||
"style": "form",
|
||||
"explode": false,
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "verbose",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "X-Trace-ID",
|
||||
"in": "header",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/components/responses/UserResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"operationId": "users.remove",
|
||||
"summary": "Remove a user",
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "Removed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users": {
|
||||
"post": {
|
||||
"operationId": "users.create",
|
||||
"summary": "Create a user",
|
||||
"security": [
|
||||
{
|
||||
"ApiKey": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": ["admin", "member"]
|
||||
}
|
||||
},
|
||||
"required": ["name", "email"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"content": {
|
||||
"application/vnd.example+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/User"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/search": {
|
||||
"get": {
|
||||
"operationId": "search.run",
|
||||
"summary": "Search users",
|
||||
"security": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "filter",
|
||||
"in": "query",
|
||||
"style": "deepObject",
|
||||
"explode": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string"
|
||||
},
|
||||
"page": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": ["query"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tags",
|
||||
"in": "query",
|
||||
"style": "form",
|
||||
"explode": true,
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Summary",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"parameters": {
|
||||
"UserId": {
|
||||
"name": "userId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"UserResponse": {
|
||||
"description": "A user",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/User"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"User": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": ["admin", "member"]
|
||||
}
|
||||
},
|
||||
"required": ["id", "name", "email"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"securitySchemes": {
|
||||
"BearerAuth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer"
|
||||
},
|
||||
"ApiKey": {
|
||||
"type": "apiKey",
|
||||
"in": "query",
|
||||
"name": "api_key"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-23730
@@ -1,23730 +0,0 @@
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "opencode HttpApi",
|
||||
"version": "0.0.1",
|
||||
"description": "Experimental HttpApi surface for selected instance routes."
|
||||
},
|
||||
"paths": {
|
||||
"/api/health": {
|
||||
"get": {
|
||||
"tags": ["server.health"],
|
||||
"operationId": "v2.health.get",
|
||||
"parameters": [],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"healthy": {
|
||||
"type": "boolean",
|
||||
"enum": [true]
|
||||
}
|
||||
},
|
||||
"required": ["healthy"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Check whether the API server is ready to accept requests.",
|
||||
"summary": "Check server health"
|
||||
}
|
||||
},
|
||||
"/api/location": {
|
||||
"get": {
|
||||
"tags": ["server.location"],
|
||||
"operationId": "v2.location.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Location.Info",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Resolve the requested location or the server default location.",
|
||||
"summary": "Get location"
|
||||
}
|
||||
},
|
||||
"/api/agent": {
|
||||
"get": {
|
||||
"tags": ["server.agent"],
|
||||
"operationId": "v2.agent.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/AgentV2.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve currently registered agents.",
|
||||
"summary": "List agents"
|
||||
}
|
||||
},
|
||||
"/api/plugin": {
|
||||
"get": {
|
||||
"tags": ["plugins"],
|
||||
"operationId": "v2.plugin.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Plugin.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve currently loaded plugins.",
|
||||
"summary": "List plugins"
|
||||
}
|
||||
},
|
||||
"/api/session": {
|
||||
"get": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "workspace",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^wrk"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Maximum number of sessions to return. Defaults to the newest 50 sessions."
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "order",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["asc", "desc"]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Session order for the first page. Use desc for newest first or asc for oldest first."
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "search",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "parentID",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["null"]
|
||||
}
|
||||
],
|
||||
"description": "Filter by parent session. Use null to return only root sessions."
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "directory",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "project",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "subpath",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "cursor",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Opaque pagination cursor returned as cursor.previous or cursor.next in the previous response."
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "SessionsResponse",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionsResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidCursorError | InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidCursorError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve sessions in the requested order. Items keep that order across pages; use cursor.next or cursor.previous to move through the ordered list.",
|
||||
"summary": "List sessions"
|
||||
},
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.create",
|
||||
"parameters": [],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/SessionV2.Info"
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Create a session at the requested location.",
|
||||
"summary": "Create session",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"agent": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"model": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/active": {
|
||||
"get": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.active",
|
||||
"parameters": [],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^ses": {
|
||||
"$ref": "#/components/schemas/SessionActive"
|
||||
}
|
||||
}
|
||||
},
|
||||
"watermarks": {
|
||||
"$ref": "#/components/schemas/SessionWatermarks"
|
||||
}
|
||||
},
|
||||
"required": ["data", "watermarks"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve foreground Session drains currently owned by this OpenCode process. Sessions absent from the result are inactive. Watermarks are the durable log positions read alongside the activity snapshot; activity itself is process state, so the pairing is advisory rather than transactional.",
|
||||
"summary": "List active sessions"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}": {
|
||||
"get": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/SessionV2.Info"
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve a session by ID.",
|
||||
"summary": "Get session"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/fork": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.fork",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/SessionV2.Info"
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | MessageNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MessageNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Create a child session by copying projected history from the parent. When messageID is supplied, copy messages before that boundary.",
|
||||
"summary": "Fork session",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"messageID": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/agent": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.switchAgent",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Switch the agent used by subsequent provider turns.",
|
||||
"summary": "Switch session agent",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["agent"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/model": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.switchModel",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Switch the model used by subsequent provider turns.",
|
||||
"summary": "Switch session model",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"model": {
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
}
|
||||
},
|
||||
"required": ["model"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/rename": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.rename",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Update the session title.",
|
||||
"summary": "Rename session",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["title"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/prompt": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.prompt",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/SessionInput.Admitted"
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "ConflictError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ConflictError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Durably admit one session input and schedule agent-loop execution unless resume is false.",
|
||||
"summary": "Send message",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"prompt": {
|
||||
"$ref": "#/components/schemas/PromptInput"
|
||||
},
|
||||
"delivery": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["steer", "queue"]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resume": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["prompt"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/command": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.command",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/SessionInput.Admitted"
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | CommandNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/CommandNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "ConflictError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ConflictError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "CommandEvaluationError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CommandEvaluationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Resolve a slash command into prompt input, admit it durably, and schedule execution unless resume is false.",
|
||||
"summary": "Run command",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"arguments": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"agent": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"model": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PromptInput.FileAttachment"
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Prompt.AgentAttachment"
|
||||
}
|
||||
},
|
||||
"delivery": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["steer", "queue"]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resume": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["command"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/skill": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.skill",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | SkillNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SkillNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Activate a skill for a session by appending a skill message and resuming execution.",
|
||||
"summary": "Activate skill",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"skill": {
|
||||
"type": "string"
|
||||
},
|
||||
"resume": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["skill"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/synthetic": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.synthetic",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Append a synthetic message to a session and resume execution.",
|
||||
"summary": "Add synthetic message",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/compact": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.compact",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "SessionBusyError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionBusyError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "UnknownError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnknownError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"503": {
|
||||
"description": "ServiceUnavailableError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ServiceUnavailableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Compact a session conversation.",
|
||||
"summary": "Compact session"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/wait": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.wait",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"503": {
|
||||
"description": "ServiceUnavailableError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ServiceUnavailableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Wait for a session agent loop to become idle.",
|
||||
"summary": "Wait for session"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/revert/stage": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.revert.stage",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Revert.State"
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "MessageNotFoundError | SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MessageNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "SessionBusyError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionBusyError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "UnknownError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnknownError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Stage or move a reversible session boundary and optionally apply its file changes.",
|
||||
"summary": "Stage session revert",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"files": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["messageID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/revert/clear": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.revert.clear",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "SessionBusyError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionBusyError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "UnknownError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnknownError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Clear staged revert"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/revert/commit": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.revert.commit",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "SessionBusyError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionBusyError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Commit staged revert"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/context": {
|
||||
"get": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.context",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Session.Message"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "UnknownError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnknownError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve the active context messages for a session (all messages after the last compaction).",
|
||||
"summary": "Get session context"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/context-entry": {
|
||||
"get": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.context.entry.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SessionContextEntry.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "List API-managed context entries attached to the session's system context.",
|
||||
"summary": "List context entries"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/context-entry/{key}": {
|
||||
"put": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.context.entry.put",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionContextEntry.Key"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Attach or replace one durable context entry. The value is rendered into the session's system context; changes announce as updates at the next turn boundary.",
|
||||
"summary": "Put context entry",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {}
|
||||
},
|
||||
"required": ["value"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.context.entry.remove",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionContextEntry.Key"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Remove one context entry; the removal is announced to the model at the next turn boundary.",
|
||||
"summary": "Remove context entry"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/log": {
|
||||
"get": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.log",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "after",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "follow",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["true", "false"]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"text/event-stream": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"event": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/SessionLogItemStream"
|
||||
}
|
||||
},
|
||||
"required": ["id", "event", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"x-effect-stream": {
|
||||
"encoding": "sse",
|
||||
"causeSchema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["Fail"]
|
||||
},
|
||||
"error": {
|
||||
"not": {}
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "error"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["Die"]
|
||||
},
|
||||
"defect": {}
|
||||
},
|
||||
"required": ["_tag", "defect"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["Interrupt"]
|
||||
},
|
||||
"fiberId": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "fiberId"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"errorSchema": {
|
||||
"not": {}
|
||||
},
|
||||
"failureEvent": "effect/httpapi/stream/failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Durable, ordered, gap-free read of public session events after an exclusive aggregate sequence. Emits a synced marker once replay reaches the captured watermark, then completes; with follow=true it continues with live events instead. The only event API that promises reliability: attach after a snapshot watermark to compose fetch and stream without a race window.",
|
||||
"summary": "Read the session log"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/interrupt": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.interrupt",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Interrupt active execution owned by this OpenCode process. Idle interruption is a no-op.",
|
||||
"summary": "Interrupt session execution"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/background": {
|
||||
"post": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.background",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Move active foreground backgroundable tools for this session into background observation. Idle requests are a no-op.",
|
||||
"summary": "Background blocking session tools"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/message/{messageID}": {
|
||||
"get": {
|
||||
"tags": ["sessions"],
|
||||
"operationId": "v2.session.message",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "messageID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Session.Message"
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | MessageNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MessageNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve one projected message owned by the Session.",
|
||||
"summary": "Get session message"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/message": {
|
||||
"get": {
|
||||
"tags": ["messages"],
|
||||
"operationId": "v2.session.messages",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Maximum number of messages to return. When omitted, the endpoint returns its default page size."
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "order",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["asc", "desc"]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Message order for the first page. Use desc for newest first or asc for oldest first."
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "cursor",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Opaque pagination cursor returned as cursor.previous or cursor.next in the previous response. Do not combine with order."
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "SessionMessagesResponse",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionMessagesResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidCursorError | InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidCursorError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "UnknownError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnknownError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve projected messages for a session. Items keep the requested order across pages; use cursor.next or cursor.previous to move through the ordered timeline.",
|
||||
"summary": "Get session messages"
|
||||
}
|
||||
},
|
||||
"/api/model": {
|
||||
"get": {
|
||||
"tags": ["models"],
|
||||
"operationId": "v2.model.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ModelV2.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"503": {
|
||||
"description": "ServiceUnavailableError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ServiceUnavailableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve available models ordered by release date.",
|
||||
"summary": "List models"
|
||||
}
|
||||
},
|
||||
"/api/model/default": {
|
||||
"get": {
|
||||
"tags": ["models"],
|
||||
"operationId": "v2.model.default",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ModelV2.Info"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"503": {
|
||||
"description": "ServiceUnavailableError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ServiceUnavailableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve the model used when a session has no explicit model selection.",
|
||||
"summary": "Get default model"
|
||||
}
|
||||
},
|
||||
"/api/generate": {
|
||||
"post": {
|
||||
"tags": ["generate"],
|
||||
"operationId": "v2.generate.text",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "GenerateTextResponse",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GenerateTextResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"503": {
|
||||
"description": "ServiceUnavailableError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ServiceUnavailableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Run one stateless model generation at the requested location and return the assistant text. Uses the location's default model when none is specified.",
|
||||
"summary": "Generate text",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"prompt": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["prompt"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/provider": {
|
||||
"get": {
|
||||
"tags": ["providers"],
|
||||
"operationId": "v2.provider.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ProviderV2.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"503": {
|
||||
"description": "ServiceUnavailableError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ServiceUnavailableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve active AI providers so clients can show provider availability and configuration.",
|
||||
"summary": "List providers"
|
||||
}
|
||||
},
|
||||
"/api/provider/{providerID}": {
|
||||
"get": {
|
||||
"tags": ["providers"],
|
||||
"operationId": "v2.provider.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "providerID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/ProviderV2.Info"
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "ProviderNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProviderNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"503": {
|
||||
"description": "ServiceUnavailableError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ServiceUnavailableError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve a single AI provider so clients can inspect its availability and endpoint settings.",
|
||||
"summary": "Get provider"
|
||||
}
|
||||
},
|
||||
"/api/integration": {
|
||||
"get": {
|
||||
"tags": ["integrations"],
|
||||
"operationId": "v2.integration.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Integration.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve available integrations and their authentication methods.",
|
||||
"summary": "List integrations"
|
||||
}
|
||||
},
|
||||
"/api/integration/{integrationID}": {
|
||||
"get": {
|
||||
"tags": ["integrations"],
|
||||
"operationId": "v2.integration.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "integrationID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Integration.Info"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve one integration and its authentication methods.",
|
||||
"summary": "Get integration"
|
||||
}
|
||||
},
|
||||
"/api/integration/{integrationID}/connect/key": {
|
||||
"post": {
|
||||
"tags": ["integrations"],
|
||||
"operationId": "v2.integration.connect.key",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "integrationID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Run a key authentication method and store the resulting credential.",
|
||||
"summary": "Connect with key",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["key"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/integration/{integrationID}/connect/oauth": {
|
||||
"post": {
|
||||
"tags": ["integrations"],
|
||||
"operationId": "v2.integration.connect.oauth",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "integrationID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Integration.Attempt"
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Start an OAuth attempt and return the authorization details.",
|
||||
"summary": "Begin OAuth connection",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"methodID": {
|
||||
"type": "string"
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"label": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["methodID", "inputs"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/integration/attempt/{attemptID}": {
|
||||
"get": {
|
||||
"tags": ["integrations"],
|
||||
"operationId": "v2.integration.attempt.status",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "attemptID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Integration.AttemptStatus"
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Poll the current status of an OAuth attempt.",
|
||||
"summary": "Get OAuth attempt status"
|
||||
},
|
||||
"delete": {
|
||||
"tags": ["integrations"],
|
||||
"operationId": "v2.integration.attempt.cancel",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "attemptID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Cancel an OAuth attempt and release its resources.",
|
||||
"summary": "Cancel OAuth connection"
|
||||
}
|
||||
},
|
||||
"/api/integration/attempt/{attemptID}/complete": {
|
||||
"post": {
|
||||
"tags": ["integrations"],
|
||||
"operationId": "v2.integration.attempt.complete",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "attemptID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Complete a code-based OAuth attempt and store the resulting credential.",
|
||||
"summary": "Complete OAuth connection",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/mcp": {
|
||||
"get": {
|
||||
"tags": ["mcp"],
|
||||
"operationId": "v2.mcp.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Mcp.Server"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve configured MCP servers and their connection status.",
|
||||
"summary": "List MCP servers"
|
||||
}
|
||||
},
|
||||
"/api/credential/{credentialID}": {
|
||||
"patch": {
|
||||
"tags": ["server.credential"],
|
||||
"operationId": "v2.credential.update",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "credentialID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Update a stored credential label.",
|
||||
"summary": "Update credential",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["label"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": ["server.credential"],
|
||||
"operationId": "v2.credential.remove",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "credentialID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Remove a stored integration credential.",
|
||||
"summary": "Remove credential"
|
||||
}
|
||||
},
|
||||
"/api/project/current": {
|
||||
"get": {
|
||||
"tags": ["projects"],
|
||||
"operationId": "v2.project.current",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Project.Current",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Project.Current"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Resolve the project for the requested location.",
|
||||
"summary": "Get current project"
|
||||
}
|
||||
},
|
||||
"/api/project/{projectID}/directories": {
|
||||
"get": {
|
||||
"tags": ["projects"],
|
||||
"operationId": "v2.project.directories",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "projectID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Project.Directories",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Project.Directories"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "List known local absolute directories for a project.",
|
||||
"summary": "List project directories"
|
||||
}
|
||||
},
|
||||
"/api/form/request": {
|
||||
"get": {
|
||||
"tags": ["forms"],
|
||||
"operationId": "v2.form.request.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.FormInfo"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.UrlInfo"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve pending forms for a location.",
|
||||
"summary": "List pending form requests"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/form": {
|
||||
"get": {
|
||||
"tags": ["forms"],
|
||||
"operationId": "v2.session.form.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.FormInfo"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.UrlInfo"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve pending forms for a session.",
|
||||
"summary": "List session forms"
|
||||
},
|
||||
"post": {
|
||||
"tags": ["forms"],
|
||||
"operationId": "v2.session.form.create",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.FormInfo"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.UrlInfo"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "ConflictError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ConflictError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Create a form for a session.",
|
||||
"summary": "Create session form",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Form.CreatePayload"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/form/{formID}": {
|
||||
"get": {
|
||||
"tags": ["forms"],
|
||||
"operationId": "v2.session.form.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "formID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.FormInfo"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.UrlInfo"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | FormNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/FormNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve a form for a session.",
|
||||
"summary": "Get session form"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/form/{formID}/state": {
|
||||
"get": {
|
||||
"tags": ["forms"],
|
||||
"operationId": "v2.session.form.state",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "formID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Form.State"
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | FormNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/FormNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve the current state for a form.",
|
||||
"summary": "Get form state"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/form/{formID}/reply": {
|
||||
"post": {
|
||||
"tags": ["forms"],
|
||||
"operationId": "v2.session.form.reply",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "formID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "FormInvalidAnswerError | InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/FormInvalidAnswerError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | FormNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/FormNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "FormAlreadySettledError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/FormAlreadySettledError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Submit an answer to a pending form.",
|
||||
"summary": "Reply to form",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Form.Reply"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/form/{formID}/cancel": {
|
||||
"post": {
|
||||
"tags": ["forms"],
|
||||
"operationId": "v2.session.form.cancel",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "formID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | FormNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/FormNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "FormAlreadySettledError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/FormAlreadySettledError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Cancel a pending form.",
|
||||
"summary": "Cancel form"
|
||||
}
|
||||
},
|
||||
"/api/permission/request": {
|
||||
"get": {
|
||||
"tags": ["permissions"],
|
||||
"operationId": "v2.permission.request.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Request"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve pending permission requests for a location.",
|
||||
"summary": "List pending permission requests"
|
||||
}
|
||||
},
|
||||
"/api/permission/saved": {
|
||||
"get": {
|
||||
"tags": ["permissions"],
|
||||
"operationId": "v2.permission.saved.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "projectID",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PermissionSaved.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve saved permissions, optionally filtered by project.",
|
||||
"summary": "List saved permissions"
|
||||
}
|
||||
},
|
||||
"/api/permission/saved/{id}": {
|
||||
"delete": {
|
||||
"tags": ["permissions"],
|
||||
"operationId": "v2.permission.saved.remove",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Remove a saved permission by ID.",
|
||||
"summary": "Remove saved permission"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/permission": {
|
||||
"post": {
|
||||
"tags": ["permissions"],
|
||||
"operationId": "v2.session.permission.create",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^per"
|
||||
}
|
||||
]
|
||||
},
|
||||
"effect": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Effect"
|
||||
}
|
||||
},
|
||||
"required": ["id", "effect"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Evaluate and, when approval is required, create a permission request for a session.",
|
||||
"summary": "Create permission request",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^per"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"resources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"save": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Source"
|
||||
},
|
||||
"agent": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["action", "resources"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"tags": ["permissions"],
|
||||
"operationId": "v2.session.permission.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Request"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve pending permission requests owned by a session.",
|
||||
"summary": "List session permission requests"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/permission/{requestID}": {
|
||||
"get": {
|
||||
"tags": ["permissions"],
|
||||
"operationId": "v2.session.permission.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "requestID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^per"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Request"
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | PermissionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PermissionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve a pending permission request owned by a session.",
|
||||
"summary": "Get permission request"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/permission/{requestID}/reply": {
|
||||
"post": {
|
||||
"tags": ["permissions"],
|
||||
"operationId": "v2.session.permission.reply",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "requestID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^per"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | PermissionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PermissionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Respond to a pending permission request owned by a session.",
|
||||
"summary": "Reply to pending permission request",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reply": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Reply"
|
||||
},
|
||||
"message": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["reply"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/fs/read/*": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
"operationId": "v2.fs.read",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/octet-stream": {
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "binary"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Serve one file relative to the requested location.",
|
||||
"summary": "Read file"
|
||||
}
|
||||
},
|
||||
"/api/fs/list": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
"operationId": "v2.fs.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
},
|
||||
{
|
||||
"name": "path",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/FileSystem.Entry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "List direct children of one directory relative to the requested location.",
|
||||
"summary": "List directory"
|
||||
}
|
||||
},
|
||||
"/api/fs/find": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
"operationId": "v2.fs.find",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
},
|
||||
{
|
||||
"name": "query",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["file", "directory"]
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/FileSystem.Entry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Find recursively ranked filesystem entries relative to the requested location.",
|
||||
"summary": "Find files"
|
||||
}
|
||||
},
|
||||
"/api/command": {
|
||||
"get": {
|
||||
"tags": ["commands"],
|
||||
"operationId": "v2.command.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/CommandV2.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve currently registered commands.",
|
||||
"summary": "List commands"
|
||||
}
|
||||
},
|
||||
"/api/skill": {
|
||||
"get": {
|
||||
"tags": ["skills"],
|
||||
"operationId": "v2.skill.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SkillV2.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve currently registered skills.",
|
||||
"summary": "List skills"
|
||||
}
|
||||
},
|
||||
"/api/event": {
|
||||
"get": {
|
||||
"tags": ["events"],
|
||||
"operationId": "v2.event.subscribe",
|
||||
"parameters": [],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"text/event-stream": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"event": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/V2EventStream"
|
||||
}
|
||||
},
|
||||
"required": ["id", "event", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"x-effect-stream": {
|
||||
"encoding": "sse",
|
||||
"causeSchema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["Fail"]
|
||||
},
|
||||
"error": {
|
||||
"not": {}
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "error"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["Die"]
|
||||
},
|
||||
"defect": {}
|
||||
},
|
||||
"required": ["_tag", "defect"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["Interrupt"]
|
||||
},
|
||||
"fiberId": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "fiberId"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"errorSchema": {
|
||||
"not": {}
|
||||
},
|
||||
"failureEvent": "effect/httpapi/stream/failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Subscribe to native event payloads for the server. Volatile by contract: a slow consumer overflows and fails the stream, and events during disconnection are missed. Consumers that need reliability should combine the changes feed with durable session log reads.",
|
||||
"summary": "Subscribe to events"
|
||||
}
|
||||
},
|
||||
"/api/event/changes": {
|
||||
"get": {
|
||||
"tags": ["events"],
|
||||
"operationId": "v2.event.changes",
|
||||
"parameters": [],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"text/event-stream": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"event": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/EventLog.ChangeStream"
|
||||
}
|
||||
},
|
||||
"required": ["id", "event", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"x-effect-stream": {
|
||||
"encoding": "sse",
|
||||
"causeSchema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["Fail"]
|
||||
},
|
||||
"error": {
|
||||
"not": {}
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "error"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["Die"]
|
||||
},
|
||||
"defect": {}
|
||||
},
|
||||
"required": ["_tag", "defect"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["Interrupt"]
|
||||
},
|
||||
"fiberId": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "fiberId"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"errorSchema": {
|
||||
"not": {}
|
||||
},
|
||||
"failureEvent": "effect/httpapi/stream/failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Payload-free hint channel: after an event commits, a subscriber eventually receives a hint for that aggregate with seq at or beyond the event, or a sweep-required marker. Hints coalesce to the latest seq per aggregate under backpressure and the stream never fails from overflow. No consumer may derive correctness from receiving a hint; correctness always comes from durable log reads plus the consumer's own checkpoint. A sweep-required marker is emitted first on every (re)subscribe and whenever hint retention is exceeded: treat every aggregate as potentially dirty and recover via bounded sweep plus log reads.",
|
||||
"summary": "Subscribe to change hints"
|
||||
}
|
||||
},
|
||||
"/api/pty": {
|
||||
"get": {
|
||||
"tags": ["pty"],
|
||||
"operationId": "v2.pty.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Pty"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "List PTY sessions for a location, including exited sessions retained until removal.",
|
||||
"summary": "List PTY sessions"
|
||||
},
|
||||
"post": {
|
||||
"tags": ["pty"],
|
||||
"operationId": "v2.pty.create",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Pty"
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Create a pseudo-terminal session for a location.",
|
||||
"summary": "Create PTY session",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"args": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"env": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/pty/{ptyID}": {
|
||||
"get": {
|
||||
"tags": ["pty"],
|
||||
"operationId": "v2.pty.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "ptyID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^pty"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Pty"
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "PtyNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PtyNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Get one PTY session, including its exit code once exited.",
|
||||
"summary": "Get PTY session"
|
||||
},
|
||||
"put": {
|
||||
"tags": ["pty"],
|
||||
"operationId": "v2.pty.update",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "ptyID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^pty"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Pty"
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "PtyNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PtyNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Update the title or viewport size of one PTY session.",
|
||||
"summary": "Update PTY session",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"rows": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"exclusiveMinimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"cols": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"exclusiveMinimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["rows", "cols"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": ["pty"],
|
||||
"operationId": "v2.pty.remove",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "ptyID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^pty"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "PtyNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PtyNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Terminate and remove one PTY session.",
|
||||
"summary": "Remove PTY session"
|
||||
}
|
||||
},
|
||||
"/api/pty/{ptyID}/connect-token": {
|
||||
"post": {
|
||||
"tags": ["pty"],
|
||||
"operationId": "v2.pty.connectToken",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "ptyID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^pty"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/PtyTicket.ConnectToken"
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "ForbiddenError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ForbiddenError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "PtyNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PtyNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Create a short-lived single-use ticket for opening a PTY WebSocket connection.",
|
||||
"summary": "Create PTY WebSocket token"
|
||||
}
|
||||
},
|
||||
"/api/pty/{ptyID}/connect": {
|
||||
"get": {
|
||||
"tags": ["pty"],
|
||||
"operationId": "v2.pty.connect",
|
||||
"x-websocket": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "ptyID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^pty"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "location[directory]",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "location[workspace]",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "cursor",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "ticket",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "ForbiddenError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ForbiddenError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "PtyNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PtyNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Establish a WebSocket connection streaming PTY output and accepting terminal input.",
|
||||
"summary": "Connect to PTY session"
|
||||
}
|
||||
},
|
||||
"/api/shell": {
|
||||
"get": {
|
||||
"tags": ["shell"],
|
||||
"operationId": "v2.shell.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Shell1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "List currently running shell commands for a location. Exited commands are not included.",
|
||||
"summary": "List running shell commands"
|
||||
},
|
||||
"post": {
|
||||
"tags": ["shell"],
|
||||
"operationId": "v2.shell.create",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Shell1"
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Spawn one non-interactive shell command for a location. Combined stdout/stderr is captured to a file pageable via output.",
|
||||
"summary": "Run shell command",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"timeout": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["command"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/shell/{id}": {
|
||||
"get": {
|
||||
"tags": ["shell"],
|
||||
"operationId": "v2.shell.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^sh_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/Shell1"
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "ShellNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ShellNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Get one shell command, including its status and exit code once exited.",
|
||||
"summary": "Get shell command"
|
||||
},
|
||||
"delete": {
|
||||
"tags": ["shell"],
|
||||
"operationId": "v2.shell.remove",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^sh_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "ShellNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ShellNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Terminate and remove one shell command and its retained output.",
|
||||
"summary": "Remove shell command"
|
||||
}
|
||||
},
|
||||
"/api/shell/{id}/output": {
|
||||
"get": {
|
||||
"tags": ["shell"],
|
||||
"operationId": "v2.shell.output",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^sh_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
},
|
||||
{
|
||||
"name": "cursor",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^[+-]?\\d*\\.?\\d+(?:[Ee][+-]?\\d+)?$"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^[+-]?\\d*\\.?\\d+(?:[Ee][+-]?\\d+)?$"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"output": {
|
||||
"type": "string"
|
||||
},
|
||||
"cursor": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"truncated": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["output", "cursor", "size", "truncated"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "ShellNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ShellNotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Page through captured combined output by absolute byte cursor.",
|
||||
"summary": "Read shell output"
|
||||
}
|
||||
},
|
||||
"/api/question/request": {
|
||||
"get": {
|
||||
"tags": ["session questions"],
|
||||
"operationId": "v2.question.request.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Request"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve pending question requests for a location.",
|
||||
"summary": "List pending question requests"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/question": {
|
||||
"get": {
|
||||
"tags": ["session questions"],
|
||||
"operationId": "v2.session.question.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Request"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Retrieve pending question requests owned by a session.",
|
||||
"summary": "List session question requests"
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/question/{requestID}/reply": {
|
||||
"post": {
|
||||
"tags": ["session questions"],
|
||||
"operationId": "v2.session.question.reply",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "requestID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^que"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | QuestionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/QuestionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Answer a pending question request owned by a session.",
|
||||
"summary": "Reply to pending question request",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Reply"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/session/{sessionID}/question/{requestID}/reject": {
|
||||
"post": {
|
||||
"tags": ["session questions"],
|
||||
"operationId": "v2.session.question.reject",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "requestID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^que"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "SessionNotFoundError | QuestionNotFoundError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/QuestionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionNotFoundError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Reject a pending question request owned by a session.",
|
||||
"summary": "Reject pending question request"
|
||||
}
|
||||
},
|
||||
"/api/reference": {
|
||||
"get": {
|
||||
"tags": ["reference"],
|
||||
"operationId": "v2.reference.list",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Reference.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "List references available in the requested location.",
|
||||
"summary": "List references"
|
||||
}
|
||||
},
|
||||
"/experimental/project/{projectID}/copy": {
|
||||
"post": {
|
||||
"tags": ["projectCopy"],
|
||||
"operationId": "v2.projectCopy.create",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "projectID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ProjectCopy.Copy",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProjectCopy.Copy"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "ProjectCopyError | InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProjectCopyError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"strategy": {
|
||||
"type": "string"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["strategy", "directory"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": ["projectCopy"],
|
||||
"operationId": "v2.projectCopy.remove",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "projectID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "ProjectCopyError | InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProjectCopyError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
"force": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["directory", "force"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/experimental/project/{projectID}/copy/refresh": {
|
||||
"post": {
|
||||
"tags": ["projectCopy"],
|
||||
"operationId": "v2.projectCopy.refresh",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "projectID",
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "<No Content>"
|
||||
},
|
||||
"400": {
|
||||
"description": "ProjectCopyError | InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProjectCopyError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/vcs/status": {
|
||||
"get": {
|
||||
"tags": ["vcs"],
|
||||
"operationId": "v2.vcs.status",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Vcs.FileStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "List uncommitted working-copy changes relative to the requested location.",
|
||||
"summary": "VCS status"
|
||||
}
|
||||
},
|
||||
"/api/vcs/diff": {
|
||||
"get": {
|
||||
"tags": ["vcs"],
|
||||
"operationId": "v2.vcs.diff",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"workspace": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false,
|
||||
"style": "deepObject",
|
||||
"explode": true
|
||||
},
|
||||
{
|
||||
"name": "mode",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Vcs.Mode"
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "context",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"security": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Info"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SnapshotFileDiff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["location", "data"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "InvalidRequestError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InvalidRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "UnauthorizedError",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UnauthorizedError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Diff the working copy against HEAD (mode git) or the default-branch merge base (mode branch) for the requested location.",
|
||||
"summary": "VCS diff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"UnauthorizedError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["UnauthorizedError"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"InvalidRequestError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["InvalidRequestError"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"field": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Location.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspaceID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^wrk"
|
||||
}
|
||||
]
|
||||
},
|
||||
"project": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "directory"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["directory", "project"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Model.Ref": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"variant": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "providerID"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Provider.Settings": {
|
||||
"type": "object"
|
||||
},
|
||||
"Provider.Request": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"settings": {
|
||||
"$ref": "#/components/schemas/Provider.Settings"
|
||||
},
|
||||
"headers": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["settings", "headers", "body"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Agent.Color": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^#[0-9a-fA-F]{6}$"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["primary", "secondary", "accent", "success", "warning", "error", "info"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"PermissionV2.Effect": {
|
||||
"type": "string",
|
||||
"enum": ["allow", "deny", "ask"]
|
||||
},
|
||||
"PermissionV2.Rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"resource": {
|
||||
"type": "string"
|
||||
},
|
||||
"effect": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Effect"
|
||||
}
|
||||
},
|
||||
"required": ["action", "resource", "effect"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PermissionV2.Ruleset": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Rule"
|
||||
}
|
||||
},
|
||||
"AgentV2.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
},
|
||||
"request": {
|
||||
"$ref": "#/components/schemas/Provider.Request"
|
||||
},
|
||||
"system": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["subagent", "primary", "all"]
|
||||
},
|
||||
"hidden": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"color": {
|
||||
"$ref": "#/components/schemas/Agent.Color"
|
||||
},
|
||||
"steps": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"exclusiveMinimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Ruleset"
|
||||
}
|
||||
},
|
||||
"required": ["id", "request", "mode", "hidden", "permissions"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Plugin.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Location.Ref": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspaceID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^wrk"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["directory"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"File.Diff": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["added", "modified", "deleted"]
|
||||
},
|
||||
"additions": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"deletions": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"patch": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["path", "status", "additions", "deletions", "patch"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Revert.State": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"partID": {
|
||||
"type": "string"
|
||||
},
|
||||
"snapshot": {
|
||||
"type": "string"
|
||||
},
|
||||
"diff": {
|
||||
"type": "string"
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/File.Diff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["messageID"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionV2.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"parentID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"projectID": {
|
||||
"type": "string"
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
},
|
||||
"cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "number"
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["read", "write"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["input", "output", "reasoning", "cache"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
},
|
||||
"updated": {
|
||||
"type": "number"
|
||||
},
|
||||
"archived": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created", "updated"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"subpath": {
|
||||
"type": "string"
|
||||
},
|
||||
"revert": {
|
||||
"$ref": "#/components/schemas/Revert.State"
|
||||
}
|
||||
},
|
||||
"required": ["id", "projectID", "cost", "tokens", "time", "title", "location"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionWatermarks": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^ses": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"description": "Durable log seq each session's snapshot was computed at. Attach a live log read after the watermark to compose fetch and stream gap-free; apply a snapshot only where its watermark is at or beyond already-applied events. Sessions without durable events are absent."
|
||||
},
|
||||
"SessionsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SessionV2.Info"
|
||||
}
|
||||
},
|
||||
"watermarks": {
|
||||
"$ref": "#/components/schemas/SessionWatermarks"
|
||||
},
|
||||
"cursor": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"previous": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"next": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["data", "watermarks", "cursor"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"InvalidCursorError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["InvalidCursorError"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"InvalidRequestError1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["InvalidRequestError"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"field": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionActive": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["running"]
|
||||
}
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["SessionNotFoundError"]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "sessionID", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MessageNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["MessageNotFoundError"]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "sessionID", "messageID", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Prompt.Source": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "number"
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["start", "end", "text"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PromptInput.FileAttachment": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/components/schemas/Prompt.Source"
|
||||
}
|
||||
},
|
||||
"required": ["uri"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Prompt.AgentAttachment": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/components/schemas/Prompt.Source"
|
||||
}
|
||||
},
|
||||
"required": ["name"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PromptInput": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PromptInput.FileAttachment"
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Prompt.AgentAttachment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["text"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Prompt.FileAttachment": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"mime": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/components/schemas/Prompt.Source"
|
||||
}
|
||||
},
|
||||
"required": ["uri", "mime"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Prompt": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Prompt.FileAttachment"
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Prompt.AgentAttachment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["text"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionInput.Admitted": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"admittedSeq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"prompt": {
|
||||
"$ref": "#/components/schemas/Prompt"
|
||||
},
|
||||
"delivery": {
|
||||
"type": "string",
|
||||
"enum": ["steer", "queue"]
|
||||
},
|
||||
"timeCreated": {
|
||||
"type": "number"
|
||||
},
|
||||
"promotedSeq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["admittedSeq", "id", "sessionID", "prompt", "delivery", "timeCreated"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ConflictError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["ConflictError"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"resource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CommandNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["CommandNotFoundError"]
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "command", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CommandEvaluationError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["CommandEvaluationError"]
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "command", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SkillNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["SkillNotFoundError"]
|
||||
},
|
||||
"skill": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "skill", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionBusyError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["SessionBusyError"]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "sessionID", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ServiceUnavailableError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["ServiceUnavailableError"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"service": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UnknownError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["UnknownError"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.AgentSwitched": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["agent-switched"]
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "time", "type", "agent"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.ModelSwitched": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["model-switched"]
|
||||
},
|
||||
"model": {
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
}
|
||||
},
|
||||
"required": ["id", "time", "type", "model"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.User": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Prompt.FileAttachment"
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Prompt.AgentAttachment"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["user"]
|
||||
}
|
||||
},
|
||||
"required": ["id", "time", "text", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.Synthetic": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["synthetic"]
|
||||
}
|
||||
},
|
||||
"required": ["id", "time", "sessionID", "text", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.System": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["system"]
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "time", "type", "text"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.Skill": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["skill"]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "time", "type", "name", "text"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.Shell": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
},
|
||||
"completed": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["shell"]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"output": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "time", "type", "callID", "command", "output"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.Assistant.Text": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["text"]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type", "id", "text"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LLM.ProviderMetadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"Session.Message.Assistant.Reasoning": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["reasoning"]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"providerMetadata": {
|
||||
"$ref": "#/components/schemas/LLM.ProviderMetadata"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
},
|
||||
"completed": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["type", "id", "text"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.ToolState.Pending": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["pending"]
|
||||
},
|
||||
"input": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["status", "input"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Tool.TextContent": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["text"]
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type", "text"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Tool.FileContent": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["file"]
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"mime": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type", "uri", "mime"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LLM.ToolContent": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Tool.TextContent"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Tool.FileContent"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Session.Message.ToolState.Running": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["running"]
|
||||
},
|
||||
"input": {
|
||||
"type": "object"
|
||||
},
|
||||
"structured": {
|
||||
"type": "object"
|
||||
},
|
||||
"content": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LLM.ToolContent"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["status", "input", "structured", "content"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.ToolState.Completed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["completed"]
|
||||
},
|
||||
"input": {
|
||||
"type": "object"
|
||||
},
|
||||
"attachments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Prompt.FileAttachment"
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LLM.ToolContent"
|
||||
}
|
||||
},
|
||||
"outputPaths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"structured": {
|
||||
"type": "object"
|
||||
},
|
||||
"result": {}
|
||||
},
|
||||
"required": ["status", "input", "content", "structured"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Error.Unknown": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["unknown"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.ToolState.Error": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["error"]
|
||||
},
|
||||
"input": {
|
||||
"type": "object"
|
||||
},
|
||||
"content": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LLM.ToolContent"
|
||||
}
|
||||
},
|
||||
"structured": {
|
||||
"type": "object"
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/components/schemas/Session.Error.Unknown"
|
||||
},
|
||||
"result": {}
|
||||
},
|
||||
"required": ["status", "input", "content", "structured", "error"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.Assistant.Tool": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["tool"]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"provider": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"executed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/LLM.ProviderMetadata"
|
||||
},
|
||||
"resultMetadata": {
|
||||
"$ref": "#/components/schemas/LLM.ProviderMetadata"
|
||||
}
|
||||
},
|
||||
"required": ["executed"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"state": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.ToolState.Pending"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.ToolState.Running"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.ToolState.Completed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.ToolState.Error"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
},
|
||||
"ran": {
|
||||
"type": "number"
|
||||
},
|
||||
"completed": {
|
||||
"type": "number"
|
||||
},
|
||||
"pruned": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["type", "id", "name", "state", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.Assistant": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
},
|
||||
"completed": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["assistant"]
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
},
|
||||
"content": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.Assistant.Text"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.Assistant.Reasoning"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.Assistant.Tool"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"snapshot": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "string"
|
||||
},
|
||||
"end": {
|
||||
"type": "string"
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"finish": {
|
||||
"type": "string"
|
||||
},
|
||||
"cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "number"
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["read", "write"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["input", "output", "reasoning", "cache"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/components/schemas/Session.Error.Unknown"
|
||||
}
|
||||
},
|
||||
"required": ["id", "time", "type", "agent", "model", "content"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message.Compaction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["compaction"]
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"enum": ["auto", "manual"]
|
||||
},
|
||||
"summary": {
|
||||
"type": "string"
|
||||
},
|
||||
"recent": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["type", "reason", "summary", "recent", "id", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Session.Message": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.AgentSwitched"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.ModelSwitched"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.User"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.Synthetic"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.System"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.Skill"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.Shell"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.Assistant"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Session.Message.Compaction"
|
||||
}
|
||||
]
|
||||
},
|
||||
"SessionContextEntry.Key": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^[a-z0-9][a-z0-9._-]*$",
|
||||
"description": "Context entry key (lowercase alphanumerics plus . _ -)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"SessionContextEntry.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"$ref": "#/components/schemas/SessionContextEntry.Key"
|
||||
},
|
||||
"value": {}
|
||||
},
|
||||
"required": ["key", "value"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.agent.switched": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.agent.switched"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "agent"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.model.switched": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.model.switched"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"model": {
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "model"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.moved": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.moved"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"subdirectory": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "location"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.renamed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.renamed"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "title"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.forked": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.forked"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"parentID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "parentID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.prompted": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.prompted"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"prompt": {
|
||||
"$ref": "#/components/schemas/Prompt"
|
||||
},
|
||||
"delivery": {
|
||||
"type": "string",
|
||||
"enum": ["steer", "queue"]
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "prompt", "delivery"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.prompt.admitted": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.prompt.admitted"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"prompt": {
|
||||
"$ref": "#/components/schemas/Prompt"
|
||||
},
|
||||
"delivery": {
|
||||
"type": "string",
|
||||
"enum": ["steer", "queue"]
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "prompt", "delivery"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.context.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.context.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.synthetic": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.synthetic"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.skill.activated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.skill.activated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "name", "text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.shell.started": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.shell.started"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "callID", "command"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.shell.ended": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.shell.ended"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"output": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "callID", "output"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.step.started": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.step.started"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
},
|
||||
"snapshot": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "agent", "model"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.step.ended": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.step.ended"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"finish": {
|
||||
"type": "string"
|
||||
},
|
||||
"cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "number"
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["read", "write"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["input", "output", "reasoning", "cache"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"snapshot": {
|
||||
"type": "string"
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "finish", "cost", "tokens"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.step.failed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.step.failed"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/components/schemas/Session.Error.Unknown"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "error"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.text.started": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.text.started"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"textID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "textID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.text.ended": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.text.ended"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"textID": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "textID", "text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.tool.input.started": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.tool.input.started"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "callID", "name"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.tool.input.ended": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.tool.input.ended"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "callID", "text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LLM.ProviderMetadata3": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"session.next.tool.called": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.tool.called"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"tool": {
|
||||
"type": "string"
|
||||
},
|
||||
"input": {
|
||||
"type": "object"
|
||||
},
|
||||
"provider": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"executed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/LLM.ProviderMetadata3"
|
||||
}
|
||||
},
|
||||
"required": ["executed"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "callID", "tool", "input", "provider"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.tool.progress": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.tool.progress"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"structured": {
|
||||
"type": "object"
|
||||
},
|
||||
"content": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LLM.ToolContent"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "callID", "structured", "content"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LLM.ProviderMetadata4": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"session.next.tool.success": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.tool.success"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"structured": {
|
||||
"type": "object"
|
||||
},
|
||||
"content": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LLM.ToolContent"
|
||||
}
|
||||
},
|
||||
"outputPaths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"result": {},
|
||||
"provider": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"executed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/LLM.ProviderMetadata4"
|
||||
}
|
||||
},
|
||||
"required": ["executed"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "callID", "structured", "content", "provider"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LLM.ProviderMetadata5": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"session.next.tool.failed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.tool.failed"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/components/schemas/Session.Error.Unknown"
|
||||
},
|
||||
"result": {},
|
||||
"provider": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"executed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/LLM.ProviderMetadata5"
|
||||
}
|
||||
},
|
||||
"required": ["executed"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "callID", "error", "provider"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LLM.ProviderMetadata6": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"session.next.reasoning.started": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.reasoning.started"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reasoningID": {
|
||||
"type": "string"
|
||||
},
|
||||
"providerMetadata": {
|
||||
"$ref": "#/components/schemas/LLM.ProviderMetadata6"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "reasoningID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LLM.ProviderMetadata7": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"session.next.reasoning.ended": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.reasoning.ended"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reasoningID": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"providerMetadata": {
|
||||
"$ref": "#/components/schemas/LLM.ProviderMetadata7"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "reasoningID", "text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.retry_error": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"statusCode": {
|
||||
"type": "number"
|
||||
},
|
||||
"isRetryable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"responseHeaders": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"responseBody": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["message", "isRetryable"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.retried": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.retried"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"attempt": {
|
||||
"type": "number"
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/components/schemas/session.next.retry_error"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "attempt", "error"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.compaction.started": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.compaction.started"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"enum": ["auto", "manual"]
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "reason"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.compaction.ended": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.compaction.ended"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"enum": ["auto", "manual"]
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"recent": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "reason", "text", "recent"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.revert.staged": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.revert.staged"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"revert": {
|
||||
"$ref": "#/components/schemas/Revert.State"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "revert"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.revert.cleared": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.revert.cleared"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.revert.committed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.revert.committed"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionDurableEvent": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.agent.switched"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.model.switched"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.moved"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.renamed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.forked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.prompted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.prompt.admitted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.context.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.synthetic"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.skill.activated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.shell.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.shell.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.step.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.step.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.step.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.text.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.text.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.input.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.input.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.called"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.progress"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.success"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.reasoning.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.reasoning.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.retried"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.compaction.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.compaction.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.revert.staged"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.revert.cleared"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.revert.committed"
|
||||
}
|
||||
]
|
||||
},
|
||||
"EventLog.Synced": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["log.synced"]
|
||||
},
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["type", "aggregateID"],
|
||||
"additionalProperties": false,
|
||||
"description": "Marker emitted once when a log read reaches its captured watermark. The reader holds every event committed at or below seq."
|
||||
},
|
||||
"SessionLogItem": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SessionDurableEvent"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/EventLog.Synced"
|
||||
}
|
||||
]
|
||||
},
|
||||
"SessionLogItemStream": {
|
||||
"type": "string",
|
||||
"contentSchema": {
|
||||
"$ref": "#/components/schemas/SessionLogItem"
|
||||
},
|
||||
"contentMediaType": "application/json"
|
||||
},
|
||||
"SessionMessagesResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Session.Message"
|
||||
}
|
||||
},
|
||||
"watermark": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"cursor": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"previous": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"next": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["data", "cursor"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Model.Api": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["aisdk"]
|
||||
},
|
||||
"package": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"settings": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "package"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["native"]
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"settings": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "settings"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"Model.Capabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tools": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"input": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["tools", "input", "output"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Model.Cost": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tier": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["context"]
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": ["type", "size"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"input": {
|
||||
"type": "number"
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["read", "write"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["input", "output", "cache"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ModelV2.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"family": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"api": {
|
||||
"$ref": "#/components/schemas/Model.Api"
|
||||
},
|
||||
"capabilities": {
|
||||
"$ref": "#/components/schemas/Model.Capabilities"
|
||||
},
|
||||
"request": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"settings": {
|
||||
"$ref": "#/components/schemas/Provider.Settings"
|
||||
},
|
||||
"headers": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"type": "object"
|
||||
},
|
||||
"variant": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["settings", "headers", "body"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"variants": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "#/components/schemas/Provider.Settings"
|
||||
},
|
||||
"headers": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["id", "settings", "headers", "body"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"released": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["released"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"cost": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Model.Cost"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["alpha", "beta", "deprecated", "active"]
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"limit": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"context": {
|
||||
"type": "integer"
|
||||
},
|
||||
"input": {
|
||||
"type": "integer"
|
||||
},
|
||||
"output": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": ["context", "output"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"providerID",
|
||||
"name",
|
||||
"api",
|
||||
"capabilities",
|
||||
"request",
|
||||
"variants",
|
||||
"time",
|
||||
"cost",
|
||||
"status",
|
||||
"enabled",
|
||||
"limit"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"GenerateTextResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Provider.AISDK": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["aisdk"]
|
||||
},
|
||||
"package": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"settings": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["type", "package"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Provider.Native": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["native"]
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"settings": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["type", "settings"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Provider.Api": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Provider.AISDK"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Provider.Native"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ProviderV2.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"integrationID": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"disabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"api": {
|
||||
"$ref": "#/components/schemas/Provider.Api"
|
||||
},
|
||||
"request": {
|
||||
"$ref": "#/components/schemas/Provider.Request"
|
||||
}
|
||||
},
|
||||
"required": ["id", "name", "api", "request"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ProviderNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["ProviderNotFoundError"]
|
||||
},
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "providerID", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Integration.When": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"op": {
|
||||
"type": "string",
|
||||
"enum": ["eq", "neq"]
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["key", "op", "value"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Integration.TextPrompt": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["text"]
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"placeholder": {
|
||||
"type": "string"
|
||||
},
|
||||
"when": {
|
||||
"$ref": "#/components/schemas/Integration.When"
|
||||
}
|
||||
},
|
||||
"required": ["type", "key", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Integration.SelectPrompt": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["select"]
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"hint": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["label", "value"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"when": {
|
||||
"$ref": "#/components/schemas/Integration.When"
|
||||
}
|
||||
},
|
||||
"required": ["type", "key", "message", "options"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Integration.OAuthMethod": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["oauth"]
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"prompts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Integration.TextPrompt"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Integration.SelectPrompt"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "label"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Integration.KeyMethod": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["key"]
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Integration.EnvMethod": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["env"]
|
||||
},
|
||||
"names": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["type", "names"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Integration.Method": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Integration.OAuthMethod"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Integration.KeyMethod"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Integration.EnvMethod"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Connection.CredentialInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["credential"]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type", "id", "label"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Connection.EnvInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["env"]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type", "name"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Connection.Info": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Connection.CredentialInfo"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Connection.EnvInfo"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Integration.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"methods": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Integration.Method"
|
||||
}
|
||||
},
|
||||
"connections": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Connection.Info"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["id", "name", "methods", "connections"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Integration.Attempt": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"attemptID": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"instructions": {
|
||||
"type": "string"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["auto", "code"]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"expires": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["created", "expires"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["attemptID", "url", "instructions", "mode", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Integration.AttemptStatus": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["pending"]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"expires": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["created", "expires"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["status", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["complete"]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"expires": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["created", "expires"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["status", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["failed"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"expires": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["created", "expires"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["status", "message", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["expired"]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"expires": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["created", "expires"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["status", "time"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"Mcp.Status.Connected": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["connected"]
|
||||
}
|
||||
},
|
||||
"required": ["status"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Mcp.Status.Disconnected": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["disconnected"]
|
||||
}
|
||||
},
|
||||
"required": ["status"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Mcp.Status.Disabled": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["disabled"]
|
||||
}
|
||||
},
|
||||
"required": ["status"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Mcp.Status.Failed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["failed"]
|
||||
},
|
||||
"error": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["status", "error"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Mcp.Status.NeedsAuth": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["needs_auth"]
|
||||
}
|
||||
},
|
||||
"required": ["status"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Mcp.Status.NeedsClientRegistration": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["needs_client_registration"]
|
||||
},
|
||||
"error": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["status", "error"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Mcp.Server": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Mcp.Status.Connected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Mcp.Status.Disconnected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Mcp.Status.Disabled"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Mcp.Status.Failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Mcp.Status.NeedsAuth"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Mcp.Status.NeedsClientRegistration"
|
||||
}
|
||||
]
|
||||
},
|
||||
"integrationID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "status"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Project.Current": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "directory"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Project.Directory": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
"strategy": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["directory"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Project.Directories": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Project.Directory"
|
||||
}
|
||||
},
|
||||
"Form.Metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"Form.When": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"op": {
|
||||
"type": "string",
|
||||
"enum": ["eq", "neq"]
|
||||
},
|
||||
"value": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["key", "op", "value"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.Option": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["value", "label"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.StringField": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["string"]
|
||||
},
|
||||
"format": {
|
||||
"type": "string",
|
||||
"enum": ["email", "uri", "date", "date-time"]
|
||||
},
|
||||
"minLength": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxLength": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"pattern": {
|
||||
"type": "string"
|
||||
},
|
||||
"placeholder": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.Option"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["key", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.NumberField": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["number"]
|
||||
},
|
||||
"minimum": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"maximum": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["key", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.IntegerField": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["integer"]
|
||||
},
|
||||
"minimum": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"maximum": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["key", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.BooleanField": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["boolean"]
|
||||
},
|
||||
"default": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["key", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.MultiselectField": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["multiselect"]
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.Option"
|
||||
}
|
||||
},
|
||||
"minItems": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxItems": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"custom": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"default": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["key", "type", "options"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.FormInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/Form.Metadata"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["form"]
|
||||
},
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.StringField"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.NumberField"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.IntegerField"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.BooleanField"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.MultiselectField"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "mode", "fields"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.UrlInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/Form.Metadata"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["url"]
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "mode", "url"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.CreatePayload": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/Form.Metadata"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["form", "url"]
|
||||
},
|
||||
"fields": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.StringField"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.NumberField"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.IntegerField"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.BooleanField"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.MultiselectField"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["mode"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FormNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["FormNotFoundError"]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "id", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.Value": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Form.Answer": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/components/schemas/Form.Value"
|
||||
}
|
||||
},
|
||||
"Form.State": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["pending"]
|
||||
}
|
||||
},
|
||||
"required": ["status"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["answered"]
|
||||
},
|
||||
"answer": {
|
||||
"$ref": "#/components/schemas/Form.Answer"
|
||||
}
|
||||
},
|
||||
"required": ["status", "answer"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["cancelled"]
|
||||
}
|
||||
},
|
||||
"required": ["status"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"Form.Reply": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"answer": {
|
||||
"$ref": "#/components/schemas/Form.Answer"
|
||||
}
|
||||
},
|
||||
"required": ["answer"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FormAlreadySettledError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["FormAlreadySettledError"]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "id", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FormInvalidAnswerError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["FormInvalidAnswerError"]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "id", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PermissionV2.Source": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["tool"]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string"
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type", "messageID", "callID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"PermissionV2.Request": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^per"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"resources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"save": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Source"
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "action", "resources"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PermissionSaved.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"projectID": {
|
||||
"type": "string"
|
||||
},
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"resource": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "projectID", "action", "resource"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PermissionNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["PermissionNotFoundError"]
|
||||
},
|
||||
"requestID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "requestID", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PermissionV2.Reply": {
|
||||
"type": "string",
|
||||
"enum": ["once", "always", "reject"]
|
||||
},
|
||||
"FileSystem.Entry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["file", "directory"]
|
||||
}
|
||||
},
|
||||
"required": ["path", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CommandV2.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"template": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"$ref": "#/components/schemas/Model.Ref"
|
||||
},
|
||||
"subtask": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["name", "template"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SkillV2.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"slash": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"autoinvoke": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"location": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "location", "content"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"models-dev.refreshed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["models-dev.refreshed"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"integration.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["integration.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"integration.connection.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["integration.connection.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"integrationID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["integrationID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"catalog.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["catalog.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"agent.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["agent.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SnapshotFileDiff": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"patch": {
|
||||
"type": "string"
|
||||
},
|
||||
"additions": {
|
||||
"type": "number"
|
||||
},
|
||||
"deletions": {
|
||||
"type": "number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["added", "deleted", "modified"]
|
||||
}
|
||||
},
|
||||
"required": ["additions", "deletions"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PermissionAction": {
|
||||
"type": "string",
|
||||
"enum": ["allow", "deny", "ask"]
|
||||
},
|
||||
"PermissionRule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"permission": {
|
||||
"type": "string"
|
||||
},
|
||||
"pattern": {
|
||||
"type": "string"
|
||||
},
|
||||
"action": {
|
||||
"$ref": "#/components/schemas/PermissionAction"
|
||||
}
|
||||
},
|
||||
"required": ["permission", "pattern", "action"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PermissionRuleset": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PermissionRule"
|
||||
}
|
||||
},
|
||||
"Session": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"slug": {
|
||||
"type": "string"
|
||||
},
|
||||
"projectID": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspaceID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^wrk"
|
||||
}
|
||||
]
|
||||
},
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"parentID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"additions": {
|
||||
"type": "number"
|
||||
},
|
||||
"deletions": {
|
||||
"type": "number"
|
||||
},
|
||||
"files": {
|
||||
"type": "number"
|
||||
},
|
||||
"diffs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SnapshotFileDiff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["additions", "deletions", "files"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"input": {
|
||||
"type": "number"
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["read", "write"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["input", "output", "reasoning", "cache"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"share": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["url"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"variant": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "providerID"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"compacting": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"archived": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["created", "updated"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"permission": {
|
||||
"$ref": "#/components/schemas/PermissionRuleset"
|
||||
},
|
||||
"revert": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"partID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"snapshot": {
|
||||
"type": "string"
|
||||
},
|
||||
"diff": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["messageID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "slug", "projectID", "directory", "title", "version", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.created": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.created"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"info": {
|
||||
"$ref": "#/components/schemas/Session"
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "info"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"info": {
|
||||
"$ref": "#/components/schemas/Session"
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "info"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.deleted": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.deleted"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"info": {
|
||||
"$ref": "#/components/schemas/Session"
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "info"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"JSONSchema": {
|
||||
"type": "object"
|
||||
},
|
||||
"OutputFormat": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["text"]
|
||||
}
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["json_schema"]
|
||||
},
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/JSONSchema"
|
||||
},
|
||||
"retryCount": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["type", "schema"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"UserMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": ["user"]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"format": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/OutputFormat"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"diffs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SnapshotFileDiff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["diffs"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"modelID": {
|
||||
"type": "string"
|
||||
},
|
||||
"variant": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["providerID", "modelID"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"system": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "role", "time", "agent", "model"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ProviderAuthError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"enum": ["ProviderAuthError"]
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["providerID", "message"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["name", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UnknownError1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"enum": ["UnknownError"]
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["message"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["name", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MessageOutputLengthError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"enum": ["MessageOutputLengthError"]
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["name", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MessageAbortedError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"enum": ["MessageAbortedError"]
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["message"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["name", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"StructuredOutputError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"enum": ["StructuredOutputError"]
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"retries": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["message", "retries"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["name", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ContextOverflowError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"enum": ["ContextOverflowError"]
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"responseBody": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["message"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["name", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ContentFilterError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"enum": ["ContentFilterError"]
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["message"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["name", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"APIError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"enum": ["APIError"]
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"statusCode": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"isRetryable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"responseHeaders": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"responseBody": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["message", "isRetryable"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["name", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"AssistantMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": ["assistant"]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"completed": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"error": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProviderAuthError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/UnknownError1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/MessageOutputLengthError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/MessageAbortedError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/StructuredOutputError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ContextOverflowError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentFilterError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/APIError"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"parentID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"modelID": {
|
||||
"type": "string"
|
||||
},
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string"
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"root": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["cwd", "root"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"summary": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"input": {
|
||||
"type": "number"
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["read", "write"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["input", "output", "reasoning", "cache"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"structured": {
|
||||
"anyOf": [
|
||||
{},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"variant": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"finish": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"sessionID",
|
||||
"role",
|
||||
"time",
|
||||
"parentID",
|
||||
"modelID",
|
||||
"providerID",
|
||||
"mode",
|
||||
"agent",
|
||||
"path",
|
||||
"cost",
|
||||
"tokens"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Message": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/UserMessage"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AssistantMessage"
|
||||
}
|
||||
]
|
||||
},
|
||||
"message.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["message.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"info": {
|
||||
"$ref": "#/components/schemas/Message"
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "info"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"message.removed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["message.removed"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "messageID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"TextPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["text"]
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"synthetic": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ignored": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"end": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["start"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "text"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SubtaskPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["subtask"]
|
||||
},
|
||||
"prompt": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"providerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"modelID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["providerID", "modelID"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"command": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "prompt", "description", "agent"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ReasoningPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["reasoning"]
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"end": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["start"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "text", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FilePartSourceText": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"start": {
|
||||
"type": "number"
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["value", "start", "end"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FileSource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"$ref": "#/components/schemas/FilePartSourceText"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["file"]
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["text", "type", "path"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Range": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"line": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"character": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["line", "character"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"end": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"line": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"character": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["line", "character"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["start", "end"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SymbolSource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"$ref": "#/components/schemas/FilePartSourceText"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["symbol"]
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"range": {
|
||||
"$ref": "#/components/schemas/Range"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["text", "type", "path", "range", "name", "kind"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ResourceSource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"$ref": "#/components/schemas/FilePartSourceText"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["resource"]
|
||||
},
|
||||
"clientName": {
|
||||
"type": "string"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["text", "type", "clientName", "uri"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FilePartSource": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/FileSource"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SymbolSource"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ResourceSource"
|
||||
}
|
||||
]
|
||||
},
|
||||
"FilePart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["file"]
|
||||
},
|
||||
"mime": {
|
||||
"type": "string"
|
||||
},
|
||||
"filename": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/FilePartSource"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "mime", "url"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ToolStatePending": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["pending"]
|
||||
},
|
||||
"input": {
|
||||
"type": "object"
|
||||
},
|
||||
"raw": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["status", "input", "raw"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ToolStateRunning": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["running"]
|
||||
},
|
||||
"input": {
|
||||
"type": "object"
|
||||
},
|
||||
"title": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["start"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["status", "input", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ToolStateCompleted": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["completed"]
|
||||
},
|
||||
"input": {
|
||||
"type": "object"
|
||||
},
|
||||
"output": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"end": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"compacted": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["start", "end"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"attachments": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/FilePart"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["status", "input", "output", "title", "metadata", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ToolStateError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["error"]
|
||||
},
|
||||
"input": {
|
||||
"type": "object"
|
||||
},
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"end": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["start", "end"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["status", "input", "error", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ToolState": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ToolStatePending"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ToolStateRunning"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ToolStateCompleted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ToolStateError"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ToolPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["tool"]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"tool": {
|
||||
"type": "string"
|
||||
},
|
||||
"state": {
|
||||
"$ref": "#/components/schemas/ToolState"
|
||||
},
|
||||
"metadata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "callID", "tool", "state"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"StepStartPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["step-start"]
|
||||
},
|
||||
"snapshot": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"StepFinishPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["step-finish"]
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"snapshot": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"tokens": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"input": {
|
||||
"type": "number"
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["read", "write"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["input", "output", "reasoning", "cache"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "reason", "cost", "tokens"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SnapshotPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["snapshot"]
|
||||
},
|
||||
"snapshot": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "snapshot"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PatchPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["patch"]
|
||||
},
|
||||
"hash": {
|
||||
"type": "string"
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "hash", "files"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"AgentPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["agent"]
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "string"
|
||||
},
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"end": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["value", "start", "end"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "name"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RetryPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["retry"]
|
||||
},
|
||||
"attempt": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/components/schemas/APIError"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["created"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "attempt", "error", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CompactionPart": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["compaction"]
|
||||
},
|
||||
"auto": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"overflow": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tail_start_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "messageID", "type", "auto"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Part": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/TextPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SubtaskPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ReasoningPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/FilePart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ToolPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/StepStartPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/StepFinishPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/SnapshotPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/PatchPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AgentPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/RetryPart"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/CompactionPart"
|
||||
}
|
||||
]
|
||||
},
|
||||
"message.part.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["message.part.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"part": {
|
||||
"$ref": "#/components/schemas/Part"
|
||||
},
|
||||
"time": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "part", "time"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"message.part.removed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["message.part.removed"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"partID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^prt"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "messageID", "partID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.execution.settled": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.execution.settled"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outcome": {
|
||||
"type": "string",
|
||||
"enum": ["success", "failure", "interrupted"]
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/components/schemas/Session.Error.Unknown"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "outcome"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.text.delta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.text.delta"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"textID": {
|
||||
"type": "string"
|
||||
},
|
||||
"delta": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "textID", "delta"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.reasoning.delta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.reasoning.delta"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reasoningID": {
|
||||
"type": "string"
|
||||
},
|
||||
"delta": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "reasoningID", "delta"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.tool.input.delta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.tool.input.delta"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"assistantMessageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
},
|
||||
"delta": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "assistantMessageID", "callID", "delta"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.next.compaction.delta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.next.compaction.delta"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "number"
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["timestamp", "sessionID", "messageID", "text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"file.edited": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["file.edited"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["file"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"reference.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["reference.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"permission.v2.asked": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["permission.v2.asked"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^per"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"resources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"save": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Source"
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "action", "resources"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"permission.v2.replied": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["permission.v2.replied"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requestID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^per"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reply": {
|
||||
"$ref": "#/components/schemas/PermissionV2.Reply"
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "requestID", "reply"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"plugin.added": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["plugin.added"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"project.directories.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["project.directories.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"projectID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["projectID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"command.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["command.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"skill.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["skill.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"file.watcher.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["file.watcher.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"event": {
|
||||
"type": "string",
|
||||
"enum": ["add", "change", "unlink"]
|
||||
}
|
||||
},
|
||||
"required": ["file", "event"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Pty": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^pty"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"args": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["running", "exited"]
|
||||
},
|
||||
"pid": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"exitCode": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "title", "command", "args", "cwd", "status", "pid"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"pty.created": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["pty.created"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"info": {
|
||||
"$ref": "#/components/schemas/Pty"
|
||||
}
|
||||
},
|
||||
"required": ["info"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"pty.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["pty.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"info": {
|
||||
"$ref": "#/components/schemas/Pty"
|
||||
}
|
||||
},
|
||||
"required": ["info"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"pty.exited": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["pty.exited"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^pty"
|
||||
}
|
||||
]
|
||||
},
|
||||
"exitCode": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "exitCode"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"pty.deleted": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["pty.deleted"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^pty"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Shell": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^sh_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["running", "exited", "timeout", "killed"]
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"shell": {
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"pid": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"exit": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"started": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"completed": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["started"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "status", "command", "cwd", "shell", "file", "metadata", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"shell.created": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["shell.created"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"info": {
|
||||
"$ref": "#/components/schemas/Shell"
|
||||
}
|
||||
},
|
||||
"required": ["info"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"shell.exited": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["shell.exited"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^sh_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"exit": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["running", "exited", "timeout", "killed"]
|
||||
}
|
||||
},
|
||||
"required": ["id", "status"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"shell.deleted": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["shell.deleted"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^sh_"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionV2.Option": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Display text (1-5 words, concise)"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Explanation of choice"
|
||||
}
|
||||
},
|
||||
"required": ["label", "description"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionV2.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"question": {
|
||||
"type": "string",
|
||||
"description": "Complete question"
|
||||
},
|
||||
"header": {
|
||||
"type": "string",
|
||||
"description": "Very short label (max 30 chars)"
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Option"
|
||||
},
|
||||
"description": "Available choices"
|
||||
},
|
||||
"multiple": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"custom": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["question", "header", "options"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionV2.Tool": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"messageID": {
|
||||
"type": "string"
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["messageID", "callID"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"question.v2.asked": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["question.v2.asked"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^que"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Info"
|
||||
},
|
||||
"description": "Questions to ask"
|
||||
},
|
||||
"tool": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Tool"
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "questions"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionV2.Answer": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"question.v2.replied": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["question.v2.replied"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requestID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^que"
|
||||
}
|
||||
]
|
||||
},
|
||||
"answers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Answer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "requestID", "answers"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"question.v2.rejected": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["question.v2.rejected"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requestID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^que"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "requestID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.Metadata1": {
|
||||
"type": "object"
|
||||
},
|
||||
"Form.When1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"op": {
|
||||
"type": "string",
|
||||
"enum": ["eq", "neq"]
|
||||
},
|
||||
"value": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["key", "op", "value"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.StringField1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When1"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["string"]
|
||||
},
|
||||
"format": {
|
||||
"type": "string",
|
||||
"enum": ["email", "uri", "date", "date-time"]
|
||||
},
|
||||
"minLength": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxLength": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"pattern": {
|
||||
"type": "string"
|
||||
},
|
||||
"placeholder": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.Option"
|
||||
}
|
||||
},
|
||||
"custom": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["key", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.NumberField1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When1"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["number"]
|
||||
},
|
||||
"minimum": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"maximum": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["key", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.IntegerField1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When1"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["integer"]
|
||||
},
|
||||
"minimum": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"maximum": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["key", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.BooleanField1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When1"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["boolean"]
|
||||
},
|
||||
"default": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["key", "type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.MultiselectField1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"when": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.When1"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["multiselect"]
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Form.Option"
|
||||
}
|
||||
},
|
||||
"minItems": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxItems": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"custom": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"default": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["key", "type", "options"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.FormInfo1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/Form.Metadata1"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["form"]
|
||||
},
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.StringField1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.NumberField1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.IntegerField1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.BooleanField1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.MultiselectField1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "mode", "fields"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.UrlInfo1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/Form.Metadata1"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["url"]
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "mode", "url"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"form.created": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["form.created"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"form": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.FormInfo1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Form.UrlInfo1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["form"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Form.Value1": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Form.Answer1": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/components/schemas/Form.Value1"
|
||||
}
|
||||
},
|
||||
"form.replied": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["form.replied"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
},
|
||||
"answer": {
|
||||
"$ref": "#/components/schemas/Form.Answer1"
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "answer"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"form.cancelled": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["form.cancelled"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^frm_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Todo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Brief description of the task"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Current status of the task: pending, in_progress, completed, cancelled"
|
||||
},
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"description": "Priority level of the task: high, medium, low"
|
||||
}
|
||||
},
|
||||
"required": ["content", "status", "priority"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"todo.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["todo.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"todos": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Todo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "todos"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SessionStatus": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["idle"]
|
||||
}
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["retry"]
|
||||
},
|
||||
"attempt": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"action": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"provider": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"link": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["reason", "provider", "title", "message", "label"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"next": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["type", "attempt", "message", "next"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["busy"]
|
||||
}
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"session.status": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.status"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/components/schemas/SessionStatus"
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "status"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.idle": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.idle"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["sessionID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"tui.prompt.append": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["tui.prompt.append"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["text"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"tui.command.execute": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["tui.command.execute"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"session.list",
|
||||
"session.new",
|
||||
"session.share",
|
||||
"session.interrupt",
|
||||
"session.background",
|
||||
"session.compact",
|
||||
"session.page.up",
|
||||
"session.page.down",
|
||||
"session.line.up",
|
||||
"session.line.down",
|
||||
"session.half.page.up",
|
||||
"session.half.page.down",
|
||||
"session.first",
|
||||
"session.last",
|
||||
"prompt.clear",
|
||||
"prompt.submit",
|
||||
"agent.cycle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["command"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"tui.toast.show": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["tui.toast.show"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"variant": {
|
||||
"type": "string",
|
||||
"enum": ["info", "success", "warning", "error"]
|
||||
},
|
||||
"duration": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"exclusiveMinimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["message", "variant"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"tui.session.select": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["tui.session.select"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses",
|
||||
"description": "Session ID to navigate to"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["sessionID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"installation.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["installation.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["version"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"installation.update-available": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["installation.update-available"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["version"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"vcs.branch.updated": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["vcs.branch.updated"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"branch": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"mcp.status.changed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["mcp.status.changed"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"server": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["server"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"permission.asked": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["permission.asked"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^per"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"permission": {
|
||||
"type": "string"
|
||||
},
|
||||
"patterns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"always": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"tool": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"messageID": {
|
||||
"type": "string"
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["messageID", "callID"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "permission", "patterns", "metadata", "always"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"permission.replied": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["permission.replied"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requestID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^per"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reply": {
|
||||
"type": "string",
|
||||
"enum": ["once", "always", "reject"]
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "requestID", "reply"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionOption": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Display text (1-5 words, concise)"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Explanation of choice"
|
||||
}
|
||||
},
|
||||
"required": ["label", "description"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"question": {
|
||||
"type": "string",
|
||||
"description": "Complete question"
|
||||
},
|
||||
"header": {
|
||||
"type": "string",
|
||||
"description": "Very short label (max 30 chars)"
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionOption"
|
||||
},
|
||||
"description": "Available choices"
|
||||
},
|
||||
"multiple": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Allow selecting multiple choices"
|
||||
},
|
||||
"custom": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Allow typing a custom answer (default: true)"
|
||||
}
|
||||
},
|
||||
"required": ["question", "header", "options"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionTool": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"messageID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^msg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"callID": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["messageID", "callID"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"question.asked": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["question.asked"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^que"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionInfo"
|
||||
},
|
||||
"description": "Questions to ask"
|
||||
},
|
||||
"tool": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/QuestionTool"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "questions"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionAnswer": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"question.replied": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["question.replied"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requestID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^que"
|
||||
}
|
||||
]
|
||||
},
|
||||
"answers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionAnswer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "requestID", "answers"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"question.rejected": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["question.rejected"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requestID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^que"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "requestID"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"session.error": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["session.error"]
|
||||
},
|
||||
"durable": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProviderAuthError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/UnknownError1"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/MessageOutputLengthError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/MessageAbortedError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/StructuredOutputError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ContextOverflowError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentFilterError"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/APIError"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"V2Event.server.connected": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^evt_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"durable": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["aggregateID", "seq", "version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Location.Ref"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["server.connected"]
|
||||
},
|
||||
"data": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["id", "type", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"V2Event": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/models-dev.refreshed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/integration.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/integration.connection.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/catalog.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/agent.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.deleted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/message.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/message.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/message.part.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/message.part.removed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.agent.switched"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.model.switched"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.moved"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.renamed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.forked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.prompted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.prompt.admitted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.execution.settled"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.context.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.synthetic"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.skill.activated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.shell.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.shell.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.step.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.step.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.step.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.text.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.text.delta"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.text.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.reasoning.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.reasoning.delta"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.reasoning.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.input.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.input.delta"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.input.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.called"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.progress"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.success"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.tool.failed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.retried"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.compaction.started"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.compaction.delta"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.compaction.ended"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.revert.staged"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.revert.cleared"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.next.revert.committed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/file.edited"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/reference.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/permission.v2.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/permission.v2.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/plugin.added"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/project.directories.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/command.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/skill.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/file.watcher.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/pty.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/pty.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/pty.exited"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/pty.deleted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/shell.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/shell.exited"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/shell.deleted"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/question.v2.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/question.v2.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/question.v2.rejected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/form.created"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/form.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/form.cancelled"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/todo.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.status"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.idle"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/tui.prompt.append"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/tui.command.execute"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/tui.toast.show"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/tui.session.select"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/installation.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/installation.update-available"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/vcs.branch.updated"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/mcp.status.changed"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/permission.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/permission.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/question.asked"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/question.replied"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/question.rejected"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/session.error"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/V2Event.server.connected"
|
||||
}
|
||||
]
|
||||
},
|
||||
"V2EventStream": {
|
||||
"type": "string",
|
||||
"contentSchema": {
|
||||
"$ref": "#/components/schemas/V2Event"
|
||||
},
|
||||
"contentMediaType": "application/json"
|
||||
},
|
||||
"EventLog.Hint": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["log.hint"]
|
||||
},
|
||||
"aggregateID": {
|
||||
"type": "string"
|
||||
},
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["type", "aggregateID", "seq"],
|
||||
"additionalProperties": false,
|
||||
"description": "Payload-free change hint: the aggregate's durable log advanced to at least seq. Hints coalesce under backpressure (latest per aggregate) and are never a delivery guarantee."
|
||||
},
|
||||
"EventLog.SweepRequired": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["log.sweep_required"]
|
||||
}
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": false,
|
||||
"description": "Hints may have been lost; treat every aggregate as potentially dirty and recover via bounded sweep plus durable log reads. Emitted first on every (re)subscribe."
|
||||
},
|
||||
"EventLog.Change": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/EventLog.Hint"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/EventLog.SweepRequired"
|
||||
}
|
||||
]
|
||||
},
|
||||
"EventLog.ChangeStream": {
|
||||
"type": "string",
|
||||
"contentSchema": {
|
||||
"$ref": "#/components/schemas/EventLog.Change"
|
||||
},
|
||||
"contentMediaType": "application/json"
|
||||
},
|
||||
"PtyNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["PtyNotFoundError"]
|
||||
},
|
||||
"ptyID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "ptyID", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PtyTicket.ConnectToken": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ticket": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_in": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"exclusiveMinimum": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["ticket", "expires_in"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ForbiddenError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["ForbiddenError"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Shell1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^sh_"
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["running", "exited", "timeout", "killed"]
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"shell": {
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"pid": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"exit": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"time": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"started": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"completed": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["NaN"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity"]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["-Infinity"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["Infinity", "-Infinity", "NaN"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["started"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["id", "status", "command", "cwd", "shell", "file", "metadata", "time"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ShellNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["ShellNotFoundError"]
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "id", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionV2.Request": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^que"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sessionID": {
|
||||
"type": "string",
|
||||
"allOf": [
|
||||
{
|
||||
"pattern": "^ses"
|
||||
}
|
||||
]
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Info"
|
||||
},
|
||||
"description": "Questions to ask"
|
||||
},
|
||||
"tool": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Tool"
|
||||
}
|
||||
},
|
||||
"required": ["id", "sessionID", "questions"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionV2.Reply": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"answers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/QuestionV2.Answer"
|
||||
},
|
||||
"description": "User answers in order of questions (each answer is an array of selected labels)"
|
||||
}
|
||||
},
|
||||
"required": ["answers"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"QuestionNotFoundError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_tag": {
|
||||
"type": "string",
|
||||
"enum": ["QuestionNotFoundError"]
|
||||
},
|
||||
"requestID": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["_tag", "requestID", "message"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Reference.LocalSource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["local"]
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"hidden": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["type", "path"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Reference.GitSource": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["git"]
|
||||
},
|
||||
"repository": {
|
||||
"type": "string"
|
||||
},
|
||||
"branch": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"hidden": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["type", "repository"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Reference.Source": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Reference.LocalSource"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Reference.GitSource"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Reference.Info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"hidden": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/components/schemas/Reference.Source"
|
||||
}
|
||||
},
|
||||
"required": ["name", "path", "source"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ProjectCopy.Copy": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"directory": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["directory"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ProjectCopyError": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"enum": ["ProjectCopyError"]
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"forceRequired": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["message"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["name", "data"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Vcs.FileStatus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"additions": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"deletions": {
|
||||
"type": "integer",
|
||||
"allOf": [
|
||||
{
|
||||
"minimum": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["added", "deleted", "modified"]
|
||||
}
|
||||
},
|
||||
"required": ["file", "additions", "deletions", "status"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Vcs.Mode": {
|
||||
"type": "string",
|
||||
"enum": ["working", "branch"]
|
||||
}
|
||||
},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": [
|
||||
{
|
||||
"name": "server.health"
|
||||
},
|
||||
{
|
||||
"name": "server.location"
|
||||
},
|
||||
{
|
||||
"name": "server.agent"
|
||||
},
|
||||
{
|
||||
"name": "plugins",
|
||||
"description": "Experimental plugin routes."
|
||||
},
|
||||
{
|
||||
"name": "sessions",
|
||||
"description": "Experimental session routes."
|
||||
},
|
||||
{
|
||||
"name": "messages",
|
||||
"description": "Experimental message routes."
|
||||
},
|
||||
{
|
||||
"name": "models",
|
||||
"description": "Experimental model routes."
|
||||
},
|
||||
{
|
||||
"name": "generate",
|
||||
"description": "Experimental one-shot generation routes."
|
||||
},
|
||||
{
|
||||
"name": "providers",
|
||||
"description": "Experimental provider routes."
|
||||
},
|
||||
{
|
||||
"name": "integrations",
|
||||
"description": "Integration discovery and authentication routes."
|
||||
},
|
||||
{
|
||||
"name": "mcp",
|
||||
"description": "MCP server status routes."
|
||||
},
|
||||
{
|
||||
"name": "server.credential"
|
||||
},
|
||||
{
|
||||
"name": "projects",
|
||||
"description": "Location-scoped project routes."
|
||||
},
|
||||
{
|
||||
"name": "forms",
|
||||
"description": "Session form routes."
|
||||
},
|
||||
{
|
||||
"name": "permissions",
|
||||
"description": "Experimental permission routes."
|
||||
},
|
||||
{
|
||||
"name": "filesystem",
|
||||
"description": "Experimental location-scoped filesystem routes."
|
||||
},
|
||||
{
|
||||
"name": "commands",
|
||||
"description": "Experimental command routes."
|
||||
},
|
||||
{
|
||||
"name": "skills",
|
||||
"description": "Experimental skill routes."
|
||||
},
|
||||
{
|
||||
"name": "events",
|
||||
"description": "Experimental event stream routes."
|
||||
},
|
||||
{
|
||||
"name": "pty",
|
||||
"description": "Experimental location-scoped PTY routes."
|
||||
},
|
||||
{
|
||||
"name": "shell",
|
||||
"description": "Experimental location-scoped shell command routes."
|
||||
},
|
||||
{
|
||||
"name": "session questions",
|
||||
"description": "Experimental session question routes."
|
||||
},
|
||||
{
|
||||
"name": "reference",
|
||||
"description": "Location-scoped project references."
|
||||
},
|
||||
{
|
||||
"name": "projectCopy",
|
||||
"description": "Project copy management routes."
|
||||
},
|
||||
{
|
||||
"name": "vcs",
|
||||
"description": "Location-scoped version control routes."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,964 +0,0 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Effect, Layer, Option } from "effect"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
import { CodeMode, OpenAPI } from "../src/index.js"
|
||||
import { inputTypeScript, outputTypeScript, Tool } from "../src/tool.js"
|
||||
|
||||
const baseUrl = "http://localhost:4096"
|
||||
type Document = OpenAPI.Document
|
||||
|
||||
type Recorded = {
|
||||
readonly method: string
|
||||
readonly url: string
|
||||
readonly headers: Record<string, string>
|
||||
readonly body: unknown
|
||||
}
|
||||
|
||||
const opencodeSpec = async (): Promise<Document> => {
|
||||
return Bun.file(new URL("./fixtures/opencode-v2-openapi.json", import.meta.url)).json() as Promise<Document>
|
||||
}
|
||||
|
||||
const happyPathSpec = async (): Promise<Document> => {
|
||||
return Bun.file(new URL("./fixtures/openapi-happy-path.json", import.meta.url)).json() as Promise<Document>
|
||||
}
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
typeof value === "object" && value !== null && !Array.isArray(value)
|
||||
|
||||
const toolAt = (tools: unknown, name: string) =>
|
||||
name.split(".").reduce<unknown>((current, segment) => (isRecord(current) ? current[segment] : undefined), tools)
|
||||
|
||||
const recordingClient = (respond: (request: HttpClientRequest.HttpClientRequest) => Response) => {
|
||||
const requests: Array<Recorded> = []
|
||||
const layer = Layer.succeed(HttpClient.HttpClient)(
|
||||
HttpClient.make((request) =>
|
||||
Effect.gen(function* () {
|
||||
const body =
|
||||
request.body._tag === "Uint8Array" ? JSON.parse(new TextDecoder().decode(request.body.body)) : undefined
|
||||
const url = Option.map(HttpClientRequest.toUrl(request), (resolved) => resolved.toString())
|
||||
requests.push({
|
||||
method: request.method,
|
||||
url: Option.getOrElse(url, () => request.url),
|
||||
headers: { ...request.headers },
|
||||
body,
|
||||
})
|
||||
return HttpClientResponse.fromWeb(request, respond(request))
|
||||
}),
|
||||
),
|
||||
)
|
||||
return { requests, layer }
|
||||
}
|
||||
|
||||
const json = (value: unknown, status = 200) =>
|
||||
new Response(JSON.stringify(value), { status, headers: { "content-type": "application/json" } })
|
||||
|
||||
const singleOperation = (operation: Record<string, unknown>, method = "get"): Document => ({
|
||||
openapi: "3.1.0",
|
||||
paths: {
|
||||
"/test": { [method]: { operationId: "test", responses: { 200: { description: "Success" } }, ...operation } },
|
||||
},
|
||||
})
|
||||
|
||||
describe("OpenAPI.fromSpec", () => {
|
||||
test("covers a representative API from generation through execution", async () => {
|
||||
const resolutions: Array<string> = []
|
||||
const client = recordingClient((request) => {
|
||||
const url = Option.getOrElse(HttpClientRequest.toUrl(request), () => new URL(request.url))
|
||||
if (request.method === "POST") {
|
||||
return new Response(
|
||||
JSON.stringify({ id: "user-2", name: "Grace", email: "grace@example.test", role: "admin" }),
|
||||
{ status: 201, headers: { "content-type": "application/vnd.example+json" } },
|
||||
)
|
||||
}
|
||||
if (request.method === "DELETE") return new Response(null, { status: 204 })
|
||||
if (url.pathname === "/search") {
|
||||
return new Response("2 matches", { headers: { "content-type": "text/plain" } })
|
||||
}
|
||||
return json({ id: "user-1", name: "Ada", email: "ada@example.test", role: "member" })
|
||||
})
|
||||
const api = OpenAPI.fromSpec({
|
||||
spec: await happyPathSpec(),
|
||||
baseUrl,
|
||||
auth: {
|
||||
resolve: ({ name }) => {
|
||||
resolutions.push(name)
|
||||
return Effect.succeed(
|
||||
name === "BearerAuth"
|
||||
? { type: "bearer", token: "bearer-secret" }
|
||||
: { type: "apiKey", value: "api-secret" },
|
||||
)
|
||||
},
|
||||
},
|
||||
})
|
||||
const get = toolAt(api.tools, "users.get")
|
||||
const create = toolAt(api.tools, "users.create")
|
||||
const search = toolAt(api.tools, "search.run")
|
||||
const remove = toolAt(api.tools, "users.remove")
|
||||
|
||||
expect(api.skipped).toEqual([])
|
||||
if (
|
||||
!Tool.isDefinition(get) ||
|
||||
!Tool.isDefinition(create) ||
|
||||
!Tool.isDefinition(search) ||
|
||||
!Tool.isDefinition(remove)
|
||||
) {
|
||||
throw new Error("happy-path fixture did not generate every operation")
|
||||
}
|
||||
expect(inputTypeScript(get)).toBe(
|
||||
'{ userId: string; include?: Array<string>; verbose?: boolean; "X-Trace-ID"?: string }',
|
||||
)
|
||||
expect(inputTypeScript(create)).toBe('{ name: string; email: string; role?: "admin" | "member" }')
|
||||
expect(inputTypeScript(search)).toBe("{ filter?: { query: string; page?: number }; tags?: Array<string> }")
|
||||
expect(inputTypeScript(remove)).toBe("{ userId: string }")
|
||||
expect(outputTypeScript(get)).toContain("id: string")
|
||||
expect(outputTypeScript(create)).toContain('role?: "admin" | "member"')
|
||||
expect(outputTypeScript(search)).toBe("string")
|
||||
expect(outputTypeScript(remove)).toBe("null")
|
||||
|
||||
const result = await Effect.runPromise(
|
||||
CodeMode.make({ tools: { api: api.tools } })
|
||||
.execute(
|
||||
`
|
||||
const user = await tools.api.users.get({
|
||||
userId: "user-1",
|
||||
include: ["profile", "permissions"],
|
||||
verbose: true,
|
||||
"X-Trace-ID": "trace-1",
|
||||
})
|
||||
const created = await tools.api.users.create({
|
||||
name: "Grace",
|
||||
email: "grace@example.test",
|
||||
role: "admin",
|
||||
})
|
||||
const summary = await tools.api.search.run({
|
||||
filter: { query: "effect", page: 2 },
|
||||
tags: ["typescript", "runtime"],
|
||||
})
|
||||
const removed = await tools.api.users.remove({ userId: "user-1" })
|
||||
return { user, created, summary, removed }
|
||||
`,
|
||||
)
|
||||
.pipe(Effect.provide(client.layer)),
|
||||
)
|
||||
|
||||
expect(result).toMatchObject({
|
||||
ok: true,
|
||||
value: {
|
||||
user: { id: "user-1", name: "Ada" },
|
||||
created: { id: "user-2", name: "Grace" },
|
||||
summary: "2 matches",
|
||||
removed: null,
|
||||
},
|
||||
})
|
||||
expect(resolutions).toEqual(["BearerAuth", "ApiKey", "BearerAuth"])
|
||||
expect(client.requests).toHaveLength(4)
|
||||
|
||||
const getUrl = new URL(client.requests[0]!.url)
|
||||
expect(getUrl.pathname).toBe("/users/user-1")
|
||||
expect(getUrl.searchParams.get("include")).toBe("profile,permissions")
|
||||
expect(getUrl.searchParams.get("verbose")).toBe("true")
|
||||
expect(client.requests[0]!.headers["x-trace-id"]).toBe("trace-1")
|
||||
expect(client.requests[0]!.headers.authorization).toBe("Bearer bearer-secret")
|
||||
|
||||
const createUrl = new URL(client.requests[1]!.url)
|
||||
expect(createUrl.searchParams.get("api_key")).toBe("api-secret")
|
||||
expect(client.requests[1]!.body).toEqual({ name: "Grace", email: "grace@example.test", role: "admin" })
|
||||
|
||||
const searchUrl = new URL(client.requests[2]!.url)
|
||||
expect(searchUrl.searchParams.get("filter[query]")).toBe("effect")
|
||||
expect(searchUrl.searchParams.get("filter[page]")).toBe("2")
|
||||
expect(searchUrl.searchParams.getAll("tags")).toEqual(["typescript", "runtime"])
|
||||
expect(client.requests[2]!.headers.authorization).toBeUndefined()
|
||||
expect(new URL(client.requests[3]!.url).pathname).toBe("/users/user-1")
|
||||
expect(client.requests[3]!.headers.authorization).toBe("Bearer bearer-secret")
|
||||
})
|
||||
|
||||
test("converts representative opencode operations into the expected tool shape", async () => {
|
||||
const spec = await opencodeSpec()
|
||||
const result = OpenAPI.fromSpec({ spec, baseUrl })
|
||||
|
||||
expect(result.skipped).toHaveLength(5)
|
||||
expect(result.skipped).toContainEqual({
|
||||
method: "GET",
|
||||
path: "/api/pty/{ptyID}/connect",
|
||||
reason: "WebSocket operations are not supported",
|
||||
})
|
||||
expect(result.skipped.filter((item) => item.reason === "SSE operations are not supported")).toHaveLength(3)
|
||||
expect(result.skipped).toContainEqual({
|
||||
method: "GET",
|
||||
path: "/api/fs/read/*",
|
||||
reason: "binary responses are not supported",
|
||||
})
|
||||
expect(toolAt(result.tools, "v2.health.get")).not.toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.session.get")).not.toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.session.create")).not.toBeUndefined()
|
||||
|
||||
const sessionGet = toolAt(result.tools, "v2.session.get")
|
||||
expect(Tool.isDefinition(sessionGet)).toBe(true)
|
||||
if (!Tool.isDefinition(sessionGet)) throw new Error("v2.session.get was not generated")
|
||||
expect(inputTypeScript(sessionGet)).toBe("{ sessionID: string }")
|
||||
expect(outputTypeScript(sessionGet)).toContain("id: string")
|
||||
expect(outputTypeScript(sessionGet)).toContain("additions: number")
|
||||
|
||||
const switchAgent = toolAt(result.tools, "v2.session.switchAgent")
|
||||
expect(Tool.isDefinition(switchAgent)).toBe(true)
|
||||
if (!Tool.isDefinition(switchAgent)) throw new Error("v2.session.switchAgent was not generated")
|
||||
expect(inputTypeScript(switchAgent)).toBe("{ sessionID: string; agent: string }")
|
||||
|
||||
const contextEntryPut = toolAt(result.tools, "v2.session.contextEntry.put")
|
||||
expect(Tool.isDefinition(contextEntryPut)).toBe(true)
|
||||
if (!Tool.isDefinition(contextEntryPut)) throw new Error("v2.session.contextEntry.put was not generated")
|
||||
expect(inputTypeScript(contextEntryPut)).toBe("{ sessionID: string; key: string; value: unknown }")
|
||||
expect(toolAt(result.tools, "v2_session_context_entry_put_2")).toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.pty.connect")).toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.session.log")).toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.event.subscribe")).toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.event.changes")).toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.fs.read")).toBeUndefined()
|
||||
expect(toolAt(result.tools, "v2.pty.connectToken")).not.toBeUndefined()
|
||||
})
|
||||
|
||||
test("preserves operation path sanitization and collision handling", () => {
|
||||
const response = { responses: { 200: { description: "Success" } } }
|
||||
const result = OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
openapi: "3.1.0",
|
||||
paths: {
|
||||
"/first": { get: { ...response, operationId: "group.item" } },
|
||||
"/second": { get: { ...response, operationId: "group.item" } },
|
||||
"/third": { get: { ...response, operationId: "group..other" } },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(Tool.isDefinition(toolAt(result.tools, "group.item"))).toBe(true)
|
||||
expect(Tool.isDefinition(toolAt(result.tools, "group_item_2"))).toBe(true)
|
||||
expect(Tool.isDefinition(toolAt(result.tools, "group.operation.other"))).toBe(true)
|
||||
})
|
||||
|
||||
test("synthesizes flat operation IDs from methods and paths", () => {
|
||||
const response = { responses: { 200: { description: "Success" } } }
|
||||
const tools = OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
openapi: "3.1.0",
|
||||
paths: {
|
||||
"/users": { get: response, post: response },
|
||||
"/users/{id}": { get: response, patch: response, delete: response },
|
||||
"/organizations/{organizationId}/users/{id}": { get: response },
|
||||
},
|
||||
},
|
||||
}).tools
|
||||
|
||||
for (const path of [
|
||||
"getUsers",
|
||||
"postUsers",
|
||||
"getUsersById",
|
||||
"patchUsersById",
|
||||
"deleteUsersById",
|
||||
"getOrganizationsByOrganizationidUsersById",
|
||||
]) {
|
||||
expect(Tool.isDefinition(toolAt(tools, path))).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
test("lets operation parameters override matching path parameters", () => {
|
||||
const tool = toolAt(
|
||||
OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
openapi: "3.1.0",
|
||||
paths: {
|
||||
"/test": {
|
||||
parameters: [{ name: "limit", in: "query", schema: { type: "string" } }],
|
||||
get: {
|
||||
operationId: "test",
|
||||
parameters: [{ name: "limit", in: "query", required: true, schema: { type: "number" } }],
|
||||
responses: { 200: { description: "Success" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).tools,
|
||||
"test",
|
||||
)
|
||||
|
||||
if (!Tool.isDefinition(tool)) throw new Error("test was not generated")
|
||||
expect(inputTypeScript(tool)).toBe("{ limit: number }")
|
||||
})
|
||||
|
||||
test("normalizes OpenAPI 3.0 schemas with Effect", () => {
|
||||
const result = OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
openapi: "3.0.3",
|
||||
paths: {
|
||||
"/search": {
|
||||
get: {
|
||||
operationId: "search",
|
||||
parameters: [
|
||||
{
|
||||
in: "query",
|
||||
name: "value",
|
||||
schema: { type: "string", nullable: true, minLength: 2 },
|
||||
},
|
||||
],
|
||||
responses: { 200: { description: "Success" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
const search = toolAt(result.tools, "search")
|
||||
|
||||
expect(Tool.isDefinition(search)).toBe(true)
|
||||
if (!Tool.isDefinition(search)) throw new Error("search was not generated")
|
||||
expect(inputTypeScript(search)).toBe("{ value?: string | null }")
|
||||
const schema: unknown = search.input
|
||||
const input = isRecord(schema) ? schema : {}
|
||||
const properties = isRecord(input.properties) ? input.properties : {}
|
||||
const value = isRecord(properties.value) ? properties.value : {}
|
||||
expect(value.minLength).toBe(2)
|
||||
})
|
||||
|
||||
test("preserves schema-local definitions alongside component definitions", () => {
|
||||
const tool = toolAt(
|
||||
OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
openapi: "3.1.0",
|
||||
paths: {
|
||||
"/test": {
|
||||
get: {
|
||||
operationId: "test",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Success",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: { $ref: "#/$defs/Local", $defs: { Local: { type: "string" } } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
components: { schemas: { Global: { type: "number" } } },
|
||||
},
|
||||
}).tools,
|
||||
"test",
|
||||
)
|
||||
|
||||
if (!Tool.isDefinition(tool) || !isRecord(tool.output)) throw new Error("test output was not generated")
|
||||
expect(tool.output.$defs).toMatchObject({ Local: { type: "string" }, Global: { type: "number" } })
|
||||
})
|
||||
|
||||
test("documents that the opencode fixture is unauthenticated", async () => {
|
||||
const spec = await opencodeSpec()
|
||||
const components = isRecord(spec.components) ? spec.components : {}
|
||||
const result = OpenAPI.fromSpec({ spec, baseUrl })
|
||||
|
||||
expect(spec.security).toStrictEqual([])
|
||||
expect(isRecord(components.securitySchemes) ? Object.keys(components.securitySchemes) : []).toStrictEqual([])
|
||||
const health = toolAt(result.tools, "v2.health.get")
|
||||
const healthInput = isRecord(health) ? health.input : undefined
|
||||
expect(healthInput).toMatchObject({ type: "object", properties: {} })
|
||||
const input = isRecord(healthInput) ? healthInput : {}
|
||||
expect(Object.keys(isRecord(input.properties) ? input.properties : {})).toStrictEqual([])
|
||||
})
|
||||
|
||||
test("exposes real opencode operations through CodeMode discovery", async () => {
|
||||
const { layer } = recordingClient(() => json({}))
|
||||
const runtime = CodeMode.make({
|
||||
tools: { opencode: OpenAPI.fromSpec({ spec: await opencodeSpec(), baseUrl }).tools },
|
||||
})
|
||||
const result = await Effect.runPromise(
|
||||
runtime
|
||||
.execute(
|
||||
`
|
||||
return await tools.$codemode.search({ query: "global health", namespace: "opencode", limit: 1 })
|
||||
`,
|
||||
)
|
||||
.pipe(Effect.provide(layer)),
|
||||
)
|
||||
|
||||
expect(result).toMatchObject({ ok: true })
|
||||
if (!result.ok) return
|
||||
expect(result.value).toMatchObject({
|
||||
items: [
|
||||
{
|
||||
path: "tools.opencode.v2.health.get",
|
||||
description: "Check whether the API server is ready to accept requests.",
|
||||
},
|
||||
],
|
||||
})
|
||||
expect(JSON.stringify(result.value)).toContain("healthy: true")
|
||||
})
|
||||
|
||||
test("invokes real opencode path parameters and JSON request bodies", async () => {
|
||||
const { requests, layer } = recordingClient((request) => {
|
||||
if (request.method === "GET") return json({ id: "ses_123" })
|
||||
return json({ id: "ses_456" })
|
||||
})
|
||||
const runtime = CodeMode.make({
|
||||
tools: { opencode: OpenAPI.fromSpec({ spec: await opencodeSpec(), baseUrl }).tools },
|
||||
})
|
||||
|
||||
const result = await Effect.runPromise(
|
||||
runtime
|
||||
.execute(
|
||||
`
|
||||
const existing = await tools.opencode.v2.session.get({ sessionID: "ses_123" })
|
||||
const created = await tools.opencode.v2.session.create({ id: "ses_456" })
|
||||
return { existing, created }
|
||||
`,
|
||||
)
|
||||
.pipe(Effect.provide(layer)),
|
||||
)
|
||||
|
||||
expect(result).toMatchObject({ ok: true })
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(requests[0]).toMatchObject({ method: "GET", body: undefined })
|
||||
expect(new URL(requests[0]!.url).pathname).toBe("/api/session/ses_123")
|
||||
expect(requests[1]).toMatchObject({
|
||||
method: "POST",
|
||||
url: "http://localhost:4096/api/session",
|
||||
body: { id: "ses_456" },
|
||||
})
|
||||
})
|
||||
|
||||
test("serializes deep-object query parameters from the opencode fixture", async () => {
|
||||
const client = recordingClient(() => json({ directory: "/tmp" }))
|
||||
const location = toolAt(OpenAPI.fromSpec({ spec: await opencodeSpec(), baseUrl }).tools, "v2.location.get")
|
||||
if (!Tool.isDefinition(location)) throw new Error("v2.location.get was not generated")
|
||||
|
||||
await Effect.runPromise(
|
||||
location.run({ location: { directory: "/tmp", workspace: "workspace-1" } }).pipe(Effect.provide(client.layer)),
|
||||
)
|
||||
|
||||
const url = new URL(client.requests[0]!.url)
|
||||
expect(url.searchParams.get("location[directory]")).toBe("/tmp")
|
||||
expect(url.searchParams.get("location[workspace]")).toBe("workspace-1")
|
||||
})
|
||||
|
||||
test("serializes supported simple and form parameter shapes", async () => {
|
||||
const client = recordingClient(() => json({ ok: true }))
|
||||
const result = OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
openapi: "3.1.0",
|
||||
paths: {
|
||||
"/items/{keys}": {
|
||||
get: {
|
||||
operationId: "items",
|
||||
parameters: [
|
||||
{ name: "keys", in: "path", required: true, schema: { type: "array", items: { type: "string" } } },
|
||||
{ name: "tags", in: "query", style: "form", explode: false, schema: { type: "array" } },
|
||||
{ name: "filter", in: "query", style: "form", explode: true, schema: { type: "object" } },
|
||||
{ name: "nullable", in: "query", required: true, schema: { type: ["string", "null"] } },
|
||||
{ name: "constructor", in: "query", schema: { type: "string" } },
|
||||
{ name: "meta", in: "header", style: "simple", explode: true, schema: { type: "object" } },
|
||||
],
|
||||
responses: { 200: { description: "Success" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
const tool = toolAt(result.tools, "items")
|
||||
if (!Tool.isDefinition(tool)) throw new Error("items was not generated")
|
||||
|
||||
await Effect.runPromise(
|
||||
tool
|
||||
.run({
|
||||
keys: ["a!", "b*"],
|
||||
tags: ["x", "y"],
|
||||
filter: { state: "open", page: 2 },
|
||||
nullable: null,
|
||||
constructor_2: "safe",
|
||||
meta: { a: "b", c: "d" },
|
||||
})
|
||||
.pipe(Effect.provide(client.layer)),
|
||||
)
|
||||
|
||||
const url = new URL(client.requests[0]!.url)
|
||||
expect(url.pathname).toBe("/items/a%21,b%2A")
|
||||
expect(url.searchParams.get("tags")).toBe("x,y")
|
||||
expect(url.searchParams.get("state")).toBe("open")
|
||||
expect(url.searchParams.get("page")).toBe("2")
|
||||
expect(url.searchParams.get("nullable")).toBe("null")
|
||||
expect(url.searchParams.get("constructor")).toBe("safe")
|
||||
expect(client.requests[0]!.headers.meta).toBe("a=b,c=d")
|
||||
await expect(Effect.runPromise(tool.run({ keys: [undefined] }).pipe(Effect.provide(client.layer)))).rejects.toThrow(
|
||||
"unsupported nested value",
|
||||
)
|
||||
})
|
||||
|
||||
test("skips unsupported parameter encodings and malformed security", () => {
|
||||
const result = OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
openapi: "3.1.0",
|
||||
security: [{ bearer: [] }],
|
||||
paths: {
|
||||
"/cookie": {
|
||||
get: {
|
||||
operationId: "cookie",
|
||||
parameters: [{ name: "session", in: "cookie", schema: { type: "string" } }],
|
||||
responses: { 200: { description: "Success" } },
|
||||
},
|
||||
},
|
||||
"/reserved": {
|
||||
get: {
|
||||
operationId: "reserved",
|
||||
parameters: [{ name: "query", in: "query", allowReserved: true, schema: { type: "string" } }],
|
||||
responses: { 200: { description: "Success" } },
|
||||
},
|
||||
},
|
||||
"/invalid-style": {
|
||||
get: {
|
||||
operationId: "invalidStyle",
|
||||
parameters: [{ name: "query", in: "query", style: 42, schema: { type: "string" } }],
|
||||
responses: { 200: { description: "Success" } },
|
||||
},
|
||||
},
|
||||
"/security": {
|
||||
get: { operationId: "security", security: null, responses: { 200: { description: "Success" } } },
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.tools).toEqual({})
|
||||
expect(result.skipped.map((item) => item.reason)).toEqual([
|
||||
"cookie parameter 'session' is not supported",
|
||||
"parameter 'query' uses unsupported allowReserved encoding",
|
||||
"parameter 'query' has an invalid style",
|
||||
"security declaration is not an array",
|
||||
])
|
||||
})
|
||||
|
||||
test("fails closed on prototype-named missing security schemes", () => {
|
||||
const result = OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: singleOperation({ security: [JSON.parse('{"__proto__":[]}')] }),
|
||||
})
|
||||
|
||||
expect(result.tools).toEqual({})
|
||||
expect(result.skipped[0]?.reason).toBe("security requirement references missing or malformed scheme: __proto__")
|
||||
})
|
||||
|
||||
test("resolves bearer authentication without exposing it as input", async () => {
|
||||
const contexts: Array<Parameters<OpenAPI.AuthResolver>[0]> = []
|
||||
const client = recordingClient(() => json({ ok: true }))
|
||||
const spec = {
|
||||
...singleOperation({ operationId: undefined }),
|
||||
security: [{ bearer: [] }],
|
||||
components: { securitySchemes: { bearer: { type: "http", scheme: "bearer" } } },
|
||||
} satisfies Document
|
||||
const tool = toolAt(
|
||||
OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec,
|
||||
auth: {
|
||||
resolve: (context) => {
|
||||
contexts.push(context)
|
||||
return Effect.succeed({ type: "bearer", token: "secret" })
|
||||
},
|
||||
},
|
||||
}).tools,
|
||||
"getTest",
|
||||
)
|
||||
if (!Tool.isDefinition(tool)) throw new Error("test was not generated")
|
||||
|
||||
await Effect.runPromise(tool.run({}).pipe(Effect.provide(client.layer)))
|
||||
|
||||
expect(inputTypeScript(tool)).toBe("{}")
|
||||
expect(client.requests[0]!.headers.authorization).toBe("Bearer secret")
|
||||
expect(contexts).toEqual([
|
||||
{
|
||||
name: "bearer",
|
||||
definition: { type: "http", scheme: "bearer" },
|
||||
scopes: [],
|
||||
operation: {
|
||||
operationId: undefined,
|
||||
method: "GET",
|
||||
path: "/test",
|
||||
summary: undefined,
|
||||
description: undefined,
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test("applies authentication carriers without prototype or collision loss", async () => {
|
||||
const client = recordingClient(() => json({ ok: true }))
|
||||
const authenticated = (
|
||||
security: ReadonlyArray<Record<string, ReadonlyArray<string>>>,
|
||||
schemes: Record<string, unknown>,
|
||||
) =>
|
||||
OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: { ...singleOperation({}), security, components: { securitySchemes: schemes } },
|
||||
auth: { resolve: () => Effect.succeed({ type: "apiKey", value: "secret" }) },
|
||||
})
|
||||
const prototype = toolAt(
|
||||
authenticated([{ key: [] }], { key: { type: "apiKey", in: "query", name: "__proto__" } }).tools,
|
||||
"test",
|
||||
)
|
||||
if (!Tool.isDefinition(prototype)) throw new Error("prototype auth tool was not generated")
|
||||
|
||||
await Effect.runPromise(prototype.run({}).pipe(Effect.provide(client.layer)))
|
||||
expect(new URL(client.requests[0]!.url).searchParams.get("__proto__")).toBe("secret")
|
||||
|
||||
const duplicate = toolAt(
|
||||
authenticated([{ first: [], second: [] }], {
|
||||
first: { type: "apiKey", in: "header", name: "x-key" },
|
||||
second: { type: "apiKey", in: "header", name: "x-key" },
|
||||
}).tools,
|
||||
"test",
|
||||
)
|
||||
if (!Tool.isDefinition(duplicate)) throw new Error("duplicate auth tool was not generated")
|
||||
await expect(Effect.runPromise(duplicate.run({}).pipe(Effect.provide(client.layer)))).rejects.toThrow(
|
||||
"multiple credentials",
|
||||
)
|
||||
|
||||
const cookie = authenticated([{ key: [] }], { key: { type: "apiKey", in: "cookie", name: "session" } })
|
||||
expect(cookie.tools).toEqual({})
|
||||
expect(cookie.skipped[0]?.reason).toBe("cookie authentication 'key' is not supported")
|
||||
|
||||
const alternative = OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
...singleOperation({}),
|
||||
security: [{ cookie: [] }, { bearer: [] }],
|
||||
components: {
|
||||
securitySchemes: {
|
||||
cookie: { type: "apiKey", in: "cookie", name: "session" },
|
||||
bearer: { type: "http", scheme: "bearer" },
|
||||
},
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
resolve: ({ name }) => Effect.succeed(name === "bearer" ? { type: "bearer", token: "secret" } : undefined),
|
||||
},
|
||||
})
|
||||
const alternativeTool = toolAt(alternative.tools, "test")
|
||||
if (!Tool.isDefinition(alternativeTool)) throw new Error("supported auth alternative was not generated")
|
||||
await Effect.runPromise(alternativeTool.run({}).pipe(Effect.provide(client.layer)))
|
||||
expect(client.requests.at(-1)?.headers.authorization).toBe("Bearer secret")
|
||||
})
|
||||
|
||||
test("honors server precedence and rejects ambiguous base URLs", async () => {
|
||||
const client = recordingClient(() => json({ ok: true }))
|
||||
const spec = {
|
||||
...singleOperation({ servers: [{ url: "https://operation.example/v1" }] }),
|
||||
servers: [{ url: "https://document.example" }],
|
||||
} satisfies Document
|
||||
const tool = toolAt(OpenAPI.fromSpec({ spec }).tools, "test")
|
||||
if (!Tool.isDefinition(tool)) throw new Error("test was not generated")
|
||||
|
||||
await Effect.runPromise(tool.run({}).pipe(Effect.provide(client.layer)))
|
||||
expect(client.requests[0]?.url).toBe("https://operation.example/v1/test")
|
||||
|
||||
const invalid = OpenAPI.fromSpec({ spec, baseUrl: "https://example.com/api?tenant=one" })
|
||||
expect(invalid.tools).toEqual({})
|
||||
expect(invalid.skipped[0]?.reason).toContain("unsupported query string or fragment")
|
||||
|
||||
const malformed = OpenAPI.fromSpec({ spec, baseUrl: "https:/example.com" })
|
||||
expect(malformed.tools).toEqual({})
|
||||
expect(malformed.skipped[0]?.reason).toContain("not an absolute HTTP(S) URL")
|
||||
})
|
||||
|
||||
test("resolves chained response refs before detecting unsupported transports", () => {
|
||||
const result = OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
...singleOperation({ responses: { 200: { $ref: "#/components/responses/First" } } }),
|
||||
components: {
|
||||
responses: {
|
||||
First: { $ref: "#/components/responses/Stream" },
|
||||
Stream: { content: { "text/event-stream": { schema: { type: "string" } } } },
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.tools).toEqual({})
|
||||
expect(result.skipped[0]?.reason).toBe("SSE operations are not supported")
|
||||
})
|
||||
|
||||
test("resolves response schemas before detecting binary output", () => {
|
||||
const result = OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
...singleOperation({
|
||||
responses: {
|
||||
200: {
|
||||
content: { "text/plain": { schema: { $ref: "#/components/schemas/File" } } },
|
||||
},
|
||||
},
|
||||
}),
|
||||
components: { schemas: { File: { type: "string", format: "binary" } } },
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.tools).toEqual({})
|
||||
expect(result.skipped[0]?.reason).toBe("binary responses are not supported")
|
||||
})
|
||||
|
||||
test("validates composite parameters before resolving auth", async () => {
|
||||
const resolutions: Array<string> = []
|
||||
const client = recordingClient(() => json({ ok: true }))
|
||||
const tool = toolAt(
|
||||
OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: {
|
||||
...singleOperation({
|
||||
parameters: [{ name: "filter", in: "query", style: "form", explode: true, schema: { type: "object" } }],
|
||||
}),
|
||||
security: [{ bearer: [] }],
|
||||
components: { securitySchemes: { bearer: { type: "http", scheme: "bearer" } } },
|
||||
},
|
||||
auth: {
|
||||
resolve: ({ name }) => {
|
||||
resolutions.push(name)
|
||||
return Effect.succeed({ type: "bearer", token: "secret" })
|
||||
},
|
||||
},
|
||||
}).tools,
|
||||
"test",
|
||||
)
|
||||
if (!Tool.isDefinition(tool)) throw new Error("test was not generated")
|
||||
|
||||
await expect(
|
||||
Effect.runPromise(tool.run({ filter: { value: undefined } }).pipe(Effect.provide(client.layer))),
|
||||
).rejects.toThrow("unsupported nested value")
|
||||
expect(resolutions).toEqual([])
|
||||
expect(client.requests).toEqual([])
|
||||
})
|
||||
|
||||
test("preserves JSON media types and rejects unencodable bodies", async () => {
|
||||
const client = recordingClient(() => json({ ok: true }))
|
||||
const tool = toolAt(
|
||||
OpenAPI.fromSpec({
|
||||
baseUrl,
|
||||
spec: singleOperation(
|
||||
{
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: { "application/merge-patch+json": { schema: { type: "object" } } },
|
||||
},
|
||||
},
|
||||
"post",
|
||||
),
|
||||
}).tools,
|
||||
"test",
|
||||
)
|
||||
if (!Tool.isDefinition(tool)) throw new Error("test was not generated")
|
||||
|
||||
await Effect.runPromise(tool.run({ body: { name: "updated" } }).pipe(Effect.provide(client.layer)))
|
||||
expect(client.requests[0]!.headers["content-type"]).toBe("application/merge-patch+json")
|
||||
const cyclic: Record<string, unknown> = {}
|
||||
cyclic.self = cyclic
|
||||
await expect(Effect.runPromise(tool.run({ body: cyclic }).pipe(Effect.provide(client.layer)))).rejects.toThrow(
|
||||
"Invalid JSON body",
|
||||
)
|
||||
})
|
||||
|
||||
test("rejects oversized and malformed JSON responses", async () => {
|
||||
const tool = toolAt(OpenAPI.fromSpec({ baseUrl, spec: singleOperation({}) }).tools, "test")
|
||||
if (!Tool.isDefinition(tool)) throw new Error("test was not generated")
|
||||
const oversized = recordingClient(
|
||||
() => new Response(null, { headers: { "content-length": String(50 * 1024 * 1024 + 1) } }),
|
||||
)
|
||||
const malformed = recordingClient(() => new Response("{", { headers: { "content-type": "application/json" } }))
|
||||
const chunked = recordingClient(() => new Response(new Uint8Array(50 * 1024 * 1024 + 1)))
|
||||
|
||||
await expect(Effect.runPromise(tool.run({}).pipe(Effect.provide(oversized.layer)))).rejects.toThrow(
|
||||
"response exceeds 50 MiB",
|
||||
)
|
||||
await expect(Effect.runPromise(tool.run({}).pipe(Effect.provide(malformed.layer)))).rejects.toThrow(
|
||||
"returned malformed JSON",
|
||||
)
|
||||
await expect(Effect.runPromise(tool.run({}).pipe(Effect.provide(chunked.layer)))).rejects.toThrow(
|
||||
"response exceeds 50 MiB",
|
||||
)
|
||||
})
|
||||
|
||||
test("keeps non-JSON responses raw and unions every success output", async () => {
|
||||
const spec = singleOperation({
|
||||
responses: {
|
||||
200: { description: "Text", content: { "text/plain": { schema: { type: "string" } } } },
|
||||
204: { description: "Empty" },
|
||||
},
|
||||
})
|
||||
const tool = toolAt(OpenAPI.fromSpec({ baseUrl, spec }).tools, "test")
|
||||
if (!Tool.isDefinition(tool)) throw new Error("test was not generated")
|
||||
const client = recordingClient(() => new Response("123", { headers: { "content-type": "text/plain" } }))
|
||||
|
||||
expect(outputTypeScript(tool)).toBe("string | null")
|
||||
await expect(Effect.runPromise(tool.run({}).pipe(Effect.provide(client.layer)))).resolves.toBe("123")
|
||||
})
|
||||
|
||||
test("fails missing required parameters before auth and network", async () => {
|
||||
const { requests, layer } = recordingClient(() => json({}))
|
||||
const runtime = CodeMode.make({
|
||||
tools: { opencode: OpenAPI.fromSpec({ spec: await opencodeSpec(), baseUrl }).tools },
|
||||
})
|
||||
|
||||
const result = await Effect.runPromise(
|
||||
runtime.execute("return await tools.opencode.v2.session.get({})").pipe(Effect.provide(layer)),
|
||||
)
|
||||
|
||||
expect(result).toMatchObject({ ok: false })
|
||||
expect(JSON.stringify(result)).toContain("Missing required path parameter 'sessionID'")
|
||||
expect(requests).toHaveLength(0)
|
||||
})
|
||||
|
||||
test("prefixes cross-location collisions and reconstructs the HTTP request", async () => {
|
||||
const spec = {
|
||||
openapi: "3.1.0",
|
||||
info: { title: "collision", version: "1.0.0" },
|
||||
paths: {
|
||||
"/echo": {
|
||||
post: {
|
||||
operationId: "echo",
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: { "application/json": { schema: { type: "string" } } },
|
||||
},
|
||||
responses: { "204": { description: "Echoed" } },
|
||||
},
|
||||
},
|
||||
"/things/{id}": {
|
||||
post: {
|
||||
operationId: "things.update",
|
||||
parameters: [
|
||||
{ name: "id", in: "path", required: true, schema: { type: "string" } },
|
||||
{ name: "id", in: "query", required: true, schema: { type: "string" } },
|
||||
{ name: "path_id", in: "query", schema: { type: "string" } },
|
||||
{ name: "id", in: "header", required: true, schema: { type: "string" } },
|
||||
],
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: { id: { type: "string" } },
|
||||
required: ["id"],
|
||||
additionalProperties: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: { "204": { description: "Updated" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies Document
|
||||
const { requests, layer } = recordingClient(() => new Response(null, { status: 204 }))
|
||||
const tools = OpenAPI.fromSpec({ spec, baseUrl }).tools
|
||||
const update = toolAt(tools, "things.update")
|
||||
const echo = toolAt(tools, "echo")
|
||||
|
||||
expect(Tool.isDefinition(update)).toBe(true)
|
||||
if (!Tool.isDefinition(update)) throw new Error("things.update was not generated")
|
||||
expect(inputTypeScript(update)).toBe(
|
||||
"{ path_id: string; query_id: string; path_id_2?: string; header_id: string; body_id: string }",
|
||||
)
|
||||
expect(Tool.isDefinition(echo)).toBe(true)
|
||||
if (!Tool.isDefinition(echo)) throw new Error("echo was not generated")
|
||||
expect(inputTypeScript(echo)).toBe("{ body: string }")
|
||||
|
||||
const runtime = CodeMode.make({ tools })
|
||||
const result = await Effect.runPromise(
|
||||
runtime
|
||||
.execute(
|
||||
`
|
||||
const updated = await tools.things.update({ path_id: "path", query_id: "query", path_id_2: "literal", header_id: "header", body_id: "body" })
|
||||
const echoed = await tools.echo({ body: "hello" })
|
||||
return { updated, echoed }
|
||||
`,
|
||||
)
|
||||
.pipe(Effect.provide(layer)),
|
||||
)
|
||||
|
||||
expect(result).toMatchObject({ ok: true })
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(new URL(requests[0]!.url).pathname).toBe("/things/path")
|
||||
expect(new URL(requests[0]!.url).searchParams.get("id")).toBe("query")
|
||||
expect(new URL(requests[0]!.url).searchParams.get("path_id")).toBe("literal")
|
||||
expect(requests[0]!.headers.id).toBe("header")
|
||||
expect(requests[0]!.body).toStrictEqual({ id: "body" })
|
||||
expect(requests[1]!.body).toBe("hello")
|
||||
})
|
||||
|
||||
test("keeps bodies nested when flattening would lose schema semantics", () => {
|
||||
const body = (schema: Record<string, unknown>, required = true) => ({
|
||||
required,
|
||||
content: { "application/json": { schema } },
|
||||
})
|
||||
const spec = {
|
||||
openapi: "3.1.0",
|
||||
info: { title: "bodies", version: "1.0.0" },
|
||||
paths: Object.fromEntries(
|
||||
[
|
||||
[
|
||||
"optional",
|
||||
body(
|
||||
{
|
||||
type: "object",
|
||||
properties: { name: { type: "string" } },
|
||||
required: ["name"],
|
||||
additionalProperties: false,
|
||||
},
|
||||
false,
|
||||
),
|
||||
],
|
||||
["dictionary", body({ type: "object", additionalProperties: { type: "string" } })],
|
||||
[
|
||||
"composed",
|
||||
body({
|
||||
type: "object",
|
||||
allOf: [{ type: "object", properties: { name: { type: "string" } }, required: ["name"] }],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
],
|
||||
[
|
||||
"nullable",
|
||||
body({
|
||||
type: ["object", "null"],
|
||||
properties: { name: { type: "string" } },
|
||||
additionalProperties: false,
|
||||
}),
|
||||
],
|
||||
].map(([name, requestBody]) => [
|
||||
`/body/${name}`,
|
||||
{
|
||||
post: {
|
||||
operationId: `body.${name}`,
|
||||
requestBody,
|
||||
responses: { "204": { description: "Accepted" } },
|
||||
},
|
||||
},
|
||||
]),
|
||||
),
|
||||
} satisfies Document
|
||||
const tools = OpenAPI.fromSpec({ spec, baseUrl }).tools
|
||||
|
||||
for (const name of ["optional", "dictionary", "composed", "nullable"]) {
|
||||
const tool = toolAt(tools, `body.${name}`)
|
||||
expect(Tool.isDefinition(tool)).toBe(true)
|
||||
if (!Tool.isDefinition(tool)) throw new Error(`body.${name} was not generated`)
|
||||
const input = isRecord(tool.input) ? tool.input : {}
|
||||
expect(Object.keys(isRecord(input.properties) ? input.properties : {})).toStrictEqual(["body"])
|
||||
}
|
||||
const optional = toolAt(tools, "body.optional")
|
||||
if (!Tool.isDefinition(optional)) throw new Error("body.optional was not generated")
|
||||
expect(inputTypeScript(optional)).toBe("{ body?: { name: string } }")
|
||||
})
|
||||
})
|
||||
@@ -159,8 +159,8 @@ describe("pretty signature rendering", () => {
|
||||
$ref: "#/$defs/Node",
|
||||
$defs: { Node: { type: "object", properties: { child: { $ref: "#/$defs/Node" }, name: { type: "string" } } } },
|
||||
} as const
|
||||
expect(jsonSchemaToTypeScript(cyclic)).toBe("{ child?: unknown; name?: string }")
|
||||
expect(jsonSchemaToTypeScript(cyclic, true)).toContain("child?: unknown")
|
||||
expect(jsonSchemaToTypeScript(cyclic)).toBe("{ child?: Node; name?: string }")
|
||||
expect(jsonSchemaToTypeScript(cyclic, true)).toContain("child?: Node")
|
||||
|
||||
let deep: Record<string, unknown> = { type: "string" }
|
||||
for (let level = 0; level < 12; level += 1) deep = { type: "object", properties: { next: deep } }
|
||||
@@ -170,43 +170,6 @@ describe("pretty signature rendering", () => {
|
||||
expect(rendered).toContain("next?:")
|
||||
}
|
||||
})
|
||||
|
||||
test("intersects ref and union siblings instead of discarding them", () => {
|
||||
expect(
|
||||
jsonSchemaToTypeScript({
|
||||
$ref: "#/$defs/User",
|
||||
properties: { active: { type: "boolean" } },
|
||||
required: ["active"],
|
||||
$defs: {
|
||||
User: { type: "object", properties: { id: { type: "string" } }, required: ["id"] },
|
||||
},
|
||||
}),
|
||||
).toBe("{ id: string } & { active: boolean }")
|
||||
expect(
|
||||
jsonSchemaToTypeScript({
|
||||
type: "object",
|
||||
properties: { common: { type: "boolean" } },
|
||||
required: ["common"],
|
||||
anyOf: [
|
||||
{ type: "object", properties: { name: { type: "string" } }, required: ["name"] },
|
||||
{ type: "object", properties: { count: { type: "number" } }, required: ["count"] },
|
||||
],
|
||||
}),
|
||||
).toBe("({ name: string } | { count: number }) & { common: boolean }")
|
||||
expect(jsonSchemaToTypeScript({ $ref: "https://example.com/schema.json" })).toBe("unknown")
|
||||
expect(
|
||||
jsonSchemaToTypeScript({
|
||||
$ref: "#/$defs/User/properties/id",
|
||||
$defs: { User: { type: "object" }, id: { type: "string" } },
|
||||
}),
|
||||
).toBe("unknown")
|
||||
expect(
|
||||
jsonSchemaToTypeScript({
|
||||
type: ["object", "null"],
|
||||
properties: { name: { type: "string" } },
|
||||
}),
|
||||
).toBe("{ name?: string } | null")
|
||||
})
|
||||
})
|
||||
|
||||
describe("non-identifier property names render as quoted keys", () => {
|
||||
@@ -305,31 +268,6 @@ describe("union schemas render every alternative", () => {
|
||||
expect(inputTypeScript(tool)).toBe("{ value?: string | number }")
|
||||
expect(outputTypeScript(tool)).toBe("number | boolean")
|
||||
})
|
||||
|
||||
test("allOf renders intersections with parenthesized union members", () => {
|
||||
const schema = {
|
||||
allOf: [{ type: "object", properties: { id: { type: "string" } } }, { type: ["string", "null"] }],
|
||||
} as const
|
||||
expect(jsonSchemaToTypeScript(schema)).toBe("{ id?: string } & (string | null)")
|
||||
})
|
||||
|
||||
test("allOf does not discard an unresolved constraint", () => {
|
||||
expect(jsonSchemaToTypeScript({ allOf: [{ type: "string" }, { $ref: "https://example.com/external.json" }] })).toBe(
|
||||
"unknown",
|
||||
)
|
||||
expect(
|
||||
jsonSchemaToTypeScript({
|
||||
allOf: [{ type: "string" }, { allOf: [{ $ref: "https://example.com/external.json" }] }],
|
||||
}),
|
||||
).toBe("unknown")
|
||||
expect(
|
||||
jsonSchemaToTypeScript({
|
||||
type: "string",
|
||||
allOf: [{ $ref: "#/$defs/Constraint" }],
|
||||
$defs: { Constraint: { description: "TypeScript-neutral constraint" } },
|
||||
}),
|
||||
).toBe("string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("pretty signatures in search results", () => {
|
||||
@@ -401,43 +339,3 @@ describe("pretty signatures in search results", () => {
|
||||
expect(instructions).not.toContain("/**")
|
||||
})
|
||||
})
|
||||
|
||||
describe("non-identifier tool paths", () => {
|
||||
const resolveLibrary = Tool.make({
|
||||
description: "Resolve a Context7 library ID",
|
||||
input: {
|
||||
type: "object",
|
||||
properties: {
|
||||
query: { type: "string" },
|
||||
libraryName: { type: "string" },
|
||||
},
|
||||
required: ["query", "libraryName"],
|
||||
} as const,
|
||||
run: () => Effect.succeed("/reactjs/react.dev"),
|
||||
})
|
||||
const runtime = CodeMode.make({ tools: { context7: { "resolve-library-id": resolveLibrary } } })
|
||||
|
||||
test("inline catalog uses bracket notation for dashed tool names", () => {
|
||||
const instructions = runtime.instructions()
|
||||
|
||||
expect(instructions).toContain(
|
||||
'tools.context7["resolve-library-id"](input: { query: string; libraryName: string }): Promise<unknown>',
|
||||
)
|
||||
expect(instructions).toContain("Do not infer or normalize tool names")
|
||||
expect(instructions).toContain("bracket notation and quotes are part of the path")
|
||||
expect(instructions).not.toContain("tools.context7.resolve-library-id")
|
||||
expect(instructions).not.toContain("tools.context7.resolve_library_id")
|
||||
})
|
||||
|
||||
test("search results return callable bracket-notation paths and signatures", async () => {
|
||||
const result = await Effect.runPromise(
|
||||
runtime.execute(`return await tools.$codemode.search({ query: "resolve library" })`),
|
||||
)
|
||||
expect(result.ok).toBe(true)
|
||||
if (!result.ok) throw new Error("search failed")
|
||||
|
||||
const value = result.value as { items: Array<{ path: string; signature: string }> }
|
||||
expect(value.items[0]?.path).toBe('tools.context7["resolve-library-id"]')
|
||||
expect(value.items[0]?.signature).toContain('tools.context7["resolve-library-id"](input: {')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,6 +2,6 @@ import { redirect } from "@solidjs/router"
|
||||
|
||||
export async function GET() {
|
||||
return redirect(
|
||||
"https://applink.feishu.cn/client/chat/chatter/add_by_link?link_token=52ao9352-5623-4fa0-b7dd-3407c392c1af&qr_code=true",
|
||||
"https://applink.feishu.cn/client/chat/chatter/add_by_link?link_token=738j8655-cd59-4633-a30a-1124e0096789&qr_code=true",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Stripe } from "stripe"
|
||||
import { Billing } from "@opencode-ai/console-core/billing.js"
|
||||
import type { APIEvent } from "@solidjs/start/server"
|
||||
import { and, Database, eq, isNull, sql } from "@opencode-ai/console-core/drizzle/index.js"
|
||||
import { and, Database, eq, sql } from "@opencode-ai/console-core/drizzle/index.js"
|
||||
import { BillingTable, LiteTable, PaymentTable } from "@opencode-ai/console-core/schema/billing.sql.js"
|
||||
import { Identifier } from "@opencode-ai/console-core/identifier.js"
|
||||
import { centsToMicroCents } from "@opencode-ai/console-core/util/price.js"
|
||||
@@ -350,32 +350,21 @@ export async function POST(input: APIEvent) {
|
||||
.then((rows) => rows[0]),
|
||||
)
|
||||
if (!payment) throw new Error("Payment not found")
|
||||
const amountRefunded = Math.min(centsToMicroCents(body.data.object.amount_refunded), payment.amount)
|
||||
if (!amountRefunded) throw new Error("Refund amount not found")
|
||||
|
||||
await Database.transaction(async (tx) => {
|
||||
// Payment rows record one refund transition. Claim it atomically so Stripe webhook retries
|
||||
// cannot deduct the refunded credits more than once.
|
||||
const claimed = await tx
|
||||
await tx
|
||||
.update(PaymentTable)
|
||||
.set({
|
||||
timeRefunded: new Date(body.created * 1000),
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
eq(PaymentTable.paymentID, paymentIntentID),
|
||||
eq(PaymentTable.workspaceID, workspaceID),
|
||||
isNull(PaymentTable.timeRefunded),
|
||||
),
|
||||
)
|
||||
if (claimed.rowsAffected === 0) return
|
||||
.where(and(eq(PaymentTable.paymentID, paymentIntentID), eq(PaymentTable.workspaceID, workspaceID)))
|
||||
|
||||
// deduct balance only for top up
|
||||
if (!payment.enrichment?.type) {
|
||||
await tx
|
||||
.update(BillingTable)
|
||||
.set({
|
||||
balance: sql`GREATEST(0, ${BillingTable.balance} - ${amountRefunded})`,
|
||||
balance: sql`${BillingTable.balance} - ${payment.amount}`,
|
||||
})
|
||||
.where(eq(BillingTable.workspaceID, workspaceID))
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ export function hoist<A, E, T extends Tag, const Items extends Replacements = re
|
||||
if (existing && existing !== node) {
|
||||
throw new Error(`Tag ${tag} has conflicting implementations for ${node.name}`)
|
||||
}
|
||||
hoisted.set(node.name, rewriteReplacementDependencies(node, replacementMap))
|
||||
hoisted.set(node.name, node)
|
||||
return group([])
|
||||
}
|
||||
if (node.kind === "unbound") {
|
||||
|
||||
@@ -38,7 +38,6 @@ export namespace FSUtil {
|
||||
readonly ensureDir: (path: string) => Effect.Effect<void, Error>
|
||||
readonly writeWithDirs: (path: string, content: string | Uint8Array, mode?: number) => Effect.Effect<void, Error>
|
||||
readonly readDirectoryEntries: (path: string) => Effect.Effect<DirEntry[], Error>
|
||||
readonly resolve: (path: string) => Effect.Effect<string>
|
||||
readonly findUp: (target: string, start: string, stop?: string) => Effect.Effect<string[], Error>
|
||||
readonly up: (options: { targets: string[]; start: string; stop?: string }) => Effect.Effect<string[], Error>
|
||||
readonly globUp: (pattern: string, start: string, stop?: string) => Effect.Effect<string[], Error>
|
||||
@@ -90,14 +89,6 @@ export namespace FSUtil {
|
||||
})
|
||||
})
|
||||
|
||||
const resolve = Effect.fn("FileSystem.resolve")(function* (path: string) {
|
||||
const resolved = pathResolve(windowsPath(path))
|
||||
return yield* fs.realPath(resolved).pipe(
|
||||
Effect.catchReason("PlatformError", "NotFound", () => Effect.succeed(resolved)),
|
||||
Effect.orDie,
|
||||
)
|
||||
})
|
||||
|
||||
const readJson = Effect.fn("FileSystem.readJson")(function* (path: string) {
|
||||
const text = yield* fs.readFileString(path)
|
||||
return yield* Effect.try({
|
||||
@@ -196,7 +187,6 @@ export namespace FSUtil {
|
||||
isDir,
|
||||
isFile,
|
||||
readDirectoryEntries,
|
||||
resolve,
|
||||
readJson,
|
||||
writeJson,
|
||||
ensureDir,
|
||||
|
||||
@@ -38,24 +38,22 @@ const layer = Layer.effectDiscard(
|
||||
})
|
||||
|
||||
const observe = Effect.fn("InstructionContext.observe")(function* () {
|
||||
const start = yield* fs.resolve(location.directory)
|
||||
const stop = yield* fs.resolve(location.project.directory)
|
||||
const start = FSUtil.resolve(location.directory)
|
||||
const stop = FSUtil.resolve(location.project.directory)
|
||||
const fromProject = relative(stop, start)
|
||||
const insideProject =
|
||||
fromProject === "" || (fromProject !== ".." && !fromProject.startsWith(`..${sep}`) && !isAbsolute(fromProject))
|
||||
const discovered = new Set(
|
||||
yield* Effect.forEach(
|
||||
Flag.OPENCODE_DISABLE_PROJECT_CONFIG || !insideProject
|
||||
? []
|
||||
: yield* fs.up({
|
||||
targets: ["AGENTS.md"],
|
||||
start,
|
||||
stop,
|
||||
}),
|
||||
fs.resolve,
|
||||
),
|
||||
(Flag.OPENCODE_DISABLE_PROJECT_CONFIG || !insideProject
|
||||
? []
|
||||
: yield* fs.up({
|
||||
targets: ["AGENTS.md"],
|
||||
start,
|
||||
stop,
|
||||
})
|
||||
).map(FSUtil.resolve),
|
||||
)
|
||||
const paths = Array.dedupe([yield* fs.resolve(join(global.config, "AGENTS.md")), ...discovered])
|
||||
const paths = Array.dedupe([FSUtil.resolve(join(global.config, "AGENTS.md")), ...discovered])
|
||||
const files = yield* Effect.forEach(
|
||||
paths,
|
||||
(path) =>
|
||||
|
||||
@@ -89,10 +89,6 @@ export function buildLocationServiceMap(
|
||||
LayerMap.make(
|
||||
(ref: Location.Ref) => {
|
||||
const allReplacements = replacements.concat([[Location.node, Location.boundNode(ref)]])
|
||||
// Apply replacements during hoist, not afterward: replacements can
|
||||
// introduce new tagged dependencies (Location.boundNode depends on
|
||||
// Project), and the hoist walk is the only pass that can still slice
|
||||
// those back out.
|
||||
const location = LayerNode.hoist(locationServices, Node.tags.values.global, allReplacements)
|
||||
|
||||
return LayerNode.compile(location.node).pipe(
|
||||
|
||||
@@ -57,13 +57,13 @@ export type AskResult = typeof AskResult.Type
|
||||
|
||||
export const Event = Permission.Event
|
||||
|
||||
export class DeclinedError extends Schema.TaggedErrorClass<DeclinedError>()("PermissionV2.DeclinedError", {}) {}
|
||||
export class RejectedError extends Schema.TaggedErrorClass<RejectedError>()("PermissionV2.RejectedError", {}) {}
|
||||
|
||||
export class CorrectedError extends Schema.TaggedErrorClass<CorrectedError>()("PermissionV2.CorrectedError", {
|
||||
feedback: Schema.String,
|
||||
}) {}
|
||||
|
||||
export class BlockedError extends Schema.TaggedErrorClass<BlockedError>()("PermissionV2.BlockedError", {
|
||||
export class DeniedError extends Schema.TaggedErrorClass<DeniedError>()("PermissionV2.DeniedError", {
|
||||
rules: Permission.Ruleset,
|
||||
}) {}
|
||||
|
||||
@@ -71,7 +71,7 @@ export class NotFoundError extends Schema.TaggedErrorClass<NotFoundError>()("Per
|
||||
requestID: ID,
|
||||
}) {}
|
||||
|
||||
export type Error = BlockedError | CorrectedError
|
||||
export type Error = DeniedError | RejectedError | CorrectedError
|
||||
|
||||
export function evaluate(action: string, resource: string, ...rulesets: Permission.Ruleset[]): Permission.Rule {
|
||||
return (
|
||||
@@ -103,7 +103,7 @@ export class Service extends Context.Service<Service, Interface>()("@opencode/v2
|
||||
interface Pending {
|
||||
readonly request: Request
|
||||
readonly agent?: AgentV2.ID
|
||||
readonly deferred: Deferred.Deferred<void, DeclinedError | CorrectedError>
|
||||
readonly deferred: Deferred.Deferred<void, RejectedError | CorrectedError>
|
||||
}
|
||||
|
||||
const layer = Layer.effect(
|
||||
@@ -117,7 +117,7 @@ const layer = Layer.effect(
|
||||
const pending = new Map<ID, Pending>()
|
||||
|
||||
yield* EffectRuntime.addFinalizer(() =>
|
||||
EffectRuntime.forEach(pending.values(), (item) => Deferred.fail(item.deferred, new DeclinedError()), {
|
||||
EffectRuntime.forEach(pending.values(), (item) => Deferred.fail(item.deferred, new RejectedError()), {
|
||||
discard: true,
|
||||
}).pipe(
|
||||
EffectRuntime.ensuring(
|
||||
@@ -176,7 +176,7 @@ const layer = Layer.effect(
|
||||
const create = (request: Request, agent?: AgentV2.ID) =>
|
||||
EffectRuntime.uninterruptible(
|
||||
EffectRuntime.gen(function* () {
|
||||
const deferred = yield* Deferred.make<void, DeclinedError | CorrectedError>()
|
||||
const deferred = yield* Deferred.make<void, RejectedError | CorrectedError>()
|
||||
const item = { request, agent, deferred }
|
||||
if (pending.has(request.id)) return yield* EffectRuntime.die(`Duplicate pending permission ID: ${request.id}`)
|
||||
pending.set(request.id, item)
|
||||
@@ -199,14 +199,13 @@ const layer = Layer.effect(
|
||||
EffectRuntime.gen(function* () {
|
||||
const result = yield* evaluateInput(input)
|
||||
if (result.effect === "deny") {
|
||||
return yield* new BlockedError({
|
||||
return yield* new DeniedError({
|
||||
rules: relevant(input, result.rules),
|
||||
})
|
||||
}
|
||||
if (result.effect === "allow") return
|
||||
const item = yield* create(request(input), input.agent)
|
||||
return yield* restore(Deferred.await(item.deferred)).pipe(
|
||||
EffectRuntime.catchTag("PermissionV2.DeclinedError", (error) => EffectRuntime.die(error)),
|
||||
EffectRuntime.ensuring(
|
||||
EffectRuntime.sync(() => {
|
||||
pending.delete(item.request.id)
|
||||
@@ -231,7 +230,7 @@ const layer = Layer.effect(
|
||||
if (input.reply === "reject") {
|
||||
yield* Deferred.fail(
|
||||
existing.deferred,
|
||||
input.message ? new CorrectedError({ feedback: input.message }) : new DeclinedError(),
|
||||
input.message ? new CorrectedError({ feedback: input.message }) : new RejectedError(),
|
||||
)
|
||||
pending.delete(input.requestID)
|
||||
for (const [id, item] of pending) {
|
||||
@@ -241,7 +240,7 @@ const layer = Layer.effect(
|
||||
requestID: item.request.id,
|
||||
reply: "reject",
|
||||
})
|
||||
yield* Deferred.fail(item.deferred, new DeclinedError())
|
||||
yield* Deferred.fail(item.deferred, new RejectedError())
|
||||
pending.delete(id)
|
||||
}
|
||||
return
|
||||
|
||||
@@ -139,7 +139,7 @@ const layer = Layer.effect(
|
||||
})
|
||||
|
||||
const canonical = Effect.fnUntraced(function* (input: AbsolutePath) {
|
||||
const resolved = AbsolutePath.make(yield* fs.resolve(input))
|
||||
const resolved = AbsolutePath.make(FSUtil.resolve(input))
|
||||
if (!(yield* fs.isDir(resolved))) return yield* new DirectoryUnavailableError({ directory: input })
|
||||
return resolved
|
||||
})
|
||||
|
||||
@@ -15,27 +15,39 @@ const TOOL_OUTPUT_MAX_CHARS = 2_000
|
||||
const SUMMARY_OUTPUT_TOKENS = 4_096
|
||||
const SUMMARY_TEMPLATE = `Output exactly the Markdown structure shown inside <template> and keep the section order unchanged. Do not include the <template> tags in your response.
|
||||
<template>
|
||||
## Objective
|
||||
- [one or two brief sentences describing what the user is trying to accomplish]
|
||||
## Goal
|
||||
- [single-sentence task summary]
|
||||
|
||||
## Important Details
|
||||
- [constraints/preferences, decisions and why, important facts/assumptions, exact context needed to continue, or "(none)"]
|
||||
## Constraints & Preferences
|
||||
- [user constraints, preferences, specs, or "(none)"]
|
||||
|
||||
## Work State
|
||||
- Completed: [finished work, verified facts, or changes made; otherwise "(none)"]
|
||||
- Active: [current work, partial changes, or investigation state; otherwise "(none)"]
|
||||
- Blocked: [blockers, failing commands, or unknowns; otherwise "(none)"]
|
||||
## Progress
|
||||
### Done
|
||||
- [completed work or "(none)"]
|
||||
|
||||
## Next Move
|
||||
1. [immediate concrete action, or "(none)"]
|
||||
2. [next action if known, or "(none)"]
|
||||
### In Progress
|
||||
- [current work or "(none)"]
|
||||
|
||||
### Blocked
|
||||
- [blockers or "(none)"]
|
||||
|
||||
## Key Decisions
|
||||
- [decision and why, or "(none)"]
|
||||
|
||||
## Next Steps
|
||||
- [ordered next actions or "(none)"]
|
||||
|
||||
## Critical Context
|
||||
- [important technical facts, errors, open questions, or "(none)"]
|
||||
|
||||
## Relevant Files
|
||||
- [file or directory path: why it matters, or "(none)"]
|
||||
</template>
|
||||
|
||||
Rules:
|
||||
- Keep every section, even when empty.
|
||||
- Use terse bullets, not prose paragraphs.
|
||||
- Preserve exact file paths, symbols, commands, error strings, URLs, and identifiers when known.
|
||||
- Put relevant files and symbols inside the section where they matter; do not add extra sections.
|
||||
- Preserve exact file paths, commands, error strings, and identifiers when known.
|
||||
- Do not mention the summary process or that context was compacted.`
|
||||
|
||||
type Entry = {
|
||||
|
||||
@@ -15,7 +15,6 @@ import { Database } from "../../database/database"
|
||||
import { EventV2 } from "../../event"
|
||||
import { Location } from "../../location"
|
||||
import { ModelV2 } from "../../model"
|
||||
import { PermissionV2 } from "../../permission"
|
||||
import { ProviderV2 } from "../../provider"
|
||||
import { QuestionV2 } from "../../question"
|
||||
import { SystemContext } from "../../system-context/index"
|
||||
@@ -141,13 +140,9 @@ const layer = Layer.effect(
|
||||
const awaitToolFibers = (fibers: FiberSet.FiberSet<void, ToolOutputStore.Error>) =>
|
||||
Effect.raceFirst(FiberSet.join(fibers), FiberSet.awaitEmpty(fibers))
|
||||
|
||||
// Match V1: declining a user prompt halts the loop instead of becoming model-facing tool output.
|
||||
const isUserDeclined = (cause: Cause.Cause<unknown>) =>
|
||||
cause.reasons.some(
|
||||
(reason) =>
|
||||
Cause.isDieReason(reason) &&
|
||||
(reason.defect instanceof PermissionV2.DeclinedError || reason.defect instanceof QuestionV2.RejectedError),
|
||||
)
|
||||
// Match V1: dismissing a question halts the loop instead of becoming model-facing tool output.
|
||||
const isQuestionRejected = (cause: Cause.Cause<unknown>) =>
|
||||
cause.reasons.some((reason) => Cause.isDieReason(reason) && reason.defect instanceof QuestionV2.RejectedError)
|
||||
|
||||
type TurnTransition =
|
||||
// Automatic compaction completed; rebuild the request from compacted history.
|
||||
@@ -294,7 +289,7 @@ const layer = Layer.effect(
|
||||
}
|
||||
if (stream._tag === "Failure" && Cause.hasInterrupts(stream.cause)) yield* FiberSet.clear(toolFibers)
|
||||
const settled = yield* restore(awaitToolFibers(toolFibers)).pipe(Effect.exit)
|
||||
if (settled._tag === "Failure" && isUserDeclined(settled.cause)) {
|
||||
if (settled._tag === "Failure" && isQuestionRejected(settled.cause)) {
|
||||
yield* FiberSet.clear(toolFibers)
|
||||
yield* withPublication(publisher.failUnsettledTools("Tool execution interrupted"))
|
||||
return yield* Effect.interrupt
|
||||
|
||||
@@ -78,21 +78,17 @@ const isTimeout = (error: AppProcess.AppProcessError) =>
|
||||
|
||||
const shellTokens = (command: string) => command.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) ?? []
|
||||
const unquote = (value: string) => value.replace(/^(['"])(.*)\1$/, "$2")
|
||||
const externalCommandDirectories = Effect.fn("BashTool.externalCommandDirectories")(function* (
|
||||
fs: FSUtil.Interface,
|
||||
command: string,
|
||||
cwd: string,
|
||||
) {
|
||||
const externalCommandDirectories = (command: string, cwd: string) => {
|
||||
const directories = new Set<string>()
|
||||
for (const token of shellTokens(command)) {
|
||||
const value = unquote(token).replace(/[;,|&]+$/, "")
|
||||
if (!path.isAbsolute(value)) continue
|
||||
const resolved = yield* fs.resolve(value)
|
||||
const resolved = FSUtil.resolve(value)
|
||||
if (FSUtil.contains(cwd, resolved)) continue
|
||||
directories.add(yield* fs.resolve(path.dirname(resolved)))
|
||||
directories.add(FSUtil.resolve(path.dirname(resolved)))
|
||||
}
|
||||
return [...directories]
|
||||
})
|
||||
}
|
||||
|
||||
const layer = Layer.effectDiscard(
|
||||
Effect.gen(function* () {
|
||||
@@ -135,7 +131,7 @@ const layer = Layer.effectDiscard(
|
||||
agent: context.agent,
|
||||
source,
|
||||
})
|
||||
const warnings = (yield* externalCommandDirectories(fs, input.command, target.canonical)).map(
|
||||
const warnings = externalCommandDirectories(input.command, target.canonical).map(
|
||||
(directory) =>
|
||||
`Command argument references external directory ${path.join(directory, "*").replaceAll("\\", "/")}. Bash runs with host-user filesystem, process, and network authority; this scan is advisory only.`,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Cause, Deferred, Effect, Fiber, Layer } from "effect"
|
||||
import { Deferred, Effect, Fiber, Layer } from "effect"
|
||||
import { AgentV2 } from "@opencode-ai/core/agent"
|
||||
import { Database } from "@opencode-ai/core/database/database"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
@@ -147,8 +147,8 @@ describe("PermissionV2", () => {
|
||||
const service = yield* PermissionV2.Service
|
||||
yield* service.assert(assertion())
|
||||
yield* setRules([{ action: "read", resource: "*", effect: "deny" }])
|
||||
const blocked = yield* service.assert(assertion()).pipe(Effect.flip)
|
||||
expect(blocked).toBeInstanceOf(PermissionV2.BlockedError)
|
||||
const denied = yield* service.assert(assertion()).pipe(Effect.flip)
|
||||
expect(denied).toBeInstanceOf(PermissionV2.DeniedError)
|
||||
expect(yield* service.list()).toEqual([])
|
||||
}),
|
||||
)
|
||||
@@ -265,24 +265,6 @@ describe("PermissionV2", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("defects when an asked permission is declined", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup()
|
||||
const { service, fiber, request } = yield* waitForRequest()
|
||||
yield* service.reply({ requestID: request.id, reply: "reject" })
|
||||
const exit = yield* Fiber.await(fiber)
|
||||
|
||||
expect(exit._tag).toBe("Failure")
|
||||
if (exit._tag === "Failure")
|
||||
expect(
|
||||
exit.cause.reasons.some(
|
||||
(reason) => Cause.isDieReason(reason) && reason.defect instanceof PermissionV2.DeclinedError,
|
||||
),
|
||||
).toBe(true)
|
||||
expect(yield* service.list()).toEqual([])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("stores and removes saved resources for a project", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup()
|
||||
|
||||
@@ -1097,7 +1097,7 @@ describe("SessionRunnerLLM", () => {
|
||||
currentModel = compactModel
|
||||
requests.length = 0
|
||||
responses = [
|
||||
fragmentFixture("text", "text-summary", ["## Objective\n- Preserve the task"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Preserve the task"]).completeEvents,
|
||||
fragmentFixture("text", "text-final", ["Continued"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({
|
||||
@@ -1108,22 +1108,22 @@ describe("SessionRunnerLLM", () => {
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(userTexts(requests[0])[0]).toContain("## Objective")
|
||||
expect(userTexts(requests[0])[0]).toContain("## Goal")
|
||||
expect(userTexts(requests[1])).toHaveLength(1)
|
||||
expect(userTexts(requests[1])[0]).toContain("<summary>\n## Objective\n- Preserve the task\n</summary>")
|
||||
expect(userTexts(requests[1])[0]).toContain("<summary>\n## Goal\n- Preserve the task\n</summary>")
|
||||
expect(userTexts(requests[1])[0]).toContain(`[User]: ${"Recent exact request ".repeat(180)}`)
|
||||
|
||||
const context = yield* (yield* SessionStore.Service).context(sessionID)
|
||||
expect(context.map((message) => message.type)).toEqual(["compaction", "assistant"])
|
||||
expect(context[0]).toMatchObject({
|
||||
type: "compaction",
|
||||
summary: "## Objective\n- Preserve the task",
|
||||
summary: "## Goal\n- Preserve the task",
|
||||
})
|
||||
|
||||
requests.length = 0
|
||||
executions.length = 0
|
||||
responses = [
|
||||
fragmentFixture("text", "text-summary-2", ["## Objective\n- Preserve the updated task"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary-2", ["## Goal\n- Preserve the updated task"]).completeEvents,
|
||||
fragmentFixture("text", "text-final-2", ["Continued again"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({
|
||||
@@ -1135,12 +1135,12 @@ describe("SessionRunnerLLM", () => {
|
||||
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(userTexts(requests[0])[0]).toContain(
|
||||
"<previous-summary>\n## Objective\n- Preserve the task\n</previous-summary>",
|
||||
"<previous-summary>\n## Goal\n- Preserve the task\n</previous-summary>",
|
||||
)
|
||||
expect(userTexts(requests[0])[0]).toContain("Recent exact request")
|
||||
expect((yield* (yield* SessionStore.Service).context(sessionID))[0]).toMatchObject({
|
||||
type: "compaction",
|
||||
summary: "## Objective\n- Preserve the updated task",
|
||||
summary: "## Goal\n- Preserve the updated task",
|
||||
})
|
||||
}),
|
||||
)
|
||||
@@ -1153,17 +1153,17 @@ describe("SessionRunnerLLM", () => {
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.providerError({ message: "prompt too long", classification: "context-overflow" }),
|
||||
],
|
||||
fragmentFixture("text", "text-summary", ["## Objective\n- Recover overflow"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Recover overflow"]).completeEvents,
|
||||
fragmentFixture("text", "text-final", ["Recovered"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Continue" }), resume: false })
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
expect(requests).toHaveLength(3)
|
||||
expect(userTexts(requests[1])[0]).toContain("## Objective")
|
||||
expect(userTexts(requests[2])[0]).toContain("<summary>\n## Objective\n- Recover overflow\n</summary>")
|
||||
expect(userTexts(requests[1])[0]).toContain("## Goal")
|
||||
expect(userTexts(requests[2])[0]).toContain("<summary>\n## Goal\n- Recover overflow\n</summary>")
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "compaction", summary: "## Objective\n- Recover overflow" },
|
||||
{ type: "compaction", summary: "## Goal\n- Recover overflow" },
|
||||
{ type: "assistant", finish: "stop" },
|
||||
])
|
||||
yield* replaySessionProjection(sessionID)
|
||||
@@ -1183,7 +1183,7 @@ describe("SessionRunnerLLM", () => {
|
||||
]
|
||||
responses = [
|
||||
overflow(),
|
||||
fragmentFixture("text", "text-summary", ["## Objective\n- Recover once"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Recover once"]).completeEvents,
|
||||
overflow(),
|
||||
]
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Continue" }), resume: false })
|
||||
@@ -1211,7 +1211,7 @@ describe("SessionRunnerLLM", () => {
|
||||
}),
|
||||
)
|
||||
responses = [
|
||||
fragmentFixture("text", "text-summary", ["## Objective\n- Recover raw overflow"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Recover raw overflow"]).completeEvents,
|
||||
fragmentFixture("text", "text-final", ["Recovered"]).completeEvents,
|
||||
]
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Continue" }), resume: false })
|
||||
@@ -1219,7 +1219,7 @@ describe("SessionRunnerLLM", () => {
|
||||
|
||||
expect(requests).toHaveLength(3)
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "compaction", summary: "## Objective\n- Recover raw overflow" },
|
||||
{ type: "compaction", summary: "## Goal\n- Recover raw overflow" },
|
||||
{ type: "assistant", finish: "stop" },
|
||||
])
|
||||
}),
|
||||
@@ -1250,7 +1250,7 @@ describe("SessionRunnerLLM", () => {
|
||||
const session = yield* setupOverflowRecovery
|
||||
responses = [
|
||||
[LLMEvent.providerError({ message: "prompt too long", classification: "context-overflow" })],
|
||||
fragmentFixture("text", "text-summary", ["## Objective\n- Interrupted"]).completeEvents,
|
||||
fragmentFixture("text", "text-summary", ["## Goal\n- Interrupted"]).completeEvents,
|
||||
]
|
||||
const firstGate = yield* Deferred.make<void>()
|
||||
const summaryGate = yield* Deferred.make<void>()
|
||||
@@ -2609,148 +2609,6 @@ describe("SessionRunnerLLM", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("returns policy-blocked tools to the model and continues", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
const session = yield* SessionV2.Service
|
||||
const registry = yield* ToolRegistry.Service
|
||||
yield* registry.register({
|
||||
blocked: Tool.make({
|
||||
description: "Fail because policy blocked execution",
|
||||
input: Schema.Struct({}),
|
||||
output: Schema.Struct({}),
|
||||
execute: () =>
|
||||
Effect.fail(new PermissionV2.BlockedError({ rules: [] })).pipe(
|
||||
Effect.mapError(() => new Tool.Failure({ message: "Permission blocked" })),
|
||||
),
|
||||
}),
|
||||
})
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Call blocked" }), resume: false })
|
||||
|
||||
requests.length = 0
|
||||
responses = [
|
||||
[
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.toolCall({ id: "call-blocked", name: "blocked", input: {} }),
|
||||
LLMEvent.stepFinish({ index: 0, reason: "tool-calls" }),
|
||||
LLMEvent.finish({ reason: "tool-calls" }),
|
||||
],
|
||||
[
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.stepFinish({ index: 0, reason: "stop" }),
|
||||
LLMEvent.finish({ reason: "stop" }),
|
||||
],
|
||||
]
|
||||
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Call blocked" },
|
||||
{
|
||||
type: "assistant",
|
||||
content: [
|
||||
{ type: "tool", id: "call-blocked", state: { status: "error", error: { message: "Permission blocked" } } },
|
||||
],
|
||||
},
|
||||
{ type: "assistant", finish: "stop" },
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("interrupts runner continuation when permission approval is declined", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
const session = yield* SessionV2.Service
|
||||
const registry = yield* ToolRegistry.Service
|
||||
yield* registry.register({
|
||||
declined: Tool.make({
|
||||
description: "Fail because the user declined approval",
|
||||
input: Schema.Struct({}),
|
||||
output: Schema.Struct({}),
|
||||
execute: () => Effect.die(new PermissionV2.DeclinedError()),
|
||||
}),
|
||||
})
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Call declined" }), resume: false })
|
||||
|
||||
requests.length = 0
|
||||
response = [
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.toolCall({ id: "call-declined", name: "declined", input: {} }),
|
||||
LLMEvent.stepFinish({ index: 0, reason: "tool-calls" }),
|
||||
LLMEvent.finish({ reason: "tool-calls" }),
|
||||
]
|
||||
|
||||
const exit = yield* session.resume(sessionID).pipe(Effect.exit)
|
||||
|
||||
expect(exit._tag).toBe("Failure")
|
||||
if (exit._tag === "Failure") expect(Cause.hasInterruptsOnly(exit.cause)).toBe(true)
|
||||
expect(requests).toHaveLength(1)
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Call declined" },
|
||||
{
|
||||
type: "assistant",
|
||||
content: [
|
||||
{
|
||||
type: "tool",
|
||||
id: "call-declined",
|
||||
state: { status: "error", error: { message: "Tool execution interrupted" } },
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("returns permission corrections to the model and continues", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
const session = yield* SessionV2.Service
|
||||
const registry = yield* ToolRegistry.Service
|
||||
yield* registry.register({
|
||||
corrected: Tool.make({
|
||||
description: "Fail with user correction feedback",
|
||||
input: Schema.Struct({}),
|
||||
output: Schema.Struct({}),
|
||||
execute: () =>
|
||||
Effect.fail(new PermissionV2.CorrectedError({ feedback: "Use another tool" })).pipe(
|
||||
Effect.mapError(() => new Tool.Failure({ message: "Use another tool" })),
|
||||
),
|
||||
}),
|
||||
})
|
||||
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Call corrected" }), resume: false })
|
||||
|
||||
requests.length = 0
|
||||
responses = [
|
||||
[
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.toolCall({ id: "call-corrected", name: "corrected", input: {} }),
|
||||
LLMEvent.stepFinish({ index: 0, reason: "tool-calls" }),
|
||||
LLMEvent.finish({ reason: "tool-calls" }),
|
||||
],
|
||||
[
|
||||
LLMEvent.stepStart({ index: 0 }),
|
||||
LLMEvent.stepFinish({ index: 0, reason: "stop" }),
|
||||
LLMEvent.finish({ reason: "stop" }),
|
||||
],
|
||||
]
|
||||
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
expect(requests).toHaveLength(2)
|
||||
expect(yield* session.context(sessionID)).toMatchObject([
|
||||
{ type: "user", text: "Call corrected" },
|
||||
{
|
||||
type: "assistant",
|
||||
content: [
|
||||
{ type: "tool", id: "call-corrected", state: { status: "error", error: { message: "Use another tool" } } },
|
||||
],
|
||||
},
|
||||
{ type: "assistant", finish: "stop" },
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("interrupts runner continuation when a question is dismissed", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
|
||||
@@ -40,7 +40,7 @@ const permission = Layer.succeed(
|
||||
}).pipe(
|
||||
Effect.andThen(input.action === "edit" ? Effect.suspend(afterEditApproval) : Effect.void),
|
||||
Effect.andThen(
|
||||
input.action === denyAction ? Effect.fail(new PermissionV2.BlockedError({ rules: [] })) : Effect.void,
|
||||
input.action === denyAction ? Effect.fail(new PermissionV2.DeniedError({ rules: [] })) : Effect.void,
|
||||
),
|
||||
),
|
||||
ask: () => Effect.die("unused"),
|
||||
|
||||
@@ -51,7 +51,7 @@ const permission = Layer.succeed(
|
||||
Effect.sync(() => assertions.push(input)).pipe(
|
||||
Effect.andThen(Effect.suspend(() => afterPermission(input))),
|
||||
Effect.andThen(
|
||||
input.action === denyAction ? Effect.fail(new PermissionV2.BlockedError({ rules: [] })) : Effect.void,
|
||||
input.action === denyAction ? Effect.fail(new PermissionV2.DeniedError({ rules: [] })) : Effect.void,
|
||||
),
|
||||
),
|
||||
ask: () => Effect.die("unused"),
|
||||
|
||||
@@ -33,7 +33,7 @@ const permission = Layer.succeed(
|
||||
assert: (input) =>
|
||||
Effect.sync(() => assertions.push(input)).pipe(
|
||||
Effect.andThen(
|
||||
input.action === denyAction ? Effect.fail(new PermissionV2.BlockedError({ rules: [] })) : Effect.void,
|
||||
input.action === denyAction ? Effect.fail(new PermissionV2.DeniedError({ rules: [] })) : Effect.void,
|
||||
),
|
||||
),
|
||||
ask: () => Effect.die("unused"),
|
||||
|
||||
@@ -22,7 +22,7 @@ const permission = Layer.succeed(
|
||||
PermissionV2.Service.of({
|
||||
assert: (input) =>
|
||||
Effect.sync(() => assertions.push(input)).pipe(
|
||||
Effect.andThen(deny ? Effect.fail(new PermissionV2.BlockedError({ rules: [] })) : Effect.void),
|
||||
Effect.andThen(deny ? Effect.fail(new PermissionV2.DeniedError({ rules: [] })) : Effect.void),
|
||||
),
|
||||
ask: () => Effect.die("unused"),
|
||||
reply: () => Effect.die("unused"),
|
||||
|
||||
@@ -64,7 +64,7 @@ const permission = Layer.succeed(
|
||||
assert: (input) =>
|
||||
Effect.sync(() => {
|
||||
assertions.push(input)
|
||||
}).pipe(Effect.andThen(allow ? Effect.void : Effect.fail(new PermissionV2.BlockedError({ rules: [] })))),
|
||||
}).pipe(Effect.andThen(allow ? Effect.void : Effect.fail(new PermissionV2.DeniedError({ rules: [] })))),
|
||||
ask: () => Effect.die("unused"),
|
||||
reply: () => Effect.die("unused"),
|
||||
get: () => Effect.die("unused"),
|
||||
|
||||
@@ -47,7 +47,7 @@ describe("SkillTool", () => {
|
||||
PermissionV2.Service.of({
|
||||
assert: (input) =>
|
||||
Effect.sync(() => assertions.push(input)).pipe(
|
||||
Effect.andThen(deny ? Effect.fail(new PermissionV2.BlockedError({ rules: [] })) : Effect.void),
|
||||
Effect.andThen(deny ? Effect.fail(new PermissionV2.DeniedError({ rules: [] })) : Effect.void),
|
||||
),
|
||||
ask: () => Effect.die("unused"),
|
||||
reply: () => Effect.die("unused"),
|
||||
|
||||
@@ -26,7 +26,7 @@ const permission = Layer.succeed(
|
||||
PermissionV2.Service.of({
|
||||
assert: (input) =>
|
||||
Effect.sync(() => assertions.push(input)).pipe(
|
||||
Effect.andThen(deny ? Effect.fail(new PermissionV2.BlockedError({ rules: [] })) : Effect.void),
|
||||
Effect.andThen(deny ? Effect.fail(new PermissionV2.DeniedError({ rules: [] })) : Effect.void),
|
||||
),
|
||||
ask: () => Effect.die("unused"),
|
||||
reply: () => Effect.die("unused"),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user