Initial codex telegram bot source
This commit is contained in:
18
.env.example
Normal file
18
.env.example
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
TELEGRAM_BOT_TOKEN=
|
||||||
|
|
||||||
|
# Use absolute host paths. The socket is mounted at the same path in the container.
|
||||||
|
HOST_CODEX_SOCKET=/absolute/path/to/codex-telegram-bot/run/codex.sock
|
||||||
|
HOST_CODEX_RUN_DIR=/absolute/path/to/codex-telegram-bot/run
|
||||||
|
HOST_UPLOAD_DIR=/absolute/path/to/codex-telegram-bot/uploads
|
||||||
|
|
||||||
|
# Host-side SQLite directory mounted to /data in the container.
|
||||||
|
DB_DIR=./data
|
||||||
|
|
||||||
|
# Leave empty to use Codex defaults.
|
||||||
|
DEFAULT_MODEL=
|
||||||
|
DEFAULT_SANDBOX=workspace-write
|
||||||
|
POLL_TIMEOUT_SECONDS=30
|
||||||
|
|
||||||
|
# Container should usually match the host user so SQLite files remain writable.
|
||||||
|
BOT_UID=1001
|
||||||
|
BOT_GID=1001
|
||||||
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Local configuration and secrets
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# Runtime state
|
||||||
|
/data/
|
||||||
|
/run/
|
||||||
|
/uploads/
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
*.sock
|
||||||
|
*.pid
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
/bin/
|
||||||
|
/dist/
|
||||||
|
/build/
|
||||||
|
/tmp/
|
||||||
|
|
||||||
|
# Go/test artifacts
|
||||||
|
*.test
|
||||||
|
coverage.out
|
||||||
|
|
||||||
|
# Editor/OS noise
|
||||||
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
FROM golang:1.23-alpine AS build
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
COPY go.mod go.sum* ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 go build -o /out/codex-telegram-bot ./cmd/bot
|
||||||
|
|
||||||
|
FROM alpine:3.20
|
||||||
|
|
||||||
|
RUN adduser -D -h /home/bot bot
|
||||||
|
COPY --from=build /out/codex-telegram-bot /usr/local/bin/codex-telegram-bot
|
||||||
|
|
||||||
|
USER bot
|
||||||
|
ENTRYPOINT ["/usr/local/bin/codex-telegram-bot"]
|
||||||
97
PLAN.md
Normal file
97
PLAN.md
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# Codex Telegram Bot Hybrid Host/App-Server Plan
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Create `codex-telegram-bot/` as a Docker Compose managed Go Telegram bot that connects to a **host-launched Codex CLI app-server**. Codex is not containerized: it runs from the installed host `codex` binary, using the host user's `~/.codex`, sandboxing, and workspace paths. The bot runs in Docker Compose, stores state in SQLite, and communicates with Codex through a bind-mounted Unix socket.
|
||||||
|
|
||||||
|
## Research
|
||||||
|
|
||||||
|
Before implementation, carefully read the official docs and check against the guidelines below. Create/Update them properly if discrepancies or new findings occur. If you are not sure, ask the user for advice/instruction.
|
||||||
|
|
||||||
|
- Codex App Server official docs: https://developers.openai.com/codex/app-server
|
||||||
|
- App-server is intended for rich clients with authentication, conversation history, approvals, and streamed agent events.
|
||||||
|
- Protocol is JSON-RPC 2.0 with the `jsonrpc` field omitted.
|
||||||
|
- Important: `unix://` transport is WebSocket over Unix socket using HTTP Upgrade, not raw newline JSON.
|
||||||
|
- Start flow: connect, send `initialize`, send `initialized`, then `thread/start` and `turn/start`.
|
||||||
|
- Generate version-matched protocol schemas with `codex app-server generate-json-schema --out ./schemas`.
|
||||||
|
|
||||||
|
- Telegram Bot API official docs: https://core.telegram.org/bots/api
|
||||||
|
- `sendMessage` and `editMessageText` are limited to 1-4096 chars after entity parsing.
|
||||||
|
- Callback buttons require `answerCallbackQuery`.
|
||||||
|
- `getFile` downloads are limited to 20 MB via cloud Bot API.
|
||||||
|
- `sendDocument` supports bot-sent files up to 50 MB via cloud Bot API.
|
||||||
|
- Use long polling for MVP unless webhook deployment is explicitly needed.
|
||||||
|
|
||||||
|
- Telegram bot feature docs: https://core.telegram.org/bots/features
|
||||||
|
- Validate commands server-side regardless of BotFather command scopes.
|
||||||
|
- Reject group/supergroup/channel updates in code even if group joining is disabled.
|
||||||
|
- Use inline keyboards for approve/deny/details actions.
|
||||||
|
|
||||||
|
## Key requirements
|
||||||
|
|
||||||
|
- Scaffold a Go bot project:
|
||||||
|
- `cmd/bot` for the bot process.
|
||||||
|
- `internal/telegram` for commands, callbacks, message rendering, and Telegram file downloads.
|
||||||
|
- `internal/codexapp` for app-server WebSocket-over-Unix-socket JSON-RPC.
|
||||||
|
- `internal/store` for SQLite state and migrations.
|
||||||
|
- `scripts/start-codex-app-server`, `scripts/allow-user`, `scripts/remove-user`, `scripts/list-users`, `scripts/add-workspace`, `scripts/list-workspaces`.
|
||||||
|
|
||||||
|
- Docker Compose runs only the bot:
|
||||||
|
- Build the Go bot image locally.
|
||||||
|
- Mount persistent SQLite data.
|
||||||
|
- Bind-mount the host socket path into the bot container.
|
||||||
|
- Bind-mount an upload staging directory at the same absolute path visible to host Codex.
|
||||||
|
- Do not install or run Codex CLI inside the bot container.
|
||||||
|
|
||||||
|
- Host Codex app-server:
|
||||||
|
- Started outside Compose with `scripts/start-codex-app-server`.
|
||||||
|
- Default command: `codex app-server --listen unix://$HOST_CODEX_SOCKET`.
|
||||||
|
- Uses host `~/.codex`, host workspaces, and host sandbox behavior.
|
||||||
|
- Socket defaults to an absolute path under the project, e.g. `/home/.../codex-telegram-bot/run/codex.sock`.
|
||||||
|
|
||||||
|
- Telegram UX:
|
||||||
|
- One-to-one chats only; reject groups, supergroups, and channels.
|
||||||
|
- Allowlisted Telegram user IDs only.
|
||||||
|
- Commands: `/start`, `/help`, `/new`, `/threads`, `/resume`, `/fork`, `/archive`, `/status`, `/cancel`, `/workspaces`, `/workspace`, `/model`, `/sandbox`, `/diff`.
|
||||||
|
- Plain text continues the active Codex thread, creating one if needed.
|
||||||
|
- Send assistant messages and rendered tool/status blocks as separate Telegram messages; chunk only when a single message exceeds Telegram limits.
|
||||||
|
- Send long output, logs, and diffs as chunked messages.
|
||||||
|
- Consider using HTML to render if markdown is weak/awkward.
|
||||||
|
- Render Codex approval requests as inline keyboards with approve, deny, and details actions.
|
||||||
|
|
||||||
|
- SQLite state:
|
||||||
|
- `allowed_users`, `workspaces`, `sessions`, `threads`, `pending_approvals`, `audit_log`.
|
||||||
|
- Workspace paths are host absolute paths used as Codex `cwd`.
|
||||||
|
- The bot does not need direct workspace access except for upload staging.
|
||||||
|
|
||||||
|
## Test Plan
|
||||||
|
Any interactive related test that requires user action should be done properly - ask the user to do X in telegram, then verify.
|
||||||
|
|
||||||
|
- Unit tests:
|
||||||
|
- Allowlist enforcement and group-chat rejection.
|
||||||
|
- Workspace path validation.
|
||||||
|
- Telegram escaping, chunking, document fallback, and callback validation.
|
||||||
|
- WebSocket-over-Unix-socket JSON-RPC request correlation and reconnect behavior.
|
||||||
|
- SQLite migrations and admin scripts.
|
||||||
|
|
||||||
|
- Integration tests:
|
||||||
|
- Use a low/mini model in codex for testing.
|
||||||
|
- Verify initialize, thread start, turn start, streamed output, approval, and cancellation.
|
||||||
|
- Verify `/start`, `/new`, `/threads`, `/resume`, `/workspace`, `/cancel`, image input, and document staging.
|
||||||
|
- Verify non-allowlisted users are rejected and logged.
|
||||||
|
|
||||||
|
- Manual acceptance:
|
||||||
|
- Start host Codex app-server with `scripts/start-codex-app-server`.
|
||||||
|
- Run `docker compose up --build`.
|
||||||
|
- Add an allowlisted user and workspace with scripts.
|
||||||
|
- In a one-to-one Telegram chat, run `/start`, select workspace, create a thread, send a prompt, approve a Codex request, inspect output, and cancel a running turn.
|
||||||
|
|
||||||
|
## Assumptions
|
||||||
|
|
||||||
|
- Bot runtime is Docker Compose.
|
||||||
|
- Codex CLI app-server is launched from the installed host binary, outside Docker.
|
||||||
|
- The Unix socket is the only v1 connection between bot and Codex.
|
||||||
|
- Go is used for the bot.
|
||||||
|
- SQLite is used for state and admin-managed allowlist/workspaces.
|
||||||
|
- Codex-in-container and `codex exec` are both out of scope for MVP.
|
||||||
|
- This computer is resource limited. Use docker/docker compose for large tools/SDKs to avoid installing locally.
|
||||||
49
README.md
Normal file
49
README.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Codex Telegram Bot
|
||||||
|
|
||||||
|
Docker Compose runs only the Go Telegram bot. Codex runs on the host through `codex app-server` and is reached through a bind-mounted Unix socket.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. Copy `.env.example` to `.env` and set `TELEGRAM_BOT_TOKEN`, `HOST_CODEX_SOCKET`, and `HOST_UPLOAD_DIR`.
|
||||||
|
2. Start the host Codex app-server:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/start-codex-app-server
|
||||||
|
```
|
||||||
|
|
||||||
|
The script starts Codex detached, writes `run/codex-app-server.pid`, logs to `run/codex-app-server.log`, and is idempotent if the socket is already live.
|
||||||
|
|
||||||
|
3. Add at least one Telegram user and workspace:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/allow-user 123456789 username
|
||||||
|
scripts/add-workspace /absolute/path/to/workspace "Workspace name" --default
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Build the bot binary when source changes:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
scripts/build-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Start or restart the bot without rebuilding:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
For normal restarts, use `docker compose restart bot`. The container runs `./bin/codex-telegram-bot` mounted read-only into Alpine; Compose does not compile Go code.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
The bot accepts one-to-one chats from allowlisted Telegram user IDs only. It rejects group, supergroup, and channel updates in code.
|
||||||
|
|
||||||
|
Supported commands: `/start`, `/help`, `/new`, `/threads`, `/resume`, `/fork`, `/archive`, `/status`, `/cancel`, `/workspaces`, `/workspace`, `/model`, `/sandbox`, `/diff`. `/model` lists available Codex models as inline buttons, then shows reasoning-effort buttons for the selected model.
|
||||||
|
|
||||||
|
Plain text continues the active Codex thread and creates one if needed. Telegram images are staged under `HOST_UPLOAD_DIR` and sent as `localImage` inputs. Other uploaded documents are staged and passed to Codex as host-visible file paths.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `HOST_UPLOAD_DIR` must be the same absolute path inside the bot container and on the host so host Codex can read staged files.
|
||||||
|
- `HOST_CODEX_SOCKET` must point to the host app-server socket. `HOST_CODEX_RUN_DIR` is mounted into the bot container at the same absolute path so socket recreation is visible without rebuilding.
|
||||||
|
- Use long polling for the MVP; webhooks are not required.
|
||||||
172
cmd/admin/main.go
Normal file
172
cmd/admin/main.go
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"codex-telegram-bot/internal/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := run(context.Background(), os.Args[1:]); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(ctx context.Context, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return usage()
|
||||||
|
}
|
||||||
|
dbPath := os.Getenv("DB_PATH")
|
||||||
|
if dbPath == "" {
|
||||||
|
dbPath = filepath.Join("data", "bot.db")
|
||||||
|
}
|
||||||
|
st, err := store.Open(ctx, dbPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
switch args[0] {
|
||||||
|
case "allow-user":
|
||||||
|
return allowUser(ctx, st, args[1:])
|
||||||
|
case "remove-user":
|
||||||
|
return removeUser(ctx, st, args[1:])
|
||||||
|
case "list-users":
|
||||||
|
return listUsers(ctx, st)
|
||||||
|
case "add-workspace":
|
||||||
|
return addWorkspace(ctx, st, args[1:])
|
||||||
|
case "list-workspaces":
|
||||||
|
return listWorkspaces(ctx, st)
|
||||||
|
default:
|
||||||
|
return usage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func usage() error {
|
||||||
|
return errors.New(`usage:
|
||||||
|
admin allow-user TELEGRAM_USER_ID [username] [notes...]
|
||||||
|
admin remove-user TELEGRAM_USER_ID
|
||||||
|
admin list-users
|
||||||
|
admin add-workspace ABSOLUTE_PATH [label] [--default]
|
||||||
|
admin list-workspaces`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func allowUser(ctx context.Context, st *store.Store, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return errors.New("allow-user requires TELEGRAM_USER_ID")
|
||||||
|
}
|
||||||
|
userID, err := strconv.ParseInt(args[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid telegram user id: %w", err)
|
||||||
|
}
|
||||||
|
username := ""
|
||||||
|
notes := ""
|
||||||
|
if len(args) >= 2 {
|
||||||
|
username = args[1]
|
||||||
|
}
|
||||||
|
if len(args) >= 3 {
|
||||||
|
notes = strings.Join(args[2:], " ")
|
||||||
|
}
|
||||||
|
if err := st.AddAllowedUser(ctx, userID, username, notes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("allowed user %d\n", userID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeUser(ctx context.Context, st *store.Store, args []string) error {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return errors.New("remove-user requires TELEGRAM_USER_ID")
|
||||||
|
}
|
||||||
|
userID, err := strconv.ParseInt(args[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid telegram user id: %w", err)
|
||||||
|
}
|
||||||
|
if err := st.RemoveAllowedUser(ctx, userID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("removed user %d\n", userID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listUsers(ctx context.Context, st *store.Store) error {
|
||||||
|
users, err := st.ListAllowedUsers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(users) == 0 {
|
||||||
|
fmt.Println("no allowed users")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, user := range users {
|
||||||
|
if user.Username == "" && user.Notes == "" {
|
||||||
|
fmt.Printf("%d\n", user.TelegramUserID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("%d\t%s\t%s\n", user.TelegramUserID, user.Username, user.Notes)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addWorkspace(ctx context.Context, st *store.Store, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return errors.New("add-workspace requires ABSOLUTE_PATH")
|
||||||
|
}
|
||||||
|
path := args[0]
|
||||||
|
label := ""
|
||||||
|
isDefault := false
|
||||||
|
for _, arg := range args[1:] {
|
||||||
|
if arg == "--default" {
|
||||||
|
isDefault = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if label == "" {
|
||||||
|
label = arg
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
label += " " + arg
|
||||||
|
}
|
||||||
|
clean, err := store.ValidateWorkspacePath(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info, err := os.Stat(clean)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("workspace path is not accessible: %w", err)
|
||||||
|
}
|
||||||
|
if !info.IsDir() {
|
||||||
|
return errors.New("workspace path must be a directory")
|
||||||
|
}
|
||||||
|
workspace, err := st.AddWorkspace(ctx, clean, label, isDefault)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("workspace %d\t%s\t%s\n", workspace.ID, workspace.Label, workspace.Path)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listWorkspaces(ctx context.Context, st *store.Store) error {
|
||||||
|
workspaces, err := st.ListWorkspaces(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(workspaces) == 0 {
|
||||||
|
fmt.Println("no workspaces")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, workspace := range workspaces {
|
||||||
|
marker := ""
|
||||||
|
if workspace.IsDefault {
|
||||||
|
marker = "default"
|
||||||
|
}
|
||||||
|
fmt.Printf("%d\t%s\t%s\t%s\n", workspace.ID, marker, workspace.Label, workspace.Path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
44
cmd/bot/main.go
Normal file
44
cmd/bot/main.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"codex-telegram-bot/internal/codexapp"
|
||||||
|
"codex-telegram-bot/internal/config"
|
||||||
|
"codex-telegram-bot/internal/store"
|
||||||
|
"codex-telegram-bot/internal/telegram"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
logger := log.New(os.Stdout, "", log.LstdFlags)
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
cfg, err := config.Load()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("config: %v", err)
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(cfg.UploadDir, 0o755); err != nil {
|
||||||
|
logger.Fatalf("upload dir: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
st, err := store.Open(ctx, cfg.DatabasePath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("store: %v", err)
|
||||||
|
}
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
tg := telegram.NewClient(cfg.TelegramToken)
|
||||||
|
codex := codexapp.New(cfg.CodexSocketPath, cfg.AppVersion)
|
||||||
|
defer codex.Close()
|
||||||
|
|
||||||
|
bot := telegram.NewBot(tg, st, codex, cfg.UploadDir, cfg.DefaultModel, cfg.DefaultSandbox, cfg.PollTimeout, logger)
|
||||||
|
logger.Printf("bot starting: db=%s codex_socket=%s upload_dir=%s", cfg.DatabasePath, cfg.CodexSocketPath, cfg.UploadDir)
|
||||||
|
if err := bot.Run(ctx); err != nil && err != context.Canceled {
|
||||||
|
logger.Fatalf("bot: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
23
docker-compose.yml
Normal file
23
docker-compose.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
services:
|
||||||
|
bot:
|
||||||
|
image: alpine:3.20
|
||||||
|
restart: unless-stopped
|
||||||
|
user: "${BOT_UID:-1001}:${BOT_GID:-1001}"
|
||||||
|
entrypoint: ["/app/codex-telegram-bot"]
|
||||||
|
env_file:
|
||||||
|
- path: .env
|
||||||
|
required: false
|
||||||
|
environment:
|
||||||
|
TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN:?set TELEGRAM_BOT_TOKEN}
|
||||||
|
DEFAULT_MODEL: ${DEFAULT_MODEL:-}
|
||||||
|
DEFAULT_SANDBOX: ${DEFAULT_SANDBOX:-workspace-write}
|
||||||
|
POLL_TIMEOUT_SECONDS: ${POLL_TIMEOUT_SECONDS:-30}
|
||||||
|
DB_PATH: /data/bot.db
|
||||||
|
HOST_CODEX_SOCKET: ${HOST_CODEX_SOCKET:?set HOST_CODEX_SOCKET}
|
||||||
|
HOST_UPLOAD_DIR: ${HOST_UPLOAD_DIR:?set HOST_UPLOAD_DIR}
|
||||||
|
HOST_CODEX_RUN_DIR: ${HOST_CODEX_RUN_DIR:?set HOST_CODEX_RUN_DIR}
|
||||||
|
volumes:
|
||||||
|
- ./bin/codex-telegram-bot:/app/codex-telegram-bot:ro
|
||||||
|
- ${DB_DIR:-./data}:/data
|
||||||
|
- ${HOST_CODEX_RUN_DIR:?set HOST_CODEX_RUN_DIR}:${HOST_CODEX_RUN_DIR:?set HOST_CODEX_RUN_DIR}
|
||||||
|
- ${HOST_UPLOAD_DIR:?set HOST_UPLOAD_DIR}:${HOST_UPLOAD_DIR:?set HOST_UPLOAD_DIR}
|
||||||
24
go.mod
Normal file
24
go.mod
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
module codex-telegram-bot
|
||||||
|
|
||||||
|
go 1.23.2
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gorilla/websocket v1.5.3
|
||||||
|
modernc.org/sqlite v1.33.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
||||||
|
modernc.org/libc v1.55.3 // indirect
|
||||||
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
|
modernc.org/memory v1.8.0 // indirect
|
||||||
|
modernc.org/strutil v1.2.0 // indirect
|
||||||
|
modernc.org/token v1.1.0 // indirect
|
||||||
|
)
|
||||||
51
go.sum
Normal file
51
go.sum
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
|
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
|
||||||
|
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
|
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||||
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||||
|
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||||
|
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
|
||||||
|
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||||
|
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
|
||||||
|
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
|
||||||
|
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||||
|
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||||
|
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||||
|
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||||
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
|
||||||
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
||||||
|
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
|
||||||
|
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
|
||||||
|
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||||
|
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||||
|
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||||
|
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||||
|
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||||
|
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
|
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
||||||
|
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
|
||||||
|
modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM=
|
||||||
|
modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
|
||||||
|
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||||
|
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||||
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
479
internal/codexapp/client.go
Normal file
479
internal/codexapp/client.go
Normal file
@@ -0,0 +1,479 @@
|
|||||||
|
package codexapp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
socketPath string
|
||||||
|
version string
|
||||||
|
|
||||||
|
nextID int64
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
conn *websocket.Conn
|
||||||
|
pending map[int64]chan rpcResult
|
||||||
|
events chan Event
|
||||||
|
connected bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Event struct {
|
||||||
|
ID *int64
|
||||||
|
Method string
|
||||||
|
Params json.RawMessage
|
||||||
|
ServerRequest bool
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type RPCError struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data json.RawMessage `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e RPCError) Error() string {
|
||||||
|
if e.Code == 0 {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d: %s", e.Code, e.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Thread struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SessionID string `json:"sessionId,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Preview string `json:"preview,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Turn struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InputItem struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
Path string `json:"path,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Model struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
DisplayName string `json:"displayName"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
IsDefault bool `json:"isDefault"`
|
||||||
|
DefaultReasoningEffort string `json:"defaultReasoningEffort"`
|
||||||
|
SupportedReasoningEfforts []ReasoningEffortOption `json:"supportedReasoningEfforts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReasoningEffortOption struct {
|
||||||
|
Description string `json:"description"`
|
||||||
|
ReasoningEffort string `json:"reasoningEffort"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(socketPath, version string) *Client {
|
||||||
|
return &Client{
|
||||||
|
socketPath: socketPath,
|
||||||
|
version: version,
|
||||||
|
pending: make(map[int64]chan rpcResult),
|
||||||
|
events: make(chan Event, 128),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Events() <-chan Event {
|
||||||
|
return c.events
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) EnsureConnected(ctx context.Context) error {
|
||||||
|
c.mu.Lock()
|
||||||
|
connected := c.connected && c.conn != nil
|
||||||
|
c.mu.Unlock()
|
||||||
|
if connected {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return c.Connect(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Connect(ctx context.Context) error {
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.connected && c.conn != nil {
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
dialer := websocket.Dialer{
|
||||||
|
NetDialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
var d net.Dialer
|
||||||
|
return d.DialContext(ctx, "unix", c.socketPath)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
conn, _, err := dialer.DialContext(ctx, "ws://codex-app-server/", http.Header{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("connect codex app-server unix socket %s: %w", c.socketPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
c.conn = conn
|
||||||
|
c.connected = true
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
go c.readLoop(conn)
|
||||||
|
|
||||||
|
if err := c.initialize(ctx); err != nil {
|
||||||
|
_ = c.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Close() error {
|
||||||
|
c.mu.Lock()
|
||||||
|
conn := c.conn
|
||||||
|
c.conn = nil
|
||||||
|
c.connected = false
|
||||||
|
c.mu.Unlock()
|
||||||
|
if conn == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) initialize(ctx context.Context) error {
|
||||||
|
params := map[string]any{
|
||||||
|
"clientInfo": map[string]any{
|
||||||
|
"name": "codex_telegram_bot",
|
||||||
|
"title": "Codex Telegram Bot",
|
||||||
|
"version": c.version,
|
||||||
|
},
|
||||||
|
"capabilities": map[string]any{
|
||||||
|
"experimentalApi": true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var ignored json.RawMessage
|
||||||
|
if err := c.call(ctx, "initialize", params, &ignored); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.notify("initialized", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) StartThread(ctx context.Context, cwd, model, sandbox string) (Thread, error) {
|
||||||
|
if err := c.EnsureConnected(ctx); err != nil {
|
||||||
|
return Thread{}, err
|
||||||
|
}
|
||||||
|
params := map[string]any{
|
||||||
|
"cwd": cwd,
|
||||||
|
"approvalPolicy": "on-request",
|
||||||
|
"sandbox": threadSandbox(sandbox),
|
||||||
|
"serviceName": "codex_telegram_bot",
|
||||||
|
}
|
||||||
|
if model != "" {
|
||||||
|
params["model"] = model
|
||||||
|
}
|
||||||
|
var result struct {
|
||||||
|
Thread Thread `json:"thread"`
|
||||||
|
}
|
||||||
|
if err := c.call(ctx, "thread/start", params, &result); err != nil {
|
||||||
|
return Thread{}, err
|
||||||
|
}
|
||||||
|
return result.Thread, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ResumeThread(ctx context.Context, threadID string) (Thread, error) {
|
||||||
|
if err := c.EnsureConnected(ctx); err != nil {
|
||||||
|
return Thread{}, err
|
||||||
|
}
|
||||||
|
var result struct {
|
||||||
|
Thread Thread `json:"thread"`
|
||||||
|
}
|
||||||
|
if err := c.call(ctx, "thread/resume", map[string]any{"threadId": threadID}, &result); err != nil {
|
||||||
|
return Thread{}, err
|
||||||
|
}
|
||||||
|
return result.Thread, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ForkThread(ctx context.Context, threadID string) (Thread, error) {
|
||||||
|
if err := c.EnsureConnected(ctx); err != nil {
|
||||||
|
return Thread{}, err
|
||||||
|
}
|
||||||
|
var result struct {
|
||||||
|
Thread Thread `json:"thread"`
|
||||||
|
}
|
||||||
|
if err := c.call(ctx, "thread/fork", map[string]any{"threadId": threadID}, &result); err != nil {
|
||||||
|
return Thread{}, err
|
||||||
|
}
|
||||||
|
return result.Thread, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ArchiveThread(ctx context.Context, threadID string) error {
|
||||||
|
if err := c.EnsureConnected(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var ignored json.RawMessage
|
||||||
|
return c.call(ctx, "thread/archive", map[string]any{"threadId": threadID}, &ignored)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) StartTurn(ctx context.Context, threadID, cwd, model, reasoningEffort, sandbox string, input []InputItem) (Turn, error) {
|
||||||
|
if err := c.EnsureConnected(ctx); err != nil {
|
||||||
|
return Turn{}, err
|
||||||
|
}
|
||||||
|
params := map[string]any{
|
||||||
|
"threadId": threadID,
|
||||||
|
"input": input,
|
||||||
|
"cwd": cwd,
|
||||||
|
"approvalPolicy": "on-request",
|
||||||
|
"sandboxPolicy": SandboxPolicy(sandbox, cwd),
|
||||||
|
}
|
||||||
|
if model != "" {
|
||||||
|
params["model"] = model
|
||||||
|
}
|
||||||
|
if reasoningEffort != "" {
|
||||||
|
params["effort"] = reasoningEffort
|
||||||
|
}
|
||||||
|
var result struct {
|
||||||
|
Turn Turn `json:"turn"`
|
||||||
|
}
|
||||||
|
if err := c.call(ctx, "turn/start", params, &result); err != nil {
|
||||||
|
return Turn{}, err
|
||||||
|
}
|
||||||
|
return result.Turn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) InterruptTurn(ctx context.Context, threadID, turnID string) error {
|
||||||
|
if err := c.EnsureConnected(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var ignored json.RawMessage
|
||||||
|
return c.call(ctx, "turn/interrupt", map[string]any{
|
||||||
|
"threadId": threadID,
|
||||||
|
"turnId": turnID,
|
||||||
|
}, &ignored)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListModels(ctx context.Context) ([]Model, error) {
|
||||||
|
if err := c.EnsureConnected(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var result struct {
|
||||||
|
Data []Model `json:"data"`
|
||||||
|
}
|
||||||
|
if err := c.call(ctx, "model/list", map[string]any{"limit": 50, "includeHidden": false}, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RespondServerRequest(ctx context.Context, requestID int64, result any) error {
|
||||||
|
if err := c.EnsureConnected(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
done := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
done <- c.write(responseEnvelope{ID: requestID, Result: result})
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case err := <-done:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) call(ctx context.Context, method string, params any, result any) error {
|
||||||
|
id := atomic.AddInt64(&c.nextID, 1)
|
||||||
|
ch := make(chan rpcResult, 1)
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.conn == nil {
|
||||||
|
c.mu.Unlock()
|
||||||
|
return errors.New("codex app-server is not connected")
|
||||||
|
}
|
||||||
|
c.pending[id] = ch
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
if err := c.write(requestEnvelope{ID: id, Method: method, Params: params}); err != nil {
|
||||||
|
c.mu.Lock()
|
||||||
|
delete(c.pending, id)
|
||||||
|
c.mu.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
c.mu.Lock()
|
||||||
|
delete(c.pending, id)
|
||||||
|
c.mu.Unlock()
|
||||||
|
return ctx.Err()
|
||||||
|
case rpc := <-ch:
|
||||||
|
if rpc.err != nil {
|
||||||
|
return rpc.err
|
||||||
|
}
|
||||||
|
if result == nil || len(rpc.result) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return json.Unmarshal(rpc.result, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) notify(method string, params any) error {
|
||||||
|
return c.write(notificationEnvelope{Method: method, Params: params})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) write(message any) error {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if c.conn == nil {
|
||||||
|
return errors.New("codex app-server is not connected")
|
||||||
|
}
|
||||||
|
return c.conn.WriteJSON(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) readLoop(conn *websocket.Conn) {
|
||||||
|
for {
|
||||||
|
var env incomingEnvelope
|
||||||
|
if err := conn.ReadJSON(&env); err != nil {
|
||||||
|
c.failConnection(conn, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if env.Method != "" && env.ID != nil {
|
||||||
|
c.events <- Event{
|
||||||
|
ID: env.ID,
|
||||||
|
Method: env.Method,
|
||||||
|
Params: env.Params,
|
||||||
|
ServerRequest: true,
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if env.ID != nil {
|
||||||
|
c.completeCall(*env.ID, env.Result, env.Error)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if env.Method != "" {
|
||||||
|
c.events <- Event{
|
||||||
|
Method: env.Method,
|
||||||
|
Params: env.Params,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) completeCall(id int64, result json.RawMessage, rpcErr *RPCError) {
|
||||||
|
c.mu.Lock()
|
||||||
|
ch := c.pending[id]
|
||||||
|
delete(c.pending, id)
|
||||||
|
c.mu.Unlock()
|
||||||
|
if ch == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rpcErr != nil {
|
||||||
|
ch <- rpcResult{err: *rpcErr}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ch <- rpcResult{result: result}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) failConnection(conn *websocket.Conn, err error) {
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.conn == conn {
|
||||||
|
c.conn = nil
|
||||||
|
c.connected = false
|
||||||
|
}
|
||||||
|
pending := c.pending
|
||||||
|
c.pending = make(map[int64]chan rpcResult)
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
for _, ch := range pending {
|
||||||
|
ch <- rpcResult{err: err}
|
||||||
|
}
|
||||||
|
c.events <- Event{Method: "connection/closed", Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeParams[T any](event Event) (T, error) {
|
||||||
|
var value T
|
||||||
|
if len(event.Params) == 0 {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(event.Params, &value)
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NormalizeSandbox(value string) (string, error) {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||||
|
case "", "workspace-write", "workspacewrite":
|
||||||
|
return "workspace-write", nil
|
||||||
|
case "read-only", "readonly":
|
||||||
|
return "read-only", nil
|
||||||
|
case "danger-full-access", "dangerfullaccess":
|
||||||
|
return "danger-full-access", nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("unsupported sandbox %q", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SandboxPolicy(sandbox, cwd string) map[string]any {
|
||||||
|
normalized, err := NormalizeSandbox(sandbox)
|
||||||
|
if err != nil {
|
||||||
|
normalized = "workspace-write"
|
||||||
|
}
|
||||||
|
switch normalized {
|
||||||
|
case "read-only":
|
||||||
|
return map[string]any{"type": "readOnly"}
|
||||||
|
case "danger-full-access":
|
||||||
|
return map[string]any{"type": "dangerFullAccess"}
|
||||||
|
default:
|
||||||
|
return map[string]any{
|
||||||
|
"type": "workspaceWrite",
|
||||||
|
"writableRoots": []string{cwd},
|
||||||
|
"networkAccess": false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func threadSandbox(sandbox string) string {
|
||||||
|
normalized, err := NormalizeSandbox(sandbox)
|
||||||
|
if err != nil {
|
||||||
|
return "workspace-write"
|
||||||
|
}
|
||||||
|
return normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestEnvelope struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
Params any `json:"params,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type notificationEnvelope struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Params any `json:"params,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type responseEnvelope struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Result any `json:"result,omitempty"`
|
||||||
|
Error any `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type incomingEnvelope struct {
|
||||||
|
ID *int64 `json:"id,omitempty"`
|
||||||
|
Method string `json:"method,omitempty"`
|
||||||
|
Params json.RawMessage `json:"params,omitempty"`
|
||||||
|
Result json.RawMessage `json:"result,omitempty"`
|
||||||
|
Error *RPCError `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type rpcResult struct {
|
||||||
|
result json.RawMessage
|
||||||
|
err error
|
||||||
|
}
|
||||||
155
internal/codexapp/client_test.go
Normal file
155
internal/codexapp/client_test.go
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package codexapp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClientWebSocketUnixJSONRPC(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
socketPath := filepath.Join(t.TempDir(), "codex.sock")
|
||||||
|
serverDone := make(chan error, 1)
|
||||||
|
ln, err := net.Listen("unix", socketPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(socketPath)
|
||||||
|
|
||||||
|
upgrader := websocket.Upgrader{}
|
||||||
|
server := &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
serverDone <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
var initialize map[string]any
|
||||||
|
if err := conn.ReadJSON(&initialize); err != nil {
|
||||||
|
serverDone <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if initialize["method"] != "initialize" {
|
||||||
|
serverDone <- unexpectedMessage("initialize", initialize["method"])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := conn.WriteJSON(map[string]any{"id": initialize["id"], "result": map[string]any{"userAgent": "test"}}); err != nil {
|
||||||
|
serverDone <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var initialized map[string]any
|
||||||
|
if err := conn.ReadJSON(&initialized); err != nil {
|
||||||
|
serverDone <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if initialized["method"] != "initialized" {
|
||||||
|
serverDone <- unexpectedMessage("initialized", initialized["method"])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.WriteJSON(map[string]any{
|
||||||
|
"id": 99,
|
||||||
|
"method": "item/commandExecution/requestApproval",
|
||||||
|
"params": map[string]any{"threadId": "thr_1"},
|
||||||
|
}); err != nil {
|
||||||
|
serverDone <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var start map[string]any
|
||||||
|
if err := conn.ReadJSON(&start); err != nil {
|
||||||
|
serverDone <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if start["method"] != "thread/start" {
|
||||||
|
serverDone <- unexpectedMessage("thread/start", start["method"])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := conn.WriteJSON(map[string]any{
|
||||||
|
"id": start["id"],
|
||||||
|
"result": map[string]any{
|
||||||
|
"thread": map[string]any{"id": "thr_1", "preview": "test"},
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
serverDone <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response map[string]any
|
||||||
|
if err := conn.ReadJSON(&response); err != nil {
|
||||||
|
serverDone <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if response["id"].(float64) != 99 || response["result"] != "accept" {
|
||||||
|
payload, _ := json.Marshal(response)
|
||||||
|
serverDone <- unexpectedMessage("approval response", string(payload))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
serverDone <- nil
|
||||||
|
})}
|
||||||
|
defer server.Close()
|
||||||
|
go func() {
|
||||||
|
_ = server.Serve(ln)
|
||||||
|
}()
|
||||||
|
|
||||||
|
client := New(socketPath, "test")
|
||||||
|
if err := client.Connect(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case event := <-client.Events():
|
||||||
|
if !event.ServerRequest || event.ID == nil || *event.ID != 99 {
|
||||||
|
t.Fatalf("unexpected event: %+v", event)
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
t.Fatal(ctx.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
thread, err := client.StartThread(ctx, "/tmp/project", "", "workspace-write")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if thread.ID != "thr_1" {
|
||||||
|
t.Fatalf("unexpected thread: %+v", thread)
|
||||||
|
}
|
||||||
|
if err := client.RespondServerRequest(ctx, 99, "accept"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err := <-serverDone:
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
t.Fatal(ctx.Err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errUnexpected string
|
||||||
|
|
||||||
|
func (e errUnexpected) Error() string {
|
||||||
|
return "unexpected " + string(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unexpectedMessage(want string, got any) error {
|
||||||
|
return errUnexpected("message: want " + want + ", got " + jsonString(got))
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonString(value any) string {
|
||||||
|
data, _ := json.Marshal(value)
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
18
internal/codexapp/turn.go
Normal file
18
internal/codexapp/turn.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package codexapp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Client) SteerTurn(ctx context.Context, threadID, expectedTurnID string, input []InputItem) error {
|
||||||
|
if err := c.EnsureConnected(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var ignored json.RawMessage
|
||||||
|
return c.call(ctx, "turn/steer", map[string]any{
|
||||||
|
"threadId": threadID,
|
||||||
|
"expectedTurnId": expectedTurnID,
|
||||||
|
"input": input,
|
||||||
|
}, &ignored)
|
||||||
|
}
|
||||||
61
internal/config/config.go
Normal file
61
internal/config/config.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
TelegramToken string
|
||||||
|
DatabasePath string
|
||||||
|
CodexSocketPath string
|
||||||
|
UploadDir string
|
||||||
|
DefaultModel string
|
||||||
|
DefaultSandbox string
|
||||||
|
PollTimeout time.Duration
|
||||||
|
AppVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Load() (Config, error) {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := Config{
|
||||||
|
TelegramToken: os.Getenv("TELEGRAM_BOT_TOKEN"),
|
||||||
|
DatabasePath: envOr("DB_PATH", filepath.Join(wd, "data", "bot.db")),
|
||||||
|
CodexSocketPath: envOr("HOST_CODEX_SOCKET", filepath.Join(wd, "run", "codex.sock")),
|
||||||
|
UploadDir: envOr("HOST_UPLOAD_DIR", filepath.Join(wd, "uploads")),
|
||||||
|
DefaultModel: os.Getenv("DEFAULT_MODEL"),
|
||||||
|
DefaultSandbox: envOr("DEFAULT_SANDBOX", "workspace-write"),
|
||||||
|
PollTimeout: durationSeconds("POLL_TIMEOUT_SECONDS", 30),
|
||||||
|
AppVersion: envOr("APP_VERSION", "0.1.0"),
|
||||||
|
}
|
||||||
|
if cfg.TelegramToken == "" {
|
||||||
|
return Config{}, errors.New("TELEGRAM_BOT_TOKEN is required")
|
||||||
|
}
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func envOr(key, fallback string) string {
|
||||||
|
if value := os.Getenv(key); value != "" {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
func durationSeconds(key string, fallback int) time.Duration {
|
||||||
|
raw := os.Getenv(key)
|
||||||
|
if raw == "" {
|
||||||
|
return time.Duration(fallback) * time.Second
|
||||||
|
}
|
||||||
|
value, err := strconv.Atoi(raw)
|
||||||
|
if err != nil || value <= 0 {
|
||||||
|
return time.Duration(fallback) * time.Second
|
||||||
|
}
|
||||||
|
return time.Duration(value) * time.Second
|
||||||
|
}
|
||||||
94
internal/store/migrations.go
Normal file
94
internal/store/migrations.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
type migration struct {
|
||||||
|
Name string
|
||||||
|
SQL string
|
||||||
|
}
|
||||||
|
|
||||||
|
var migrations = []migration{
|
||||||
|
{
|
||||||
|
Name: "initial_state",
|
||||||
|
SQL: `
|
||||||
|
CREATE TABLE allowed_users (
|
||||||
|
telegram_user_id INTEGER PRIMARY KEY,
|
||||||
|
username TEXT NOT NULL DEFAULT '',
|
||||||
|
notes TEXT NOT NULL DEFAULT '',
|
||||||
|
added_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE workspaces (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
path TEXT NOT NULL UNIQUE,
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
is_default INTEGER NOT NULL DEFAULT 0,
|
||||||
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sessions (
|
||||||
|
telegram_user_id INTEGER PRIMARY KEY,
|
||||||
|
active_thread_id INTEGER,
|
||||||
|
active_workspace_id INTEGER,
|
||||||
|
model TEXT NOT NULL DEFAULT '',
|
||||||
|
sandbox TEXT NOT NULL DEFAULT 'workspace-write',
|
||||||
|
active_turn_id TEXT NOT NULL DEFAULT '',
|
||||||
|
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||||
|
FOREIGN KEY(active_thread_id) REFERENCES threads(id) ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY(active_workspace_id) REFERENCES workspaces(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE threads (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
telegram_user_id INTEGER NOT NULL,
|
||||||
|
codex_thread_id TEXT NOT NULL UNIQUE,
|
||||||
|
workspace_id INTEGER NOT NULL,
|
||||||
|
title TEXT NOT NULL DEFAULT '',
|
||||||
|
archived INTEGER NOT NULL DEFAULT 0,
|
||||||
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||||
|
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||||
|
FOREIGN KEY(workspace_id) REFERENCES workspaces(id) ON DELETE RESTRICT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_threads_user_updated ON threads(telegram_user_id, archived, updated_at DESC);
|
||||||
|
|
||||||
|
CREATE TABLE pending_approvals (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
telegram_user_id INTEGER NOT NULL,
|
||||||
|
codex_request_id TEXT NOT NULL,
|
||||||
|
codex_thread_id TEXT NOT NULL,
|
||||||
|
turn_id TEXT NOT NULL DEFAULT '',
|
||||||
|
item_id TEXT NOT NULL DEFAULT '',
|
||||||
|
kind TEXT NOT NULL,
|
||||||
|
payload_json TEXT NOT NULL,
|
||||||
|
message_chat_id INTEGER NOT NULL DEFAULT 0,
|
||||||
|
message_id INTEGER NOT NULL DEFAULT 0,
|
||||||
|
status TEXT NOT NULL DEFAULT 'pending',
|
||||||
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||||
|
resolved_at TEXT NOT NULL DEFAULT '',
|
||||||
|
UNIQUE(telegram_user_id, codex_request_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_pending_approvals_status ON pending_approvals(telegram_user_id, status);
|
||||||
|
|
||||||
|
CREATE TABLE audit_log (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
telegram_user_id INTEGER NOT NULL DEFAULT 0,
|
||||||
|
action TEXT NOT NULL,
|
||||||
|
details TEXT NOT NULL DEFAULT '',
|
||||||
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_audit_user_created ON audit_log(telegram_user_id, created_at DESC);
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "session_reasoning_effort",
|
||||||
|
SQL: "ALTER TABLE sessions ADD COLUMN reasoning_effort TEXT NOT NULL DEFAULT ''",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "session_settings_message",
|
||||||
|
SQL: `
|
||||||
|
ALTER TABLE sessions ADD COLUMN settings_chat_id INTEGER NOT NULL DEFAULT 0;
|
||||||
|
ALTER TABLE sessions ADD COLUMN settings_message_id INTEGER NOT NULL DEFAULT 0;
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
516
internal/store/store.go
Normal file
516
internal/store/store.go
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
_ "modernc.org/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Store struct {
|
||||||
|
db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllowedUser struct {
|
||||||
|
TelegramUserID int64
|
||||||
|
Username string
|
||||||
|
Notes string
|
||||||
|
AddedAt string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Workspace struct {
|
||||||
|
ID int64
|
||||||
|
Path string
|
||||||
|
Label string
|
||||||
|
IsDefault bool
|
||||||
|
CreatedAt string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Session struct {
|
||||||
|
TelegramUserID int64
|
||||||
|
ActiveThreadID int64
|
||||||
|
ActiveWorkspaceID int64
|
||||||
|
Model string
|
||||||
|
ReasoningEffort string
|
||||||
|
Sandbox string
|
||||||
|
ActiveTurnID string
|
||||||
|
SettingsChatID int64
|
||||||
|
SettingsMessageID int
|
||||||
|
UpdatedAt string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Thread struct {
|
||||||
|
ID int64
|
||||||
|
TelegramUserID int64
|
||||||
|
CodexThreadID string
|
||||||
|
WorkspaceID int64
|
||||||
|
Title string
|
||||||
|
Archived bool
|
||||||
|
CreatedAt string
|
||||||
|
UpdatedAt string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PendingApproval struct {
|
||||||
|
ID int64
|
||||||
|
TelegramUserID int64
|
||||||
|
CodexRequestID string
|
||||||
|
CodexThreadID string
|
||||||
|
TurnID string
|
||||||
|
ItemID string
|
||||||
|
Kind string
|
||||||
|
PayloadJSON string
|
||||||
|
MessageChatID int64
|
||||||
|
MessageID int
|
||||||
|
Status string
|
||||||
|
CreatedAt string
|
||||||
|
ResolvedAt string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Open(ctx context.Context, path string) (*Store, error) {
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
db, err := sql.Open("sqlite", path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
db.SetMaxOpenConns(1)
|
||||||
|
|
||||||
|
s := &Store{db: db}
|
||||||
|
if err := s.configure(ctx); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := s.migrate(ctx); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) Close() error {
|
||||||
|
return s.db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) configure(ctx context.Context) error {
|
||||||
|
statements := []string{
|
||||||
|
"PRAGMA foreign_keys = ON",
|
||||||
|
"PRAGMA journal_mode = WAL",
|
||||||
|
"PRAGMA busy_timeout = 5000",
|
||||||
|
}
|
||||||
|
for _, statement := range statements {
|
||||||
|
if _, err := s.db.ExecContext(ctx, statement); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) migrate(ctx context.Context) error {
|
||||||
|
if _, err := s.db.ExecContext(ctx, `
|
||||||
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||||
|
version INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
|
)`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var current int
|
||||||
|
if err := s.db.QueryRowContext(ctx, "SELECT COALESCE(MAX(version), 0) FROM schema_migrations").Scan(¤t); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := current; i < len(migrations); i++ {
|
||||||
|
version := i + 1
|
||||||
|
tx, err := s.db.BeginTx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := tx.ExecContext(ctx, migrations[i].SQL); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return fmt.Errorf("migration %d %s: %w", version, migrations[i].Name, err)
|
||||||
|
}
|
||||||
|
if _, err := tx.ExecContext(ctx, "INSERT INTO schema_migrations (version, name) VALUES (?, ?)", version, migrations[i].Name); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateWorkspacePath(path string) (string, error) {
|
||||||
|
if path == "" {
|
||||||
|
return "", errors.New("workspace path is required")
|
||||||
|
}
|
||||||
|
if strings.ContainsRune(path, 0) {
|
||||||
|
return "", errors.New("workspace path contains a NUL byte")
|
||||||
|
}
|
||||||
|
if !filepath.IsAbs(path) {
|
||||||
|
return "", errors.New("workspace path must be absolute")
|
||||||
|
}
|
||||||
|
clean := filepath.Clean(path)
|
||||||
|
if clean == string(filepath.Separator) {
|
||||||
|
return "", errors.New("workspace path cannot be filesystem root")
|
||||||
|
}
|
||||||
|
return clean, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) IsAllowed(ctx context.Context, telegramUserID int64) (bool, error) {
|
||||||
|
var exists int
|
||||||
|
err := s.db.QueryRowContext(ctx, "SELECT 1 FROM allowed_users WHERE telegram_user_id = ?", telegramUserID).Scan(&exists)
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return err == nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) AddAllowedUser(ctx context.Context, telegramUserID int64, username, notes string) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, `
|
||||||
|
INSERT INTO allowed_users (telegram_user_id, username, notes)
|
||||||
|
VALUES (?, ?, ?)
|
||||||
|
ON CONFLICT(telegram_user_id) DO UPDATE SET username = excluded.username, notes = excluded.notes`,
|
||||||
|
telegramUserID, username, notes)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) RemoveAllowedUser(ctx context.Context, telegramUserID int64) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "DELETE FROM allowed_users WHERE telegram_user_id = ?", telegramUserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) ListAllowedUsers(ctx context.Context) ([]AllowedUser, error) {
|
||||||
|
rows, err := s.db.QueryContext(ctx, "SELECT telegram_user_id, username, notes, added_at FROM allowed_users ORDER BY telegram_user_id")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var users []AllowedUser
|
||||||
|
for rows.Next() {
|
||||||
|
var user AllowedUser
|
||||||
|
if err := rows.Scan(&user.TelegramUserID, &user.Username, &user.Notes, &user.AddedAt); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
users = append(users, user)
|
||||||
|
}
|
||||||
|
return users, rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) AddWorkspace(ctx context.Context, path, label string, isDefault bool) (Workspace, error) {
|
||||||
|
clean, err := ValidateWorkspacePath(path)
|
||||||
|
if err != nil {
|
||||||
|
return Workspace{}, err
|
||||||
|
}
|
||||||
|
if label == "" {
|
||||||
|
label = filepath.Base(clean)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := s.db.BeginTx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return Workspace{}, err
|
||||||
|
}
|
||||||
|
if isDefault {
|
||||||
|
if _, err := tx.ExecContext(ctx, "UPDATE workspaces SET is_default = 0"); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return Workspace{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result, err := tx.ExecContext(ctx, `
|
||||||
|
INSERT INTO workspaces (path, label, is_default)
|
||||||
|
VALUES (?, ?, ?)
|
||||||
|
ON CONFLICT(path) DO UPDATE SET label = excluded.label, is_default = excluded.is_default`,
|
||||||
|
clean, label, boolInt(isDefault))
|
||||||
|
if err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return Workspace{}, err
|
||||||
|
}
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return Workspace{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
id, _ := result.LastInsertId()
|
||||||
|
if id == 0 {
|
||||||
|
return s.GetWorkspaceByPath(ctx, clean)
|
||||||
|
}
|
||||||
|
return s.GetWorkspaceByPath(ctx, clean)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) ListWorkspaces(ctx context.Context) ([]Workspace, error) {
|
||||||
|
rows, err := s.db.QueryContext(ctx, "SELECT id, path, label, is_default, created_at FROM workspaces ORDER BY is_default DESC, label, path")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var workspaces []Workspace
|
||||||
|
for rows.Next() {
|
||||||
|
workspace, err := scanWorkspace(rows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
workspaces = append(workspaces, workspace)
|
||||||
|
}
|
||||||
|
return workspaces, rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetWorkspaceByID(ctx context.Context, id int64) (Workspace, error) {
|
||||||
|
row := s.db.QueryRowContext(ctx, "SELECT id, path, label, is_default, created_at FROM workspaces WHERE id = ?", id)
|
||||||
|
return scanWorkspace(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetWorkspaceByPath(ctx context.Context, path string) (Workspace, error) {
|
||||||
|
row := s.db.QueryRowContext(ctx, "SELECT id, path, label, is_default, created_at FROM workspaces WHERE path = ?", path)
|
||||||
|
return scanWorkspace(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) DefaultWorkspace(ctx context.Context) (Workspace, error) {
|
||||||
|
row := s.db.QueryRowContext(ctx, "SELECT id, path, label, is_default, created_at FROM workspaces ORDER BY is_default DESC, id ASC LIMIT 1")
|
||||||
|
return scanWorkspace(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetOrCreateSession(ctx context.Context, telegramUserID int64, defaultModel, defaultSandbox string) (Session, error) {
|
||||||
|
if defaultSandbox == "" {
|
||||||
|
defaultSandbox = "workspace-write"
|
||||||
|
}
|
||||||
|
_, err := s.db.ExecContext(ctx, `
|
||||||
|
INSERT INTO sessions (telegram_user_id, model, sandbox)
|
||||||
|
VALUES (?, ?, ?)
|
||||||
|
ON CONFLICT(telegram_user_id) DO NOTHING`, telegramUserID, defaultModel, defaultSandbox)
|
||||||
|
if err != nil {
|
||||||
|
return Session{}, err
|
||||||
|
}
|
||||||
|
return s.GetSession(ctx, telegramUserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetSession(ctx context.Context, telegramUserID int64) (Session, error) {
|
||||||
|
row := s.db.QueryRowContext(ctx, `
|
||||||
|
SELECT telegram_user_id, COALESCE(active_thread_id, 0), COALESCE(active_workspace_id, 0), model, COALESCE(reasoning_effort, ''), sandbox, active_turn_id, COALESCE(settings_chat_id, 0), COALESCE(settings_message_id, 0), updated_at
|
||||||
|
FROM sessions WHERE telegram_user_id = ?`, telegramUserID)
|
||||||
|
var session Session
|
||||||
|
err := row.Scan(&session.TelegramUserID, &session.ActiveThreadID, &session.ActiveWorkspaceID, &session.Model, &session.ReasoningEffort, &session.Sandbox, &session.ActiveTurnID, &session.SettingsChatID, &session.SettingsMessageID, &session.UpdatedAt)
|
||||||
|
return session, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) SetSessionWorkspace(ctx context.Context, telegramUserID, workspaceID int64) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, `
|
||||||
|
UPDATE sessions SET active_workspace_id = ?, updated_at = datetime('now')
|
||||||
|
WHERE telegram_user_id = ?`, workspaceID, telegramUserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) SetSessionModel(ctx context.Context, telegramUserID int64, model string) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "UPDATE sessions SET model = ?, reasoning_effort = '', updated_at = datetime('now') WHERE telegram_user_id = ?", model, telegramUserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) SetSessionReasoningEffort(ctx context.Context, telegramUserID int64, effort string) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "UPDATE sessions SET reasoning_effort = ?, updated_at = datetime('now') WHERE telegram_user_id = ?", effort, telegramUserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) SetSessionSettingsMessage(ctx context.Context, telegramUserID int64, chatID int64, messageID int) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "UPDATE sessions SET settings_chat_id = ?, settings_message_id = ?, updated_at = datetime('now') WHERE telegram_user_id = ?", chatID, messageID, telegramUserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) SetSessionSandbox(ctx context.Context, telegramUserID int64, sandbox string) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "UPDATE sessions SET sandbox = ?, updated_at = datetime('now') WHERE telegram_user_id = ?", sandbox, telegramUserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) SetActiveThread(ctx context.Context, telegramUserID, threadID int64) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, `
|
||||||
|
UPDATE sessions SET active_thread_id = ?, active_turn_id = '', updated_at = datetime('now')
|
||||||
|
WHERE telegram_user_id = ?`, threadID, telegramUserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) SetActiveTurn(ctx context.Context, telegramUserID int64, turnID string) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "UPDATE sessions SET active_turn_id = ?, updated_at = datetime('now') WHERE telegram_user_id = ?", turnID, telegramUserID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) ClearActiveTurns(ctx context.Context) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "UPDATE sessions SET active_turn_id = '', updated_at = datetime('now') WHERE active_turn_id <> ''")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) CreateThread(ctx context.Context, telegramUserID int64, codexThreadID string, workspaceID int64, title string) (Thread, error) {
|
||||||
|
result, err := s.db.ExecContext(ctx, `
|
||||||
|
INSERT INTO threads (telegram_user_id, codex_thread_id, workspace_id, title)
|
||||||
|
VALUES (?, ?, ?, ?)`, telegramUserID, codexThreadID, workspaceID, title)
|
||||||
|
if err != nil {
|
||||||
|
return Thread{}, err
|
||||||
|
}
|
||||||
|
id, err := result.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
return Thread{}, err
|
||||||
|
}
|
||||||
|
return s.GetThreadByID(ctx, telegramUserID, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetThreadByID(ctx context.Context, telegramUserID, id int64) (Thread, error) {
|
||||||
|
row := s.db.QueryRowContext(ctx, `
|
||||||
|
SELECT id, telegram_user_id, codex_thread_id, workspace_id, title, archived, created_at, updated_at
|
||||||
|
FROM threads WHERE telegram_user_id = ? AND id = ?`, telegramUserID, id)
|
||||||
|
return scanThread(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetThreadByCodexID(ctx context.Context, codexThreadID string) (Thread, error) {
|
||||||
|
row := s.db.QueryRowContext(ctx, `
|
||||||
|
SELECT id, telegram_user_id, codex_thread_id, workspace_id, title, archived, created_at, updated_at
|
||||||
|
FROM threads WHERE codex_thread_id = ?`, codexThreadID)
|
||||||
|
return scanThread(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) ListThreads(ctx context.Context, telegramUserID int64, includeArchived bool) ([]Thread, error) {
|
||||||
|
return s.ListThreadsPage(ctx, telegramUserID, includeArchived, 20, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) ListThreadsPage(ctx context.Context, telegramUserID int64, includeArchived bool, limit, offset int) ([]Thread, error) {
|
||||||
|
if limit <= 0 {
|
||||||
|
limit = 20
|
||||||
|
}
|
||||||
|
if offset < 0 {
|
||||||
|
offset = 0
|
||||||
|
}
|
||||||
|
query := `
|
||||||
|
SELECT id, telegram_user_id, codex_thread_id, workspace_id, title, archived, created_at, updated_at
|
||||||
|
FROM threads WHERE telegram_user_id = ?`
|
||||||
|
args := []any{telegramUserID}
|
||||||
|
if !includeArchived {
|
||||||
|
query += " AND archived = 0"
|
||||||
|
}
|
||||||
|
query += " ORDER BY updated_at DESC, id DESC LIMIT ? OFFSET ?"
|
||||||
|
args = append(args, limit, offset)
|
||||||
|
|
||||||
|
rows, err := s.db.QueryContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var threads []Thread
|
||||||
|
for rows.Next() {
|
||||||
|
thread, err := scanThread(rows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
threads = append(threads, thread)
|
||||||
|
}
|
||||||
|
return threads, rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) ArchiveThread(ctx context.Context, telegramUserID, id int64) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, `
|
||||||
|
UPDATE threads SET archived = 1, updated_at = datetime('now')
|
||||||
|
WHERE telegram_user_id = ? AND id = ?`, telegramUserID, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) TouchThread(ctx context.Context, codexThreadID string) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "UPDATE threads SET updated_at = datetime('now') WHERE codex_thread_id = ?", codexThreadID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpsertPendingApproval(ctx context.Context, approval PendingApproval) (PendingApproval, error) {
|
||||||
|
_, err := s.db.ExecContext(ctx, `
|
||||||
|
INSERT INTO pending_approvals (
|
||||||
|
telegram_user_id, codex_request_id, codex_thread_id, turn_id, item_id, kind, payload_json,
|
||||||
|
message_chat_id, message_id, status
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')
|
||||||
|
ON CONFLICT(telegram_user_id, codex_request_id) DO UPDATE SET
|
||||||
|
payload_json = excluded.payload_json,
|
||||||
|
message_chat_id = excluded.message_chat_id,
|
||||||
|
message_id = excluded.message_id,
|
||||||
|
status = 'pending',
|
||||||
|
resolved_at = ''`,
|
||||||
|
approval.TelegramUserID, approval.CodexRequestID, approval.CodexThreadID, approval.TurnID,
|
||||||
|
approval.ItemID, approval.Kind, approval.PayloadJSON, approval.MessageChatID, approval.MessageID)
|
||||||
|
if err != nil {
|
||||||
|
return PendingApproval{}, err
|
||||||
|
}
|
||||||
|
return s.GetPendingApprovalByRequest(ctx, approval.TelegramUserID, approval.CodexRequestID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) UpdatePendingApprovalMessage(ctx context.Context, id int64, chatID int64, messageID int) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "UPDATE pending_approvals SET message_chat_id = ?, message_id = ? WHERE id = ?", chatID, messageID, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetPendingApproval(ctx context.Context, telegramUserID, id int64) (PendingApproval, error) {
|
||||||
|
row := s.db.QueryRowContext(ctx, `
|
||||||
|
SELECT id, telegram_user_id, codex_request_id, codex_thread_id, turn_id, item_id, kind, payload_json,
|
||||||
|
message_chat_id, message_id, status, created_at, COALESCE(resolved_at, '')
|
||||||
|
FROM pending_approvals WHERE telegram_user_id = ? AND id = ?`, telegramUserID, id)
|
||||||
|
return scanPendingApproval(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetPendingApprovalByRequest(ctx context.Context, telegramUserID int64, requestID string) (PendingApproval, error) {
|
||||||
|
row := s.db.QueryRowContext(ctx, `
|
||||||
|
SELECT id, telegram_user_id, codex_request_id, codex_thread_id, turn_id, item_id, kind, payload_json,
|
||||||
|
message_chat_id, message_id, status, created_at, COALESCE(resolved_at, '')
|
||||||
|
FROM pending_approvals WHERE telegram_user_id = ? AND codex_request_id = ?`, telegramUserID, requestID)
|
||||||
|
return scanPendingApproval(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) ResolvePendingApproval(ctx context.Context, telegramUserID, id int64, status string) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, `
|
||||||
|
UPDATE pending_approvals SET status = ?, resolved_at = datetime('now')
|
||||||
|
WHERE telegram_user_id = ? AND id = ? AND status = 'pending'`, status, telegramUserID, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) Audit(ctx context.Context, telegramUserID int64, action, details string) error {
|
||||||
|
_, err := s.db.ExecContext(ctx, "INSERT INTO audit_log (telegram_user_id, action, details) VALUES (?, ?, ?)", telegramUserID, action, details)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type scanner interface {
|
||||||
|
Scan(dest ...any) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanWorkspace(row scanner) (Workspace, error) {
|
||||||
|
var workspace Workspace
|
||||||
|
var isDefault int
|
||||||
|
if err := row.Scan(&workspace.ID, &workspace.Path, &workspace.Label, &isDefault, &workspace.CreatedAt); err != nil {
|
||||||
|
return Workspace{}, err
|
||||||
|
}
|
||||||
|
workspace.IsDefault = isDefault != 0
|
||||||
|
return workspace, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanThread(row scanner) (Thread, error) {
|
||||||
|
var thread Thread
|
||||||
|
var archived int
|
||||||
|
if err := row.Scan(&thread.ID, &thread.TelegramUserID, &thread.CodexThreadID, &thread.WorkspaceID, &thread.Title, &archived, &thread.CreatedAt, &thread.UpdatedAt); err != nil {
|
||||||
|
return Thread{}, err
|
||||||
|
}
|
||||||
|
thread.Archived = archived != 0
|
||||||
|
return thread, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanPendingApproval(row scanner) (PendingApproval, error) {
|
||||||
|
var approval PendingApproval
|
||||||
|
if err := row.Scan(&approval.ID, &approval.TelegramUserID, &approval.CodexRequestID, &approval.CodexThreadID,
|
||||||
|
&approval.TurnID, &approval.ItemID, &approval.Kind, &approval.PayloadJSON, &approval.MessageChatID,
|
||||||
|
&approval.MessageID, &approval.Status, &approval.CreatedAt, &approval.ResolvedAt); err != nil {
|
||||||
|
return PendingApproval{}, err
|
||||||
|
}
|
||||||
|
return approval, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func boolInt(value bool) int {
|
||||||
|
if value {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
137
internal/store/store_test.go
Normal file
137
internal/store/store_test.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStoreUsersWorkspacesSessions(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
st, err := Open(ctx, filepath.Join(t.TempDir(), "bot.db"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
allowed, err := st.IsAllowed(ctx, 42)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if allowed {
|
||||||
|
t.Fatal("new user should not be allowed")
|
||||||
|
}
|
||||||
|
if err := st.AddAllowedUser(ctx, 42, "alice", "owner"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
allowed, err = st.IsAllowed(ctx, 42)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !allowed {
|
||||||
|
t.Fatal("user should be allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
workspacePath := t.TempDir()
|
||||||
|
ws, err := st.AddWorkspace(ctx, workspacePath, "repo", true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !ws.IsDefault {
|
||||||
|
t.Fatal("workspace should be default")
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := st.GetOrCreateSession(ctx, 42, "test-model", "read-only")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if session.Model != "test-model" || session.Sandbox != "read-only" || session.ReasoningEffort != "" {
|
||||||
|
t.Fatalf("unexpected session defaults: %+v", session)
|
||||||
|
}
|
||||||
|
if err := st.SetSessionWorkspace(ctx, 42, ws.ID); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
effort := "value-returned-by-server"
|
||||||
|
if err := st.SetSessionReasoningEffort(ctx, 42, effort); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
session, err = st.GetSession(ctx, 42)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if session.ActiveWorkspaceID != ws.ID || session.ReasoningEffort != effort {
|
||||||
|
t.Fatalf("workspace not saved: %+v", session)
|
||||||
|
}
|
||||||
|
if err := st.SetSessionSettingsMessage(ctx, 42, 1001, 2002); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
session, err = st.GetSession(ctx, 42)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if session.SettingsChatID != 1001 || session.SettingsMessageID != 2002 {
|
||||||
|
t.Fatalf("settings message not saved: %+v", session)
|
||||||
|
}
|
||||||
|
if err := st.SetActiveTurn(ctx, 42, "turn-123"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := st.ClearActiveTurns(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
session, err = st.GetSession(ctx, 42)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if session.ActiveTurnID != "" {
|
||||||
|
t.Fatalf("active turn not cleared: %+v", session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListThreadsPage(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
st, err := Open(ctx, filepath.Join(t.TempDir(), "bot.db"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
ws, err := st.AddWorkspace(ctx, t.TempDir(), "repo", true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
if _, err := st.CreateThread(ctx, 42, string(rune('a'+i)), ws.ID, "thread"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
threads, err := st.ListThreadsPage(ctx, 42, false, 2, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(threads) != 2 {
|
||||||
|
t.Fatalf("got %d threads, want 2", len(threads))
|
||||||
|
}
|
||||||
|
threads, err = st.ListThreadsPage(ctx, 42, false, 2, 2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(threads) != 1 {
|
||||||
|
t.Fatalf("got %d threads on second page, want 1", len(threads))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateWorkspacePath(t *testing.T) {
|
||||||
|
if _, err := ValidateWorkspacePath("relative/path"); err == nil {
|
||||||
|
t.Fatal("relative path should be rejected")
|
||||||
|
}
|
||||||
|
if _, err := ValidateWorkspacePath("/"); err == nil {
|
||||||
|
t.Fatal("filesystem root should be rejected")
|
||||||
|
}
|
||||||
|
clean, err := ValidateWorkspacePath("/tmp/../tmp/project")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if clean != "/tmp/project" {
|
||||||
|
t.Fatalf("unexpected clean path: %s", clean)
|
||||||
|
}
|
||||||
|
}
|
||||||
211
internal/telegram/api.go
Normal file
211
internal/telegram/api.go
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
package telegram
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
token string
|
||||||
|
baseURL string
|
||||||
|
fileBaseURL string
|
||||||
|
httpClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(token string) *Client {
|
||||||
|
return &Client{
|
||||||
|
token: token,
|
||||||
|
baseURL: "https://api.telegram.org/bot" + token,
|
||||||
|
fileBaseURL: "https://api.telegram.org/file/bot" + token,
|
||||||
|
httpClient: &http.Client{Timeout: 90 * time.Second},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetUpdates(ctx context.Context, offset int, timeoutSeconds int) ([]Update, error) {
|
||||||
|
params := map[string]any{
|
||||||
|
"offset": offset,
|
||||||
|
"timeout": timeoutSeconds,
|
||||||
|
"allowed_updates": []string{"message", "callback_query"},
|
||||||
|
}
|
||||||
|
var updates []Update
|
||||||
|
if err := c.postJSON(ctx, "getUpdates", params, &updates); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return updates, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SendMessage(ctx context.Context, chatID int64, text string, opts SendMessageOptions) (Message, error) {
|
||||||
|
params := map[string]any{
|
||||||
|
"chat_id": chatID,
|
||||||
|
"text": text,
|
||||||
|
}
|
||||||
|
if opts.ParseMode != "" {
|
||||||
|
params["parse_mode"] = opts.ParseMode
|
||||||
|
}
|
||||||
|
if opts.ReplyMarkup != nil {
|
||||||
|
params["reply_markup"] = opts.ReplyMarkup
|
||||||
|
}
|
||||||
|
var message Message
|
||||||
|
if err := c.postJSON(ctx, "sendMessage", params, &message); err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) EditMessageText(ctx context.Context, chatID int64, messageID int, text string, opts EditMessageTextOptions) (Message, error) {
|
||||||
|
params := map[string]any{
|
||||||
|
"chat_id": chatID,
|
||||||
|
"message_id": messageID,
|
||||||
|
"text": text,
|
||||||
|
}
|
||||||
|
if opts.ParseMode != "" {
|
||||||
|
params["parse_mode"] = opts.ParseMode
|
||||||
|
}
|
||||||
|
if opts.ReplyMarkup != nil {
|
||||||
|
params["reply_markup"] = opts.ReplyMarkup
|
||||||
|
}
|
||||||
|
var message Message
|
||||||
|
if err := c.postJSON(ctx, "editMessageText", params, &message); err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) PinChatMessage(ctx context.Context, chatID int64, messageID int, disableNotification bool) error {
|
||||||
|
params := map[string]any{
|
||||||
|
"chat_id": chatID,
|
||||||
|
"message_id": messageID,
|
||||||
|
"disable_notification": disableNotification,
|
||||||
|
}
|
||||||
|
var ignored bool
|
||||||
|
return c.postJSON(ctx, "pinChatMessage", params, &ignored)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AnswerCallbackQuery(ctx context.Context, callbackQueryID, text string) error {
|
||||||
|
params := map[string]any{
|
||||||
|
"callback_query_id": callbackQueryID,
|
||||||
|
}
|
||||||
|
if text != "" {
|
||||||
|
params["text"] = text
|
||||||
|
}
|
||||||
|
var ignored bool
|
||||||
|
return c.postJSON(ctx, "answerCallbackQuery", params, &ignored)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetFile(ctx context.Context, fileID string) (File, error) {
|
||||||
|
var file File
|
||||||
|
if err := c.postJSON(ctx, "getFile", map[string]any{"file_id": fileID}, &file); err != nil {
|
||||||
|
return File{}, err
|
||||||
|
}
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DownloadFile(ctx context.Context, filePath string) ([]byte, error) {
|
||||||
|
u := c.fileBaseURL + "/" + url.PathEscape(filePath)
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
return nil, fmt.Errorf("download file: telegram returned %s", resp.Status)
|
||||||
|
}
|
||||||
|
return io.ReadAll(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SendDocumentBytes(ctx context.Context, chatID int64, filename string, data []byte, caption string) (Message, error) {
|
||||||
|
var body bytes.Buffer
|
||||||
|
writer := multipart.NewWriter(&body)
|
||||||
|
if err := writer.WriteField("chat_id", fmt.Sprint(chatID)); err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
if caption != "" {
|
||||||
|
if err := writer.WriteField("caption", caption); err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
part, err := writer.CreateFormFile("document", filepath.Base(filename))
|
||||||
|
if err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
if _, err := part.Write(data); err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
if err := writer.Close(); err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/sendDocument", &body)
|
||||||
|
if err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
payload, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
|
||||||
|
return Message{}, fmt.Errorf("sendDocument: telegram returned %s: %s", resp.Status, string(payload))
|
||||||
|
}
|
||||||
|
var decoded apiResponse[Message]
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&decoded); err != nil {
|
||||||
|
return Message{}, err
|
||||||
|
}
|
||||||
|
if !decoded.OK {
|
||||||
|
return Message{}, fmt.Errorf("sendDocument: telegram error %d: %s", decoded.ErrorCode, decoded.Description)
|
||||||
|
}
|
||||||
|
return decoded.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) postJSON(ctx context.Context, method string, params any, result any) error {
|
||||||
|
body, err := json.Marshal(params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/"+method, bytes.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
payload, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
|
||||||
|
return fmt.Errorf("%s: telegram returned %s: %s", method, resp.Status, string(payload))
|
||||||
|
}
|
||||||
|
var decoded apiResponse[json.RawMessage]
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&decoded); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !decoded.OK {
|
||||||
|
return fmt.Errorf("%s: telegram error %d: %s", method, decoded.ErrorCode, decoded.Description)
|
||||||
|
}
|
||||||
|
if result == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return json.Unmarshal(decoded.Result, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
type apiResponse[T any] struct {
|
||||||
|
OK bool `json:"ok"`
|
||||||
|
Result T `json:"result"`
|
||||||
|
ErrorCode int `json:"error_code,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
}
|
||||||
1760
internal/telegram/bot.go
Normal file
1760
internal/telegram/bot.go
Normal file
File diff suppressed because it is too large
Load Diff
26
internal/telegram/download.go
Normal file
26
internal/telegram/download.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package telegram
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Client) DownloadFilePath(ctx context.Context, filePath string) ([]byte, error) {
|
||||||
|
u := c.fileBaseURL + "/" + strings.TrimLeft(filePath, "/")
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
return nil, fmt.Errorf("download file: telegram returned %s", resp.Status)
|
||||||
|
}
|
||||||
|
return io.ReadAll(resp.Body)
|
||||||
|
}
|
||||||
183
internal/telegram/render.go
Normal file
183
internal/telegram/render.go
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
package telegram
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"html"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const TelegramMessageLimit = 4096
|
||||||
|
const TelegramHTMLMessageLimit = 3900
|
||||||
|
|
||||||
|
func EscapeHTML(text string) string {
|
||||||
|
return html.EscapeString(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SummaryDetailsHTML(summary, details string) string {
|
||||||
|
summary = strings.TrimSpace(summary)
|
||||||
|
details = strings.TrimSpace(details)
|
||||||
|
if details == "" {
|
||||||
|
return EscapeHTML(summary)
|
||||||
|
}
|
||||||
|
if summary == "" {
|
||||||
|
return ExpandableQuoteHTML(details)
|
||||||
|
}
|
||||||
|
return EscapeHTML(summary) + "\n" + ExpandableQuoteHTML(details)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExpandableQuoteHTML(text string) string {
|
||||||
|
text = strings.TrimSpace(text)
|
||||||
|
if text == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return "<blockquote expandable>" + EscapeHTML(text) + "</blockquote>"
|
||||||
|
}
|
||||||
|
|
||||||
|
func SummaryDetailsHTMLLimited(summary, details string, limit int) string {
|
||||||
|
if limit <= 0 {
|
||||||
|
limit = TelegramHTMLMessageLimit
|
||||||
|
}
|
||||||
|
summary = strings.TrimSpace(summary)
|
||||||
|
details = strings.TrimSpace(details)
|
||||||
|
out := SummaryDetailsHTML(summary, details)
|
||||||
|
if len([]rune(out)) <= limit || details == "" {
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
suffix := "\n...[truncated]"
|
||||||
|
runes := []rune(details)
|
||||||
|
for len(runes) > 0 {
|
||||||
|
candidateLen := len(runes) - max(1, (len([]rune(out))-limit)/2)
|
||||||
|
if candidateLen < 0 {
|
||||||
|
candidateLen = 0
|
||||||
|
}
|
||||||
|
if candidateLen > len(runes) {
|
||||||
|
candidateLen = len(runes)
|
||||||
|
}
|
||||||
|
candidate := strings.TrimSpace(string(runes[:candidateLen])) + suffix
|
||||||
|
out = SummaryDetailsHTML(summary, candidate)
|
||||||
|
if len([]rune(out)) <= limit || candidateLen == 0 {
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
runes = runes[:candidateLen]
|
||||||
|
}
|
||||||
|
return SummaryDetailsHTML(summary, suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChunkText(text string, max int) []string {
|
||||||
|
if max <= 0 {
|
||||||
|
max = TelegramMessageLimit
|
||||||
|
}
|
||||||
|
runes := []rune(text)
|
||||||
|
if len(runes) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var chunks []string
|
||||||
|
for len(runes) > max {
|
||||||
|
cut := max
|
||||||
|
for i := max; i > max/2; i-- {
|
||||||
|
if runes[i-1] == '\n' {
|
||||||
|
cut = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chunks = append(chunks, string(runes[:cut]))
|
||||||
|
runes = runes[cut:]
|
||||||
|
}
|
||||||
|
if len(runes) > 0 {
|
||||||
|
chunks = append(chunks, string(runes))
|
||||||
|
}
|
||||||
|
return chunks
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApprovalCallbackData(id int64, decision string) string {
|
||||||
|
return fmt.Sprintf("approval:%d:%s", id, decision)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseApprovalCallbackData(data string) (int64, string, bool) {
|
||||||
|
parts := strings.Split(data, ":")
|
||||||
|
if len(parts) != 3 || parts[0] != "approval" {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
id, err := strconv.ParseInt(parts[1], 10, 64)
|
||||||
|
if err != nil || id <= 0 {
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
switch parts[2] {
|
||||||
|
case "accept", "acceptForSession", "decline", "cancel", "details":
|
||||||
|
return id, parts[2], true
|
||||||
|
default:
|
||||||
|
return 0, "", false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WorkspaceCallbackData(id int64) string {
|
||||||
|
return fmt.Sprintf("workspace:%d", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseWorkspaceCallbackData(data string) (int64, bool) {
|
||||||
|
if !strings.HasPrefix(data, "workspace:") {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
id, err := strconv.ParseInt(strings.TrimPrefix(data, "workspace:"), 10, 64)
|
||||||
|
return id, err == nil && id > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResumeThreadCallbackData(id int64) string {
|
||||||
|
return fmt.Sprintf("resume:thread:%d", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseResumeThreadCallbackData(data string) (int64, bool) {
|
||||||
|
if !strings.HasPrefix(data, "resume:thread:") {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
id, err := strconv.ParseInt(strings.TrimPrefix(data, "resume:thread:"), 10, 64)
|
||||||
|
return id, err == nil && id > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResumePageCallbackData(page int) string {
|
||||||
|
return fmt.Sprintf("resume:page:%d", page)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseResumePageCallbackData(data string) (int, bool) {
|
||||||
|
if !strings.HasPrefix(data, "resume:page:") {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
page, err := strconv.Atoi(strings.TrimPrefix(data, "resume:page:"))
|
||||||
|
return page, err == nil && page >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func ModelCallbackData(modelID string) (string, bool) {
|
||||||
|
encoded := base64.RawURLEncoding.EncodeToString([]byte(modelID))
|
||||||
|
data := "model:" + encoded
|
||||||
|
return data, len([]rune(data)) <= 64
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseModelCallbackData(data string) (string, bool) {
|
||||||
|
if !strings.HasPrefix(data, "model:") {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
decoded, err := base64.RawURLEncoding.DecodeString(strings.TrimPrefix(data, "model:"))
|
||||||
|
if err != nil || len(decoded) == 0 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return string(decoded), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func EffortCallbackData(effort string) string {
|
||||||
|
encoded := base64.RawURLEncoding.EncodeToString([]byte(effort))
|
||||||
|
return "effort:" + encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseEffortCallbackData(data string) (string, bool) {
|
||||||
|
if !strings.HasPrefix(data, "effort:") {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
decoded, err := base64.RawURLEncoding.DecodeString(strings.TrimPrefix(data, "effort:"))
|
||||||
|
if err != nil || len(decoded) == 0 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return string(decoded), true
|
||||||
|
}
|
||||||
152
internal/telegram/render_test.go
Normal file
152
internal/telegram/render_test.go
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
package telegram
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"codex-telegram-bot/internal/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEscapeHTML(t *testing.T) {
|
||||||
|
got := EscapeHTML(`<run & "test">`)
|
||||||
|
want := "<run & "test">"
|
||||||
|
if got != want {
|
||||||
|
t.Fatalf("EscapeHTML() = %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChunkText(t *testing.T) {
|
||||||
|
text := strings.Repeat("a", 25)
|
||||||
|
chunks := ChunkText(text, 10)
|
||||||
|
if len(chunks) != 3 {
|
||||||
|
t.Fatalf("got %d chunks", len(chunks))
|
||||||
|
}
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
if len([]rune(chunk)) > 10 {
|
||||||
|
t.Fatalf("chunk too long: %q", chunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApprovalCallbackData(t *testing.T) {
|
||||||
|
data := ApprovalCallbackData(12, "accept")
|
||||||
|
id, decision, ok := ParseApprovalCallbackData(data)
|
||||||
|
if !ok || id != 12 || decision != "accept" {
|
||||||
|
t.Fatalf("unexpected callback parse: id=%d decision=%s ok=%v", id, decision, ok)
|
||||||
|
}
|
||||||
|
if _, _, ok := ParseApprovalCallbackData("approval:12:unknown"); ok {
|
||||||
|
t.Fatal("unknown decisions should be rejected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApprovalResponseForPermissions(t *testing.T) {
|
||||||
|
approval := store.PendingApproval{
|
||||||
|
Kind: "item/permissions/requestApproval",
|
||||||
|
PayloadJSON: `{"permissions":{"network":{"enabled":true}}}`,
|
||||||
|
}
|
||||||
|
response, ok := approvalResponse(approval, "accept").(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("approval response should be a map")
|
||||||
|
}
|
||||||
|
if response["scope"] != "turn" {
|
||||||
|
t.Fatalf("scope = %v, want turn", response["scope"])
|
||||||
|
}
|
||||||
|
permissions, ok := response["permissions"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("permissions should be a map")
|
||||||
|
}
|
||||||
|
network, ok := permissions["network"].(map[string]any)
|
||||||
|
if !ok || network["enabled"] != true {
|
||||||
|
t.Fatalf("unexpected permissions: %#v", permissions)
|
||||||
|
}
|
||||||
|
|
||||||
|
denied, ok := approvalResponse(approval, "decline").(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("denied response should be a map")
|
||||||
|
}
|
||||||
|
deniedPermissions, ok := denied["permissions"].(map[string]any)
|
||||||
|
if !ok || len(deniedPermissions) != 0 {
|
||||||
|
t.Fatalf("denied permissions = %#v, want empty map", denied["permissions"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseCommand(t *testing.T) {
|
||||||
|
name, args, ok := parseCommand("/resume@my_bot 123")
|
||||||
|
if !ok || name != "resume" || len(args) != 1 || args[0] != "123" {
|
||||||
|
t.Fatalf("unexpected command parse: %q %#v %v", name, args, ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRenderCodexCommandExecutionItem(t *testing.T) {
|
||||||
|
output := "line 1\nline 2"
|
||||||
|
exitCode := 0
|
||||||
|
item := codexThreadItemView{
|
||||||
|
Type: "commandExecution",
|
||||||
|
Command: "go test ./...",
|
||||||
|
AggregatedOutput: &output,
|
||||||
|
ExitCode: &exitCode,
|
||||||
|
}
|
||||||
|
text := renderCodexItemCompleted(item)
|
||||||
|
for _, want := range []string{"Tool call: command finished", "Command: go test ./...", "Exit code: 0", "line 1"} {
|
||||||
|
if !strings.Contains(text, want) {
|
||||||
|
t.Fatalf("rendered command item missing %q in %q", want, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRenderCodexStartedItems(t *testing.T) {
|
||||||
|
text := renderCodexItemStarted(codexThreadItemView{Type: "webSearch", Query: "telegram bot api"})
|
||||||
|
if !strings.Contains(text, "web search started") || !strings.Contains(text, "telegram bot api") {
|
||||||
|
t.Fatalf("unexpected web search render: %q", text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResumeCallbackData(t *testing.T) {
|
||||||
|
threadID, ok := ParseResumeThreadCallbackData(ResumeThreadCallbackData(123))
|
||||||
|
if !ok || threadID != 123 {
|
||||||
|
t.Fatalf("unexpected resume thread callback: id=%d ok=%v", threadID, ok)
|
||||||
|
}
|
||||||
|
page, ok := ParseResumePageCallbackData(ResumePageCallbackData(2))
|
||||||
|
if !ok || page != 2 {
|
||||||
|
t.Fatalf("unexpected resume page callback: page=%d ok=%v", page, ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResumeThreadListText(t *testing.T) {
|
||||||
|
threads := []store.Thread{{ID: 42, Title: "do xyz"}, {ID: 43, Title: "executed xxx command"}}
|
||||||
|
text := resumeThreadListText(threads, 0)
|
||||||
|
for _, want := range []string{"Thread ID 42: do xyz", "Thread ID 43: executed xxx command"} {
|
||||||
|
if !strings.Contains(text, want) {
|
||||||
|
t.Fatalf("resume list missing %q in %q", want, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
markup := resumeThreadMarkup(threads, 0, true)
|
||||||
|
if len(markup.InlineKeyboard) != 2 || markup.InlineKeyboard[0][0].Text != "ID 42" || markup.InlineKeyboard[0][1].Text != "ID 43" {
|
||||||
|
t.Fatalf("unexpected resume buttons: %#v", markup.InlineKeyboard)
|
||||||
|
}
|
||||||
|
firstID, ok := ParseResumeThreadCallbackData(markup.InlineKeyboard[0][0].CallbackData)
|
||||||
|
if !ok || firstID != 42 {
|
||||||
|
t.Fatalf("first resume button targets id=%d ok=%v", firstID, ok)
|
||||||
|
}
|
||||||
|
secondID, ok := ParseResumeThreadCallbackData(markup.InlineKeyboard[0][1].CallbackData)
|
||||||
|
if !ok || secondID != 43 {
|
||||||
|
t.Fatalf("second resume button targets id=%d ok=%v", secondID, ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModelAndEffortCallbackData(t *testing.T) {
|
||||||
|
modelID := strings.Join([]string{"server", "model", "id"}, "-")
|
||||||
|
data, ok := ModelCallbackData(modelID)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("model callback should fit")
|
||||||
|
}
|
||||||
|
model, ok := ParseModelCallbackData(data)
|
||||||
|
if !ok || model != modelID {
|
||||||
|
t.Fatalf("unexpected model callback parse: model=%q ok=%v", model, ok)
|
||||||
|
}
|
||||||
|
effortName := strings.Join([]string{"server", "effort"}, "-")
|
||||||
|
effort, ok := ParseEffortCallbackData(EffortCallbackData(effortName))
|
||||||
|
if !ok || effort != effortName {
|
||||||
|
t.Fatalf("unexpected effort callback parse: effort=%q ok=%v", effort, ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
76
internal/telegram/types.go
Normal file
76
internal/telegram/types.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package telegram
|
||||||
|
|
||||||
|
type Update struct {
|
||||||
|
UpdateID int `json:"update_id"`
|
||||||
|
Message *Message `json:"message,omitempty"`
|
||||||
|
CallbackQuery *CallbackQuery `json:"callback_query,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
IsBot bool `json:"is_bot"`
|
||||||
|
FirstName string `json:"first_name,omitempty"`
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Chat struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
MessageID int `json:"message_id"`
|
||||||
|
From *User `json:"from,omitempty"`
|
||||||
|
Chat Chat `json:"chat"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
Caption string `json:"caption,omitempty"`
|
||||||
|
Document *Document `json:"document,omitempty"`
|
||||||
|
Photo []PhotoSize `json:"photo,omitempty"`
|
||||||
|
PinnedMessage *Message `json:"pinned_message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Document struct {
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
FileName string `json:"file_name,omitempty"`
|
||||||
|
MimeType string `json:"mime_type,omitempty"`
|
||||||
|
FileSize int64 `json:"file_size,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PhotoSize struct {
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
FileSize int64 `json:"file_size,omitempty"`
|
||||||
|
Width int `json:"width"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CallbackQuery struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
From User `json:"from"`
|
||||||
|
Message *Message `json:"message,omitempty"`
|
||||||
|
Data string `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
FilePath string `json:"file_path,omitempty"`
|
||||||
|
FileSize int64 `json:"file_size,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InlineKeyboardMarkup struct {
|
||||||
|
InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InlineKeyboardButton struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
CallbackData string `json:"callback_data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SendMessageOptions struct {
|
||||||
|
ParseMode string `json:"parse_mode,omitempty"`
|
||||||
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type EditMessageTextOptions struct {
|
||||||
|
ParseMode string `json:"parse_mode,omitempty"`
|
||||||
|
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||||
|
}
|
||||||
114
schemas/ApplyPatchApprovalParams.json
Normal file
114
schemas/ApplyPatchApprovalParams.json
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ApplyPatchApprovalParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"callId",
|
||||||
|
"conversationId",
|
||||||
|
"fileChanges"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"callId": {
|
||||||
|
"description": "Use to correlate this with [codex_protocol::protocol::PatchApplyBeginEvent] and [codex_protocol::protocol::PatchApplyEndEvent].",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"conversationId": {
|
||||||
|
"$ref": "#/definitions/ThreadId"
|
||||||
|
},
|
||||||
|
"fileChanges": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/FileChange"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"grantRoot": {
|
||||||
|
"description": "When set, the agent is asking the user to allow writes under this root for the remainder of the session (unclear if this is honored today).",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
"description": "Optional explanatory reason (e.g. request for extra write access).",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"FileChange": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"content",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"content": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"add"
|
||||||
|
],
|
||||||
|
"title": "AddFileChangeType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "AddFileChange"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"content",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"content": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"delete"
|
||||||
|
],
|
||||||
|
"title": "DeleteFileChangeType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "DeleteFileChange"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"unified_diff"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"move_path": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"update"
|
||||||
|
],
|
||||||
|
"title": "UpdateFileChangeType"
|
||||||
|
},
|
||||||
|
"unified_diff": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "UpdateFileChange"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ThreadId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
124
schemas/ApplyPatchApprovalResponse.json
Normal file
124
schemas/ApplyPatchApprovalResponse.json
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ApplyPatchApprovalResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"decision"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"decision": {
|
||||||
|
"$ref": "#/definitions/ReviewDecision"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"NetworkPolicyAmendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"action",
|
||||||
|
"host"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"action": {
|
||||||
|
"$ref": "#/definitions/NetworkPolicyRuleAction"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NetworkPolicyRuleAction": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"allow",
|
||||||
|
"deny"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ReviewDecision": {
|
||||||
|
"description": "User's decision in response to an ExecApprovalRequest.",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "User has approved this command and the agent should execute it.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"approved"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User has approved this command and wants to apply the proposed execpolicy amendment so future matching commands are permitted.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"approved_execpolicy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"approved_execpolicy_amendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"proposed_execpolicy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"proposed_execpolicy_amendment": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "ApprovedExecpolicyAmendmentReviewDecision"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User has approved this request and wants future prompts in the same session-scoped approval cache to be automatically approved for the remainder of the session.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"approved_for_session"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User chose to persist a network policy rule (allow/deny) for future requests to the same host.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"network_policy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"network_policy_amendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"network_policy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"network_policy_amendment": {
|
||||||
|
"$ref": "#/definitions/NetworkPolicyAmendment"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "NetworkPolicyAmendmentReviewDecision"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User has denied this command and the agent should not execute it, but it should continue the session and try something else.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"denied"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Automatic approval review timed out before reaching a decision.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"timed_out"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User has denied this command and the agent should not do anything until the user's next command.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"abort"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
schemas/AttestationGenerateParams.json
Normal file
5
schemas/AttestationGenerateParams.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AttestationGenerateParams",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
14
schemas/AttestationGenerateResponse.json
Normal file
14
schemas/AttestationGenerateResponse.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AttestationGenerateResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"token"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"token": {
|
||||||
|
"description": "Opaque client attestation token.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
schemas/ChatgptAuthTokensRefreshParams.json
Normal file
33
schemas/ChatgptAuthTokensRefreshParams.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ChatgptAuthTokensRefreshParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"reason"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"previousAccountId": {
|
||||||
|
"description": "Workspace/account identifier that Codex was previously using.\n\nClients that manage multiple accounts/workspaces can use this as a hint to refresh the token for the correct workspace.\n\nThis may be `null` when the prior auth state did not include a workspace identifier (`chatgpt_account_id`).",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
"$ref": "#/definitions/ChatgptAuthTokensRefreshReason"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"ChatgptAuthTokensRefreshReason": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Codex attempted a backend request and received `401 Unauthorized`.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"unauthorized"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
schemas/ChatgptAuthTokensRefreshResponse.json
Normal file
23
schemas/ChatgptAuthTokensRefreshResponse.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ChatgptAuthTokensRefreshResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"accessToken",
|
||||||
|
"chatgptAccountId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"accessToken": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"chatgptAccountId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"chatgptPlanType": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
schemas/ClientNotification.json
Normal file
22
schemas/ClientNotification.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ClientNotification",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"method"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"method": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"initialized"
|
||||||
|
],
|
||||||
|
"title": "InitializedNotificationMethod"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "InitializedNotification"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
5972
schemas/ClientRequest.json
Normal file
5972
schemas/ClientRequest.json
Normal file
File diff suppressed because it is too large
Load Diff
616
schemas/CommandExecutionRequestApprovalParams.json
Normal file
616
schemas/CommandExecutionRequestApprovalParams.json
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecutionRequestApprovalParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"itemId",
|
||||||
|
"startedAtMs",
|
||||||
|
"threadId",
|
||||||
|
"turnId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"turnId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"approvalId": {
|
||||||
|
"description": "Unique identifier for this specific approval callback.\n\nFor regular shell/unified_exec approvals, this is null.\n\nFor zsh-exec-bridge subcommand approvals, multiple callbacks can belong to one parent `itemId`, so `approvalId` is a distinct opaque callback id (a UUID) used to disambiguate routing.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"command": {
|
||||||
|
"description": "The command to be executed.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"commandActions": {
|
||||||
|
"description": "Best-effort parsed command actions for friendly display.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/CommandAction"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cwd": {
|
||||||
|
"description": "The command's working directory.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"itemId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"networkApprovalContext": {
|
||||||
|
"description": "Optional context for a managed-network approval prompt.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/NetworkApprovalContext"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"proposedExecpolicyAmendment": {
|
||||||
|
"description": "Optional proposed execpolicy amendment to allow similar commands without prompting.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"proposedNetworkPolicyAmendments": {
|
||||||
|
"description": "Optional proposed network policy amendments (allow/deny host) for future requests.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/NetworkPolicyAmendment"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
"description": "Optional explanatory reason (e.g. request for network access).",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"startedAtMs": {
|
||||||
|
"description": "Unix timestamp (in milliseconds) when this approval request started.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AbsolutePathBuf": {
|
||||||
|
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"AdditionalFileSystemPermissions": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"entries": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/FileSystemSandboxEntry"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"globScanMaxDepth": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 1.0
|
||||||
|
},
|
||||||
|
"read": {
|
||||||
|
"description": "This will be removed in favor of `entries`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"write": {
|
||||||
|
"description": "This will be removed in favor of `entries`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AdditionalNetworkPermissions": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AdditionalPermissionProfile": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"fileSystem": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AdditionalFileSystemPermissions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"network": {
|
||||||
|
"description": "Partial overlay used for per-command permission requests.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AdditionalNetworkPermissions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CommandAction": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"command",
|
||||||
|
"name",
|
||||||
|
"path",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"read"
|
||||||
|
],
|
||||||
|
"title": "ReadCommandActionType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ReadCommandAction"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"command",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"listFiles"
|
||||||
|
],
|
||||||
|
"title": "ListFilesCommandActionType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ListFilesCommandAction"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"command",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"search"
|
||||||
|
],
|
||||||
|
"title": "SearchCommandActionType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SearchCommandAction"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"command",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"unknown"
|
||||||
|
],
|
||||||
|
"title": "UnknownCommandActionType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "UnknownCommandAction"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"CommandExecutionApprovalDecision": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "User approved the command.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"accept"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User approved the command and future prompts in the same session-scoped approval cache should run without prompting.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"acceptForSession"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User approved the command, and wants to apply the proposed execpolicy amendment so future matching commands can run without prompting.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"acceptWithExecpolicyAmendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"acceptWithExecpolicyAmendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"execpolicy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"execpolicy_amendment": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "AcceptWithExecpolicyAmendmentCommandExecutionApprovalDecision"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User chose a persistent network policy rule (allow/deny) for this host.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"applyNetworkPolicyAmendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"applyNetworkPolicyAmendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"network_policy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"network_policy_amendment": {
|
||||||
|
"$ref": "#/definitions/NetworkPolicyAmendment"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "ApplyNetworkPolicyAmendmentCommandExecutionApprovalDecision"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User denied the command. The agent will continue the turn.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"decline"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User denied the command. The turn will also be immediately interrupted.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"cancel"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FileSystemAccessMode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"read",
|
||||||
|
"write",
|
||||||
|
"none"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FileSystemPath": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"path",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"title": "PathFileSystemPathType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "PathFileSystemPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"pattern",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"pattern": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"glob_pattern"
|
||||||
|
],
|
||||||
|
"title": "GlobPatternFileSystemPathType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "GlobPatternFileSystemPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"special"
|
||||||
|
],
|
||||||
|
"title": "SpecialFileSystemPathType"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"$ref": "#/definitions/FileSystemSpecialPath"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SpecialFileSystemPath"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FileSystemSandboxEntry": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"access",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"access": {
|
||||||
|
"$ref": "#/definitions/FileSystemAccessMode"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"$ref": "#/definitions/FileSystemPath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FileSystemSpecialPath": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"root"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "RootFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"minimal"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "MinimalFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"project_roots"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subpath": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "KindFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"tmpdir"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "TmpdirFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"slash_tmp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SlashTmpFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"unknown"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"subpath": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"NetworkApprovalContext": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"host",
|
||||||
|
"protocol"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"protocol": {
|
||||||
|
"$ref": "#/definitions/NetworkApprovalProtocol"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NetworkApprovalProtocol": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"http",
|
||||||
|
"https",
|
||||||
|
"socks5Tcp",
|
||||||
|
"socks5Udp"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"NetworkPolicyAmendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"action",
|
||||||
|
"host"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"action": {
|
||||||
|
"$ref": "#/definitions/NetworkPolicyRuleAction"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NetworkPolicyRuleAction": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"allow",
|
||||||
|
"deny"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
116
schemas/CommandExecutionRequestApprovalResponse.json
Normal file
116
schemas/CommandExecutionRequestApprovalResponse.json
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecutionRequestApprovalResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"decision"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"decision": {
|
||||||
|
"$ref": "#/definitions/CommandExecutionApprovalDecision"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"CommandExecutionApprovalDecision": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "User approved the command.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"accept"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User approved the command and future prompts in the same session-scoped approval cache should run without prompting.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"acceptForSession"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User approved the command, and wants to apply the proposed execpolicy amendment so future matching commands can run without prompting.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"acceptWithExecpolicyAmendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"acceptWithExecpolicyAmendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"execpolicy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"execpolicy_amendment": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "AcceptWithExecpolicyAmendmentCommandExecutionApprovalDecision"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User chose a persistent network policy rule (allow/deny) for this host.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"applyNetworkPolicyAmendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"applyNetworkPolicyAmendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"network_policy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"network_policy_amendment": {
|
||||||
|
"$ref": "#/definitions/NetworkPolicyAmendment"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "ApplyNetworkPolicyAmendmentCommandExecutionApprovalDecision"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User denied the command. The agent will continue the turn.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"decline"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User denied the command. The turn will also be immediately interrupted.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"cancel"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"NetworkPolicyAmendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"action",
|
||||||
|
"host"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"action": {
|
||||||
|
"$ref": "#/definitions/NetworkPolicyRuleAction"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NetworkPolicyRuleAction": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"allow",
|
||||||
|
"deny"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
schemas/DynamicToolCallParams.json
Normal file
33
schemas/DynamicToolCallParams.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "DynamicToolCallParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"arguments",
|
||||||
|
"callId",
|
||||||
|
"threadId",
|
||||||
|
"tool",
|
||||||
|
"turnId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"arguments": true,
|
||||||
|
"callId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"namespace": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tool": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"turnId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
66
schemas/DynamicToolCallResponse.json
Normal file
66
schemas/DynamicToolCallResponse.json
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "DynamicToolCallResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"contentItems",
|
||||||
|
"success"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"contentItems": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/DynamicToolCallOutputContentItem"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"DynamicToolCallOutputContentItem": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"text",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"text": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"inputText"
|
||||||
|
],
|
||||||
|
"title": "InputTextDynamicToolCallOutputContentItemType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "InputTextDynamicToolCallOutputContentItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"imageUrl",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"imageUrl": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"inputImage"
|
||||||
|
],
|
||||||
|
"title": "InputImageDynamicToolCallOutputContentItemType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "InputImageDynamicToolCallOutputContentItem"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
165
schemas/ExecCommandApprovalParams.json
Normal file
165
schemas/ExecCommandApprovalParams.json
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExecCommandApprovalParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"callId",
|
||||||
|
"command",
|
||||||
|
"conversationId",
|
||||||
|
"cwd",
|
||||||
|
"parsedCmd"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"approvalId": {
|
||||||
|
"description": "Identifier for this specific approval callback.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"callId": {
|
||||||
|
"description": "Use to correlate this with [codex_protocol::protocol::ExecCommandBeginEvent] and [codex_protocol::protocol::ExecCommandEndEvent].",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"command": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conversationId": {
|
||||||
|
"$ref": "#/definitions/ThreadId"
|
||||||
|
},
|
||||||
|
"cwd": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"parsedCmd": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ParsedCommand"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"ParsedCommand": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"cmd",
|
||||||
|
"name",
|
||||||
|
"path",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cmd": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"description": "(Best effort) Path to the file being read by the command. When possible, this is an absolute path, though when relative, it should be resolved against the `cwd`` that will be used to run the command to derive the absolute path.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"read"
|
||||||
|
],
|
||||||
|
"title": "ReadParsedCommandType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ReadParsedCommand"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"cmd",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cmd": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"list_files"
|
||||||
|
],
|
||||||
|
"title": "ListFilesParsedCommandType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ListFilesParsedCommand"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"cmd",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cmd": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"search"
|
||||||
|
],
|
||||||
|
"title": "SearchParsedCommandType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SearchParsedCommand"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"cmd",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cmd": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"unknown"
|
||||||
|
],
|
||||||
|
"title": "UnknownParsedCommandType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "UnknownParsedCommand"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ThreadId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
124
schemas/ExecCommandApprovalResponse.json
Normal file
124
schemas/ExecCommandApprovalResponse.json
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExecCommandApprovalResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"decision"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"decision": {
|
||||||
|
"$ref": "#/definitions/ReviewDecision"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"NetworkPolicyAmendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"action",
|
||||||
|
"host"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"action": {
|
||||||
|
"$ref": "#/definitions/NetworkPolicyRuleAction"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NetworkPolicyRuleAction": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"allow",
|
||||||
|
"deny"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ReviewDecision": {
|
||||||
|
"description": "User's decision in response to an ExecApprovalRequest.",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "User has approved this command and the agent should execute it.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"approved"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User has approved this command and wants to apply the proposed execpolicy amendment so future matching commands are permitted.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"approved_execpolicy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"approved_execpolicy_amendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"proposed_execpolicy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"proposed_execpolicy_amendment": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "ApprovedExecpolicyAmendmentReviewDecision"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User has approved this request and wants future prompts in the same session-scoped approval cache to be automatically approved for the remainder of the session.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"approved_for_session"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User chose to persist a network policy rule (allow/deny) for future requests to the same host.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"network_policy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"network_policy_amendment": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"network_policy_amendment"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"network_policy_amendment": {
|
||||||
|
"$ref": "#/definitions/NetworkPolicyAmendment"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "NetworkPolicyAmendmentReviewDecision"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User has denied this command and the agent should not execute it, but it should continue the session and try something else.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"denied"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Automatic approval review timed out before reaching a decision.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"timed_out"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User has denied this command and the agent should not do anything until the user's next command.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"abort"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
schemas/FileChangeRequestApprovalParams.json
Normal file
41
schemas/FileChangeRequestApprovalParams.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "FileChangeRequestApprovalParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"itemId",
|
||||||
|
"startedAtMs",
|
||||||
|
"threadId",
|
||||||
|
"turnId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"grantRoot": {
|
||||||
|
"description": "[UNSTABLE] When set, the agent is asking the user to allow writes under this root for the remainder of the session (unclear if this is honored today).",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"itemId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
"description": "Optional explanatory reason (e.g. request for extra write access).",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"startedAtMs": {
|
||||||
|
"description": "Unix timestamp (in milliseconds) when this approval request started.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"turnId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
schemas/FileChangeRequestApprovalResponse.json
Normal file
47
schemas/FileChangeRequestApprovalResponse.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "FileChangeRequestApprovalResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"decision"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"decision": {
|
||||||
|
"$ref": "#/definitions/FileChangeApprovalDecision"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"FileChangeApprovalDecision": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "User approved the file changes.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"accept"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User approved the file changes and future changes to the same files should run without prompting.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"acceptForSession"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User denied the file changes. The agent will continue the turn.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"decline"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User denied the file changes. The turn will also be immediately interrupted.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"cancel"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
schemas/FuzzyFileSearchParams.json
Normal file
26
schemas/FuzzyFileSearchParams.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "FuzzyFileSearchParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"query",
|
||||||
|
"roots"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cancellationToken": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"roots": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
66
schemas/FuzzyFileSearchResponse.json
Normal file
66
schemas/FuzzyFileSearchResponse.json
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "FuzzyFileSearchResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"files"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"files": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/FuzzyFileSearchResult"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"FuzzyFileSearchMatchType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"file",
|
||||||
|
"directory"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FuzzyFileSearchResult": {
|
||||||
|
"description": "Superset of [`codex_file_search::FileMatch`]",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"file_name",
|
||||||
|
"match_type",
|
||||||
|
"path",
|
||||||
|
"root",
|
||||||
|
"score"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"file_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"indices": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"match_type": {
|
||||||
|
"$ref": "#/definitions/FuzzyFileSearchMatchType"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"score": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
schemas/FuzzyFileSearchSessionCompletedNotification.json
Normal file
13
schemas/FuzzyFileSearchSessionCompletedNotification.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "FuzzyFileSearchSessionCompletedNotification",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"sessionId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"sessionId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
schemas/FuzzyFileSearchSessionUpdatedNotification.json
Normal file
74
schemas/FuzzyFileSearchSessionUpdatedNotification.json
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "FuzzyFileSearchSessionUpdatedNotification",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"files",
|
||||||
|
"query",
|
||||||
|
"sessionId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"files": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/FuzzyFileSearchResult"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sessionId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"FuzzyFileSearchMatchType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"file",
|
||||||
|
"directory"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FuzzyFileSearchResult": {
|
||||||
|
"description": "Superset of [`codex_file_search::FileMatch`]",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"file_name",
|
||||||
|
"match_type",
|
||||||
|
"path",
|
||||||
|
"root",
|
||||||
|
"score"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"file_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"indices": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"match_type": {
|
||||||
|
"$ref": "#/definitions/FuzzyFileSearchMatchType"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"score": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
schemas/JSONRPCError.json
Normal file
48
schemas/JSONRPCError.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "JSONRPCError",
|
||||||
|
"description": "A response to a request that indicates an error occurred.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"error",
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"error": {
|
||||||
|
"$ref": "#/definitions/JSONRPCErrorError"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"$ref": "#/definitions/RequestId"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"JSONRPCErrorError": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"code",
|
||||||
|
"message"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"data": true,
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RequestId": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
schemas/JSONRPCErrorError.json
Normal file
19
schemas/JSONRPCErrorError.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "JSONRPCErrorError",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"code",
|
||||||
|
"message"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"data": true,
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
137
schemas/JSONRPCMessage.json
Normal file
137
schemas/JSONRPCMessage.json
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "JSONRPCMessage",
|
||||||
|
"description": "Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/JSONRPCRequest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/JSONRPCNotification"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/JSONRPCResponse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/JSONRPCError"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"definitions": {
|
||||||
|
"JSONRPCError": {
|
||||||
|
"description": "A response to a request that indicates an error occurred.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"error",
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"error": {
|
||||||
|
"$ref": "#/definitions/JSONRPCErrorError"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"$ref": "#/definitions/RequestId"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"JSONRPCErrorError": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"code",
|
||||||
|
"message"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"data": true,
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"JSONRPCNotification": {
|
||||||
|
"description": "A notification which does not expect a response.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"method"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"method": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"params": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"JSONRPCRequest": {
|
||||||
|
"description": "A request that expects a response.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"method"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"$ref": "#/definitions/RequestId"
|
||||||
|
},
|
||||||
|
"method": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"params": true,
|
||||||
|
"trace": {
|
||||||
|
"description": "Optional W3C Trace Context for distributed tracing.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/W3cTraceContext"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"JSONRPCResponse": {
|
||||||
|
"description": "A successful (non-error) response to a request.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"result"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"$ref": "#/definitions/RequestId"
|
||||||
|
},
|
||||||
|
"result": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RequestId": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"W3cTraceContext": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"traceparent": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tracestate": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
schemas/JSONRPCNotification.json
Normal file
15
schemas/JSONRPCNotification.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "JSONRPCNotification",
|
||||||
|
"description": "A notification which does not expect a response.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"method"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"method": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"params": true
|
||||||
|
}
|
||||||
|
}
|
||||||
60
schemas/JSONRPCRequest.json
Normal file
60
schemas/JSONRPCRequest.json
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "JSONRPCRequest",
|
||||||
|
"description": "A request that expects a response.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"method"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"$ref": "#/definitions/RequestId"
|
||||||
|
},
|
||||||
|
"method": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"params": true,
|
||||||
|
"trace": {
|
||||||
|
"description": "Optional W3C Trace Context for distributed tracing.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/W3cTraceContext"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"RequestId": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"W3cTraceContext": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"traceparent": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tracestate": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
schemas/JSONRPCResponse.json
Normal file
29
schemas/JSONRPCResponse.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "JSONRPCResponse",
|
||||||
|
"description": "A successful (non-error) response to a request.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"result"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"$ref": "#/definitions/RequestId"
|
||||||
|
},
|
||||||
|
"result": true
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"RequestId": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
609
schemas/McpServerElicitationRequestParams.json
Normal file
609
schemas/McpServerElicitationRequestParams.json
Normal file
@@ -0,0 +1,609 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "McpServerElicitationRequestParams",
|
||||||
|
"type": "object",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"message",
|
||||||
|
"mode",
|
||||||
|
"requestedSchema"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"_meta": true,
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"form"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"requestedSchema": {
|
||||||
|
"$ref": "#/definitions/McpElicitationSchema"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"elicitationId",
|
||||||
|
"message",
|
||||||
|
"mode",
|
||||||
|
"url"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"_meta": true,
|
||||||
|
"elicitationId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"url"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required": [
|
||||||
|
"serverName",
|
||||||
|
"threadId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"serverName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"turnId": {
|
||||||
|
"description": "Active Codex turn when this elicitation was observed, if app-server could correlate one.\n\nThis is nullable because MCP models elicitation as a standalone server-to-client request identified by the MCP server request id. It may be triggered during a turn, but turn context is app-server correlation rather than part of the protocol identity of the elicitation itself.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"McpElicitationArrayType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"array"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationBooleanSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationBooleanType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationBooleanType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"boolean"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationConstOption": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"const",
|
||||||
|
"title"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"const": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationEnumSchema": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationSingleSelectEnumSchema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationMultiSelectEnumSchema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationLegacyTitledEnumSchema"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationLegacyTitledEnumSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enum",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"enum": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enumNames": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationStringType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationMultiSelectEnumSchema": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationUntitledMultiSelectEnumSchema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationTitledMultiSelectEnumSchema"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationNumberSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": [
|
||||||
|
"number",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "double"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"maximum": {
|
||||||
|
"type": [
|
||||||
|
"number",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "double"
|
||||||
|
},
|
||||||
|
"minimum": {
|
||||||
|
"type": [
|
||||||
|
"number",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "double"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationNumberType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationNumberType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"number",
|
||||||
|
"integer"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationObjectType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"object"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationPrimitiveSchema": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationEnumSchema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationStringSchema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationNumberSchema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationBooleanSchema"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationSchema": {
|
||||||
|
"description": "Typed form schema for MCP `elicitation/create` requests.\n\nThis matches the `requestedSchema` shape from the MCP 2025-11-25 `ElicitRequestFormParams` schema.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"properties",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"$schema": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/McpElicitationPrimitiveSchema"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationObjectType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationSingleSelectEnumSchema": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationUntitledSingleSelectEnumSchema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationTitledSingleSelectEnumSchema"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationStringFormat": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"email",
|
||||||
|
"uri",
|
||||||
|
"date",
|
||||||
|
"date-time"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationStringSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/McpElicitationStringFormat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"maxLength": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"minLength": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationStringType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationStringType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"McpElicitationTitledEnumItems": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"anyOf"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"anyOf": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/McpElicitationConstOption"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationTitledMultiSelectEnumSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"items",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/McpElicitationTitledEnumItems"
|
||||||
|
},
|
||||||
|
"maxItems": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"minItems": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationArrayType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationTitledSingleSelectEnumSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"oneOf",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"oneOf": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/McpElicitationConstOption"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationStringType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationUntitledEnumItems": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enum",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enum": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationStringType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationUntitledMultiSelectEnumSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"items",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/McpElicitationUntitledEnumItems"
|
||||||
|
},
|
||||||
|
"maxItems": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"minItems": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationArrayType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"McpElicitationUntitledSingleSelectEnumSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enum",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"enum": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"$ref": "#/definitions/McpElicitationStringType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
schemas/McpServerElicitationRequestResponse.json
Normal file
29
schemas/McpServerElicitationRequestResponse.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "McpServerElicitationRequestResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"action"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"_meta": {
|
||||||
|
"description": "Optional client metadata for form-mode action handling."
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"$ref": "#/definitions/McpServerElicitationAction"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"description": "Structured user input for accepted elicitations, mirroring RMCP `CreateElicitationResult`.\n\nThis is nullable because decline/cancel responses have no content."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"McpServerElicitationAction": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"accept",
|
||||||
|
"decline",
|
||||||
|
"cancel"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
322
schemas/PermissionsRequestApprovalParams.json
Normal file
322
schemas/PermissionsRequestApprovalParams.json
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "PermissionsRequestApprovalParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"cwd",
|
||||||
|
"itemId",
|
||||||
|
"permissions",
|
||||||
|
"startedAtMs",
|
||||||
|
"threadId",
|
||||||
|
"turnId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cwd": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
"itemId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"permissions": {
|
||||||
|
"$ref": "#/definitions/RequestPermissionProfile"
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"startedAtMs": {
|
||||||
|
"description": "Unix timestamp (in milliseconds) when this approval request started.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"turnId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AbsolutePathBuf": {
|
||||||
|
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"AdditionalFileSystemPermissions": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"entries": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/FileSystemSandboxEntry"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"globScanMaxDepth": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 1.0
|
||||||
|
},
|
||||||
|
"read": {
|
||||||
|
"description": "This will be removed in favor of `entries`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"write": {
|
||||||
|
"description": "This will be removed in favor of `entries`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AdditionalNetworkPermissions": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FileSystemAccessMode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"read",
|
||||||
|
"write",
|
||||||
|
"none"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FileSystemPath": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"path",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"title": "PathFileSystemPathType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "PathFileSystemPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"pattern",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"pattern": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"glob_pattern"
|
||||||
|
],
|
||||||
|
"title": "GlobPatternFileSystemPathType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "GlobPatternFileSystemPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"special"
|
||||||
|
],
|
||||||
|
"title": "SpecialFileSystemPathType"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"$ref": "#/definitions/FileSystemSpecialPath"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SpecialFileSystemPath"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FileSystemSandboxEntry": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"access",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"access": {
|
||||||
|
"$ref": "#/definitions/FileSystemAccessMode"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"$ref": "#/definitions/FileSystemPath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FileSystemSpecialPath": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"root"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "RootFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"minimal"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "MinimalFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"project_roots"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subpath": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "KindFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"tmpdir"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "TmpdirFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"slash_tmp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SlashTmpFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"unknown"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"subpath": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"RequestPermissionProfile": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"fileSystem": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AdditionalFileSystemPermissions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"network": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AdditionalNetworkPermissions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
315
schemas/PermissionsRequestApprovalResponse.json
Normal file
315
schemas/PermissionsRequestApprovalResponse.json
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "PermissionsRequestApprovalResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"permissions"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"permissions": {
|
||||||
|
"$ref": "#/definitions/GrantedPermissionProfile"
|
||||||
|
},
|
||||||
|
"scope": {
|
||||||
|
"default": "turn",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/PermissionGrantScope"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"strictAutoReview": {
|
||||||
|
"description": "Review every subsequent command in this turn before normal sandboxed execution.",
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AbsolutePathBuf": {
|
||||||
|
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"AdditionalFileSystemPermissions": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"entries": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/FileSystemSandboxEntry"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"globScanMaxDepth": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 1.0
|
||||||
|
},
|
||||||
|
"read": {
|
||||||
|
"description": "This will be removed in favor of `entries`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"write": {
|
||||||
|
"description": "This will be removed in favor of `entries`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AdditionalNetworkPermissions": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FileSystemAccessMode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"read",
|
||||||
|
"write",
|
||||||
|
"none"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FileSystemPath": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"path",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"title": "PathFileSystemPathType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "PathFileSystemPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"pattern",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"pattern": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"glob_pattern"
|
||||||
|
],
|
||||||
|
"title": "GlobPatternFileSystemPathType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "GlobPatternFileSystemPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"special"
|
||||||
|
],
|
||||||
|
"title": "SpecialFileSystemPathType"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"$ref": "#/definitions/FileSystemSpecialPath"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SpecialFileSystemPath"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FileSystemSandboxEntry": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"access",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"access": {
|
||||||
|
"$ref": "#/definitions/FileSystemAccessMode"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"$ref": "#/definitions/FileSystemPath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FileSystemSpecialPath": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"root"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "RootFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"minimal"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "MinimalFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"project_roots"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subpath": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "KindFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"tmpdir"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "TmpdirFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"slash_tmp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SlashTmpFileSystemSpecialPath"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"unknown"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"subpath": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"GrantedPermissionProfile": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"fileSystem": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AdditionalFileSystemPermissions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"network": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AdditionalNetworkPermissions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PermissionGrantScope": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"turn",
|
||||||
|
"session"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
schemas/RequestId.json
Normal file
13
schemas/RequestId.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "RequestId",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
6160
schemas/ServerNotification.json
Normal file
6160
schemas/ServerNotification.json
Normal file
File diff suppressed because it is too large
Load Diff
2001
schemas/ServerRequest.json
Normal file
2001
schemas/ServerRequest.json
Normal file
File diff suppressed because it is too large
Load Diff
84
schemas/ToolRequestUserInputParams.json
Normal file
84
schemas/ToolRequestUserInputParams.json
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ToolRequestUserInputParams",
|
||||||
|
"description": "EXPERIMENTAL. Params sent with a request_user_input event.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"itemId",
|
||||||
|
"questions",
|
||||||
|
"threadId",
|
||||||
|
"turnId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"itemId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"questions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ToolRequestUserInputQuestion"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"turnId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"ToolRequestUserInputOption": {
|
||||||
|
"description": "EXPERIMENTAL. Defines a single selectable option for request_user_input.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"description",
|
||||||
|
"label"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ToolRequestUserInputQuestion": {
|
||||||
|
"description": "EXPERIMENTAL. Represents one request_user_input question and its required options.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"header",
|
||||||
|
"id",
|
||||||
|
"question"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"header": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isOther": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"isSecret": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ToolRequestUserInputOption"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
schemas/ToolRequestUserInputResponse.json
Normal file
34
schemas/ToolRequestUserInputResponse.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ToolRequestUserInputResponse",
|
||||||
|
"description": "EXPERIMENTAL. Response payload mapping question ids to answers.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"answers"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"answers": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/ToolRequestUserInputAnswer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"ToolRequestUserInputAnswer": {
|
||||||
|
"description": "EXPERIMENTAL. Captures a user's answer to a request_user_input question.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"answers"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"answers": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18535
schemas/codex_app_server_protocol.schemas.json
Normal file
18535
schemas/codex_app_server_protocol.schemas.json
Normal file
File diff suppressed because it is too large
Load Diff
16358
schemas/codex_app_server_protocol.v2.schemas.json
Normal file
16358
schemas/codex_app_server_protocol.v2.schemas.json
Normal file
File diff suppressed because it is too large
Load Diff
72
schemas/v1/InitializeParams.json
Normal file
72
schemas/v1/InitializeParams.json
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "InitializeParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"clientInfo"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"capabilities": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/InitializeCapabilities"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"clientInfo": {
|
||||||
|
"$ref": "#/definitions/ClientInfo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"ClientInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"InitializeCapabilities": {
|
||||||
|
"description": "Client-declared capabilities negotiated during initialize.",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"experimentalApi": {
|
||||||
|
"description": "Opt into receiving experimental API methods and fields.",
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"optOutNotificationMethods": {
|
||||||
|
"description": "Exact notification method names that should be suppressed for this connection (for example `thread/started`).",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requestAttestation": {
|
||||||
|
"description": "Opt into `attestation/generate` requests for upstream `x-oai-attestation`.",
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
schemas/v1/InitializeResponse.json
Normal file
38
schemas/v1/InitializeResponse.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "InitializeResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"codexHome",
|
||||||
|
"platformFamily",
|
||||||
|
"platformOs",
|
||||||
|
"userAgent"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"codexHome": {
|
||||||
|
"description": "Absolute path to the server's $CODEX_HOME directory.",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"platformFamily": {
|
||||||
|
"description": "Platform family for the running app-server target, for example `\"unix\"` or `\"windows\"`.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"platformOs": {
|
||||||
|
"description": "Operating system for the running app-server target, for example `\"macos\"`, `\"linux\"`, or `\"windows\"`.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userAgent": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AbsolutePathBuf": {
|
||||||
|
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
schemas/v2/AccountLoginCompletedNotification.json
Normal file
25
schemas/v2/AccountLoginCompletedNotification.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AccountLoginCompletedNotification",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"success"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"error": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"loginId": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
156
schemas/v2/AccountRateLimitsUpdatedNotification.json
Normal file
156
schemas/v2/AccountRateLimitsUpdatedNotification.json
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AccountRateLimitsUpdatedNotification",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"rateLimits"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"rateLimits": {
|
||||||
|
"$ref": "#/definitions/RateLimitSnapshot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"CreditsSnapshot": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"hasCredits",
|
||||||
|
"unlimited"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"balance": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hasCredits": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"unlimited": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PlanType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"free",
|
||||||
|
"go",
|
||||||
|
"plus",
|
||||||
|
"pro",
|
||||||
|
"prolite",
|
||||||
|
"team",
|
||||||
|
"self_serve_business_usage_based",
|
||||||
|
"business",
|
||||||
|
"enterprise_cbp_usage_based",
|
||||||
|
"enterprise",
|
||||||
|
"edu",
|
||||||
|
"unknown"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"RateLimitReachedType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"rate_limit_reached",
|
||||||
|
"workspace_owner_credits_depleted",
|
||||||
|
"workspace_member_credits_depleted",
|
||||||
|
"workspace_owner_usage_limit_reached",
|
||||||
|
"workspace_member_usage_limit_reached"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"RateLimitSnapshot": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"credits": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/CreditsSnapshot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"limitId": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"limitName": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"planType": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/PlanType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"primary": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/RateLimitWindow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rateLimitReachedType": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/RateLimitReachedType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"secondary": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/RateLimitWindow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RateLimitWindow": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"usedPercent"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"resetsAt": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"usedPercent": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"windowDurationMins": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
schemas/v2/AccountUpdatedNotification.json
Normal file
79
schemas/v2/AccountUpdatedNotification.json
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AccountUpdatedNotification",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"authMode": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AuthMode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"planType": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/PlanType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AuthMode": {
|
||||||
|
"description": "Authentication mode for OpenAI-backed providers.",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "OpenAI API key provided by the caller and stored by Codex.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"apikey"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ChatGPT OAuth managed by Codex (tokens persisted and refreshed by Codex).",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"chatgpt"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "[UNSTABLE] FOR OPENAI INTERNAL USE ONLY - DO NOT USE.\n\nChatGPT auth tokens are supplied by an external host app and are only stored in memory. Token refresh must be handled by the external host app.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"chatgptAuthTokens"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Programmatic Codex auth backed by a registered Agent Identity.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"agentIdentity"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PlanType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"free",
|
||||||
|
"go",
|
||||||
|
"plus",
|
||||||
|
"pro",
|
||||||
|
"prolite",
|
||||||
|
"team",
|
||||||
|
"self_serve_business_usage_based",
|
||||||
|
"business",
|
||||||
|
"enterprise_cbp_usage_based",
|
||||||
|
"enterprise",
|
||||||
|
"edu",
|
||||||
|
"unknown"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
schemas/v2/AgentMessageDeltaNotification.json
Normal file
25
schemas/v2/AgentMessageDeltaNotification.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AgentMessageDeltaNotification",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"delta",
|
||||||
|
"itemId",
|
||||||
|
"threadId",
|
||||||
|
"turnId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"delta": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"itemId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"turnId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
276
schemas/v2/AppListUpdatedNotification.json
Normal file
276
schemas/v2/AppListUpdatedNotification.json
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AppListUpdatedNotification",
|
||||||
|
"description": "EXPERIMENTAL - notification emitted when the app list changes.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AppInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AppBranding": {
|
||||||
|
"description": "EXPERIMENTAL - app metadata returned by app-list APIs.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"isDiscoverableApp"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"category": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"developer": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isDiscoverableApp": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"privacyPolicy": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"termsOfService": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"website": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppInfo": {
|
||||||
|
"description": "EXPERIMENTAL - app metadata returned by app-list APIs.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"appMetadata": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppMetadata"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branding": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppBranding"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"distributionChannel": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"installUrl": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isAccessible": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"isEnabled": {
|
||||||
|
"description": "Whether this app is enabled in config.toml. Example: ```toml [apps.bad_app] enabled = false ```",
|
||||||
|
"default": true,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"logoUrl": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"logoUrlDark": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pluginDisplayNames": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppMetadata": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"categories": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"developer": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"firstPartyRequiresInstall": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"firstPartyType": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"review": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppReview"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"screenshots": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AppScreenshot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seoDescription": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"showInComposerWhenUnlinked": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subCategories": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"versionId": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"versionNotes": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppReview": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"status"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppScreenshot": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"userPrompt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"fileId": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"userPrompt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
schemas/v2/AppsListParams.json
Normal file
35
schemas/v2/AppsListParams.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AppsListParams",
|
||||||
|
"description": "EXPERIMENTAL - list available apps/connectors.",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"cursor": {
|
||||||
|
"description": "Opaque pagination cursor returned by a previous call.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"forceRefetch": {
|
||||||
|
"description": "When true, bypass app caches and fetch the latest data from sources.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"limit": {
|
||||||
|
"description": "Optional page size; defaults to a reasonable server-side value.",
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"description": "Optional thread id used to evaluate app feature gating from that thread's config.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
283
schemas/v2/AppsListResponse.json
Normal file
283
schemas/v2/AppsListResponse.json
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "AppsListResponse",
|
||||||
|
"description": "EXPERIMENTAL - app list response.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AppInfo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextCursor": {
|
||||||
|
"description": "Opaque cursor to pass to the next call to continue after the last item. If None, there are no more items to return.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AppBranding": {
|
||||||
|
"description": "EXPERIMENTAL - app metadata returned by app-list APIs.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"isDiscoverableApp"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"category": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"developer": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isDiscoverableApp": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"privacyPolicy": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"termsOfService": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"website": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppInfo": {
|
||||||
|
"description": "EXPERIMENTAL - app metadata returned by app-list APIs.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"appMetadata": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppMetadata"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branding": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppBranding"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"distributionChannel": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"installUrl": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isAccessible": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"isEnabled": {
|
||||||
|
"description": "Whether this app is enabled in config.toml. Example: ```toml [apps.bad_app] enabled = false ```",
|
||||||
|
"default": true,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"logoUrl": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"logoUrlDark": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pluginDisplayNames": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppMetadata": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"categories": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"developer": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"firstPartyRequiresInstall": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"firstPartyType": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"review": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppReview"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"screenshots": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AppScreenshot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seoDescription": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"showInComposerWhenUnlinked": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subCategories": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"versionId": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"versionNotes": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppReview": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"status"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppScreenshot": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"userPrompt"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"fileId": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"userPrompt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
schemas/v2/CancelLoginAccountParams.json
Normal file
13
schemas/v2/CancelLoginAccountParams.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CancelLoginAccountParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"loginId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"loginId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
schemas/v2/CancelLoginAccountResponse.json
Normal file
22
schemas/v2/CancelLoginAccountResponse.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CancelLoginAccountResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"status"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"status": {
|
||||||
|
"$ref": "#/definitions/CancelLoginAccountStatus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"CancelLoginAccountStatus": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"canceled",
|
||||||
|
"notFound"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
schemas/v2/CommandExecOutputDeltaNotification.json
Normal file
55
schemas/v2/CommandExecOutputDeltaNotification.json
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecOutputDeltaNotification",
|
||||||
|
"description": "Base64-encoded output chunk emitted for a streaming `command/exec` request.\n\nThese notifications are connection-scoped. If the originating connection closes, the server terminates the process.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"capReached",
|
||||||
|
"deltaBase64",
|
||||||
|
"processId",
|
||||||
|
"stream"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"capReached": {
|
||||||
|
"description": "`true` on the final streamed chunk for a stream when `outputBytesCap` truncated later output on that stream.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"deltaBase64": {
|
||||||
|
"description": "Base64-encoded output bytes.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"processId": {
|
||||||
|
"description": "Client-supplied, connection-scoped `processId` from the original `command/exec` request.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"stream": {
|
||||||
|
"description": "Output stream for this chunk.",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/CommandExecOutputStream"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"CommandExecOutputStream": {
|
||||||
|
"description": "Stream label for `command/exec/outputDelta` notifications.",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "stdout stream. PTY mode multiplexes terminal output here.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"stdout"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "stderr stream.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"stderr"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
258
schemas/v2/CommandExecParams.json
Normal file
258
schemas/v2/CommandExecParams.json
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecParams",
|
||||||
|
"description": "Run a standalone command (argv vector) in the server sandbox without creating a thread or turn.\n\nThe final `command/exec` response is deferred until the process exits and is sent only after all `command/exec/outputDelta` notifications for that connection have been emitted.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"command"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"description": "Command argv vector. Empty arrays are rejected.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cwd": {
|
||||||
|
"description": "Optional working directory. Defaults to the server cwd.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disableOutputCap": {
|
||||||
|
"description": "Disable stdout/stderr capture truncation for this request.\n\nCannot be combined with `outputBytesCap`.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"disableTimeout": {
|
||||||
|
"description": "Disable the timeout entirely for this request.\n\nCannot be combined with `timeoutMs`.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"description": "Optional environment overrides merged into the server-computed environment.\n\nMatching names override inherited values. Set a key to `null` to unset an inherited variable.",
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputBytesCap": {
|
||||||
|
"description": "Optional per-stream stdout/stderr capture cap in bytes.\n\nWhen omitted, the server default applies. Cannot be combined with `disableOutputCap`.",
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"tty": {
|
||||||
|
"description": "Enable PTY mode.\n\nThis implies `streamStdin` and `streamStdoutStderr`.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"processId": {
|
||||||
|
"description": "Optional client-supplied, connection-scoped process id.\n\nRequired for `tty`, `streamStdin`, `streamStdoutStderr`, and follow-up `command/exec/write`, `command/exec/resize`, and `command/exec/terminate` calls. When omitted, buffered execution gets an internal id that is not exposed to the client.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sandboxPolicy": {
|
||||||
|
"description": "Optional sandbox policy for this command.\n\nUses the same shape as thread/turn execution sandbox configuration and defaults to the user's configured policy when omitted. Cannot be combined with `permissionProfile`.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/SandboxPolicy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"description": "Optional initial PTY size in character cells. Only valid when `tty` is true.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/CommandExecTerminalSize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"streamStdin": {
|
||||||
|
"description": "Allow follow-up `command/exec/write` requests to write stdin bytes.\n\nRequires a client-supplied `processId`.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"streamStdoutStderr": {
|
||||||
|
"description": "Stream stdout/stderr via `command/exec/outputDelta` notifications.\n\nStreamed bytes are not duplicated into the final response and require a client-supplied `processId`.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"timeoutMs": {
|
||||||
|
"description": "Optional timeout in milliseconds.\n\nWhen omitted, the server default applies. Cannot be combined with `disableTimeout`.",
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "int64"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AbsolutePathBuf": {
|
||||||
|
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ActivePermissionProfile": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"extends": {
|
||||||
|
"description": "Parent profile identifier once permissions profiles support inheritance. This is currently always `null`.",
|
||||||
|
"default": null,
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "Identifier from `default_permissions` or the implicit built-in default, such as `:workspace` or a user-defined `[permissions.<id>]` profile.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CommandExecTerminalSize": {
|
||||||
|
"description": "PTY size in character cells for `command/exec` PTY sessions.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"cols",
|
||||||
|
"rows"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cols": {
|
||||||
|
"description": "Terminal width in character cells.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"rows": {
|
||||||
|
"description": "Terminal height in character cells.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NetworkAccess": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"restricted",
|
||||||
|
"enabled"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"SandboxPolicy": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"dangerFullAccess"
|
||||||
|
],
|
||||||
|
"title": "DangerFullAccessSandboxPolicyType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "DangerFullAccessSandboxPolicy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"networkAccess": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"readOnly"
|
||||||
|
],
|
||||||
|
"title": "ReadOnlySandboxPolicyType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ReadOnlySandboxPolicy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"networkAccess": {
|
||||||
|
"default": "restricted",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/NetworkAccess"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"externalSandbox"
|
||||||
|
],
|
||||||
|
"title": "ExternalSandboxSandboxPolicyType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ExternalSandboxSandboxPolicy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"excludeSlashTmp": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"excludeTmpdirEnvVar": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"networkAccess": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"workspaceWrite"
|
||||||
|
],
|
||||||
|
"title": "WorkspaceWriteSandboxPolicyType"
|
||||||
|
},
|
||||||
|
"writableRoots": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "WorkspaceWriteSandboxPolicy"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
schemas/v2/CommandExecResizeParams.json
Normal file
48
schemas/v2/CommandExecResizeParams.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecResizeParams",
|
||||||
|
"description": "Resize a running PTY-backed `command/exec` session.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"processId",
|
||||||
|
"size"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"processId": {
|
||||||
|
"description": "Client-supplied, connection-scoped `processId` from the original `command/exec` request.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"description": "New PTY size in character cells.",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/CommandExecTerminalSize"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"CommandExecTerminalSize": {
|
||||||
|
"description": "PTY size in character cells for `command/exec` PTY sessions.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"cols",
|
||||||
|
"rows"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cols": {
|
||||||
|
"description": "Terminal width in character cells.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"rows": {
|
||||||
|
"description": "Terminal height in character cells.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
schemas/v2/CommandExecResizeResponse.json
Normal file
6
schemas/v2/CommandExecResizeResponse.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecResizeResponse",
|
||||||
|
"description": "Empty success response for `command/exec/resize`.",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
26
schemas/v2/CommandExecResponse.json
Normal file
26
schemas/v2/CommandExecResponse.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecResponse",
|
||||||
|
"description": "Final buffered result for `command/exec`.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"exitCode",
|
||||||
|
"stderr",
|
||||||
|
"stdout"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"exitCode": {
|
||||||
|
"description": "Process exit code.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"stderr": {
|
||||||
|
"description": "Buffered stderr capture.\n\nEmpty when stderr was streamed via `command/exec/outputDelta`.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"stdout": {
|
||||||
|
"description": "Buffered stdout capture.\n\nEmpty when stdout was streamed via `command/exec/outputDelta`.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
schemas/v2/CommandExecTerminateParams.json
Normal file
15
schemas/v2/CommandExecTerminateParams.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecTerminateParams",
|
||||||
|
"description": "Terminate a running `command/exec` session.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"processId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"processId": {
|
||||||
|
"description": "Client-supplied, connection-scoped `processId` from the original `command/exec` request.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
schemas/v2/CommandExecTerminateResponse.json
Normal file
6
schemas/v2/CommandExecTerminateResponse.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecTerminateResponse",
|
||||||
|
"description": "Empty success response for `command/exec/terminate`.",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
26
schemas/v2/CommandExecWriteParams.json
Normal file
26
schemas/v2/CommandExecWriteParams.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecWriteParams",
|
||||||
|
"description": "Write stdin bytes to a running `command/exec` session, close stdin, or both.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"processId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"closeStdin": {
|
||||||
|
"description": "Close stdin after writing `deltaBase64`, if present.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"deltaBase64": {
|
||||||
|
"description": "Optional base64-encoded stdin bytes to write.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"processId": {
|
||||||
|
"description": "Client-supplied, connection-scoped `processId` from the original `command/exec` request.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
schemas/v2/CommandExecWriteResponse.json
Normal file
6
schemas/v2/CommandExecWriteResponse.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecWriteResponse",
|
||||||
|
"description": "Empty success response for `command/exec/write`.",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
25
schemas/v2/CommandExecutionOutputDeltaNotification.json
Normal file
25
schemas/v2/CommandExecutionOutputDeltaNotification.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "CommandExecutionOutputDeltaNotification",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"delta",
|
||||||
|
"itemId",
|
||||||
|
"threadId",
|
||||||
|
"turnId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"delta": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"itemId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"turnId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
schemas/v2/ConfigBatchWriteParams.json
Normal file
59
schemas/v2/ConfigBatchWriteParams.json
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ConfigBatchWriteParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"edits"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"edits": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfigEdit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expectedVersion": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"filePath": {
|
||||||
|
"description": "Path to the config file to write; defaults to the user's `config.toml` when omitted.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"reloadUserConfig": {
|
||||||
|
"description": "When true, hot-reload the updated user config into all loaded threads after writing.",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"ConfigEdit": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"keyPath",
|
||||||
|
"mergeStrategy",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"keyPath": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"mergeStrategy": {
|
||||||
|
"$ref": "#/definitions/MergeStrategy"
|
||||||
|
},
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MergeStrategy": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"replace",
|
||||||
|
"upsert"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
schemas/v2/ConfigReadParams.json
Normal file
18
schemas/v2/ConfigReadParams.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ConfigReadParams",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"cwd": {
|
||||||
|
"description": "Optional working directory to resolve project config layers. If specified, return the effective config as seen from that directory (i.e., including any project layers between `cwd` and the project/repo root).",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"includeLayers": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
913
schemas/v2/ConfigReadResponse.json
Normal file
913
schemas/v2/ConfigReadResponse.json
Normal file
@@ -0,0 +1,913 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ConfigReadResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"config",
|
||||||
|
"origins"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"config": {
|
||||||
|
"$ref": "#/definitions/Config"
|
||||||
|
},
|
||||||
|
"layers": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfigLayer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"origins": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/ConfigLayerMetadata"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AbsolutePathBuf": {
|
||||||
|
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"AnalyticsConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"AppConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"default_tools_approval_mode": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppToolApproval"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default_tools_enabled": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"destructive_enabled": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"default": true,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"open_world_enabled": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tools": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppToolsConfig"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppToolApproval": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"auto",
|
||||||
|
"prompt",
|
||||||
|
"approve"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"AppToolConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"approval_mode": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppToolApproval"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppToolsConfig": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ApprovalsReviewer": {
|
||||||
|
"description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"user",
|
||||||
|
"auto_review",
|
||||||
|
"guardian_subagent"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"AppsConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"_default": {
|
||||||
|
"default": null,
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AppsDefaultConfig"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AppsDefaultConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"destructive_enabled": {
|
||||||
|
"default": true,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"default": true,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"open_world_enabled": {
|
||||||
|
"default": true,
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AskForApproval": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"untrusted",
|
||||||
|
"on-failure",
|
||||||
|
"on-request",
|
||||||
|
"never"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"granular"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"granular": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"mcp_elicitations",
|
||||||
|
"rules",
|
||||||
|
"sandbox_approval"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"mcp_elicitations": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"request_permissions": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"sandbox_approval": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"skill_approval": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "GranularAskForApproval"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Config": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"analytics": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AnalyticsConfig"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"approval_policy": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AskForApproval"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"approvals_reviewer": {
|
||||||
|
"description": "[UNSTABLE] Optional default for where approval requests are routed for review.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ApprovalsReviewer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"web_search": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/WebSearchMode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"compact_prompt": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"desktop": {
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"developer_instructions": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"forced_chatgpt_workspace_id": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ForcedChatgptWorkspaceIds"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"forced_login_method": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ForcedLoginMethod"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"instructions": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model_auto_compact_token_limit": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"model_context_window": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"model_provider": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model_reasoning_effort": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ReasoningEffort"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model_reasoning_summary": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ReasoningSummary"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model_verbosity": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/Verbosity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"default": {},
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/ProfileV2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"review_model": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sandbox_mode": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/SandboxMode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sandbox_workspace_write": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/SandboxWorkspaceWrite"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"service_tier": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tools": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ToolsV2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"ConfigLayer": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"config",
|
||||||
|
"name",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"config": true,
|
||||||
|
"disabledReason": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/definitions/ConfigLayerSource"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConfigLayerMetadata": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/definitions/ConfigLayerSource"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConfigLayerSource": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Managed preferences layer delivered by MDM (macOS only).",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"domain",
|
||||||
|
"key",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"domain": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"mdm"
|
||||||
|
],
|
||||||
|
"title": "MdmConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "MdmConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Managed config layer from a file (usually `managed_config.toml`).",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"file",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"file": {
|
||||||
|
"description": "This is the path to the system config.toml file, though it is not guaranteed to exist.",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"system"
|
||||||
|
],
|
||||||
|
"title": "SystemConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SystemConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User config layer from $CODEX_HOME/config.toml. This layer is special in that it is expected to be: - writable by the user - generally outside the workspace directory",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"file",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"file": {
|
||||||
|
"description": "This is the path to the user's config.toml file, though it is not guaranteed to exist.",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"description": "Name of the selected profile-v2 config layered on top of the base user config, when this layer represents one.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"title": "UserConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "UserConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Path to a .codex/ folder within a project. There could be multiple of these between `cwd` and the project/repo root.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"dotCodexFolder",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"dotCodexFolder": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"project"
|
||||||
|
],
|
||||||
|
"title": "ProjectConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ProjectConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Session-layer overrides supplied via `-c`/`--config`.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"sessionFlags"
|
||||||
|
],
|
||||||
|
"title": "SessionFlagsConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SessionFlagsConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "`managed_config.toml` was designed to be a config that was loaded as the last layer on top of everything else. This scheme did not quite work out as intended, but we keep this variant as a \"best effort\" while we phase out `managed_config.toml` in favor of `requirements.toml`.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"file",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"file": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"legacyManagedConfigTomlFromFile"
|
||||||
|
],
|
||||||
|
"title": "LegacyManagedConfigTomlFromFileConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "LegacyManagedConfigTomlFromFileConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"legacyManagedConfigTomlFromMdm"
|
||||||
|
],
|
||||||
|
"title": "LegacyManagedConfigTomlFromMdmConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "LegacyManagedConfigTomlFromMdmConfigLayerSource"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ForcedChatgptWorkspaceIds": {
|
||||||
|
"description": "Backward-compatible API shape for ChatGPT workspace login restrictions.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ForcedLoginMethod": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"chatgpt",
|
||||||
|
"api"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ProfileV2": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"approval_policy": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AskForApproval"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"approvals_reviewer": {
|
||||||
|
"description": "[UNSTABLE] Optional profile-level override for where approval requests are routed for review. If omitted, the enclosing config default is used.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ApprovalsReviewer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"chatgpt_base_url": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model_provider": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model_reasoning_effort": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ReasoningEffort"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model_reasoning_summary": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ReasoningSummary"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"model_verbosity": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/Verbosity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"service_tier": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tools": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ToolsV2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"web_search": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/WebSearchMode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": true
|
||||||
|
},
|
||||||
|
"ReasoningEffort": {
|
||||||
|
"description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"none",
|
||||||
|
"minimal",
|
||||||
|
"low",
|
||||||
|
"medium",
|
||||||
|
"high",
|
||||||
|
"xhigh"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ReasoningSummary": {
|
||||||
|
"description": "A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process. See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#reasoning-summaries",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"auto",
|
||||||
|
"concise",
|
||||||
|
"detailed"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Option to disable reasoning summaries.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"none"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"SandboxMode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"read-only",
|
||||||
|
"workspace-write",
|
||||||
|
"danger-full-access"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"SandboxWorkspaceWrite": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"exclude_slash_tmp": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"exclude_tmpdir_env_var": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"network_access": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"writable_roots": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ToolsV2": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"web_search": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/WebSearchToolConfig"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Verbosity": {
|
||||||
|
"description": "Controls output length/detail on GPT-5 models via the Responses API. Serialized with lowercase values to match the OpenAI API.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"low",
|
||||||
|
"medium",
|
||||||
|
"high"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"WebSearchContextSize": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"low",
|
||||||
|
"medium",
|
||||||
|
"high"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"WebSearchLocation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"city": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"region": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"WebSearchMode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"disabled",
|
||||||
|
"cached",
|
||||||
|
"live"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"WebSearchToolConfig": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"allowed_domains": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"context_size": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/WebSearchContextSize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/WebSearchLocation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
455
schemas/v2/ConfigRequirementsReadResponse.json
Normal file
455
schemas/v2/ConfigRequirementsReadResponse.json
Normal file
@@ -0,0 +1,455 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ConfigRequirementsReadResponse",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"requirements": {
|
||||||
|
"description": "Null if no requirements are configured (e.g. no requirements.toml/MDM entries).",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ConfigRequirements"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"ApprovalsReviewer": {
|
||||||
|
"description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"user",
|
||||||
|
"auto_review",
|
||||||
|
"guardian_subagent"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"AskForApproval": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"untrusted",
|
||||||
|
"on-failure",
|
||||||
|
"on-request",
|
||||||
|
"never"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"granular"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"granular": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"mcp_elicitations",
|
||||||
|
"rules",
|
||||||
|
"sandbox_approval"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"mcp_elicitations": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"request_permissions": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"sandbox_approval": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"skill_approval": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "GranularAskForApproval"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ConfigRequirements": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"allowManagedHooksOnly": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"allowedApprovalPolicies": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/AskForApproval"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"featureRequirements": {
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allowedSandboxModes": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/SandboxMode"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allowedWebSearchModes": {
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/WebSearchMode"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enforceResidency": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ResidencyRequirement"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConfiguredHookHandler": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"async",
|
||||||
|
"command",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"async": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"command": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"commandWindows": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"statusMessage": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timeoutSec": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint64",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"command"
|
||||||
|
],
|
||||||
|
"title": "CommandConfiguredHookHandlerType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "CommandConfiguredHookHandler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"prompt"
|
||||||
|
],
|
||||||
|
"title": "PromptConfiguredHookHandlerType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "PromptConfiguredHookHandler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"agent"
|
||||||
|
],
|
||||||
|
"title": "AgentConfiguredHookHandlerType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "AgentConfiguredHookHandler"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ConfiguredHookMatcherGroup": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"hooks"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"hooks": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfiguredHookHandler"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"matcher": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ManagedHooksRequirements": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"PermissionRequest",
|
||||||
|
"PostCompact",
|
||||||
|
"PostToolUse",
|
||||||
|
"PreCompact",
|
||||||
|
"PreToolUse",
|
||||||
|
"SessionStart",
|
||||||
|
"Stop",
|
||||||
|
"UserPromptSubmit"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"PermissionRequest": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PostCompact": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PostToolUse": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PreCompact": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PreToolUse": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SessionStart": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Stop": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"UserPromptSubmit": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConfiguredHookMatcherGroup"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"managedDir": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"windowsManagedDir": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NetworkDomainPermission": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"allow",
|
||||||
|
"deny"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"NetworkRequirements": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"allowLocalBinding": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"allowUnixSockets": {
|
||||||
|
"description": "Legacy compatibility view derived from `unix_sockets`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allowUpstreamProxy": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"allowedDomains": {
|
||||||
|
"description": "Legacy compatibility view derived from `domains`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dangerouslyAllowAllUnixSockets": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dangerouslyAllowNonLoopbackProxy": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"deniedDomains": {
|
||||||
|
"description": "Legacy compatibility view derived from `domains`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domains": {
|
||||||
|
"description": "Canonical network permission map for `experimental_network`.",
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/NetworkDomainPermission"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"httpPort": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"managedAllowedDomainsOnly": {
|
||||||
|
"description": "When true, only managed allowlist entries are respected while managed network enforcement is active.",
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"socksPort": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"unixSockets": {
|
||||||
|
"description": "Canonical unix socket permission map for `experimental_network`.",
|
||||||
|
"type": [
|
||||||
|
"object",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/NetworkUnixSocketPermission"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NetworkUnixSocketPermission": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"allow",
|
||||||
|
"none"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ResidencyRequirement": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"us"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"SandboxMode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"read-only",
|
||||||
|
"workspace-write",
|
||||||
|
"danger-full-access"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"WebSearchMode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"disabled",
|
||||||
|
"cached",
|
||||||
|
"live"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
schemas/v2/ConfigValueWriteParams.json
Normal file
41
schemas/v2/ConfigValueWriteParams.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ConfigValueWriteParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"keyPath",
|
||||||
|
"mergeStrategy",
|
||||||
|
"value"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"expectedVersion": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"filePath": {
|
||||||
|
"description": "Path to the config file to write; defaults to the user's `config.toml` when omitted.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"keyPath": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"mergeStrategy": {
|
||||||
|
"$ref": "#/definitions/MergeStrategy"
|
||||||
|
},
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"MergeStrategy": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"replace",
|
||||||
|
"upsert"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
77
schemas/v2/ConfigWarningNotification.json
Normal file
77
schemas/v2/ConfigWarningNotification.json
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ConfigWarningNotification",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"summary"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"details": {
|
||||||
|
"description": "Optional extra guidance or error details.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"description": "Optional path to the config file that triggered the warning.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"description": "Optional range for the error location inside the config file.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/TextRange"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"summary": {
|
||||||
|
"description": "Concise summary of the warning.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"TextPosition": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"column",
|
||||||
|
"line"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"column": {
|
||||||
|
"description": "1-based column number (in Unicode scalar values).",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"line": {
|
||||||
|
"description": "1-based line number.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"TextRange": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"end",
|
||||||
|
"start"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"end": {
|
||||||
|
"$ref": "#/definitions/TextPosition"
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"$ref": "#/definitions/TextPosition"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
244
schemas/v2/ConfigWriteResponse.json
Normal file
244
schemas/v2/ConfigWriteResponse.json
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ConfigWriteResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"filePath",
|
||||||
|
"status",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"filePath": {
|
||||||
|
"description": "Canonical path to the config file that was written.",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"overriddenMetadata": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/OverriddenMetadata"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"$ref": "#/definitions/WriteStatus"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"AbsolutePathBuf": {
|
||||||
|
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ConfigLayerMetadata": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"$ref": "#/definitions/ConfigLayerSource"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConfigLayerSource": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Managed preferences layer delivered by MDM (macOS only).",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"domain",
|
||||||
|
"key",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"domain": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"mdm"
|
||||||
|
],
|
||||||
|
"title": "MdmConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "MdmConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Managed config layer from a file (usually `managed_config.toml`).",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"file",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"file": {
|
||||||
|
"description": "This is the path to the system config.toml file, though it is not guaranteed to exist.",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"system"
|
||||||
|
],
|
||||||
|
"title": "SystemConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SystemConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "User config layer from $CODEX_HOME/config.toml. This layer is special in that it is expected to be: - writable by the user - generally outside the workspace directory",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"file",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"file": {
|
||||||
|
"description": "This is the path to the user's config.toml file, though it is not guaranteed to exist.",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"description": "Name of the selected profile-v2 config layered on top of the base user config, when this layer represents one.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"title": "UserConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "UserConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Path to a .codex/ folder within a project. There could be multiple of these between `cwd` and the project/repo root.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"dotCodexFolder",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"dotCodexFolder": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"project"
|
||||||
|
],
|
||||||
|
"title": "ProjectConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ProjectConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Session-layer overrides supplied via `-c`/`--config`.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"sessionFlags"
|
||||||
|
],
|
||||||
|
"title": "SessionFlagsConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "SessionFlagsConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "`managed_config.toml` was designed to be a config that was loaded as the last layer on top of everything else. This scheme did not quite work out as intended, but we keep this variant as a \"best effort\" while we phase out `managed_config.toml` in favor of `requirements.toml`.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"file",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"file": {
|
||||||
|
"$ref": "#/definitions/AbsolutePathBuf"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"legacyManagedConfigTomlFromFile"
|
||||||
|
],
|
||||||
|
"title": "LegacyManagedConfigTomlFromFileConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "LegacyManagedConfigTomlFromFileConfigLayerSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"legacyManagedConfigTomlFromMdm"
|
||||||
|
],
|
||||||
|
"title": "LegacyManagedConfigTomlFromMdmConfigLayerSourceType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "LegacyManagedConfigTomlFromMdmConfigLayerSource"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"OverriddenMetadata": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"effectiveValue",
|
||||||
|
"message",
|
||||||
|
"overridingLayer"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"effectiveValue": true,
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"overridingLayer": {
|
||||||
|
"$ref": "#/definitions/ConfigLayerMetadata"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"WriteStatus": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"ok",
|
||||||
|
"okOverridden"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
schemas/v2/ContextCompactedNotification.json
Normal file
18
schemas/v2/ContextCompactedNotification.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ContextCompactedNotification",
|
||||||
|
"description": "Deprecated: Use `ContextCompaction` item type instead.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"threadId",
|
||||||
|
"turnId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"turnId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
schemas/v2/DeprecationNoticeNotification.json
Normal file
21
schemas/v2/DeprecationNoticeNotification.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "DeprecationNoticeNotification",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"summary"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"details": {
|
||||||
|
"description": "Optional extra guidance, such as migration steps or rationale.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"summary": {
|
||||||
|
"description": "Concise summary of what is deprecated.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
199
schemas/v2/ErrorNotification.json
Normal file
199
schemas/v2/ErrorNotification.json
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ErrorNotification",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"error",
|
||||||
|
"threadId",
|
||||||
|
"turnId",
|
||||||
|
"willRetry"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"error": {
|
||||||
|
"$ref": "#/definitions/TurnError"
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"turnId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"willRetry": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"CodexErrorInfo": {
|
||||||
|
"description": "This translation layer make sure that we expose codex error code in camel case.\n\nWhen an upstream HTTP status is available (for example, from the Responses API or a provider), it is forwarded in `httpStatusCode` on the relevant `codexErrorInfo` variant.",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"contextWindowExceeded",
|
||||||
|
"usageLimitExceeded",
|
||||||
|
"serverOverloaded",
|
||||||
|
"cyberPolicy",
|
||||||
|
"internalServerError",
|
||||||
|
"unauthorized",
|
||||||
|
"badRequest",
|
||||||
|
"threadRollbackFailed",
|
||||||
|
"sandboxError",
|
||||||
|
"other"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"httpConnectionFailed"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"httpConnectionFailed": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"httpStatusCode": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "HttpConnectionFailedCodexErrorInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Failed to connect to the response SSE stream.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"responseStreamConnectionFailed"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"responseStreamConnectionFailed": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"httpStatusCode": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "ResponseStreamConnectionFailedCodexErrorInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "The response SSE stream disconnected in the middle of a turn before completion.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"responseStreamDisconnected"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"responseStreamDisconnected": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"httpStatusCode": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "ResponseStreamDisconnectedCodexErrorInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Reached the retry limit for responses.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"responseTooManyFailedAttempts"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"responseTooManyFailedAttempts": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"httpStatusCode": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint16",
|
||||||
|
"minimum": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "ResponseTooManyFailedAttemptsCodexErrorInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Returned when `turn/start` or `turn/steer` is submitted while the current active turn cannot accept same-turn steering, for example `/review` or manual `/compact`.",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"activeTurnNotSteerable"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"activeTurnNotSteerable": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"turnKind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"turnKind": {
|
||||||
|
"$ref": "#/definitions/NonSteerableTurnKind"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"title": "ActiveTurnNotSteerableCodexErrorInfo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"NonSteerableTurnKind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"review",
|
||||||
|
"compact"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"TurnError": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"message"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"additionalDetails": {
|
||||||
|
"default": null,
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"codexErrorInfo": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/CodexErrorInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
schemas/v2/ExperimentalFeatureEnablementSetParams.json
Normal file
17
schemas/v2/ExperimentalFeatureEnablementSetParams.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExperimentalFeatureEnablementSetParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enablement"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enablement": {
|
||||||
|
"description": "Process-wide runtime feature enablement keyed by canonical feature name.\n\nOnly named features are updated. Omitted features are left unchanged. Send an empty map for a no-op.",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
schemas/v2/ExperimentalFeatureEnablementSetResponse.json
Normal file
17
schemas/v2/ExperimentalFeatureEnablementSetResponse.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExperimentalFeatureEnablementSetResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"enablement"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"enablement": {
|
||||||
|
"description": "Feature enablement entries updated by this request.",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
schemas/v2/ExperimentalFeatureListParams.json
Normal file
30
schemas/v2/ExperimentalFeatureListParams.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExperimentalFeatureListParams",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"cursor": {
|
||||||
|
"description": "Opaque pagination cursor returned by a previous call.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"limit": {
|
||||||
|
"description": "Optional page size; defaults to a reasonable server-side value.",
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"format": "uint32",
|
||||||
|
"minimum": 0.0
|
||||||
|
},
|
||||||
|
"threadId": {
|
||||||
|
"description": "Optional loaded thread id. Pass this when showing feature state for an existing thread so enablement is computed from that thread's refreshed config, including project-local config for the thread's cwd.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
116
schemas/v2/ExperimentalFeatureListResponse.json
Normal file
116
schemas/v2/ExperimentalFeatureListResponse.json
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExperimentalFeatureListResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"data"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ExperimentalFeature"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nextCursor": {
|
||||||
|
"description": "Opaque cursor to pass to the next call to continue after the last item. If None, there are no more items to return.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"ExperimentalFeature": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"defaultEnabled",
|
||||||
|
"enabled",
|
||||||
|
"name",
|
||||||
|
"stage"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"announcement": {
|
||||||
|
"description": "Announcement copy shown to users when the feature is introduced. Null when this feature is not in beta.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"defaultEnabled": {
|
||||||
|
"description": "Whether this feature is enabled by default.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"description": "Short summary describing what the feature does. Null when this feature is not in beta.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"displayName": {
|
||||||
|
"description": "User-facing display name shown in the experimental features UI. Null when this feature is not in beta.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"description": "Whether this feature is currently enabled in the loaded config.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"description": "Stable key used in config.toml and CLI flag toggles.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"stage": {
|
||||||
|
"description": "Lifecycle stage of this feature flag.",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ExperimentalFeatureStage"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ExperimentalFeatureStage": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Feature is available for user testing and feedback.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"beta"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Feature is still being built and not ready for broad use.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"underDevelopment"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Feature is production-ready.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"stable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Feature is deprecated and should be avoided.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"deprecated"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Feature flag is retained only for backwards compatibility.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"removed"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
schemas/v2/ExternalAgentConfigDetectParams.json
Normal file
21
schemas/v2/ExternalAgentConfigDetectParams.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExternalAgentConfigDetectParams",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"cwds": {
|
||||||
|
"description": "Zero or more working directories to include for repo-scoped detection.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"includeHome": {
|
||||||
|
"description": "If true, include detection under the user's home (~/.claude, ~/.codex, etc.).",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
194
schemas/v2/ExternalAgentConfigDetectResponse.json
Normal file
194
schemas/v2/ExternalAgentConfigDetectResponse.json
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExternalAgentConfigDetectResponse",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"items"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ExternalAgentConfigMigrationItem"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"CommandMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ExternalAgentConfigMigrationItem": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"description",
|
||||||
|
"itemType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cwd": {
|
||||||
|
"description": "Null or empty means home-scoped migration; non-empty means repo-scoped migration.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/MigrationDetails"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"itemType": {
|
||||||
|
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ExternalAgentConfigMigrationItemType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"AGENTS_MD",
|
||||||
|
"CONFIG",
|
||||||
|
"SKILLS",
|
||||||
|
"PLUGINS",
|
||||||
|
"MCP_SERVER_CONFIG",
|
||||||
|
"SUBAGENTS",
|
||||||
|
"HOOKS",
|
||||||
|
"COMMANDS",
|
||||||
|
"SESSIONS"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"HookMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"McpServerMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MigrationDetails": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"commands": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/CommandMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hooks": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/HookMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mcpServers": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/McpServerMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/PluginsMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sessions": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/SessionMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"subagents": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/SubagentMigration"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PluginsMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"marketplaceName",
|
||||||
|
"pluginNames"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"marketplaceName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pluginNames": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SessionMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"cwd",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cwd": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SubagentMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExternalAgentConfigImportCompletedNotification",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
194
schemas/v2/ExternalAgentConfigImportParams.json
Normal file
194
schemas/v2/ExternalAgentConfigImportParams.json
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExternalAgentConfigImportParams",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"migrationItems"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"migrationItems": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ExternalAgentConfigMigrationItem"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"CommandMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ExternalAgentConfigMigrationItem": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"description",
|
||||||
|
"itemType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cwd": {
|
||||||
|
"description": "Null or empty means home-scoped migration; non-empty means repo-scoped migration.",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/MigrationDetails"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"itemType": {
|
||||||
|
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ExternalAgentConfigMigrationItemType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"AGENTS_MD",
|
||||||
|
"CONFIG",
|
||||||
|
"SKILLS",
|
||||||
|
"PLUGINS",
|
||||||
|
"MCP_SERVER_CONFIG",
|
||||||
|
"SUBAGENTS",
|
||||||
|
"HOOKS",
|
||||||
|
"COMMANDS",
|
||||||
|
"SESSIONS"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"HookMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"McpServerMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MigrationDetails": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"commands": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/CommandMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hooks": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/HookMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mcpServers": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/McpServerMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/PluginsMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sessions": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/SessionMigration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"subagents": {
|
||||||
|
"default": [],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/SubagentMigration"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PluginsMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"marketplaceName",
|
||||||
|
"pluginNames"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"marketplaceName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pluginNames": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SessionMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"cwd",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cwd": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SubagentMigration": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
schemas/v2/ExternalAgentConfigImportResponse.json
Normal file
5
schemas/v2/ExternalAgentConfigImportResponse.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "ExternalAgentConfigImportResponse",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user