Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ A Bot is any endpoint speaking [AG-UI](https://github.com/ag-ui-protocol/ag-ui),
- **Fast, visible computer use**: actions return the changed page and fresh controls together, Bot computers are prewarmed, and one reconnecting live stream powers the resizable watch/full-screen experience without duplicate screenshot polling.
- **Take the wheel**: a Bot that hits a login wall or a 2FA prompt asks for help. Control is handed over in the same panel and recorded as `computer.help_requested`, `computer.control_taken` and `computer.control_released`. While a person is driving, Bot actions are refused rather than queued. Keyboard focus, paste, and direct file upload stay on the remote page and out of the model conversation.
- **A conversation workspace**: `Ctrl/⌘ K` opens commands, channel search jumps between matching messages, unsent text survives a reload, and messages can carry files and durable reactions. A Bot can also pin a point-in-time screenshot into the transcript.
- **Multi-Bot Workrooms**: a channel can hold up to six coworkers while an explicit responder switch keeps tool, model, and computer ownership unambiguous.
- **Continuity you can inspect**: Context Vault searches an owner-scoped transcript projection, Bots can recover exact prior details with anchored search, and long threads receive extractive recovery snapshots instead of silently losing their middle.
- **Workspace Time Machine**: every Bot text write creates a pre-write checkpoint. File-selective rollback preserves later human edits by default and creates an inverse checkpoint so the rollback itself can be undone.
- **Visible model context**: built-in Codex coworkers show their selected model, reasoning level, allowance windows, and reported token usage. Kayco does not invent a dollar cost when the connected subscription does not provide one.
- **Secrets never enter the transcript**: the trail records that a secret was requested and how long it was, not what it said.
- **Bring your own agent**: any AG-UI endpoint is a Bot, on a framework or hand written. Endpoints are validated with the same target checks used for browser navigation, and an auth header is stored write-only.
Expand All @@ -147,6 +150,8 @@ A Bot is any endpoint speaking [AG-UI](https://github.com/ag-ui-protocol/ag-ui),
- **Shared project teams**: assign several coworkers to a project, open one team channel, and explicitly choose which coworker answers each turn. Computers, credentials, and browser sessions remain isolated per Bot.
- **Portable team templates**: export a team's names and standing roles, then import them as new private coworkers. Templates never carry ids, endpoints, credentials, grants, messages, ownership, or visibility.
- **Inspectable memory**: stable user, coworker, and project context is stored in PostgreSQL with scope, source, confidence, and pinning. People can inspect, edit, or remove it; relevant user and coworker memory is supplied to the active conversation.
- **Bounded autonomy programs**: reviewed tool programs sequence existing grants without creating a new execution path; nested handoffs enforce depth, parallelism, runtime, review, and stop-tree limits; deterministic routines can run an approved program without a model call.
- **Healthy, portable behavior**: skill hashes, versions, usage, pinning, archive, and rollback make learned behavior reviewable. Bot bundles move configuration while rejecting credentials, grants, sessions, transcripts, and memory.
- **Permission-aware company knowledge**: the connector worker syncs Google Drive into lexical/vector chunks, keeps source ACLs beside them, and filters results in SQL before a Bot sees a citation.
- **An audit trail you can export**: `/admin/audit` lists what was permitted, refused and failed and downloads a redacted SHA-256-chained evidence bundle.
- **Operational readiness**: liveness and readiness endpoints surface database, model, task-lease and connector health without leaking details publicly.
Expand Down
78 changes: 78 additions & 0 deletions agent-computer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,84 @@ serve<StreamData>({
}
}

if (url.pathname === "/files/checkpoints" && request.method === "POST") {
const body = (await request.json().catch(() => null)) as {
path?: unknown;
} | null;
try {
return json(
await workspace.checkpoints(
typeof body?.path === "string" && body.path.trim()
? body.path.trim()
: undefined,
),
);
} catch (error) {
return json(
{ error: describe(error, "Checkpoints could not be listed.") },
fileStatus(error),
);
}
}

if (
url.pathname === "/files/checkpoint-diff" &&
request.method === "POST"
) {
const body = (await request.json().catch(() => null)) as {
checkpointId?: unknown;
path?: unknown;
} | null;
try {
return json(
await workspace.checkpointDiff(
String(body?.checkpointId ?? ""),
typeof body?.path === "string" ? body.path : undefined,
),
);
} catch (error) {
return json(
{ error: describe(error, "The checkpoint could not be compared.") },
fileStatus(error),
);
}
}

if (url.pathname === "/files/rollback" && request.method === "POST") {
const body = (await request.json().catch(() => null)) as {
checkpointId?: unknown;
path?: unknown;
force?: unknown;
} | null;
try {
const checkpoints = await workspace.checkpoints(
typeof body?.path === "string" ? body.path : undefined,
);
if (
typeof body?.path !== "string" ||
!checkpoints.checkpoints.some(
(checkpoint) =>
checkpoint.id === String(body.checkpointId ?? "") &&
checkpoint.path === body.path,
)
) {
throw new WorkspaceFileError(
"That checkpoint does not belong to the requested file.",
);
}
return json(
await workspace.rollback(String(body?.checkpointId ?? ""), {
force: body?.force === true,
}),
);
} catch (error) {
return json(
{ error: describe(error, "The checkpoint could not be restored.") },
fileStatus(error),
);
}
}

// The current page as text, without navigating anywhere.
//
// Reading must be available after actions too. Returning page text only from `/navigate` would be enough if
Expand Down
Loading
Loading