Skip to content
94 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.1/**
2 * Starting work on an issue in a session on the person's own Claude.
3 * Mirrors `crates/contracts/src/agent_sessions.rs` (the integrations
4 * service's `start_agent_session`, `agent_sessions_setup`,
5 * `sync_agent_session` and `stop_agent_session`).
6 */
7import type { ServiceBinding } from "./clients";
8import type { User, Viewer } from "./identity";
9import type { RepoPath } from "./repos";
10import type { Result } from "./result";
11import type { WorkSession } from "./work";
12
13/** What kind of work a session is asked for. */
14export type AgentMode = "plan" | "implement" | "review";
15
16export const AGENT_MODES: { mode: AgentMode; label: string; hint: string }[] = [
17 { mode: "implement", label: "Implement", hint: "Make the change and open a pull request." },
18 { mode: "plan", label: "Plan", hint: "Work out how, and post the plan on the issue. No code." },
19 { mode: "review", label: "Review", hint: "Review the issue's pull request." },
20];
21
22/** What `start_agent_session` started, or the hand-off to run. */
23export type AgentSessionStarted = {
24 issue: number;
25 session: WorkSession | null;
26 sessionUrl: string | null;
27 provider: string | null;
28 providerSessionId: string | null;
29 providerSessionUrl: string | null;
30 handoff: boolean;
31 command: string | null;
32 prompt: string;
33};
34
35/** Whether sessions can start on the workspace's Anthropic account. */
36export type AgentSessionsSetup = {
37 available: boolean;
38 connectionName: string | null;
39 model: string | null;
40 problem: string | null;
41};
42
43/** What to start: an issue, or a new one from a title and body. */
44export type StartAgentSessionInput = {
45 issue?: number;
46 title?: string;
47 body?: string;
48 instruction?: string;
49 mode?: AgentMode;
50 /** true: the Claude Code hand-off only; false: a session on the workspace's account, or a refusal. */
51 handoff?: boolean;
52};
53
54/** The integrations service's methods for sessions on a workspace's Anthropic account. */
55export interface AgentSessionsApi {
56 setup(workspace: string, viewer: Viewer): Promise<Result<AgentSessionsSetup>>;
57 start(actor: User, repo: RepoPath, input: StartAgentSessionInput): Promise<Result<AgentSessionStarted>>;
58 /** Reads the session now (it is otherwise followed every minute). Whether it is still going. */
59 sync(repo: RepoPath, id: string, viewer: Viewer): Promise<Result<boolean>>;
60 /** Interrupts it and ends its record. Only whoever started it. */
61 stop(actor: User, repo: RepoPath, id: string): Promise<Result<boolean>>;
62}
63
64async function rpc<T>(service: ServiceBinding, method: string, args: object): Promise<T> {
65 const response = await service.fetch(`https://service/rpc/${method}`, {
66 method: "POST",
67 headers: { "content-type": "application/json" },
68 body: JSON.stringify(args),
69 });
70 if (!response.ok) {
71 throw new Error(`${method} failed with status ${response.status}`);
72 }
73 return (await response.json()) as T;
74}
75
76export function agentSessionsClient(service: ServiceBinding): AgentSessionsApi {
77 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
78 return {
79 setup: (workspace, viewer) => call("agent_sessions_setup", { workspace, viewer }),
80 start: (actor, repo, input) =>
81 call("start_agent_session", {
82 actor,
83 repo,
84 issue: input.issue ?? null,
85 title: input.title ?? null,
86 body: input.body ?? null,
87 instruction: input.instruction ?? null,
88 mode: input.mode ?? null,
89 handoff: input.handoff ?? null,
90 }),
91 sync: (repo, id, viewer) => call("sync_agent_session", { repo, id, viewer }),
92 stop: (actor, repo, id) => call("stop_agent_session", { actor, repo, id }),
93 };
94}