@posthog/agent 1.29.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +57 -87
- package/dist/index.js +916 -2203
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/acp-extensions.ts +0 -37
- package/src/adapters/claude/claude.ts +515 -107
- package/src/adapters/claude/tools.ts +178 -101
- package/src/adapters/connection.ts +95 -0
- package/src/agent.ts +50 -184
- package/src/file-manager.ts +1 -34
- package/src/git-manager.ts +2 -20
- package/src/posthog-api.ts +4 -4
- package/src/tools/registry.ts +5 -0
- package/src/tools/types.ts +6 -0
- package/src/types.ts +5 -25
- package/src/utils/gateway.ts +15 -0
- package/src/worktree-manager.ts +92 -46
- package/dist/templates/plan-template.md +0 -41
- package/src/agents/execution.ts +0 -37
- package/src/agents/planning.ts +0 -60
- package/src/agents/research.ts +0 -160
- package/src/prompt-builder.ts +0 -497
- package/src/template-manager.ts +0 -240
- package/src/templates/plan-template.md +0 -41
- package/src/workflow/config.ts +0 -53
- package/src/workflow/steps/build.ts +0 -135
- package/src/workflow/steps/finalize.ts +0 -241
- package/src/workflow/steps/plan.ts +0 -167
- package/src/workflow/steps/research.ts +0 -223
- package/src/workflow/types.ts +0 -62
- package/src/workflow/utils.ts +0 -53
package/src/agent.ts
CHANGED
|
@@ -9,14 +9,12 @@ import { POSTHOG_NOTIFICATIONS } from "./acp-extensions.js";
|
|
|
9
9
|
import {
|
|
10
10
|
createAcpConnection,
|
|
11
11
|
type InProcessAcpConnection,
|
|
12
|
-
} from "./adapters/
|
|
12
|
+
} from "./adapters/connection.js";
|
|
13
13
|
import { PostHogFileManager } from "./file-manager.js";
|
|
14
14
|
import { GitManager } from "./git-manager.js";
|
|
15
15
|
import { PostHogAPIClient } from "./posthog-api.js";
|
|
16
|
-
import { PromptBuilder } from "./prompt-builder.js";
|
|
17
16
|
import { SessionStore } from "./session-store.js";
|
|
18
17
|
import { TaskManager } from "./task-manager.js";
|
|
19
|
-
import { TemplateManager } from "./template-manager.js";
|
|
20
18
|
import type {
|
|
21
19
|
AgentConfig,
|
|
22
20
|
CanUseTool,
|
|
@@ -25,8 +23,14 @@ import type {
|
|
|
25
23
|
TaskExecutionOptions,
|
|
26
24
|
} from "./types.js";
|
|
27
25
|
import { Logger } from "./utils/logger.js";
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Type for sending ACP notifications
|
|
29
|
+
*/
|
|
30
|
+
type SendNotification = (
|
|
31
|
+
method: string,
|
|
32
|
+
params: Record<string, unknown>,
|
|
33
|
+
) => Promise<void>;
|
|
30
34
|
|
|
31
35
|
export class Agent {
|
|
32
36
|
private workingDirectory: string;
|
|
@@ -34,10 +38,8 @@ export class Agent {
|
|
|
34
38
|
private posthogAPI?: PostHogAPIClient;
|
|
35
39
|
private fileManager: PostHogFileManager;
|
|
36
40
|
private gitManager: GitManager;
|
|
37
|
-
private templateManager: TemplateManager;
|
|
38
41
|
private logger: Logger;
|
|
39
42
|
private acpConnection?: InProcessAcpConnection;
|
|
40
|
-
private promptBuilder: PromptBuilder;
|
|
41
43
|
private mcpServers?: Record<string, any>;
|
|
42
44
|
private canUseTool?: CanUseTool;
|
|
43
45
|
private currentRunId?: string;
|
|
@@ -57,8 +59,8 @@ export class Agent {
|
|
|
57
59
|
|
|
58
60
|
// Add auth if API key provided
|
|
59
61
|
const headers: Record<string, string> = {};
|
|
60
|
-
if (config.
|
|
61
|
-
headers.Authorization = `Bearer ${config.
|
|
62
|
+
if (config.getPosthogApiKey) {
|
|
63
|
+
headers.Authorization = `Bearer ${config.getPosthogApiKey()}`;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
const defaultMcpServers = {
|
|
@@ -89,16 +91,15 @@ export class Agent {
|
|
|
89
91
|
repositoryPath: this.workingDirectory,
|
|
90
92
|
logger: this.logger.child("GitManager"),
|
|
91
93
|
});
|
|
92
|
-
this.templateManager = new TemplateManager();
|
|
93
94
|
|
|
94
95
|
if (
|
|
95
96
|
config.posthogApiUrl &&
|
|
96
|
-
config.
|
|
97
|
+
config.getPosthogApiKey &&
|
|
97
98
|
config.posthogProjectId
|
|
98
99
|
) {
|
|
99
100
|
this.posthogAPI = new PostHogAPIClient({
|
|
100
101
|
apiUrl: config.posthogApiUrl,
|
|
101
|
-
|
|
102
|
+
getApiKey: config.getPosthogApiKey,
|
|
102
103
|
projectId: config.posthogProjectId,
|
|
103
104
|
});
|
|
104
105
|
|
|
@@ -108,13 +109,6 @@ export class Agent {
|
|
|
108
109
|
this.logger.child("SessionStore"),
|
|
109
110
|
);
|
|
110
111
|
}
|
|
111
|
-
|
|
112
|
-
this.promptBuilder = new PromptBuilder({
|
|
113
|
-
getTaskFiles: (taskId: string) => this.getTaskFiles(taskId),
|
|
114
|
-
generatePlanTemplate: (vars) => this.templateManager.generatePlan(vars),
|
|
115
|
-
posthogClient: this.posthogAPI,
|
|
116
|
-
logger: this.logger.child("PromptBuilder"),
|
|
117
|
-
});
|
|
118
112
|
}
|
|
119
113
|
|
|
120
114
|
/**
|
|
@@ -126,7 +120,7 @@ export class Agent {
|
|
|
126
120
|
}
|
|
127
121
|
|
|
128
122
|
/**
|
|
129
|
-
* Configure LLM gateway environment variables for Claude Code CLI
|
|
123
|
+
* Configure LLM gateway environment variables for Claude Code CLI.
|
|
130
124
|
*/
|
|
131
125
|
private async _configureLlmGateway(): Promise<void> {
|
|
132
126
|
if (!this.posthogAPI) {
|
|
@@ -139,113 +133,25 @@ export class Agent {
|
|
|
139
133
|
process.env.ANTHROPIC_BASE_URL = gatewayUrl;
|
|
140
134
|
process.env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
141
135
|
this.ensureOpenAIGatewayEnv(gatewayUrl, apiKey);
|
|
136
|
+
this.ensureGeminiGatewayEnv(gatewayUrl, apiKey);
|
|
142
137
|
} catch (error) {
|
|
143
138
|
this.logger.error("Failed to configure LLM gateway", error);
|
|
144
139
|
throw error;
|
|
145
140
|
}
|
|
146
141
|
}
|
|
147
142
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
return this.acpConnection;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Adaptive task execution orchestrated via workflow steps
|
|
143
|
+
/**
|
|
144
|
+
* @deprecated Use runTaskV2() for local execution or runTaskCloud() for cloud execution.
|
|
145
|
+
* This method used the old workflow system which has been removed.
|
|
146
|
+
*/
|
|
158
147
|
async runTask(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
148
|
+
_taskId: string,
|
|
149
|
+
_taskRunId: string,
|
|
150
|
+
_options: import("./types.js").TaskExecutionOptions = {},
|
|
162
151
|
): Promise<void> {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const cwd = options.repositoryPath || this.workingDirectory;
|
|
167
|
-
const isCloudMode = options.isCloudMode ?? false;
|
|
168
|
-
const taskSlug = (task as any).slug || task.id;
|
|
169
|
-
|
|
170
|
-
// Use taskRunId as sessionId - they are the same identifier
|
|
171
|
-
this.currentRunId = taskRunId;
|
|
172
|
-
|
|
173
|
-
this.logger.info("Starting adaptive task execution", {
|
|
174
|
-
taskId: task.id,
|
|
175
|
-
taskSlug,
|
|
176
|
-
taskRunId,
|
|
177
|
-
isCloudMode,
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
const connection = this.getOrCreateConnection();
|
|
181
|
-
|
|
182
|
-
// Create sendNotification using ACP connection's extNotification
|
|
183
|
-
const sendNotification: SendNotification = async (method, params) => {
|
|
184
|
-
this.logger.debug(`Notification: ${method}`, params);
|
|
185
|
-
await connection.agentConnection.extNotification?.(method, params);
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.RUN_STARTED, {
|
|
189
|
-
sessionId: taskRunId,
|
|
190
|
-
runId: taskRunId,
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
await this.prepareTaskBranch(taskSlug, isCloudMode, sendNotification);
|
|
194
|
-
|
|
195
|
-
let taskError: Error | undefined;
|
|
196
|
-
try {
|
|
197
|
-
const workflowContext: WorkflowRuntime = {
|
|
198
|
-
task,
|
|
199
|
-
taskSlug,
|
|
200
|
-
runId: taskRunId,
|
|
201
|
-
cwd,
|
|
202
|
-
isCloudMode,
|
|
203
|
-
options,
|
|
204
|
-
logger: this.logger,
|
|
205
|
-
fileManager: this.fileManager,
|
|
206
|
-
gitManager: this.gitManager,
|
|
207
|
-
promptBuilder: this.promptBuilder,
|
|
208
|
-
connection: connection.agentConnection,
|
|
209
|
-
sessionId: taskRunId,
|
|
210
|
-
sendNotification,
|
|
211
|
-
mcpServers: this.mcpServers,
|
|
212
|
-
posthogAPI: this.posthogAPI,
|
|
213
|
-
stepResults: {},
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
for (const step of TASK_WORKFLOW) {
|
|
217
|
-
const result = await step.run({ step, context: workflowContext });
|
|
218
|
-
if (result.halt) {
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const shouldCreatePR = options.createPR ?? isCloudMode;
|
|
224
|
-
if (shouldCreatePR) {
|
|
225
|
-
await this.ensurePullRequest(
|
|
226
|
-
task,
|
|
227
|
-
workflowContext.stepResults,
|
|
228
|
-
sendNotification,
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
this.logger.info("Task execution complete", { taskId: task.id });
|
|
233
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.TASK_COMPLETE, {
|
|
234
|
-
sessionId: taskRunId,
|
|
235
|
-
taskId: task.id,
|
|
236
|
-
});
|
|
237
|
-
} catch (error) {
|
|
238
|
-
taskError = error instanceof Error ? error : new Error(String(error));
|
|
239
|
-
this.logger.error("Task execution failed", {
|
|
240
|
-
taskId: task.id,
|
|
241
|
-
error: taskError.message,
|
|
242
|
-
});
|
|
243
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.ERROR, {
|
|
244
|
-
sessionId: taskRunId,
|
|
245
|
-
message: taskError.message,
|
|
246
|
-
});
|
|
247
|
-
throw taskError;
|
|
248
|
-
}
|
|
152
|
+
throw new Error(
|
|
153
|
+
"runTask() is deprecated. Use runTaskV2() for local execution or runTaskCloud() for cloud execution.",
|
|
154
|
+
);
|
|
249
155
|
}
|
|
250
156
|
|
|
251
157
|
/**
|
|
@@ -262,8 +168,6 @@ export class Agent {
|
|
|
262
168
|
): Promise<InProcessAcpConnection> {
|
|
263
169
|
await this._configureLlmGateway();
|
|
264
170
|
|
|
265
|
-
const task = await this.fetchTask(taskId);
|
|
266
|
-
const taskSlug = (task as any).slug || task.id;
|
|
267
171
|
const isCloudMode = options.isCloudMode ?? false;
|
|
268
172
|
const _cwd = options.repositoryPath || this.workingDirectory;
|
|
269
173
|
|
|
@@ -271,9 +175,10 @@ export class Agent {
|
|
|
271
175
|
this.currentRunId = taskRunId;
|
|
272
176
|
|
|
273
177
|
this.acpConnection = createAcpConnection({
|
|
178
|
+
framework: options.framework,
|
|
274
179
|
sessionStore: this.sessionStore,
|
|
275
180
|
sessionId: taskRunId,
|
|
276
|
-
taskId
|
|
181
|
+
taskId,
|
|
277
182
|
});
|
|
278
183
|
|
|
279
184
|
const sendNotification: SendNotification = async (method, params) => {
|
|
@@ -284,12 +189,17 @@ export class Agent {
|
|
|
284
189
|
);
|
|
285
190
|
};
|
|
286
191
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
192
|
+
if (!options.isReconnect) {
|
|
193
|
+
await sendNotification(POSTHOG_NOTIFICATIONS.RUN_STARTED, {
|
|
194
|
+
sessionId: taskRunId,
|
|
195
|
+
runId: taskRunId,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
291
198
|
|
|
199
|
+
// Only fetch task when we need the slug for git branch creation
|
|
292
200
|
if (!options.skipGitBranch) {
|
|
201
|
+
const task = options.task ?? (await this.fetchTask(taskId));
|
|
202
|
+
const taskSlug = (task as any).slug || task.id;
|
|
293
203
|
try {
|
|
294
204
|
await this.prepareTaskBranch(taskSlug, isCloudMode, sendNotification);
|
|
295
205
|
} catch (error) {
|
|
@@ -373,9 +283,7 @@ export class Agent {
|
|
|
373
283
|
**Description**: ${taskDescription}
|
|
374
284
|
|
|
375
285
|
## Changes
|
|
376
|
-
This PR implements the changes described in the task
|
|
377
|
-
|
|
378
|
-
Generated by PostHog Agent`;
|
|
286
|
+
This PR implements the changes described in the task.`;
|
|
379
287
|
const prBody = customBody || defaultBody;
|
|
380
288
|
|
|
381
289
|
const prUrl = await this.gitManager.createPullRequest(
|
|
@@ -529,6 +437,19 @@ Generated by PostHog Agent`;
|
|
|
529
437
|
}
|
|
530
438
|
}
|
|
531
439
|
|
|
440
|
+
private ensureGeminiGatewayEnv(gatewayUrl?: string, token?: string): void {
|
|
441
|
+
const resolvedGatewayUrl = gatewayUrl || process.env.ANTHROPIC_BASE_URL;
|
|
442
|
+
const resolvedToken = token || process.env.ANTHROPIC_AUTH_TOKEN;
|
|
443
|
+
|
|
444
|
+
if (resolvedGatewayUrl) {
|
|
445
|
+
process.env.GEMINI_BASE_URL = resolvedGatewayUrl;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (resolvedToken) {
|
|
449
|
+
process.env.GEMINI_API_KEY = resolvedToken;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
532
453
|
async runTaskCloud(
|
|
533
454
|
taskId: string,
|
|
534
455
|
taskRunId: string,
|
|
@@ -741,61 +662,6 @@ Generated by PostHog Agent`;
|
|
|
741
662
|
throw error;
|
|
742
663
|
}
|
|
743
664
|
}
|
|
744
|
-
|
|
745
|
-
private async ensurePullRequest(
|
|
746
|
-
task: Task,
|
|
747
|
-
stepResults: Record<string, any>,
|
|
748
|
-
sendNotification: SendNotification,
|
|
749
|
-
): Promise<void> {
|
|
750
|
-
const latestRun = task.latest_run;
|
|
751
|
-
const existingPr =
|
|
752
|
-
latestRun?.output && typeof latestRun.output === "object"
|
|
753
|
-
? (latestRun.output as any).pr_url
|
|
754
|
-
: null;
|
|
755
|
-
|
|
756
|
-
if (existingPr) {
|
|
757
|
-
this.logger.info("PR already exists, skipping creation", {
|
|
758
|
-
taskId: task.id,
|
|
759
|
-
prUrl: existingPr,
|
|
760
|
-
});
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
const buildResult = stepResults.build;
|
|
765
|
-
if (!buildResult?.commitCreated) {
|
|
766
|
-
this.logger.warn(
|
|
767
|
-
"Build step did not produce a commit; skipping PR creation",
|
|
768
|
-
{ taskId: task.id },
|
|
769
|
-
);
|
|
770
|
-
return;
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
const branchName = await this.gitManager.getCurrentBranch();
|
|
774
|
-
const finalizeResult = stepResults.finalize;
|
|
775
|
-
const prBody = finalizeResult?.prBody;
|
|
776
|
-
|
|
777
|
-
const prUrl = await this.createPullRequest(
|
|
778
|
-
task.id,
|
|
779
|
-
branchName,
|
|
780
|
-
task.title,
|
|
781
|
-
task.description ?? "",
|
|
782
|
-
prBody,
|
|
783
|
-
);
|
|
784
|
-
|
|
785
|
-
await sendNotification(POSTHOG_NOTIFICATIONS.PR_CREATED, { prUrl });
|
|
786
|
-
|
|
787
|
-
try {
|
|
788
|
-
await this.attachPullRequestToTask(task.id, prUrl, branchName);
|
|
789
|
-
this.logger.info("PR attached to task successfully", {
|
|
790
|
-
taskId: task.id,
|
|
791
|
-
prUrl,
|
|
792
|
-
});
|
|
793
|
-
} catch (error) {
|
|
794
|
-
this.logger.warn("Could not attach PR to task", {
|
|
795
|
-
error: error instanceof Error ? error.message : String(error),
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
665
|
}
|
|
800
666
|
|
|
801
667
|
export type {
|
package/src/file-manager.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import { extname, join } from "node:path";
|
|
3
3
|
import z from "zod";
|
|
4
|
-
import type {
|
|
4
|
+
import type { SupportingFile } from "./types.js";
|
|
5
5
|
import { Logger } from "./utils/logger.js";
|
|
6
6
|
|
|
7
7
|
export interface TaskFile {
|
|
@@ -162,39 +162,6 @@ export class PostHogFileManager {
|
|
|
162
162
|
return await this.readTaskFile(taskId, "requirements.md");
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
async writeResearch(taskId: string, data: ResearchEvaluation): Promise<void> {
|
|
166
|
-
this.logger.debug("Writing research", {
|
|
167
|
-
taskId,
|
|
168
|
-
score: data.actionabilityScore,
|
|
169
|
-
hasQuestions: !!data.questions,
|
|
170
|
-
questionCount: data.questions?.length ?? 0,
|
|
171
|
-
answered: data.answered ?? false,
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
await this.writeTaskFile(taskId, {
|
|
175
|
-
name: "research.json",
|
|
176
|
-
content: JSON.stringify(data, null, 2),
|
|
177
|
-
type: "artifact",
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
this.logger.info("Research file written", {
|
|
181
|
-
taskId,
|
|
182
|
-
score: data.actionabilityScore,
|
|
183
|
-
hasQuestions: !!data.questions,
|
|
184
|
-
answered: data.answered ?? false,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async readResearch(taskId: string): Promise<ResearchEvaluation | null> {
|
|
189
|
-
try {
|
|
190
|
-
const content = await this.readTaskFile(taskId, "research.json");
|
|
191
|
-
return content ? (JSON.parse(content) as ResearchEvaluation) : null;
|
|
192
|
-
} catch (error) {
|
|
193
|
-
this.logger.debug("Failed to parse research.json", { error });
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
165
|
async writeTodos(taskId: string, data: unknown): Promise<void> {
|
|
199
166
|
const todos = z.object({
|
|
200
167
|
metadata: z.object({
|
package/src/git-manager.ts
CHANGED
|
@@ -6,8 +6,6 @@ const execAsync = promisify(exec);
|
|
|
6
6
|
|
|
7
7
|
export interface GitConfig {
|
|
8
8
|
repositoryPath: string;
|
|
9
|
-
authorName?: string;
|
|
10
|
-
authorEmail?: string;
|
|
11
9
|
logger?: Logger;
|
|
12
10
|
}
|
|
13
11
|
|
|
@@ -19,14 +17,10 @@ export interface BranchInfo {
|
|
|
19
17
|
|
|
20
18
|
export class GitManager {
|
|
21
19
|
private repositoryPath: string;
|
|
22
|
-
private authorName?: string;
|
|
23
|
-
private authorEmail?: string;
|
|
24
20
|
private logger: Logger;
|
|
25
21
|
|
|
26
22
|
constructor(config: GitConfig) {
|
|
27
23
|
this.repositoryPath = config.repositoryPath;
|
|
28
|
-
this.authorName = config.authorName;
|
|
29
|
-
this.authorEmail = config.authorEmail;
|
|
30
24
|
this.logger =
|
|
31
25
|
config.logger || new Logger({ debug: false, prefix: "[GitManager]" });
|
|
32
26
|
}
|
|
@@ -170,8 +164,7 @@ export class GitManager {
|
|
|
170
164
|
async commitChanges(
|
|
171
165
|
message: string,
|
|
172
166
|
options?: {
|
|
173
|
-
|
|
174
|
-
authorEmail?: string;
|
|
167
|
+
allowEmpty?: boolean;
|
|
175
168
|
},
|
|
176
169
|
): Promise<string> {
|
|
177
170
|
const command = this.buildCommitCommand(message, options);
|
|
@@ -244,8 +237,6 @@ export class GitManager {
|
|
|
244
237
|
message: string,
|
|
245
238
|
options?: {
|
|
246
239
|
allowEmpty?: boolean;
|
|
247
|
-
authorName?: string;
|
|
248
|
-
authorEmail?: string;
|
|
249
240
|
},
|
|
250
241
|
): string {
|
|
251
242
|
let command = `commit -m "${this.escapeShellArg(message)}"`;
|
|
@@ -254,13 +245,6 @@ export class GitManager {
|
|
|
254
245
|
command += " --allow-empty";
|
|
255
246
|
}
|
|
256
247
|
|
|
257
|
-
const authorName = options?.authorName || this.authorName;
|
|
258
|
-
const authorEmail = options?.authorEmail || this.authorEmail;
|
|
259
|
-
|
|
260
|
-
if (authorName && authorEmail) {
|
|
261
|
-
command += ` --author="${authorName} <${authorEmail}>"`;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
248
|
return command;
|
|
265
249
|
}
|
|
266
250
|
|
|
@@ -427,7 +411,6 @@ export class GitManager {
|
|
|
427
411
|
const message = `📋 Add plan for task: ${taskTitle}
|
|
428
412
|
|
|
429
413
|
Task ID: ${taskId}
|
|
430
|
-
Generated by PostHog Agent
|
|
431
414
|
|
|
432
415
|
This commit contains the implementation plan and supporting documentation
|
|
433
416
|
for the task. Review the plan before proceeding with implementation.`;
|
|
@@ -452,8 +435,7 @@ for the task. Review the plan before proceeding with implementation.`;
|
|
|
452
435
|
|
|
453
436
|
let message = `✨ Implement task: ${taskTitle}
|
|
454
437
|
|
|
455
|
-
Task ID: ${taskId}
|
|
456
|
-
Generated by PostHog Agent`;
|
|
438
|
+
Task ID: ${taskId}`;
|
|
457
439
|
|
|
458
440
|
if (planSummary) {
|
|
459
441
|
message += `\n\nPlan Summary:\n${planSummary}`;
|
package/src/posthog-api.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
TaskRunArtifact,
|
|
9
9
|
UrlMention,
|
|
10
10
|
} from "./types.js";
|
|
11
|
+
import { getLlmGatewayUrl } from "./utils/gateway.js";
|
|
11
12
|
|
|
12
13
|
interface PostHogApiResponse<T> {
|
|
13
14
|
results?: T[];
|
|
@@ -42,7 +43,7 @@ export class PostHogAPIClient {
|
|
|
42
43
|
|
|
43
44
|
private get headers(): Record<string, string> {
|
|
44
45
|
return {
|
|
45
|
-
Authorization: `Bearer ${this.config.
|
|
46
|
+
Authorization: `Bearer ${this.config.getApiKey()}`,
|
|
46
47
|
"Content-Type": "application/json",
|
|
47
48
|
};
|
|
48
49
|
}
|
|
@@ -84,12 +85,11 @@ export class PostHogAPIClient {
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
getApiKey(): string {
|
|
87
|
-
return this.config.
|
|
88
|
+
return this.config.getApiKey();
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
getLlmGatewayUrl(): string {
|
|
91
|
-
|
|
92
|
-
return `${this.baseUrl}/api/projects/${teamId}/llm_gateway`;
|
|
92
|
+
return getLlmGatewayUrl(this.baseUrl);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
async fetchTask(taskId: string): Promise<Task> {
|
package/src/tools/registry.ts
CHANGED
|
@@ -84,6 +84,11 @@ const TOOL_DEFINITIONS: Record<string, Tool> = {
|
|
|
84
84
|
category: "assistant",
|
|
85
85
|
description: "Exit plan mode and present plan to user",
|
|
86
86
|
},
|
|
87
|
+
AskUserQuestion: {
|
|
88
|
+
name: "AskUserQuestion",
|
|
89
|
+
category: "assistant",
|
|
90
|
+
description: "Ask the user a clarifying question with options",
|
|
91
|
+
},
|
|
87
92
|
SlashCommand: {
|
|
88
93
|
name: "SlashCommand",
|
|
89
94
|
category: "assistant",
|
package/src/tools/types.ts
CHANGED
|
@@ -100,6 +100,11 @@ export interface ExitPlanModeTool extends Tool {
|
|
|
100
100
|
category: "assistant";
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
export interface AskUserQuestionTool extends Tool {
|
|
104
|
+
name: "AskUserQuestion";
|
|
105
|
+
category: "assistant";
|
|
106
|
+
}
|
|
107
|
+
|
|
103
108
|
export interface SlashCommandTool extends Tool {
|
|
104
109
|
name: "SlashCommand";
|
|
105
110
|
category: "assistant";
|
|
@@ -124,4 +129,5 @@ export type KnownTool =
|
|
|
124
129
|
| TaskTool
|
|
125
130
|
| TodoWriteTool
|
|
126
131
|
| ExitPlanModeTool
|
|
132
|
+
| AskUserQuestionTool
|
|
127
133
|
| SlashCommandTool;
|
package/src/types.ts
CHANGED
|
@@ -141,6 +141,9 @@ export interface TaskExecutionOptions {
|
|
|
141
141
|
// See: https://docs.claude.com/en/api/agent-sdk/permissions
|
|
142
142
|
canUseTool?: CanUseTool;
|
|
143
143
|
skipGitBranch?: boolean; // Skip creating a task-specific git branch
|
|
144
|
+
framework?: "claude"; // Agent framework to use (defaults to "claude")
|
|
145
|
+
task?: Task; // Pre-fetched task to avoid redundant API call
|
|
146
|
+
isReconnect?: boolean; // Session recreation - skip RUN_STARTED notification
|
|
144
147
|
}
|
|
145
148
|
|
|
146
149
|
export interface ExecutionResult {
|
|
@@ -197,7 +200,7 @@ export interface AgentConfig {
|
|
|
197
200
|
|
|
198
201
|
// PostHog API configuration (optional - enables PostHog integration when provided)
|
|
199
202
|
posthogApiUrl?: string;
|
|
200
|
-
|
|
203
|
+
getPosthogApiKey?: () => string;
|
|
201
204
|
posthogProjectId?: number;
|
|
202
205
|
|
|
203
206
|
// PostHog MCP configuration
|
|
@@ -219,7 +222,7 @@ export interface AgentConfig {
|
|
|
219
222
|
|
|
220
223
|
export interface PostHogAPIConfig {
|
|
221
224
|
apiUrl: string;
|
|
222
|
-
|
|
225
|
+
getApiKey: () => string;
|
|
223
226
|
projectId: number;
|
|
224
227
|
}
|
|
225
228
|
|
|
@@ -248,29 +251,6 @@ export interface UrlMention {
|
|
|
248
251
|
label?: string;
|
|
249
252
|
}
|
|
250
253
|
|
|
251
|
-
// Research evaluation types
|
|
252
|
-
export interface ResearchQuestion {
|
|
253
|
-
id: string;
|
|
254
|
-
question: string;
|
|
255
|
-
options: string[];
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
export interface ResearchAnswer {
|
|
259
|
-
questionId: string;
|
|
260
|
-
selectedOption: string;
|
|
261
|
-
customInput?: string;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export interface ResearchEvaluation {
|
|
265
|
-
actionabilityScore: number; // 0-1 confidence score
|
|
266
|
-
context: string; // brief summary for planning
|
|
267
|
-
keyFiles: string[]; // files needing modification
|
|
268
|
-
blockers?: string[]; // what's preventing full confidence
|
|
269
|
-
questions?: ResearchQuestion[]; // only if score < 0.7
|
|
270
|
-
answered?: boolean; // whether questions have been answered
|
|
271
|
-
answers?: ResearchAnswer[]; // user's answers to questions
|
|
272
|
-
}
|
|
273
|
-
|
|
274
254
|
// Worktree types for parallel task development
|
|
275
255
|
export interface WorktreeInfo {
|
|
276
256
|
worktreePath: string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function getLlmGatewayUrl(posthogHost: string): string {
|
|
2
|
+
const url = new URL(posthogHost);
|
|
3
|
+
const hostname = url.hostname;
|
|
4
|
+
|
|
5
|
+
if (hostname === "localhost" || hostname === "127.0.0.1") {
|
|
6
|
+
return `${url.protocol}//localhost:3308`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Extract region from hostname (us.posthog.com, eu.posthog.com)
|
|
10
|
+
// app.posthog.com is legacy US
|
|
11
|
+
const regionMatch = hostname.match(/^(us|eu)\.posthog\.com$/);
|
|
12
|
+
const region = regionMatch ? regionMatch[1] : "us";
|
|
13
|
+
|
|
14
|
+
return `https://gateway.${region}.posthog.com`;
|
|
15
|
+
}
|