mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-11 10:57:07 +00:00
Give plugins an agent's background work count and a background flag on hooks (#9362)
* feat(plugins): give plugins the agent's sidebar indicator and background flag Plugin UI re-derived agent state from status and attention fields and could not see background work, so it showed agents as done while a shell they left running was still live. Agent snapshots now carry the sidebar's own bucket as indicator/indicatorLabel, computed by the same function the sidebar uses so the two cannot drift. Lifecycle hooks and the agent.open.before request now carry `background`, so a hook can skip a hidden helper agent without a lookup. A hook cannot change it; an omitted value means unchanged, like metadata. `finished` attention still means the turn finished; background work is the indicator's concern. * fix(plugins): keep session-open hooks that omit background typechecking A hook that returns its own object instead of spreading the request has no background field; the result type now treats it as optional, like metadata, matching the runtime where an omitted value means unchanged. * refactor(plugins): give agent snapshots the background work count instead of an indicator * fix(plugins): keep legacy session-open hooks that omit background typechecking
This commit is contained in:
@@ -6,7 +6,7 @@ Sets saved Codex options through `server.addHook("agent.create.before", async ..
|
||||
- Sets `config.providerOptions.approval_policy` to `on-request`.
|
||||
- Preserves other configuration and provider options.
|
||||
|
||||
Adds the `company` MCP server to Codex launches through
|
||||
Adds the `company` MCP server to Codex launches, skipping background agents, through
|
||||
`server.addHook("agent.open.before", async ...)`. The server is never saved in the agent's configuration;
|
||||
existing saved MCP servers are preserved. Existing agents receive the server through the
|
||||
[session reopen behavior](../../public-docs/plugins/hooks.md#attach-tools-to-agents).
|
||||
|
||||
@@ -20,7 +20,8 @@ export default function contribute(server: PluginServerContext) {
|
||||
});
|
||||
|
||||
server.addHook("agent.open.before", async ({ request }) => {
|
||||
if (request.provider !== "codex") {
|
||||
// Background agents are short-lived helpers; keep the company tools for the agents users open.
|
||||
if (request.provider !== "codex" || request.background) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Small callbacks using the existing SDK:
|
||||
|
||||
- Send `Try again.` when the latest output contains `out of credits`.
|
||||
- Send `Try again.` when the latest output contains `out of credits`, except to background agents.
|
||||
- Decline a shell request matching `rm -rf`; approve exactly `git status`; leave other requests alone.
|
||||
- Inject `PASEO_HOOK_CREATE_EXAMPLE=created` on creation and `PASEO_HOOK_OPEN_EXAMPLE=opened` on each session opening.
|
||||
- Change requested Codex agents to Claude Haiku before creation.
|
||||
|
||||
@@ -18,7 +18,8 @@ export default function contribute(server: PluginServerContext) {
|
||||
});
|
||||
|
||||
server.addHook("agent.turn.after", async (event, context) => {
|
||||
if (event.outcome.kind === "canceled") {
|
||||
// A background agent reports to the agent that created it, which decides whether to retry.
|
||||
if (event.outcome.kind === "canceled" || event.agent.background) {
|
||||
return;
|
||||
}
|
||||
const agent = context.paseo.agents.ref(event.agent.id);
|
||||
|
||||
@@ -4,13 +4,21 @@ import { useAgents, type PluginSidebarViewProps } from "@getpaseo/plugin/client"
|
||||
import { AgentRow, Heading } from "./rows";
|
||||
export function agentTask(agent: PluginAgentSnapshot) {
|
||||
if (agent.attentionReason === "permission") return "Respond";
|
||||
if (agent.requiresAttention || agent.status === "error") return "Review";
|
||||
if (agent.status === "running" || agent.status === "initializing") return "Wait";
|
||||
if (agent.status === "error") return "Review";
|
||||
// An agent whose turn ended still works while shells or monitors it started are live.
|
||||
if (
|
||||
agent.status === "running" ||
|
||||
agent.status === "initializing" ||
|
||||
agent.backgroundWork.count > 0
|
||||
)
|
||||
return "Wait";
|
||||
if (agent.requiresAttention) return "Review";
|
||||
return "Start";
|
||||
}
|
||||
function Task({ title, view }: { title: string; view: PluginSidebarViewProps }) {
|
||||
const agents = useAgents({
|
||||
where: (item) => agentTask(item) === title,
|
||||
// Background agents are helpers the user never opens; leave them out like the sidebar does.
|
||||
where: (item) => !item.background && agentTask(item) === title,
|
||||
orderBy: ["lastActivityAt", "desc"],
|
||||
});
|
||||
return (
|
||||
|
||||
@@ -91,7 +91,12 @@ export function AgentRow({
|
||||
() => ({ color: view.theme.colors.foreground, fontSize: 12 }),
|
||||
[view.theme],
|
||||
);
|
||||
const detail = useMemo(
|
||||
() => ({ color: view.theme.colors.foregroundMuted, fontSize: 11 }),
|
||||
[view.theme],
|
||||
);
|
||||
if (!agent) return null;
|
||||
const tasks = agent.backgroundWork.count;
|
||||
return (
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
@@ -102,6 +107,11 @@ export function AgentRow({
|
||||
<Text numberOfLines={1} style={style}>
|
||||
{agent.title ?? agent.provider}
|
||||
</Text>
|
||||
{tasks > 0 ? (
|
||||
<Text numberOfLines={1} style={detail}>
|
||||
{tasks === 1 ? "1 background task" : `${tasks} background tasks`}
|
||||
</Text>
|
||||
) : null}
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user