flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/apps/web/app/routes/repo/memory.tsx

109 lines4,658 bytesCodeBlame
1import { Brain } from "lucide-react";
2import { Link, data } from "react-router";
3
4import type { Route } from "./+types/memory";
5import { page } from "../../lib/meta";
6import { AddMemory, MemoryList, memoryAction } from "../../components/memory";
7import { ReviewQueue, reviewAction } from "../../components/context";
8import { agents, memoryReview } from "../../lib/services.server";
9import { assertSameOrigin, getViewer, requireUser, roleIn, unwrap } from "../../lib/session.server";
10
11export function meta({ params, ...args }: Route.MetaArgs) {
12 return page(args, { title: `Memory · ${params.owner}/${params.repo} · g1t` });
13}
14
15export async function loader({ params, context }: Route.LoaderArgs) {
16 const viewer = getViewer(context);
17 // Memory can hold what a workspace keeps to itself: members only.
18 if (!roleIn(viewer, params.owner)) throw data(null, { status: 404 });
19 const path = { namespace: params.owner, name: params.repo };
20 const [memories, candidates] = await Promise.all([
21 agents.listMemories(viewer, params.owner, path),
22 // Candidates waiting for review (the context hub); none if the service is not there yet.
23 memoryReview.listCandidates(viewer, params.owner, path).catch(() => null),
24 ]);
25 return { ...unwrap(memories), candidates: candidates?.ok ? candidates.value : [] };
26}
27
28export async function action({ params, context, request }: Route.ActionArgs) {
29 assertSameOrigin(request);
30 const user = requireUser(context, request);
31 const form = await request.formData();
32 return (
33 (await reviewAction(memoryReview, user, params.owner, form)) ??
34 memoryAction(agents, user, params.owner, { namespace: params.owner, name: params.repo }, form)
35 );
36}
37
38export default function ProjectMemory({ loaderData, params }: Route.ComponentProps) {
39 const { project, workspace, candidates } = loaderData;
40 const action = `/${params.owner}/${params.repo}/memory`;
41 return (
42 <div className="max-w-4xl">
43 <h2 className="flex items-center gap-2 text-xl font-semibold tracking-tight">
44 <Brain size={19} className="text-merged" />
45 Memory
46 </h2>
47 <p className="mt-1.5 max-w-2xl text-sm text-muted">
48 What agents and people have learned about this project that the next agent should know: how
49 to build and test it, its conventions, decisions and why, and its traps. Every g1t agent run
50 here is given it, pinned first, together with the workspace's memory. Agents add to it with
51 the remember tool as they work; keep it true by editing or forgetting what no longer holds.
52 </p>
53
54 <div className="mt-6">
55 <AddMemory scope="project" action={action} placeholder="The tests need TZ=UTC or the date tests fail." />
56 </div>
57
58 {candidates.length > 0 && (
59 <section className="mt-8">
60 <div className="flex items-baseline justify-between">
61 <h3 className="text-sm font-medium">Review</h3>
62 <span className="text-xs text-muted">{candidates.length} waiting</span>
63 </div>
64 <p className="mt-1 text-xs text-muted">
65 Learned by agents, from reviews and merges, and from this project's docs. No agent is given one until it is kept.
66 </p>
67 <div className="mt-3">
68 <ReviewQueue candidates={candidates} action={action} empty="" />
69 </div>
70 </section>
71 )}
72
73 <section className="mt-8">
74 <div className="flex items-baseline justify-between">
75 <h3 className="text-sm font-medium">This project</h3>
76 <span className="text-xs text-muted">{project.length} kept</span>
77 </div>
78 <div className="mt-3">
79 <MemoryList
80 memories={project}
81 action={action}
82 editable
83 empty="Nothing yet. Agents add what they learn here as they work, and so can you."
84 />
85 </div>
86 </section>
87
88 <section className="mt-10">
89 <div className="flex items-baseline justify-between">
90 <h3 className="text-sm font-medium">From the workspace</h3>
91 <Link to={`/${params.owner}/-/memory`} className="text-xs text-muted hover:text-fg">
92 Manage workspace memory
93 </Link>
94 </div>
95 <p className="mt-1 text-xs text-muted">
96 True across all of {params.owner}'s projects, and given to agents here too.
97 </p>
98 <div className="mt-3">
99 <MemoryList
100 memories={workspace}
101 action={`/${params.owner}/-/memory`}
102 editable={false}
103 empty="The workspace remembers nothing yet."
104 />
105 </div>
106 </section>
107 </div>
108 );
109}