mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 07:04:48 +00:00
feat: add native OpenCode proxy for TUI/config endpoints (#129)
This commit is contained in:
parent
c54f83e1a6
commit
77f741ff62
3 changed files with 408 additions and 44 deletions
|
|
@ -113,6 +113,7 @@ for await (const event of events.stream) {
|
||||||
- **CORS**: When using the web UI from a different origin, configure `--cors-allow-origin`
|
- **CORS**: When using the web UI from a different origin, configure `--cors-allow-origin`
|
||||||
- **Provider Selection**: Use the provider/model selector in the UI to choose which backing agent to use (claude, codex, opencode, amp)
|
- **Provider Selection**: Use the provider/model selector in the UI to choose which backing agent to use (claude, codex, opencode, amp)
|
||||||
- **Models & Variants**: Providers are grouped by backing agent (e.g. Claude Code, Codex, Amp). OpenCode models are grouped by `OpenCode (<provider>)` to preserve their native provider grouping. Each model keeps its real model ID, and variants are exposed when available (Codex/OpenCode/Amp).
|
- **Models & Variants**: Providers are grouped by backing agent (e.g. Claude Code, Codex, Amp). OpenCode models are grouped by `OpenCode (<provider>)` to preserve their native provider grouping. Each model keeps its real model ID, and variants are exposed when available (Codex/OpenCode/Amp).
|
||||||
|
- **Optional Native Proxy for TUI/Config Endpoints**: Set `OPENCODE_COMPAT_PROXY_URL` (for example `http://127.0.0.1:4096`) to proxy select OpenCode-native endpoints to a real OpenCode server. This currently applies to `/command`, `/config`, `/global/config`, and `/tui/*`. If not set, sandbox-agent uses its built-in compatibility handlers.
|
||||||
|
|
||||||
## Endpoint Coverage
|
## Endpoint Coverage
|
||||||
|
|
||||||
|
|
@ -134,10 +135,15 @@ See the full endpoint compatibility table below. Most endpoints are functional f
|
||||||
| `GET /question` | ✓ | List pending questions |
|
| `GET /question` | ✓ | List pending questions |
|
||||||
| `POST /question/{id}/reply` | ✓ | Answer agent questions |
|
| `POST /question/{id}/reply` | ✓ | Answer agent questions |
|
||||||
| `GET /provider` | ✓ | Returns provider metadata |
|
| `GET /provider` | ✓ | Returns provider metadata |
|
||||||
|
| `GET /command` | ↔ | Proxied to native OpenCode when `OPENCODE_COMPAT_PROXY_URL` is set; otherwise stub response |
|
||||||
|
| `GET /config` | ↔ | Proxied to native OpenCode when `OPENCODE_COMPAT_PROXY_URL` is set; otherwise stub response |
|
||||||
|
| `PATCH /config` | ↔ | Proxied to native OpenCode when `OPENCODE_COMPAT_PROXY_URL` is set; otherwise local compatibility behavior |
|
||||||
|
| `GET /global/config` | ↔ | Proxied to native OpenCode when `OPENCODE_COMPAT_PROXY_URL` is set; otherwise stub response |
|
||||||
|
| `PATCH /global/config` | ↔ | Proxied to native OpenCode when `OPENCODE_COMPAT_PROXY_URL` is set; otherwise local compatibility behavior |
|
||||||
|
| `/tui/*` | ↔ | Proxied to native OpenCode when `OPENCODE_COMPAT_PROXY_URL` is set; otherwise local compatibility behavior |
|
||||||
| `GET /agent` | − | Returns agent list |
|
| `GET /agent` | − | Returns agent list |
|
||||||
| `GET /config` | − | Returns config |
|
|
||||||
| *other endpoints* | − | Return empty/stub responses |
|
| *other endpoints* | − | Return empty/stub responses |
|
||||||
|
|
||||||
✓ Functional − Stubbed
|
✓ Functional ↔ Proxied (optional) − Stubbed
|
||||||
|
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
|
|
||||||
13
justfile
13
justfile
|
|
@ -50,14 +50,20 @@ fmt:
|
||||||
|
|
||||||
[group('dev')]
|
[group('dev')]
|
||||||
install-fast-sa:
|
install-fast-sa:
|
||||||
cargo build --release -p sandbox-agent
|
SANDBOX_AGENT_SKIP_INSPECTOR=1 cargo build --release -p sandbox-agent
|
||||||
|
rm -f ~/.cargo/bin/sandbox-agent
|
||||||
cp target/release/sandbox-agent ~/.cargo/bin/sandbox-agent
|
cp target/release/sandbox-agent ~/.cargo/bin/sandbox-agent
|
||||||
|
|
||||||
[group('dev')]
|
[group('dev')]
|
||||||
install-fast-gigacode:
|
install-gigacode:
|
||||||
cargo build --release -p gigacode
|
SANDBOX_AGENT_SKIP_INSPECTOR=1 cargo build --release -p gigacode
|
||||||
|
rm -f ~/.cargo/bin/gigacode
|
||||||
cp target/release/gigacode ~/.cargo/bin/gigacode
|
cp target/release/gigacode ~/.cargo/bin/gigacode
|
||||||
|
|
||||||
|
[group('dev')]
|
||||||
|
run-gigacode *ARGS:
|
||||||
|
SANDBOX_AGENT_SKIP_INSPECTOR=1 cargo run -p gigacode -- {{ ARGS }}
|
||||||
|
|
||||||
[group('dev')]
|
[group('dev')]
|
||||||
dev-docs:
|
dev-docs:
|
||||||
cd docs && pnpm dlx mintlify dev
|
cd docs && pnpm dlx mintlify dev
|
||||||
|
|
@ -77,4 +83,3 @@ install-release:
|
||||||
pnpm build --filter @sandbox-agent/inspector...
|
pnpm build --filter @sandbox-agent/inspector...
|
||||||
cargo install --path server/packages/sandbox-agent
|
cargo install --path server/packages/sandbox-agent
|
||||||
cargo install --path gigacode
|
cargo install --path gigacode
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,15 @@ use std::str::FromStr;
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use axum::body::Body;
|
||||||
use axum::extract::{Path, Query, State};
|
use axum::extract::{Path, Query, State};
|
||||||
use axum::http::{HeaderMap, StatusCode};
|
use axum::http::{header, HeaderMap, HeaderName, HeaderValue, StatusCode};
|
||||||
use axum::response::sse::{Event, KeepAlive};
|
use axum::response::sse::{Event, KeepAlive};
|
||||||
use axum::response::{IntoResponse, Sse};
|
use axum::response::{IntoResponse, Response, Sse};
|
||||||
use axum::routing::{get, patch, post, put};
|
use axum::routing::{get, patch, post, put};
|
||||||
use axum::{Json, Router};
|
use axum::{Json, Router};
|
||||||
use futures::stream;
|
use futures::stream;
|
||||||
|
use reqwest::Client;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use tokio::sync::{broadcast, Mutex};
|
use tokio::sync::{broadcast, Mutex};
|
||||||
|
|
@ -56,6 +58,7 @@ struct OpenCodeCompatConfig {
|
||||||
fixed_state: Option<String>,
|
fixed_state: Option<String>,
|
||||||
fixed_config: Option<String>,
|
fixed_config: Option<String>,
|
||||||
fixed_branch: Option<String>,
|
fixed_branch: Option<String>,
|
||||||
|
proxy_base_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpenCodeCompatConfig {
|
impl OpenCodeCompatConfig {
|
||||||
|
|
@ -70,6 +73,9 @@ impl OpenCodeCompatConfig {
|
||||||
fixed_state: std::env::var("OPENCODE_COMPAT_STATE").ok(),
|
fixed_state: std::env::var("OPENCODE_COMPAT_STATE").ok(),
|
||||||
fixed_config: std::env::var("OPENCODE_COMPAT_CONFIG").ok(),
|
fixed_config: std::env::var("OPENCODE_COMPAT_CONFIG").ok(),
|
||||||
fixed_branch: std::env::var("OPENCODE_COMPAT_BRANCH").ok(),
|
fixed_branch: std::env::var("OPENCODE_COMPAT_BRANCH").ok(),
|
||||||
|
proxy_base_url: std::env::var("OPENCODE_COMPAT_PROXY_URL")
|
||||||
|
.ok()
|
||||||
|
.and_then(normalize_proxy_base_url),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,6 +90,19 @@ impl OpenCodeCompatConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_proxy_base_url(value: String) -> Option<String> {
|
||||||
|
let trimmed = value.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let normalized = trimmed.trim_end_matches('/').to_string();
|
||||||
|
if normalized.starts_with("http://") || normalized.starts_with("https://") {
|
||||||
|
Some(normalized)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct OpenCodeSessionRecord {
|
struct OpenCodeSessionRecord {
|
||||||
id: String,
|
id: String,
|
||||||
|
|
@ -369,6 +388,10 @@ impl OpenCodeState {
|
||||||
.unwrap_or_else(|| "main".to_string())
|
.unwrap_or_else(|| "main".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn proxy_base_url(&self) -> Option<&str> {
|
||||||
|
self.config.proxy_base_url.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
async fn update_runtime(
|
async fn update_runtime(
|
||||||
&self,
|
&self,
|
||||||
session_id: &str,
|
session_id: &str,
|
||||||
|
|
@ -387,6 +410,7 @@ impl OpenCodeState {
|
||||||
pub struct OpenCodeAppState {
|
pub struct OpenCodeAppState {
|
||||||
pub inner: Arc<AppState>,
|
pub inner: Arc<AppState>,
|
||||||
pub opencode: Arc<OpenCodeState>,
|
pub opencode: Arc<OpenCodeState>,
|
||||||
|
proxy_http_client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpenCodeAppState {
|
impl OpenCodeAppState {
|
||||||
|
|
@ -394,6 +418,7 @@ impl OpenCodeAppState {
|
||||||
Arc::new(Self {
|
Arc::new(Self {
|
||||||
inner,
|
inner,
|
||||||
opencode: Arc::new(OpenCodeState::new()),
|
opencode: Arc::new(OpenCodeState::new()),
|
||||||
|
proxy_http_client: Client::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1091,6 +1116,91 @@ fn bool_ok(value: bool) -> (StatusCode, Json<Value>) {
|
||||||
(StatusCode::OK, Json(json!(value)))
|
(StatusCode::OK, Json(json!(value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn proxy_native_opencode(
|
||||||
|
state: &Arc<OpenCodeAppState>,
|
||||||
|
method: reqwest::Method,
|
||||||
|
path: &str,
|
||||||
|
headers: &HeaderMap,
|
||||||
|
body: Option<Value>,
|
||||||
|
) -> Option<Response> {
|
||||||
|
let Some(base_url) = state.opencode.proxy_base_url() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut request = state
|
||||||
|
.proxy_http_client
|
||||||
|
.request(method, format!("{base_url}{path}"));
|
||||||
|
|
||||||
|
for header_name in [
|
||||||
|
header::AUTHORIZATION,
|
||||||
|
header::ACCEPT,
|
||||||
|
HeaderName::from_static("x-opencode-directory"),
|
||||||
|
] {
|
||||||
|
if let Some(value) = headers.get(&header_name) {
|
||||||
|
request = request.header(header_name.as_str(), value.as_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(body) = body {
|
||||||
|
request = request.json(&body);
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = match request.send().await {
|
||||||
|
Ok(response) => response,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(path, ?err, "failed proxy request to native opencode");
|
||||||
|
return Some(
|
||||||
|
(
|
||||||
|
StatusCode::BAD_GATEWAY,
|
||||||
|
Json(json!({
|
||||||
|
"data": {},
|
||||||
|
"errors": [{"message": format!("failed to proxy to native opencode: {err}")}],
|
||||||
|
"success": false,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.into_response(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let status =
|
||||||
|
StatusCode::from_u16(response.status().as_u16()).unwrap_or(StatusCode::BAD_GATEWAY);
|
||||||
|
let content_type = response
|
||||||
|
.headers()
|
||||||
|
.get(reqwest::header::CONTENT_TYPE)
|
||||||
|
.and_then(|value| value.to_str().ok())
|
||||||
|
.map(|value| value.to_string());
|
||||||
|
let body_bytes = match response.bytes().await {
|
||||||
|
Ok(bytes) => bytes,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(path, ?err, "failed to read proxied response body");
|
||||||
|
return Some(
|
||||||
|
(
|
||||||
|
StatusCode::BAD_GATEWAY,
|
||||||
|
Json(json!({
|
||||||
|
"data": {},
|
||||||
|
"errors": [{"message": format!("failed to read proxied response: {err}")}],
|
||||||
|
"success": false,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.into_response(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut proxied = Response::new(Body::from(body_bytes));
|
||||||
|
*proxied.status_mut() = status;
|
||||||
|
if let Some(content_type) = content_type {
|
||||||
|
if let Ok(header_value) = HeaderValue::from_str(&content_type) {
|
||||||
|
proxied
|
||||||
|
.headers_mut()
|
||||||
|
.insert(header::CONTENT_TYPE, header_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(proxied)
|
||||||
|
}
|
||||||
|
|
||||||
fn build_user_message(
|
fn build_user_message(
|
||||||
session_id: &str,
|
session_id: &str,
|
||||||
message_id: &str,
|
message_id: &str,
|
||||||
|
|
@ -2676,8 +2786,16 @@ async fn oc_agent_list(State(state): State<Arc<OpenCodeAppState>>) -> impl IntoR
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_command_list() -> impl IntoResponse {
|
async fn oc_command_list(
|
||||||
(StatusCode::OK, Json(json!([])))
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) =
|
||||||
|
proxy_native_opencode(&state, reqwest::Method::GET, "/command", &headers, None).await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
(StatusCode::OK, Json(json!([]))).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -2686,8 +2804,13 @@ async fn oc_command_list() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_config_get() -> impl IntoResponse {
|
async fn oc_config_get(State(state): State<Arc<OpenCodeAppState>>, headers: HeaderMap) -> Response {
|
||||||
(StatusCode::OK, Json(json!({})))
|
if let Some(response) =
|
||||||
|
proxy_native_opencode(&state, reqwest::Method::GET, "/config", &headers, None).await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
(StatusCode::OK, Json(json!({}))).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -2697,8 +2820,23 @@ async fn oc_config_get() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_config_patch(Json(body): Json<Value>) -> impl IntoResponse {
|
async fn oc_config_patch(
|
||||||
(StatusCode::OK, Json(body))
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
Json(body): Json<Value>,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::PATCH,
|
||||||
|
"/config",
|
||||||
|
&headers,
|
||||||
|
Some(body.clone()),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
(StatusCode::OK, Json(body)).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -2906,8 +3044,22 @@ async fn oc_global_health() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_global_config_get() -> impl IntoResponse {
|
async fn oc_global_config_get(
|
||||||
(StatusCode::OK, Json(json!({})))
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::GET,
|
||||||
|
"/global/config",
|
||||||
|
&headers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
(StatusCode::OK, Json(json!({}))).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -2917,8 +3069,23 @@ async fn oc_global_config_get() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_global_config_patch(Json(body): Json<Value>) -> impl IntoResponse {
|
async fn oc_global_config_patch(
|
||||||
(StatusCode::OK, Json(body))
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
Json(body): Json<Value>,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::PATCH,
|
||||||
|
"/global/config",
|
||||||
|
&headers,
|
||||||
|
Some(body.clone()),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
(StatusCode::OK, Json(body)).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4563,8 +4730,19 @@ async fn oc_skill_list() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_next() -> impl IntoResponse {
|
async fn oc_tui_next(State(state): State<Arc<OpenCodeAppState>>, headers: HeaderMap) -> Response {
|
||||||
(StatusCode::OK, Json(json!({"path": "", "body": {}})))
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::GET,
|
||||||
|
"/tui/control/next",
|
||||||
|
&headers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
(StatusCode::OK, Json(json!({"path": "", "body": {}}))).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4574,8 +4752,23 @@ async fn oc_tui_next() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_response() -> impl IntoResponse {
|
async fn oc_tui_response(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
body: Option<Json<Value>>,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/control/response",
|
||||||
|
&headers,
|
||||||
|
body.map(|json| json.0),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4585,8 +4778,23 @@ async fn oc_tui_response() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_append_prompt() -> impl IntoResponse {
|
async fn oc_tui_append_prompt(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
body: Option<Json<Value>>,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/append-prompt",
|
||||||
|
&headers,
|
||||||
|
body.map(|json| json.0),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4595,8 +4803,22 @@ async fn oc_tui_append_prompt() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_open_help() -> impl IntoResponse {
|
async fn oc_tui_open_help(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/open-help",
|
||||||
|
&headers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4605,8 +4827,22 @@ async fn oc_tui_open_help() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_open_sessions() -> impl IntoResponse {
|
async fn oc_tui_open_sessions(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/open-sessions",
|
||||||
|
&headers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4615,8 +4851,22 @@ async fn oc_tui_open_sessions() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_open_themes() -> impl IntoResponse {
|
async fn oc_tui_open_themes(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/open-themes",
|
||||||
|
&headers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4625,8 +4875,22 @@ async fn oc_tui_open_themes() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_open_models() -> impl IntoResponse {
|
async fn oc_tui_open_models(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/open-models",
|
||||||
|
&headers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4636,8 +4900,23 @@ async fn oc_tui_open_models() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_submit_prompt() -> impl IntoResponse {
|
async fn oc_tui_submit_prompt(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
body: Option<Json<Value>>,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/submit-prompt",
|
||||||
|
&headers,
|
||||||
|
body.map(|json| json.0),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4646,8 +4925,22 @@ async fn oc_tui_submit_prompt() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_clear_prompt() -> impl IntoResponse {
|
async fn oc_tui_clear_prompt(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/clear-prompt",
|
||||||
|
&headers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4657,8 +4950,23 @@ async fn oc_tui_clear_prompt() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_execute_command() -> impl IntoResponse {
|
async fn oc_tui_execute_command(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
body: Option<Json<Value>>,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/execute-command",
|
||||||
|
&headers,
|
||||||
|
body.map(|json| json.0),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4668,8 +4976,23 @@ async fn oc_tui_execute_command() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_show_toast() -> impl IntoResponse {
|
async fn oc_tui_show_toast(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
body: Option<Json<Value>>,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/show-toast",
|
||||||
|
&headers,
|
||||||
|
body.map(|json| json.0),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4679,8 +5002,23 @@ async fn oc_tui_show_toast() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_publish() -> impl IntoResponse {
|
async fn oc_tui_publish(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
body: Option<Json<Value>>,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/publish",
|
||||||
|
&headers,
|
||||||
|
body.map(|json| json.0),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
|
|
@ -4690,8 +5028,23 @@ async fn oc_tui_publish() -> impl IntoResponse {
|
||||||
responses((status = 200)),
|
responses((status = 200)),
|
||||||
tag = "opencode"
|
tag = "opencode"
|
||||||
)]
|
)]
|
||||||
async fn oc_tui_select_session() -> impl IntoResponse {
|
async fn oc_tui_select_session(
|
||||||
bool_ok(true)
|
State(state): State<Arc<OpenCodeAppState>>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
body: Option<Json<Value>>,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(response) = proxy_native_opencode(
|
||||||
|
&state,
|
||||||
|
reqwest::Method::POST,
|
||||||
|
"/tui/select-session",
|
||||||
|
&headers,
|
||||||
|
body.map(|json| json.0),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
bool_ok(true).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(OpenApi)]
|
#[derive(OpenApi)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue