pi-mono/apps/p2/plugins/subagents/web.tsx
David Brailovsky e885255061 feat(p2): /tree, branches of the main conversation as Durable forks
Each branch is a top-level conversation forked from another at an entry;
the session-scoped p2.main document lists them and names the current one.
Earlier branches are read-only. The main agent's per-agent state
(subagents, artifacts, voice and chat mode, pending move) stays on
conversation 1 for every branch.

- tree plugin: SessionTree (tree, navigate, select); the worker reports
  main and branches to the catalog (Sessions v4, catalog schema 4)
- TUI: /tree and double Escape (pi's default "tree"), a tree selector
  adapted from coding-agent
- web: Edit on user messages, Branch from here on answers, branch rows
  under the session in the sidebar
- main-agent checks use the branch list instead of conversation 1
- search indexes each branch's own entries

Design: apps/p2/docs/tree.md
2026-11-04 13:40:36 +01:00

26 lines
902 B
TypeScript

import { contribute, defineFacet, liveIn } from "@p2/app/v1";
import { conversationRoute, Slots, useNavigation, useObject, useReadable, useRoute } from "@p2/app/v1/web";
import { Sessions } from "../sessions/contract.ts";
function ParentLink() {
const nav = useNavigation();
const route = useRoute();
const rows = useReadable(liveIn(useObject(Sessions, {}), "owner", "guest")?.sessions);
const main = rows?.find((row) => row.id === route.session)?.main;
if (!route.session || main === undefined || route.conversation === main) return null;
return (
<button
type="button"
className="row-button"
onClick={() => void nav.backOrPush(conversationRoute(route, route.session, main))}
>
Back to main conversation
</button>
);
}
export default defineFacet((host) => {
contribute(host, "p2.web-subagents", (self) => {
self.contribute(Slots, { "chat-parent": ParentLink });
});
});