mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-17 01:04:42 +00:00
chore: recover hamburg workspace state
This commit is contained in:
parent
5d65013aa5
commit
196541394b
15 changed files with 1082 additions and 60 deletions
|
|
@ -25,10 +25,12 @@ export function prepareMockAgentDataHome(dataHome: string): Record<string, strin
|
|||
runtimeEnv.XDG_DATA_HOME = dataHome;
|
||||
}
|
||||
|
||||
const nodeScript = String.raw`#!/usr/bin/env node
|
||||
const nodeScript = String.raw`#!/usr/bin/env node
|
||||
const { createInterface } = require("node:readline");
|
||||
|
||||
let nextSession = 0;
|
||||
let nextPermission = 0;
|
||||
const pendingPermissions = new Map();
|
||||
|
||||
function emit(value) {
|
||||
process.stdout.write(JSON.stringify(value) + "\n");
|
||||
|
|
@ -65,6 +67,38 @@ rl.on("line", (line) => {
|
|||
const hasId = Object.prototype.hasOwnProperty.call(msg, "id");
|
||||
const method = hasMethod ? msg.method : undefined;
|
||||
|
||||
if (!hasMethod && hasId) {
|
||||
const pending = pendingPermissions.get(String(msg.id));
|
||||
if (pending) {
|
||||
pendingPermissions.delete(String(msg.id));
|
||||
const outcome = msg?.result?.outcome;
|
||||
const optionId = outcome?.outcome === "selected" ? outcome.optionId : "cancelled";
|
||||
const suffix = optionId === "reject-once" ? "rejected" : "approved";
|
||||
emit({
|
||||
jsonrpc: "2.0",
|
||||
method: "session/update",
|
||||
params: {
|
||||
sessionId: pending.sessionId,
|
||||
update: {
|
||||
sessionUpdate: "agent_message_chunk",
|
||||
content: {
|
||||
type: "text",
|
||||
text: "mock permission " + suffix + ": " + optionId,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
emit({
|
||||
jsonrpc: "2.0",
|
||||
id: pending.promptId,
|
||||
result: {
|
||||
stopReason: "end_turn",
|
||||
},
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (method === "session/prompt") {
|
||||
const sessionId = typeof msg?.params?.sessionId === "string" ? msg.params.sessionId : "";
|
||||
const text = firstText(msg?.params?.prompt);
|
||||
|
|
@ -82,6 +116,51 @@ rl.on("line", (line) => {
|
|||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (text.includes("permission")) {
|
||||
nextPermission += 1;
|
||||
const permissionId = "permission-" + nextPermission;
|
||||
pendingPermissions.set(permissionId, {
|
||||
promptId: msg.id,
|
||||
sessionId,
|
||||
});
|
||||
emit({
|
||||
jsonrpc: "2.0",
|
||||
id: permissionId,
|
||||
method: "session/request_permission",
|
||||
params: {
|
||||
sessionId,
|
||||
toolCall: {
|
||||
toolCallId: "tool-call-" + nextPermission,
|
||||
title: "Write mock.txt",
|
||||
kind: "edit",
|
||||
status: "pending",
|
||||
locations: [{ path: "/tmp/mock.txt" }],
|
||||
rawInput: {
|
||||
path: "/tmp/mock.txt",
|
||||
content: "hello",
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
kind: "allow_once",
|
||||
name: "Allow once",
|
||||
optionId: "allow-once",
|
||||
},
|
||||
{
|
||||
kind: "allow_always",
|
||||
name: "Always allow",
|
||||
optionId: "allow-always",
|
||||
},
|
||||
{
|
||||
kind: "reject_once",
|
||||
name: "Reject",
|
||||
optionId: "reject-once",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasMethod || !hasId) {
|
||||
|
|
@ -117,6 +196,10 @@ rl.on("line", (line) => {
|
|||
}
|
||||
|
||||
if (method === "session/prompt") {
|
||||
const text = firstText(msg?.params?.prompt);
|
||||
if (text.includes("permission")) {
|
||||
return;
|
||||
}
|
||||
emit({
|
||||
jsonrpc: "2.0",
|
||||
id: msg.id,
|
||||
|
|
|
|||
|
|
@ -578,6 +578,42 @@ describe("Integration: TypeScript SDK flat session API", () => {
|
|||
await sdk.dispose();
|
||||
});
|
||||
|
||||
it("supports permissionMode as a first-class session helper", async () => {
|
||||
const sdk = await SandboxAgent.connect({
|
||||
baseUrl,
|
||||
token,
|
||||
});
|
||||
|
||||
const session = await sdk.createSession({
|
||||
agent: "mock",
|
||||
permissionMode: "plan",
|
||||
});
|
||||
|
||||
expect((await session.getModes())?.currentModeId).toBe("plan");
|
||||
|
||||
await session.setPermissionMode("normal");
|
||||
expect((await session.getModes())?.currentModeId).toBe("normal");
|
||||
|
||||
await sdk.dispose();
|
||||
});
|
||||
|
||||
it("rejects conflicting mode and permissionMode values", async () => {
|
||||
const sdk = await SandboxAgent.connect({
|
||||
baseUrl,
|
||||
token,
|
||||
});
|
||||
|
||||
await expect(
|
||||
sdk.createSession({
|
||||
agent: "mock",
|
||||
mode: "normal",
|
||||
permissionMode: "plan",
|
||||
}),
|
||||
).rejects.toThrow("conflicting values");
|
||||
|
||||
await sdk.dispose();
|
||||
});
|
||||
|
||||
it("setThoughtLevel happy path switches to a valid thought level", async () => {
|
||||
const sdk = await SandboxAgent.connect({
|
||||
baseUrl,
|
||||
|
|
@ -625,6 +661,43 @@ describe("Integration: TypeScript SDK flat session API", () => {
|
|||
await sdk.dispose();
|
||||
});
|
||||
|
||||
it("surfaces ACP permission requests and maps approve/reject replies", async () => {
|
||||
const sdk = await SandboxAgent.connect({
|
||||
baseUrl,
|
||||
token,
|
||||
});
|
||||
|
||||
const session = await sdk.createSession({ agent: "mock" });
|
||||
const permissionIds: string[] = [];
|
||||
const permissionTexts: string[] = [];
|
||||
|
||||
const offPermissions = session.onPermissionRequest((request) => {
|
||||
permissionIds.push(request.id);
|
||||
const reply = permissionIds.length === 1 ? "reject" : "always";
|
||||
void session.replyPermission(request.id, reply);
|
||||
});
|
||||
|
||||
const offEvents = session.onEvent((event) => {
|
||||
const text = (event.payload as any)?.params?.update?.content?.text;
|
||||
if (typeof text === "string" && text.startsWith("mock permission ")) {
|
||||
permissionTexts.push(text);
|
||||
}
|
||||
});
|
||||
|
||||
await session.prompt([{ type: "text", text: "trigger permission request one" }]);
|
||||
await session.prompt([{ type: "text", text: "trigger permission request two" }]);
|
||||
|
||||
await waitFor(() => (permissionIds.length === 2 ? permissionIds : undefined));
|
||||
await waitFor(() => (permissionTexts.length === 2 ? permissionTexts : undefined));
|
||||
|
||||
expect(permissionTexts[0]).toContain("rejected");
|
||||
expect(permissionTexts[1]).toContain("approved");
|
||||
|
||||
offEvents();
|
||||
offPermissions();
|
||||
await sdk.dispose();
|
||||
});
|
||||
|
||||
it("supports MCP and skills config HTTP helpers", async () => {
|
||||
const sdk = await SandboxAgent.connect({
|
||||
baseUrl,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue