mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-21 01:01:46 +00:00
Add foundry terminal and process pane
This commit is contained in:
parent
0471214d65
commit
28c4ac22ff
16 changed files with 2412 additions and 36 deletions
|
|
@ -3,7 +3,15 @@ import { eq } from "drizzle-orm";
|
|||
import { actor, queue } from "rivetkit";
|
||||
import { Loop, workflow } from "rivetkit/workflow";
|
||||
import type { ProviderId } from "@openhandoff/shared";
|
||||
import type { SessionEvent, SessionRecord } from "sandbox-agent";
|
||||
import type {
|
||||
ProcessCreateRequest,
|
||||
ProcessInfo,
|
||||
ProcessLogFollowQuery,
|
||||
ProcessLogsResponse,
|
||||
ProcessSignalQuery,
|
||||
SessionEvent,
|
||||
SessionRecord,
|
||||
} from "sandbox-agent";
|
||||
import { sandboxInstanceDb } from "./db/db.js";
|
||||
import { sandboxInstance as sandboxInstanceTable } from "./db/schema.js";
|
||||
import { SandboxInstancePersistDriver } from "./persist.js";
|
||||
|
|
@ -18,6 +26,11 @@ export interface SandboxInstanceInput {
|
|||
sandboxId: string;
|
||||
}
|
||||
|
||||
interface SandboxAgentConnection {
|
||||
endpoint: string;
|
||||
token?: string;
|
||||
}
|
||||
|
||||
const SANDBOX_ROW_ID = 1;
|
||||
const CREATE_SESSION_MAX_ATTEMPTS = 3;
|
||||
const CREATE_SESSION_RETRY_BASE_MS = 1_000;
|
||||
|
|
@ -79,7 +92,7 @@ function parseMetadata(metadataJson: string): Record<string, unknown> {
|
|||
}
|
||||
}
|
||||
|
||||
async function loadPersistedAgentConfig(c: any): Promise<{ endpoint: string; token?: string } | null> {
|
||||
async function loadPersistedAgentConfig(c: any): Promise<SandboxAgentConnection | null> {
|
||||
try {
|
||||
const row = await c.db
|
||||
.select({ metadataJson: sandboxInstanceTable.metadataJson })
|
||||
|
|
@ -101,7 +114,7 @@ async function loadPersistedAgentConfig(c: any): Promise<{ endpoint: string; tok
|
|||
return null;
|
||||
}
|
||||
|
||||
async function loadFreshDaytonaAgentConfig(c: any): Promise<{ endpoint: string; token?: string }> {
|
||||
async function loadFreshDaytonaAgentConfig(c: any): Promise<SandboxAgentConnection> {
|
||||
const { config, driver } = getActorRuntimeContext();
|
||||
const daytona = driver.daytona.createClient({
|
||||
apiUrl: config.providers.daytona.endpoint,
|
||||
|
|
@ -116,7 +129,7 @@ async function loadFreshDaytonaAgentConfig(c: any): Promise<{ endpoint: string;
|
|||
return preview.token ? { endpoint: preview.url, token: preview.token } : { endpoint: preview.url };
|
||||
}
|
||||
|
||||
async function loadFreshProviderAgentConfig(c: any): Promise<{ endpoint: string; token?: string }> {
|
||||
async function loadFreshProviderAgentConfig(c: any): Promise<SandboxAgentConnection> {
|
||||
const { providers } = getActorRuntimeContext();
|
||||
const provider = providers.get(c.state.providerId);
|
||||
return await provider.ensureSandboxAgent({
|
||||
|
|
@ -125,7 +138,7 @@ async function loadFreshProviderAgentConfig(c: any): Promise<{ endpoint: string;
|
|||
});
|
||||
}
|
||||
|
||||
async function loadAgentConfig(c: any): Promise<{ endpoint: string; token?: string }> {
|
||||
async function loadAgentConfig(c: any): Promise<SandboxAgentConnection> {
|
||||
const persisted = await loadPersistedAgentConfig(c);
|
||||
if (c.state.providerId === "daytona") {
|
||||
// Keep one stable signed preview endpoint per sandbox-instance actor.
|
||||
|
|
@ -282,6 +295,13 @@ async function getSandboxAgentClient(c: any) {
|
|||
});
|
||||
}
|
||||
|
||||
function broadcastProcessesUpdated(c: any): void {
|
||||
c.broadcast("processesUpdated", {
|
||||
sandboxId: c.state.sandboxId,
|
||||
at: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
async function ensureSandboxMutation(c: any, command: EnsureSandboxCommand): Promise<void> {
|
||||
const now = Date.now();
|
||||
const metadata = {
|
||||
|
|
@ -478,6 +498,56 @@ export const sandboxInstance = actor({
|
|||
sandboxId: input.sandboxId,
|
||||
}),
|
||||
actions: {
|
||||
async sandboxAgentConnection(c: any): Promise<SandboxAgentConnection> {
|
||||
return await loadAgentConfig(c);
|
||||
},
|
||||
|
||||
async createProcess(c: any, request: ProcessCreateRequest): Promise<ProcessInfo> {
|
||||
const client = await getSandboxAgentClient(c);
|
||||
const created = await client.createProcess(request);
|
||||
broadcastProcessesUpdated(c);
|
||||
return created;
|
||||
},
|
||||
|
||||
async listProcesses(c: any): Promise<{ processes: ProcessInfo[] }> {
|
||||
const client = await getSandboxAgentClient(c);
|
||||
return await client.listProcesses();
|
||||
},
|
||||
|
||||
async getProcessLogs(
|
||||
c: any,
|
||||
request: { processId: string; query?: ProcessLogFollowQuery }
|
||||
): Promise<ProcessLogsResponse> {
|
||||
const client = await getSandboxAgentClient(c);
|
||||
return await client.getProcessLogs(request.processId, request.query);
|
||||
},
|
||||
|
||||
async stopProcess(
|
||||
c: any,
|
||||
request: { processId: string; query?: ProcessSignalQuery }
|
||||
): Promise<ProcessInfo> {
|
||||
const client = await getSandboxAgentClient(c);
|
||||
const stopped = await client.stopProcess(request.processId, request.query);
|
||||
broadcastProcessesUpdated(c);
|
||||
return stopped;
|
||||
},
|
||||
|
||||
async killProcess(
|
||||
c: any,
|
||||
request: { processId: string; query?: ProcessSignalQuery }
|
||||
): Promise<ProcessInfo> {
|
||||
const client = await getSandboxAgentClient(c);
|
||||
const killed = await client.killProcess(request.processId, request.query);
|
||||
broadcastProcessesUpdated(c);
|
||||
return killed;
|
||||
},
|
||||
|
||||
async deleteProcess(c: any, request: { processId: string }): Promise<void> {
|
||||
const client = await getSandboxAgentClient(c);
|
||||
await client.deleteProcess(request.processId);
|
||||
broadcastProcessesUpdated(c);
|
||||
},
|
||||
|
||||
async providerState(c: any): Promise<{ providerId: ProviderId; sandboxId: string; state: string; at: number }> {
|
||||
const at = Date.now();
|
||||
const { config, driver } = getActorRuntimeContext();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue