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
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ members = [
]

[workspace.package]
version = "0.1.53"
version = "0.1.55"
edition = "2024"
publish = false

Expand Down
2 changes: 1 addition & 1 deletion apps/gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ tauri-build = { version = "2", features = [] }
[dependencies]
# Carries the store forward when a column changes; see crates/wt-migrate.
wt-migrate = { path = "../../crates/wt-migrate" }
agent-abstraction = "0.4.3"
agent-abstraction = "0.4.4"
az-core.workspace = true
worktable = "0.9"
# The `worktable!` macro emits code that names these by bare path rather than
Expand Down
30 changes: 22 additions & 8 deletions apps/gui/frontend/src/api/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
Agent,
AgentIoEntry,
AgentModels,
AgentStatus,
Expand Down Expand Up @@ -51,6 +52,7 @@ export interface AgencyZeroApi {
/** The name and the initial items are parsed out of the agent's first reply. */
createProject(input: {
firstMessage: string;
agent?: Agent;
model?: string;
permission?: Permission;
/** Reasoning effort, as `Request::effort`. Absent means the CLI's default. */
Expand All @@ -64,7 +66,7 @@ export interface AgencyZeroApi {
setProjectPinned(id: string, pinned: boolean): Promise<Project>;
/** Per-session override of the global moderator setting. */
setProjectModerator(id: string, enabled: boolean): Promise<Project>;
/** Claude only — `Error::Unsupported` on Codex and Copilot. */
/** Requires the provider's fork capability; unsupported providers return an error. */
forkProject(projectId: string, messageId: string): Promise<Project>;
addDir(projectId: string, path: string): Promise<Project>;
removeDir(projectId: string, path: string): Promise<Project>;
Expand Down Expand Up @@ -93,6 +95,7 @@ export interface AgencyZeroApi {
projectId: string;
body: string;
itemId?: string | null;
agent?: Agent;
model?: string;
permission?: Permission;
/** Reasoning effort, as `Request::effort`. Absent means the CLI's default. */
Expand Down Expand Up @@ -160,8 +163,6 @@ export interface AgencyZeroApi {
createWorkspaceRoot(): Promise<WorkspaceRoot>;

// — Runs and tasks ——————————————————————————————————————————
/** The tab's model and posture stick until changed again. */
setTabModel(tabKey: string, model: string, permission: Permission): Promise<void>;
/** `Run::cancel` — resolves once the process group is gone. */
cancelRun(projectId: string): Promise<void>;

Expand All @@ -174,7 +175,7 @@ export interface AgencyZeroApi {
* with the agent's own reason when it will not compact; a conversation too
* short to summarise is the common one, and is an answer rather than a fault.
*/
compactProject(projectId: string): Promise<void>;
compactProject(projectId: string, agent: Agent): Promise<void>;

/**
* What this project's agent keeps across compactions.
Expand Down Expand Up @@ -308,7 +309,12 @@ export interface AppEvents {
* the transcript's status line; `run:stopped` ends it. The mock never emits
* this, which is correct — it fakes no run.
*/
"run:accepted": { projectId: string };
"run:accepted": {
projectId: string;
agent: Agent;
model: string;
permission: Permission;
};
/**
* A message sent into a live run could not be delivered — the turn settled
* in the race window. The words are already in the transcript; this hands
Expand Down Expand Up @@ -359,7 +365,7 @@ export interface AppEvents {
* make the set per-machine. Arrives once per run, so a session that has not
* run yet has none and the composer falls back to what it knows itself.
*/
"run:commands": { projectId: string; all: string[]; skills: string[] };
"run:commands": { projectId: string; agent: Agent; all: string[]; skills: string[] };
/**
* A conversation being rewritten into a summary of itself.
*
Expand All @@ -378,6 +384,7 @@ export interface AppEvents {
*/
"run:compaction": {
projectId: string;
agent: Agent;
driver: "command" | "agent";
phase: "learning" | "started" | "finished";
ok?: boolean;
Expand All @@ -389,15 +396,22 @@ export interface AppEvents {
* blocked for the rest of the session, since `resetsAt` passing is not
* something the window can observe on its own.
*/
"run:rate_limit_cleared": { projectId: string };
"run:rate_limit_cleared": { projectId: string; agent: Agent };
/**
* A tool call is waiting on the user. The run is blocked mid-turn until
* `resolveApproval` answers, so this must render somewhere it will be seen.
*/
"run:approval": { projectId: string } & PendingApproval;
/** The question above was answered (by the user, or denied on timeout). */
"run:approval_resolved": { projectId: string; approvalId: string; allow: boolean };
"run:stopped": { projectId: string; stop: string; exitCode: number | null };
"run:stopped": {
projectId: string;
agent: Agent;
model: string;
permission: Permission;
stop: string;
exitCode: number | null;
};
}

export type AppEvent = keyof AppEvents;
Expand Down
42 changes: 40 additions & 2 deletions apps/gui/frontend/src/api/fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
Agent,
AgentModels,
AgentStatus,
GlobalSettings,
Expand Down Expand Up @@ -67,6 +68,7 @@ export const PROJECTS: Project[] = [
moderatorEnabled: true,
forkedFrom: null,
sessionId: null,
sessions: {},
lastActivityAt: ago(2 * 60_000),
},
{
Expand All @@ -79,6 +81,7 @@ export const PROJECTS: Project[] = [
moderatorEnabled: true,
forkedFrom: null,
sessionId: null,
sessions: {},
lastActivityAt: ago(9 * 60_000),
},
{
Expand All @@ -91,6 +94,7 @@ export const PROJECTS: Project[] = [
moderatorEnabled: true,
forkedFrom: null,
sessionId: null,
sessions: {},
lastActivityAt: ago(26 * 60 * 60_000),
},
];
Expand Down Expand Up @@ -368,6 +372,15 @@ export const AGENT_STATUS: AgentStatus[] = [
version: "2.1.205",
minVersion: "2.1.100",
caps: ["fork", "session id"],
capabilities: {
session: true,
fork: true,
events: true,
nativeSystem: true,
commands: true,
liveFollowUp: true,
approvals: true,
},
checkedAt: ago(2 * 60_000),
},
{
Expand All @@ -376,6 +389,15 @@ export const AGENT_STATUS: AgentStatus[] = [
version: "1.0.61",
minVersion: "1.0.75",
caps: ["session id"],
capabilities: {
session: true,
fork: false,
events: true,
nativeSystem: false,
commands: false,
liveFollowUp: false,
approvals: false,
},
checkedAt: ago(2 * 60_000),
},
{
Expand All @@ -384,6 +406,15 @@ export const AGENT_STATUS: AgentStatus[] = [
version: null,
minVersion: "0.9.0",
caps: ["thread id"],
capabilities: {
session: true,
fork: false,
events: true,
nativeSystem: false,
commands: false,
liveFollowUp: false,
approvals: false,
},
checkedAt: ago(2 * 60_000),
},
];
Expand Down Expand Up @@ -544,7 +575,13 @@ export const SETTINGS: GlobalSettings = {
},
// Deliberately not the prompt's model: a list keeper running unattended
// wants a cheap fast model far more often than a frontier one.
taskManager: { model: "haiku", effort: "medium", dirs: [] },
taskManager: {
agent: "claude",
model: "haiku",
effort: "medium",
permission: "ask",
dirs: [],
},
envPolicy: "minimal",
forwardProxyVars: false,
completedItems: "resolve",
Expand All @@ -564,10 +601,11 @@ export const SETTINGS: GlobalSettings = {
*/
export const RATE_LIMITS: Record<
string,
{ isBlocking: boolean; isWarning: boolean; message: string; resetsAt: string }
{ agent: Agent; isBlocking: boolean; isWarning: boolean; message: string; resetsAt: string }
> = {
cafe: {
// A real refusal, not the "allowed" heartbeat the provider also emits.
agent: "claude",
isBlocking: true,
isWarning: false,
message: "Rate limited",
Expand Down
1 change: 0 additions & 1 deletion apps/gui/frontend/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ const COMMAND_FOR: Partial<Record<keyof AgencyZeroApi, string>> = {
chooseAttachments: "choose_attachments",
getWorkspaceRoot: "get_workspace_root",
createWorkspaceRoot: "create_workspace_root",
setTabModel: "set_tab_model",
cancelRun: "cancel_run",
compactProject: "compact_project",
getCheckpoints: "get_checkpoints",
Expand Down
26 changes: 18 additions & 8 deletions apps/gui/frontend/src/api/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ export function createMockApi(): AgencyZeroApi {
forkedFrom: null,
// The mock never runs an agent, so there is no session to report.
sessionId: null,
sessions: {},
lastActivityAt: new Date().toISOString(),
};
projects.push(project);
Expand All @@ -152,9 +153,9 @@ export function createMockApi(): AgencyZeroApi {
projectId: project.id,
itemId: null,
author: "user",
agent: settings.defaultAgent,
agent: input.agent ?? settings.defaultAgent,
moderation: null,
model: input.model ?? settings.models[settings.defaultAgent].default,
model: input.model ?? settings.models[input.agent ?? settings.defaultAgent].default,
permission: input.permission ?? settings.defaultPermission,
usage: null,
stop: "completed",
Expand Down Expand Up @@ -350,9 +351,9 @@ export function createMockApi(): AgencyZeroApi {
projectId: input.projectId,
itemId: input.itemId ?? null,
author: "user",
agent: settings.defaultAgent,
agent: input.agent ?? settings.defaultAgent,
moderation: null,
model: input.model ?? settings.models[settings.defaultAgent].default,
model: input.model ?? settings.models[input.agent ?? settings.defaultAgent].default,
permission: input.permission ?? settings.defaultPermission,
usage: null,
stop: "completed",
Expand Down Expand Up @@ -454,14 +455,22 @@ export function createMockApi(): AgencyZeroApi {
getWorkspaceRoot: () => settle({ path: "(no filesystem)", exists: false, isDefault: true }),
createWorkspaceRoot: () => settle({ path: "(no filesystem)", exists: false, isDefault: true }),

setTabModel: () => settle(undefined),

async cancelRun(projectId) {
for (let i = running.length - 1; i >= 0; i--) {
if (running[i].projectId !== projectId) continue;
emit("task:finished", finishTask(running.splice(i, 1)[0], false));
}
emit("run:stopped", { projectId, stop: "canceled", exitCode: null });
const last = [...messages]
.reverse()
.find((message) => message.projectId === projectId && message.author === "user");
emit("run:stopped", {
projectId,
agent: last?.agent ?? "claude",
model: last?.model ?? "",
permission: last?.permission ?? "read_only",
stop: "canceled",
exitCode: null,
});
return settle(undefined);
},

Expand Down Expand Up @@ -566,7 +575,8 @@ export function createMockApi(): AgencyZeroApi {

// A fixture session id, so the design shows the faded "session" line the
// way a real first prompt would produce it.
getTaskManager: () => settle({ sessionId: taskManagerSession }),
getTaskManager: () =>
settle({ agent: settings.taskManager.agent, sessionId: taskManagerSession }),

async resetTaskManager() {
taskManagerSession = null;
Expand Down
4 changes: 1 addition & 3 deletions apps/gui/frontend/src/api/tauri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,8 @@ export function createTauriApi(): AgencyZeroApi {
getWorkspaceRoot: () => call("get_workspace_root"),
createWorkspaceRoot: () => call("create_workspace_root"),

setTabModel: (tabKey, model, permission) =>
call("set_tab_model", { tabKey, model, permission }),
cancelRun: (projectId) => call("cancel_run", { projectId }),
compactProject: (projectId) => call("compact_project", { projectId }),
compactProject: (projectId, agent) => call("compact_project", { projectId, agent }),
getCheckpoints: (projectId) => call("get_checkpoints", { projectId }),
setCheckpoints: (projectId, enabled) => call("set_checkpoints", { projectId, enabled }),
getProjectNotes: (projectId) => call("get_project_notes", { projectId }),
Expand Down
Loading
Loading