mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-17 08:01:03 +00:00
feat: expand api snapshots and schema tooling
This commit is contained in:
parent
ee014b0838
commit
011ca27287
72 changed files with 29480 additions and 1081 deletions
|
|
@ -157,6 +157,26 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/v1/sessions": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"sessions"
|
||||
],
|
||||
"operationId": "list_sessions",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SessionListResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/sessions/{session_id}": {
|
||||
"post": {
|
||||
"tags": [
|
||||
|
|
@ -1047,6 +1067,65 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"SessionInfo": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"sessionId",
|
||||
"agent",
|
||||
"agentMode",
|
||||
"permissionMode",
|
||||
"ended",
|
||||
"eventCount"
|
||||
],
|
||||
"properties": {
|
||||
"agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"agentMode": {
|
||||
"type": "string"
|
||||
},
|
||||
"agentSessionId": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"ended": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"eventCount": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": 0
|
||||
},
|
||||
"model": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"permissionMode": {
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"type": "string"
|
||||
},
|
||||
"variant": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"SessionListResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"sessions"
|
||||
],
|
||||
"properties": {
|
||||
"sessions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SessionInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Started": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"generate:openapi": "cargo check -p sandbox-agent-openapi-gen && cargo run -p sandbox-agent-openapi-gen -- --out src/generated/openapi.json",
|
||||
"generate:types": "openapi-typescript src/generated/openapi.json -o src/generated/openapi.ts",
|
||||
"generate:openapi": "cargo check -p sandbox-agent-openapi-gen && cargo run -p sandbox-agent-openapi-gen -- --out ../openapi/openapi.json",
|
||||
"generate:types": "openapi-typescript ../openapi/openapi.json -o src/generated/openapi.ts",
|
||||
"generate": "pnpm run generate:openapi && pnpm run generate:types",
|
||||
"build": "pnpm run generate && tsc -p tsconfig.json"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11,14 +11,21 @@ export type AgentInfo = components["schemas"]["AgentInfo"];
|
|||
export type AgentListResponse = components["schemas"]["AgentListResponse"];
|
||||
export type CreateSessionRequest = components["schemas"]["CreateSessionRequest"];
|
||||
export type CreateSessionResponse = components["schemas"]["CreateSessionResponse"];
|
||||
export type HealthResponse = components["schemas"]["HealthResponse"];
|
||||
export type MessageRequest = components["schemas"]["MessageRequest"];
|
||||
export type EventsQuery = components["schemas"]["EventsQuery"];
|
||||
export type EventsResponse = components["schemas"]["EventsResponse"];
|
||||
export type PermissionRequest = components["schemas"]["PermissionRequest"];
|
||||
export type QuestionReplyRequest = components["schemas"]["QuestionReplyRequest"];
|
||||
export type QuestionRequest = components["schemas"]["QuestionRequest"];
|
||||
export type PermissionReplyRequest = components["schemas"]["PermissionReplyRequest"];
|
||||
export type PermissionReply = components["schemas"]["PermissionReply"];
|
||||
export type ProblemDetails = components["schemas"]["ProblemDetails"];
|
||||
export type SessionInfo = components["schemas"]["SessionInfo"];
|
||||
export type SessionListResponse = components["schemas"]["SessionListResponse"];
|
||||
export type UniversalEvent = components["schemas"]["UniversalEvent"];
|
||||
export type UniversalMessage = components["schemas"]["UniversalMessage"];
|
||||
export type UniversalMessagePart = components["schemas"]["UniversalMessagePart"];
|
||||
|
||||
const API_PREFIX = "/v1";
|
||||
|
||||
|
|
@ -58,6 +65,7 @@ type RequestOptions = {
|
|||
body?: unknown;
|
||||
headers?: HeadersInit;
|
||||
accept?: string;
|
||||
signal?: AbortSignal;
|
||||
};
|
||||
|
||||
export class SandboxDaemonClient {
|
||||
|
|
@ -108,6 +116,10 @@ export class SandboxDaemonClient {
|
|||
return this.requestJson("GET", `${API_PREFIX}/agents`);
|
||||
}
|
||||
|
||||
async getHealth(): Promise<HealthResponse> {
|
||||
return this.requestJson("GET", `${API_PREFIX}/health`);
|
||||
}
|
||||
|
||||
async installAgent(agent: string, request: AgentInstallRequest = {}): Promise<void> {
|
||||
await this.requestJson("POST", `${API_PREFIX}/agents/${encodeURIComponent(agent)}/install`, {
|
||||
body: request,
|
||||
|
|
@ -124,6 +136,10 @@ export class SandboxDaemonClient {
|
|||
});
|
||||
}
|
||||
|
||||
async listSessions(): Promise<SessionListResponse> {
|
||||
return this.requestJson("GET", `${API_PREFIX}/sessions`);
|
||||
}
|
||||
|
||||
async postMessage(sessionId: string, request: MessageRequest): Promise<void> {
|
||||
await this.requestJson("POST", `${API_PREFIX}/sessions/${encodeURIComponent(sessionId)}/messages`, {
|
||||
body: request,
|
||||
|
|
@ -136,15 +152,20 @@ export class SandboxDaemonClient {
|
|||
});
|
||||
}
|
||||
|
||||
async getEventsSse(sessionId: string, query?: EventsQuery): Promise<Response> {
|
||||
async getEventsSse(sessionId: string, query?: EventsQuery, signal?: AbortSignal): Promise<Response> {
|
||||
return this.requestRaw("GET", `${API_PREFIX}/sessions/${encodeURIComponent(sessionId)}/events/sse`, {
|
||||
query,
|
||||
accept: "text/event-stream",
|
||||
signal,
|
||||
});
|
||||
}
|
||||
|
||||
async *streamEvents(sessionId: string, query?: EventsQuery): AsyncGenerator<UniversalEvent, void, void> {
|
||||
const response = await this.getEventsSse(sessionId, query);
|
||||
async *streamEvents(
|
||||
sessionId: string,
|
||||
query?: EventsQuery,
|
||||
signal?: AbortSignal,
|
||||
): AsyncGenerator<UniversalEvent, void, void> {
|
||||
const response = await this.getEventsSse(sessionId, query, signal);
|
||||
if (!response.body) {
|
||||
throw new Error("SSE stream is not readable in this environment.");
|
||||
}
|
||||
|
|
@ -249,7 +270,7 @@ export class SandboxDaemonClient {
|
|||
headers.set("Accept", options.accept);
|
||||
}
|
||||
|
||||
const init: RequestInit = { method, headers };
|
||||
const init: RequestInit = { method, headers, signal: options.signal };
|
||||
if (options.body !== undefined) {
|
||||
headers.set("Content-Type", "application/json");
|
||||
init.body = JSON.stringify(options.body);
|
||||
|
|
|
|||
|
|
@ -14,12 +14,19 @@ export type {
|
|||
CreateSessionResponse,
|
||||
EventsQuery,
|
||||
EventsResponse,
|
||||
HealthResponse,
|
||||
MessageRequest,
|
||||
PermissionRequest,
|
||||
PermissionReply,
|
||||
PermissionReplyRequest,
|
||||
ProblemDetails,
|
||||
QuestionRequest,
|
||||
QuestionReplyRequest,
|
||||
SessionInfo,
|
||||
SessionListResponse,
|
||||
UniversalEvent,
|
||||
UniversalMessage,
|
||||
UniversalMessagePart,
|
||||
SandboxDaemonClientOptions,
|
||||
SandboxDaemonConnectOptions,
|
||||
} from "./client.js";
|
||||
|
|
|
|||
|
|
@ -50,8 +50,9 @@ export async function spawnSandboxDaemon(
|
|||
const net = await import("node:net");
|
||||
const { createRequire } = await import("node:module");
|
||||
|
||||
const host = options.host ?? "127.0.0.1";
|
||||
const port = options.port ?? (await getFreePort(net, host));
|
||||
const bindHost = options.host ?? "127.0.0.1";
|
||||
const port = options.port ?? (await getFreePort(net, bindHost));
|
||||
const connectHost = bindHost === "0.0.0.0" || bindHost === "::" ? "127.0.0.1" : bindHost;
|
||||
const token = options.token ?? crypto.randomBytes(24).toString("hex");
|
||||
const timeoutMs = options.timeoutMs ?? 15_000;
|
||||
const logMode: SandboxDaemonSpawnLogMode = options.log ?? "inherit";
|
||||
|
|
@ -67,7 +68,7 @@ export async function spawnSandboxDaemon(
|
|||
}
|
||||
|
||||
const stdio = logMode === "inherit" ? "inherit" : logMode === "silent" ? "ignore" : "pipe";
|
||||
const args = ["--host", host, "--port", String(port), "--token", token];
|
||||
const args = ["--host", bindHost, "--port", String(port), "--token", token];
|
||||
const child = spawn(binaryPath, args, {
|
||||
stdio,
|
||||
env: {
|
||||
|
|
@ -77,8 +78,8 @@ export async function spawnSandboxDaemon(
|
|||
});
|
||||
const cleanup = registerProcessCleanup(child);
|
||||
|
||||
const baseUrl = `http://${host}:${port}`;
|
||||
const ready = waitForHealth(baseUrl, fetcher ?? globalThis.fetch, timeoutMs, child);
|
||||
const baseUrl = `http://${connectHost}:${port}`;
|
||||
const ready = waitForHealth(baseUrl, fetcher ?? globalThis.fetch, timeoutMs, child, token);
|
||||
|
||||
await ready;
|
||||
|
||||
|
|
@ -161,6 +162,7 @@ async function waitForHealth(
|
|||
fetcher: typeof fetch | undefined,
|
||||
timeoutMs: number,
|
||||
child: ChildProcess,
|
||||
token: string,
|
||||
): Promise<void> {
|
||||
if (!fetcher) {
|
||||
throw new Error("Fetch API is not available; provide a fetch implementation.");
|
||||
|
|
@ -173,7 +175,9 @@ async function waitForHealth(
|
|||
throw new Error("sandbox-agent exited before becoming healthy.");
|
||||
}
|
||||
try {
|
||||
const response = await fetcher(`${baseUrl}/v1/health`);
|
||||
const response = await fetcher(`${baseUrl}/v1/health`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
if (response.ok) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue