-
Notifications
You must be signed in to change notification settings - Fork 61
Expand file tree
/
Copy pathuseLoopBuilderTask.ts
More file actions
107 lines (99 loc) · 3.92 KB
/
Copy pathuseLoopBuilderTask.ts
File metadata and controls
107 lines (99 loc) · 3.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import type { TaskCreationInput } from "@posthog/core/task-detail/taskService";
import type { Task } from "@posthog/shared/domain-types";
import {
type InboxCloudTaskInputContext,
useInboxCloudTaskRunner,
} from "@posthog/ui/features/inbox/hooks/useInboxCloudTaskRunner";
import { useCallback, useMemo, useRef } from "react";
import { buildLoopBuilderSystemInstructions } from "../loopBuilderPrompt";
import { useLoopBuilderSessionStore } from "../loopBuilderSessionStore";
interface UseLoopBuilderTaskReturn {
/** Start an auto-mode cloud session that builds a loop from `instructions` and navigate to it. */
runTask: (instructions: string) => Promise<void>;
/** True while the session is being created. */
isRunning: boolean;
}
/**
* The loops prompt box: start a cloud sandbox agent whose job is to build a Loop
* with the user (ask clarifying questions, confirm, then create it via the PostHog
* MCP `loops-create` tool). Mirrors `useScoutChatTask` — a repo-less, auto-mode
* cloud task seeded with a canned instruction prompt. The user's typed text rides
* in through a ref so the fixed `buildInput` closure reads the latest submission.
*/
export function useLoopBuilderTask(context?: {
folderId: string;
name: string;
}): UseLoopBuilderTaskReturn {
const instructionsRef = useRef("");
const contextRef = useRef(context);
contextRef.current = context;
const buildInput = useCallback(
(ctx: InboxCloudTaskInputContext): TaskCreationInput => {
const userPrompt = instructionsRef.current.trim();
const hasSeed = !!userPrompt;
const systemInstructions = buildLoopBuilderSystemInstructions({
hasSeed,
context: contextRef.current,
});
// createTask rejects empty content and the saga drops customInstructions without message text
const taskContent = hasSeed ? userPrompt : "Build a loop";
return {
content: taskContent,
// Divergent on purpose: the description becomes the task's title, so
// the sidebar row reads as the builder instead of the raw prompt.
taskDescription: hasSeed
? `Loop builder: ${userPrompt}`
: "Loop builder",
customInstructions: systemInstructions,
// Building a loop is pure PostHog-MCP work (loops-list, integrations-list,
// loops-create); it never touches a working tree. Run repo-less so the
// sandbox skips the clone and isn't tied to some arbitrary default repo.
repository: undefined,
githubUserIntegrationId: undefined,
workspaceMode: "cloud",
executionMode: "acceptEdits",
adapter: ctx.adapter,
model: ctx.model,
reasoningLevel: ctx.reasoningLevel,
};
},
[],
);
const copy = useMemo(
() => ({
loadingTitle: "Starting loop builder...",
errorTitle: "Failed to start loop builder",
missingRepository: "Connect a GitHub repository before building a loop",
missingIntegration: "Connect a GitHub integration to build a loop",
signedOut: "Sign in to build a loop",
missingModel:
"Couldn't resolve a default model. Open a task once and pick a model, then try again.",
}),
[],
);
const handleTaskCreated = useCallback((task: Task) => {
useLoopBuilderSessionStore.getState().addSession({
taskId: task.id,
prompt: instructionsRef.current.trim() || "Build a loop",
startedAt: Date.now(),
});
}, []);
const { run, isRunning } = useInboxCloudTaskRunner({
// The loop builder never needs a repo: run repo-less so the sandbox does no
// clone and no GitHub identity is attached.
cloudRepository: null,
allowMissingRepository: true,
loggerScope: "loop-builder",
copy,
buildInput,
onTaskCreated: handleTaskCreated,
});
const runTask = useCallback(
async (instructions: string) => {
instructionsRef.current = instructions;
await run();
},
[run],
);
return { runTask, isRunning };
}