@posthog/agent 2.1.118 → 2.1.120
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/agent.js +45 -2
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.d.ts +1 -0
- package/dist/posthog-api.js +11 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.d.ts +7 -0
- package/dist/server/agent-server.js +240 -13
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +240 -13
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/claude/conversion/acp-to-sdk.ts +6 -0
- package/src/adapters/claude/permissions/permission-handlers.ts +7 -1
- package/src/posthog-api.ts +15 -0
- package/src/server/agent-server.test.ts +109 -0
- package/src/server/agent-server.ts +261 -12
- package/src/server/question-relay.test.ts +343 -0
- package/src/session-log-writer.test.ts +19 -0
- package/src/session-log-writer.ts +40 -0
- package/src/test/mocks/msw-handlers.ts +25 -1
package/dist/posthog-api.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ declare class PostHogAPIClient {
|
|
|
23
23
|
getTaskRun(taskId: string, runId: string): Promise<TaskRun>;
|
|
24
24
|
updateTaskRun(taskId: string, runId: string, payload: TaskRunUpdate): Promise<TaskRun>;
|
|
25
25
|
appendTaskRunLog(taskId: string, runId: string, entries: StoredEntry[]): Promise<TaskRun>;
|
|
26
|
+
relayMessage(taskId: string, runId: string, text: string): Promise<void>;
|
|
26
27
|
uploadTaskArtifacts(taskId: string, runId: string, artifacts: TaskArtifactUploadPayload[]): Promise<TaskRunArtifact[]>;
|
|
27
28
|
getArtifactPresignedUrl(taskId: string, runId: string, storagePath: string): Promise<string | null>;
|
|
28
29
|
/**
|
package/dist/posthog-api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "@posthog/agent",
|
|
4
|
-
version: "2.1.
|
|
4
|
+
version: "2.1.120",
|
|
5
5
|
repository: "https://github.com/PostHog/twig",
|
|
6
6
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
7
7
|
exports: {
|
|
@@ -206,6 +206,16 @@ var PostHogAPIClient = class {
|
|
|
206
206
|
}
|
|
207
207
|
);
|
|
208
208
|
}
|
|
209
|
+
async relayMessage(taskId, runId, text) {
|
|
210
|
+
const teamId = this.getTeamId();
|
|
211
|
+
await this.apiRequest(
|
|
212
|
+
`/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/relay_message/`,
|
|
213
|
+
{
|
|
214
|
+
method: "POST",
|
|
215
|
+
body: JSON.stringify({ text })
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
}
|
|
209
219
|
async uploadTaskArtifacts(taskId, runId, artifacts) {
|
|
210
220
|
if (!artifacts.length) {
|
|
211
221
|
return [];
|
package/dist/posthog-api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../package.json","../src/utils/gateway.ts","../src/posthog-api.ts"],"sourcesContent":["{\n \"name\": \"@posthog/agent\",\n \"version\": \"2.1.118\",\n \"repository\": \"https://github.com/PostHog/twig\",\n \"description\": \"TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./agent\": {\n \"types\": \"./dist/agent.d.ts\",\n \"import\": \"./dist/agent.js\"\n },\n \"./gateway-models\": {\n \"types\": \"./dist/gateway-models.d.ts\",\n \"import\": \"./dist/gateway-models.js\"\n },\n \"./posthog-api\": {\n \"types\": \"./dist/posthog-api.d.ts\",\n \"import\": \"./dist/posthog-api.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"import\": \"./dist/types.js\"\n },\n \"./adapters/claude/questions/utils\": {\n \"types\": \"./dist/adapters/claude/questions/utils.d.ts\",\n \"import\": \"./dist/adapters/claude/questions/utils.js\"\n },\n \"./adapters/claude/permissions/permission-options\": {\n \"types\": \"./dist/adapters/claude/permissions/permission-options.d.ts\",\n \"import\": \"./dist/adapters/claude/permissions/permission-options.js\"\n },\n \"./adapters/claude/tools\": {\n \"types\": \"./dist/adapters/claude/tools.d.ts\",\n \"import\": \"./dist/adapters/claude/tools.js\"\n },\n \"./adapters/claude/conversion/tool-use-to-acp\": {\n \"types\": \"./dist/adapters/claude/conversion/tool-use-to-acp.d.ts\",\n \"import\": \"./dist/adapters/claude/conversion/tool-use-to-acp.js\"\n },\n \"./server\": {\n \"types\": \"./dist/server/agent-server.d.ts\",\n \"import\": \"./dist/server/agent-server.js\"\n }\n },\n \"bin\": {\n \"agent-server\": \"./dist/server/bin.cjs\"\n },\n \"type\": \"module\",\n \"keywords\": [\n \"posthog\",\n \"claude\",\n \"agent\",\n \"ai\",\n \"git\",\n \"typescript\"\n ],\n \"author\": \"PostHog\",\n \"license\": \"SEE LICENSE IN LICENSE\",\n \"scripts\": {\n \"build\": \"rm -rf dist && tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"pnpm exec tsc --noEmit\",\n \"prepublishOnly\": \"pnpm run build\",\n \"clean\": \"rm -rf dist .turbo\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"devDependencies\": {\n \"@posthog/shared\": \"workspace:*\",\n \"@twig/git\": \"workspace:*\",\n \"@types/bun\": \"latest\",\n \"@types/tar\": \"^6.1.13\",\n \"minimatch\": \"^10.0.3\",\n \"msw\": \"^2.12.7\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.20.6\",\n \"typescript\": \"^5.5.0\",\n \"vitest\": \"^2.1.8\"\n },\n \"dependencies\": {\n \"@agentclientprotocol/sdk\": \"^0.14.0\",\n \"@anthropic-ai/claude-agent-sdk\": \"0.2.59\",\n \"@anthropic-ai/sdk\": \"^0.71.0\",\n \"@hono/node-server\": \"^1.19.9\",\n \"@opentelemetry/api-logs\": \"^0.208.0\",\n \"@opentelemetry/exporter-logs-otlp-http\": \"^0.208.0\",\n \"@opentelemetry/resources\": \"^2.0.0\",\n \"@opentelemetry/sdk-logs\": \"^0.208.0\",\n \"@opentelemetry/semantic-conventions\": \"^1.28.0\",\n \"@types/jsonwebtoken\": \"^9.0.10\",\n \"commander\": \"^14.0.2\",\n \"hono\": \"^4.11.7\",\n \"jsonwebtoken\": \"^9.0.2\",\n \"tar\": \"^7.5.0\",\n \"uuid\": \"13.0.0\",\n \"yoga-wasm-web\": \"^0.3.3\",\n \"zod\": \"^3.24.1\"\n },\n \"files\": [\n \"dist/**/*\",\n \"src/**/*\",\n \"README.md\",\n \"CLAUDE.md\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","export type GatewayProduct = \"twig\" | \"background_agents\";\n\nexport function getLlmGatewayUrl(\n posthogHost: string,\n product: GatewayProduct = \"twig\",\n): string {\n const url = new URL(posthogHost);\n const hostname = url.hostname;\n\n // Local development (normalize 127.0.0.1 to localhost)\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\") {\n return `${url.protocol}//localhost:3308/${product}`;\n }\n\n // Docker containers accessing host\n if (hostname === \"host.docker.internal\") {\n return `${url.protocol}//host.docker.internal:3308/${product}`;\n }\n\n // Production - extract region from hostname, default to US\n const region = hostname.match(/^(us|eu)\\.posthog\\.com$/)?.[1] ?? \"us\";\n return `https://gateway.${region}.posthog.com/${product}`;\n}\n","import packageJson from \"../package.json\" with { type: \"json\" };\nimport type {\n ArtifactType,\n PostHogAPIConfig,\n StoredEntry,\n Task,\n TaskRun,\n TaskRunArtifact,\n} from \"./types.js\";\nimport { getLlmGatewayUrl } from \"./utils/gateway.js\";\n\nexport { getLlmGatewayUrl };\n\nconst DEFAULT_USER_AGENT = `posthog/agent.hog.dev; version: ${packageJson.version}`;\n\nexport interface TaskArtifactUploadPayload {\n name: string;\n type: ArtifactType;\n content: string;\n content_type?: string;\n}\n\nexport type TaskRunUpdate = Partial<\n Pick<\n TaskRun,\n | \"status\"\n | \"branch\"\n | \"stage\"\n | \"error_message\"\n | \"output\"\n | \"state\"\n | \"environment\"\n >\n>;\n\nexport class PostHogAPIClient {\n private config: PostHogAPIConfig;\n\n constructor(config: PostHogAPIConfig) {\n this.config = config;\n }\n\n private get baseUrl(): string {\n const host = this.config.apiUrl.endsWith(\"/\")\n ? this.config.apiUrl.slice(0, -1)\n : this.config.apiUrl;\n return host;\n }\n\n private get headers(): Record<string, string> {\n return {\n Authorization: `Bearer ${this.config.getApiKey()}`,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.config.userAgent ?? DEFAULT_USER_AGENT,\n };\n }\n\n private async apiRequest<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const response = await fetch(url, {\n ...options,\n headers: {\n ...this.headers,\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n let errorMessage: string;\n try {\n const errorResponse = await response.json();\n errorMessage = `Failed request: [${response.status}] ${JSON.stringify(errorResponse)}`;\n } catch {\n errorMessage = `Failed request: [${response.status}] ${response.statusText}`;\n }\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n private getTeamId(): number {\n return this.config.projectId;\n }\n\n getApiKey(): string {\n return this.config.getApiKey();\n }\n\n getLlmGatewayUrl(): string {\n return getLlmGatewayUrl(this.baseUrl);\n }\n\n async getTask(taskId: string): Promise<Task> {\n const teamId = this.getTeamId();\n return this.apiRequest<Task>(`/api/projects/${teamId}/tasks/${taskId}/`);\n }\n\n async getTaskRun(taskId: string, runId: string): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/`,\n );\n }\n\n async updateTaskRun(\n taskId: string,\n runId: string,\n payload: TaskRunUpdate,\n ): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/`,\n {\n method: \"PATCH\",\n body: JSON.stringify(payload),\n },\n );\n }\n\n async appendTaskRunLog(\n taskId: string,\n runId: string,\n entries: StoredEntry[],\n ): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/append_log/`,\n {\n method: \"POST\",\n body: JSON.stringify({ entries }),\n },\n );\n }\n\n async uploadTaskArtifacts(\n taskId: string,\n runId: string,\n artifacts: TaskArtifactUploadPayload[],\n ): Promise<TaskRunArtifact[]> {\n if (!artifacts.length) {\n return [];\n }\n\n const teamId = this.getTeamId();\n const response = await this.apiRequest<{ artifacts: TaskRunArtifact[] }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/artifacts/`,\n {\n method: \"POST\",\n body: JSON.stringify({ artifacts }),\n },\n );\n\n return response.artifacts ?? [];\n }\n\n async getArtifactPresignedUrl(\n taskId: string,\n runId: string,\n storagePath: string,\n ): Promise<string | null> {\n const teamId = this.getTeamId();\n try {\n const response = await this.apiRequest<{\n url: string;\n expires_in: number;\n }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/artifacts/presign/`,\n {\n method: \"POST\",\n body: JSON.stringify({ storage_path: storagePath }),\n },\n );\n return response.url;\n } catch {\n return null;\n }\n }\n\n /**\n * Download artifact content by storage path\n * Gets a presigned URL and fetches the content\n */\n async downloadArtifact(\n taskId: string,\n runId: string,\n storagePath: string,\n ): Promise<ArrayBuffer | null> {\n const url = await this.getArtifactPresignedUrl(taskId, runId, storagePath);\n if (!url) {\n return null;\n }\n\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download artifact: ${response.status}`);\n }\n return response.arrayBuffer();\n } catch {\n return null;\n }\n }\n\n /**\n * Fetch logs for a task run via the logs API endpoint\n * @param taskRun - The task run to fetch logs for\n * @returns Array of stored entries, or empty array if no logs available\n */\n async fetchTaskRunLogs(taskRun: TaskRun): Promise<StoredEntry[]> {\n const teamId = this.getTeamId();\n\n try {\n const response = await fetch(\n `${this.baseUrl}/api/projects/${teamId}/tasks/${taskRun.task}/runs/${taskRun.id}/logs`,\n { headers: this.headers },\n );\n\n if (!response.ok) {\n if (response.status === 404) {\n return [];\n }\n throw new Error(\n `Failed to fetch logs: ${response.status} ${response.statusText}`,\n );\n }\n\n const content = await response.text();\n\n if (!content.trim()) {\n return [];\n }\n\n // Parse newline-delimited JSON\n return content\n .trim()\n .split(\"\\n\")\n .map((line) => JSON.parse(line) as StoredEntry);\n } catch (error) {\n throw new Error(\n `Failed to fetch task run logs: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../package.json","../src/utils/gateway.ts","../src/posthog-api.ts"],"sourcesContent":["{\n \"name\": \"@posthog/agent\",\n \"version\": \"2.1.120\",\n \"repository\": \"https://github.com/PostHog/twig\",\n \"description\": \"TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./agent\": {\n \"types\": \"./dist/agent.d.ts\",\n \"import\": \"./dist/agent.js\"\n },\n \"./gateway-models\": {\n \"types\": \"./dist/gateway-models.d.ts\",\n \"import\": \"./dist/gateway-models.js\"\n },\n \"./posthog-api\": {\n \"types\": \"./dist/posthog-api.d.ts\",\n \"import\": \"./dist/posthog-api.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"import\": \"./dist/types.js\"\n },\n \"./adapters/claude/questions/utils\": {\n \"types\": \"./dist/adapters/claude/questions/utils.d.ts\",\n \"import\": \"./dist/adapters/claude/questions/utils.js\"\n },\n \"./adapters/claude/permissions/permission-options\": {\n \"types\": \"./dist/adapters/claude/permissions/permission-options.d.ts\",\n \"import\": \"./dist/adapters/claude/permissions/permission-options.js\"\n },\n \"./adapters/claude/tools\": {\n \"types\": \"./dist/adapters/claude/tools.d.ts\",\n \"import\": \"./dist/adapters/claude/tools.js\"\n },\n \"./adapters/claude/conversion/tool-use-to-acp\": {\n \"types\": \"./dist/adapters/claude/conversion/tool-use-to-acp.d.ts\",\n \"import\": \"./dist/adapters/claude/conversion/tool-use-to-acp.js\"\n },\n \"./server\": {\n \"types\": \"./dist/server/agent-server.d.ts\",\n \"import\": \"./dist/server/agent-server.js\"\n }\n },\n \"bin\": {\n \"agent-server\": \"./dist/server/bin.cjs\"\n },\n \"type\": \"module\",\n \"keywords\": [\n \"posthog\",\n \"claude\",\n \"agent\",\n \"ai\",\n \"git\",\n \"typescript\"\n ],\n \"author\": \"PostHog\",\n \"license\": \"SEE LICENSE IN LICENSE\",\n \"scripts\": {\n \"build\": \"rm -rf dist && tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"pnpm exec tsc --noEmit\",\n \"prepublishOnly\": \"pnpm run build\",\n \"clean\": \"rm -rf dist .turbo\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"devDependencies\": {\n \"@posthog/shared\": \"workspace:*\",\n \"@twig/git\": \"workspace:*\",\n \"@types/bun\": \"latest\",\n \"@types/tar\": \"^6.1.13\",\n \"minimatch\": \"^10.0.3\",\n \"msw\": \"^2.12.7\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.20.6\",\n \"typescript\": \"^5.5.0\",\n \"vitest\": \"^2.1.8\"\n },\n \"dependencies\": {\n \"@agentclientprotocol/sdk\": \"^0.14.0\",\n \"@anthropic-ai/claude-agent-sdk\": \"0.2.59\",\n \"@anthropic-ai/sdk\": \"^0.71.0\",\n \"@hono/node-server\": \"^1.19.9\",\n \"@opentelemetry/api-logs\": \"^0.208.0\",\n \"@opentelemetry/exporter-logs-otlp-http\": \"^0.208.0\",\n \"@opentelemetry/resources\": \"^2.0.0\",\n \"@opentelemetry/sdk-logs\": \"^0.208.0\",\n \"@opentelemetry/semantic-conventions\": \"^1.28.0\",\n \"@types/jsonwebtoken\": \"^9.0.10\",\n \"commander\": \"^14.0.2\",\n \"hono\": \"^4.11.7\",\n \"jsonwebtoken\": \"^9.0.2\",\n \"tar\": \"^7.5.0\",\n \"uuid\": \"13.0.0\",\n \"yoga-wasm-web\": \"^0.3.3\",\n \"zod\": \"^3.24.1\"\n },\n \"files\": [\n \"dist/**/*\",\n \"src/**/*\",\n \"README.md\",\n \"CLAUDE.md\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","export type GatewayProduct = \"twig\" | \"background_agents\";\n\nexport function getLlmGatewayUrl(\n posthogHost: string,\n product: GatewayProduct = \"twig\",\n): string {\n const url = new URL(posthogHost);\n const hostname = url.hostname;\n\n // Local development (normalize 127.0.0.1 to localhost)\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\") {\n return `${url.protocol}//localhost:3308/${product}`;\n }\n\n // Docker containers accessing host\n if (hostname === \"host.docker.internal\") {\n return `${url.protocol}//host.docker.internal:3308/${product}`;\n }\n\n // Production - extract region from hostname, default to US\n const region = hostname.match(/^(us|eu)\\.posthog\\.com$/)?.[1] ?? \"us\";\n return `https://gateway.${region}.posthog.com/${product}`;\n}\n","import packageJson from \"../package.json\" with { type: \"json\" };\nimport type {\n ArtifactType,\n PostHogAPIConfig,\n StoredEntry,\n Task,\n TaskRun,\n TaskRunArtifact,\n} from \"./types.js\";\nimport { getLlmGatewayUrl } from \"./utils/gateway.js\";\n\nexport { getLlmGatewayUrl };\n\nconst DEFAULT_USER_AGENT = `posthog/agent.hog.dev; version: ${packageJson.version}`;\n\nexport interface TaskArtifactUploadPayload {\n name: string;\n type: ArtifactType;\n content: string;\n content_type?: string;\n}\n\nexport type TaskRunUpdate = Partial<\n Pick<\n TaskRun,\n | \"status\"\n | \"branch\"\n | \"stage\"\n | \"error_message\"\n | \"output\"\n | \"state\"\n | \"environment\"\n >\n>;\n\nexport class PostHogAPIClient {\n private config: PostHogAPIConfig;\n\n constructor(config: PostHogAPIConfig) {\n this.config = config;\n }\n\n private get baseUrl(): string {\n const host = this.config.apiUrl.endsWith(\"/\")\n ? this.config.apiUrl.slice(0, -1)\n : this.config.apiUrl;\n return host;\n }\n\n private get headers(): Record<string, string> {\n return {\n Authorization: `Bearer ${this.config.getApiKey()}`,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.config.userAgent ?? DEFAULT_USER_AGENT,\n };\n }\n\n private async apiRequest<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const response = await fetch(url, {\n ...options,\n headers: {\n ...this.headers,\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n let errorMessage: string;\n try {\n const errorResponse = await response.json();\n errorMessage = `Failed request: [${response.status}] ${JSON.stringify(errorResponse)}`;\n } catch {\n errorMessage = `Failed request: [${response.status}] ${response.statusText}`;\n }\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n private getTeamId(): number {\n return this.config.projectId;\n }\n\n getApiKey(): string {\n return this.config.getApiKey();\n }\n\n getLlmGatewayUrl(): string {\n return getLlmGatewayUrl(this.baseUrl);\n }\n\n async getTask(taskId: string): Promise<Task> {\n const teamId = this.getTeamId();\n return this.apiRequest<Task>(`/api/projects/${teamId}/tasks/${taskId}/`);\n }\n\n async getTaskRun(taskId: string, runId: string): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/`,\n );\n }\n\n async updateTaskRun(\n taskId: string,\n runId: string,\n payload: TaskRunUpdate,\n ): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/`,\n {\n method: \"PATCH\",\n body: JSON.stringify(payload),\n },\n );\n }\n\n async appendTaskRunLog(\n taskId: string,\n runId: string,\n entries: StoredEntry[],\n ): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/append_log/`,\n {\n method: \"POST\",\n body: JSON.stringify({ entries }),\n },\n );\n }\n\n async relayMessage(\n taskId: string,\n runId: string,\n text: string,\n ): Promise<void> {\n const teamId = this.getTeamId();\n await this.apiRequest<{ status: string }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/relay_message/`,\n {\n method: \"POST\",\n body: JSON.stringify({ text }),\n },\n );\n }\n\n async uploadTaskArtifacts(\n taskId: string,\n runId: string,\n artifacts: TaskArtifactUploadPayload[],\n ): Promise<TaskRunArtifact[]> {\n if (!artifacts.length) {\n return [];\n }\n\n const teamId = this.getTeamId();\n const response = await this.apiRequest<{ artifacts: TaskRunArtifact[] }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/artifacts/`,\n {\n method: \"POST\",\n body: JSON.stringify({ artifacts }),\n },\n );\n\n return response.artifacts ?? [];\n }\n\n async getArtifactPresignedUrl(\n taskId: string,\n runId: string,\n storagePath: string,\n ): Promise<string | null> {\n const teamId = this.getTeamId();\n try {\n const response = await this.apiRequest<{\n url: string;\n expires_in: number;\n }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/artifacts/presign/`,\n {\n method: \"POST\",\n body: JSON.stringify({ storage_path: storagePath }),\n },\n );\n return response.url;\n } catch {\n return null;\n }\n }\n\n /**\n * Download artifact content by storage path\n * Gets a presigned URL and fetches the content\n */\n async downloadArtifact(\n taskId: string,\n runId: string,\n storagePath: string,\n ): Promise<ArrayBuffer | null> {\n const url = await this.getArtifactPresignedUrl(taskId, runId, storagePath);\n if (!url) {\n return null;\n }\n\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download artifact: ${response.status}`);\n }\n return response.arrayBuffer();\n } catch {\n return null;\n }\n }\n\n /**\n * Fetch logs for a task run via the logs API endpoint\n * @param taskRun - The task run to fetch logs for\n * @returns Array of stored entries, or empty array if no logs available\n */\n async fetchTaskRunLogs(taskRun: TaskRun): Promise<StoredEntry[]> {\n const teamId = this.getTeamId();\n\n try {\n const response = await fetch(\n `${this.baseUrl}/api/projects/${teamId}/tasks/${taskRun.task}/runs/${taskRun.id}/logs`,\n { headers: this.headers },\n );\n\n if (!response.ok) {\n if (response.status === 404) {\n return [];\n }\n throw new Error(\n `Failed to fetch logs: ${response.status} ${response.statusText}`,\n );\n }\n\n const content = await response.text();\n\n if (!content.trim()) {\n return [];\n }\n\n // Parse newline-delimited JSON\n return content\n .trim()\n .split(\"\\n\")\n .map((line) => JSON.parse(line) as StoredEntry);\n } catch (error) {\n throw new Error(\n `Failed to fetch task run logs: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -20,6 +20,8 @@ declare class AgentServer {
|
|
|
20
20
|
private session;
|
|
21
21
|
private app;
|
|
22
22
|
private posthogAPI;
|
|
23
|
+
private questionRelayedToSlack;
|
|
24
|
+
private detectedPrUrl;
|
|
23
25
|
constructor(config: AgentServerConfig);
|
|
24
26
|
private getEffectiveMode;
|
|
25
27
|
private createApp;
|
|
@@ -30,10 +32,15 @@ declare class AgentServer {
|
|
|
30
32
|
private executeCommand;
|
|
31
33
|
private initializeSession;
|
|
32
34
|
private sendInitialTaskMessage;
|
|
35
|
+
private getInitialPromptOverride;
|
|
33
36
|
private buildCloudSystemPrompt;
|
|
34
37
|
private signalTaskComplete;
|
|
35
38
|
private configureEnvironment;
|
|
36
39
|
private createCloudClient;
|
|
40
|
+
private relayAgentResponse;
|
|
41
|
+
private relaySlackQuestion;
|
|
42
|
+
private getFirstQuestionMeta;
|
|
43
|
+
private isQuestionMeta;
|
|
37
44
|
private detectAndAttachPrUrl;
|
|
38
45
|
private cleanupSession;
|
|
39
46
|
private captureTreeState;
|
|
@@ -908,7 +908,7 @@ import { Hono } from "hono";
|
|
|
908
908
|
// package.json
|
|
909
909
|
var package_default = {
|
|
910
910
|
name: "@posthog/agent",
|
|
911
|
-
version: "2.1.
|
|
911
|
+
version: "2.1.120",
|
|
912
912
|
repository: "https://github.com/PostHog/twig",
|
|
913
913
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
914
914
|
exports: {
|
|
@@ -1528,6 +1528,10 @@ ${chunk.resource.text}
|
|
|
1528
1528
|
function promptToClaude(prompt) {
|
|
1529
1529
|
const content = [];
|
|
1530
1530
|
const context = [];
|
|
1531
|
+
const prContext = prompt._meta?.prContext;
|
|
1532
|
+
if (typeof prContext === "string") {
|
|
1533
|
+
content.push(sdkText(prContext));
|
|
1534
|
+
}
|
|
1531
1535
|
for (const chunk of prompt.prompt) {
|
|
1532
1536
|
processPromptChunk(chunk, content, context);
|
|
1533
1537
|
}
|
|
@@ -2974,9 +2978,10 @@ async function handleAskUserQuestionTool(context) {
|
|
|
2974
2978
|
}
|
|
2975
2979
|
});
|
|
2976
2980
|
if (response.outcome?.outcome !== "selected") {
|
|
2981
|
+
const customMessage = response._meta?.message;
|
|
2977
2982
|
return {
|
|
2978
2983
|
behavior: "deny",
|
|
2979
|
-
message: "User cancelled the questions",
|
|
2984
|
+
message: typeof customMessage === "string" ? customMessage : "User cancelled the questions",
|
|
2980
2985
|
interrupt: true
|
|
2981
2986
|
};
|
|
2982
2987
|
}
|
|
@@ -4346,6 +4351,16 @@ var PostHogAPIClient = class {
|
|
|
4346
4351
|
}
|
|
4347
4352
|
);
|
|
4348
4353
|
}
|
|
4354
|
+
async relayMessage(taskId, runId, text2) {
|
|
4355
|
+
const teamId = this.getTeamId();
|
|
4356
|
+
await this.apiRequest(
|
|
4357
|
+
`/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/relay_message/`,
|
|
4358
|
+
{
|
|
4359
|
+
method: "POST",
|
|
4360
|
+
body: JSON.stringify({ text: text2 })
|
|
4361
|
+
}
|
|
4362
|
+
);
|
|
4363
|
+
}
|
|
4349
4364
|
async uploadTaskArtifacts(taskId, runId, artifacts) {
|
|
4350
4365
|
if (!artifacts.length) {
|
|
4351
4366
|
return [];
|
|
@@ -4531,6 +4546,10 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4531
4546
|
return;
|
|
4532
4547
|
}
|
|
4533
4548
|
this.emitCoalescedMessage(sessionId, session);
|
|
4549
|
+
const nonChunkAgentText = this.extractAgentMessageText(message);
|
|
4550
|
+
if (nonChunkAgentText) {
|
|
4551
|
+
session.lastAgentMessage = nonChunkAgentText;
|
|
4552
|
+
}
|
|
4534
4553
|
const entry = {
|
|
4535
4554
|
type: "notification",
|
|
4536
4555
|
timestamp,
|
|
@@ -4630,6 +4649,7 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4630
4649
|
if (!session.chunkBuffer) return;
|
|
4631
4650
|
const { text: text2, firstTimestamp } = session.chunkBuffer;
|
|
4632
4651
|
session.chunkBuffer = void 0;
|
|
4652
|
+
session.lastAgentMessage = text2;
|
|
4633
4653
|
const entry = {
|
|
4634
4654
|
type: "notification",
|
|
4635
4655
|
timestamp: firstTimestamp,
|
|
@@ -4652,6 +4672,29 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4652
4672
|
this.scheduleFlush(sessionId);
|
|
4653
4673
|
}
|
|
4654
4674
|
}
|
|
4675
|
+
getLastAgentMessage(sessionId) {
|
|
4676
|
+
return this.sessions.get(sessionId)?.lastAgentMessage;
|
|
4677
|
+
}
|
|
4678
|
+
extractAgentMessageText(message) {
|
|
4679
|
+
if (message.method !== "session/update") {
|
|
4680
|
+
return null;
|
|
4681
|
+
}
|
|
4682
|
+
const params = message.params;
|
|
4683
|
+
const update = params?.update;
|
|
4684
|
+
if (update?.sessionUpdate !== "agent_message") {
|
|
4685
|
+
return null;
|
|
4686
|
+
}
|
|
4687
|
+
const content = update.content;
|
|
4688
|
+
if (content?.type === "text" && typeof content.text === "string") {
|
|
4689
|
+
const trimmed2 = content.text.trim();
|
|
4690
|
+
return trimmed2.length > 0 ? trimmed2 : null;
|
|
4691
|
+
}
|
|
4692
|
+
if (typeof update.message === "string") {
|
|
4693
|
+
const trimmed2 = update.message.trim();
|
|
4694
|
+
return trimmed2.length > 0 ? trimmed2 : null;
|
|
4695
|
+
}
|
|
4696
|
+
return null;
|
|
4697
|
+
}
|
|
4655
4698
|
scheduleFlush(sessionId) {
|
|
4656
4699
|
const existing = this.flushTimeouts.get(sessionId);
|
|
4657
4700
|
if (existing) clearTimeout(existing);
|
|
@@ -10324,6 +10367,8 @@ var AgentServer = class {
|
|
|
10324
10367
|
session = null;
|
|
10325
10368
|
app;
|
|
10326
10369
|
posthogAPI;
|
|
10370
|
+
questionRelayedToSlack = false;
|
|
10371
|
+
detectedPrUrl = null;
|
|
10327
10372
|
constructor(config) {
|
|
10328
10373
|
this.config = config;
|
|
10329
10374
|
this.logger = new Logger({ debug: true, prefix: "[AgentServer]" });
|
|
@@ -10536,11 +10581,21 @@ var AgentServer = class {
|
|
|
10536
10581
|
case "user_message": {
|
|
10537
10582
|
const content = params.content;
|
|
10538
10583
|
this.logger.info(
|
|
10539
|
-
`Processing user message: ${content.substring(0, 100)}...`
|
|
10584
|
+
`Processing user message (detectedPrUrl=${this.detectedPrUrl ?? "none"}): ${content.substring(0, 100)}...`
|
|
10540
10585
|
);
|
|
10541
10586
|
const result = await this.session.clientConnection.prompt({
|
|
10542
10587
|
sessionId: this.session.acpSessionId,
|
|
10543
|
-
prompt: [{ type: "text", text: content }]
|
|
10588
|
+
prompt: [{ type: "text", text: content }],
|
|
10589
|
+
...this.detectedPrUrl && {
|
|
10590
|
+
_meta: {
|
|
10591
|
+
prContext: `IMPORTANT \u2014 OVERRIDE PREVIOUS INSTRUCTIONS ABOUT CREATING BRANCHES/PRs.
|
|
10592
|
+
You already have an open pull request: ${this.detectedPrUrl}
|
|
10593
|
+
You MUST:
|
|
10594
|
+
1. Check out the existing PR branch with \`gh pr checkout ${this.detectedPrUrl}\`
|
|
10595
|
+
2. Make changes, commit, and push to that branch
|
|
10596
|
+
You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
10597
|
+
}
|
|
10598
|
+
}
|
|
10544
10599
|
});
|
|
10545
10600
|
return { stopReason: result.stopReason };
|
|
10546
10601
|
}
|
|
@@ -10625,13 +10680,29 @@ var AgentServer = class {
|
|
|
10625
10680
|
protocolVersion: PROTOCOL_VERSION,
|
|
10626
10681
|
clientCapabilities: {}
|
|
10627
10682
|
});
|
|
10683
|
+
let preTaskRun = null;
|
|
10684
|
+
try {
|
|
10685
|
+
preTaskRun = await this.posthogAPI.getTaskRun(
|
|
10686
|
+
payload.task_id,
|
|
10687
|
+
payload.run_id
|
|
10688
|
+
);
|
|
10689
|
+
} catch {
|
|
10690
|
+
this.logger.warn("Failed to fetch task run for session context", {
|
|
10691
|
+
taskId: payload.task_id,
|
|
10692
|
+
runId: payload.run_id
|
|
10693
|
+
});
|
|
10694
|
+
}
|
|
10695
|
+
const prUrl = typeof preTaskRun?.state?.slack_notified_pr_url === "string" ? (preTaskRun?.state).slack_notified_pr_url : null;
|
|
10696
|
+
if (prUrl) {
|
|
10697
|
+
this.detectedPrUrl = prUrl;
|
|
10698
|
+
}
|
|
10628
10699
|
const sessionResponse = await clientConnection.newSession({
|
|
10629
10700
|
cwd: this.config.repositoryPath,
|
|
10630
10701
|
mcpServers: [],
|
|
10631
10702
|
_meta: {
|
|
10632
10703
|
sessionId: payload.run_id,
|
|
10633
10704
|
taskRunId: payload.run_id,
|
|
10634
|
-
systemPrompt: { append: this.buildCloudSystemPrompt() }
|
|
10705
|
+
systemPrompt: { append: this.buildCloudSystemPrompt(prUrl) }
|
|
10635
10706
|
}
|
|
10636
10707
|
});
|
|
10637
10708
|
const acpSessionId = sessionResponse.sessionId;
|
|
@@ -10655,28 +10726,51 @@ var AgentServer = class {
|
|
|
10655
10726
|
}).catch(
|
|
10656
10727
|
(err) => this.logger.warn("Failed to set task run to in_progress", err)
|
|
10657
10728
|
);
|
|
10658
|
-
await this.sendInitialTaskMessage(payload);
|
|
10729
|
+
await this.sendInitialTaskMessage(payload, preTaskRun);
|
|
10659
10730
|
}
|
|
10660
|
-
async sendInitialTaskMessage(payload) {
|
|
10731
|
+
async sendInitialTaskMessage(payload, prefetchedRun) {
|
|
10661
10732
|
if (!this.session) return;
|
|
10662
10733
|
try {
|
|
10663
|
-
this.logger.info("Fetching task details", { taskId: payload.task_id });
|
|
10664
10734
|
const task = await this.posthogAPI.getTask(payload.task_id);
|
|
10665
|
-
|
|
10735
|
+
let taskRun = prefetchedRun ?? null;
|
|
10736
|
+
if (!taskRun) {
|
|
10737
|
+
try {
|
|
10738
|
+
taskRun = await this.posthogAPI.getTaskRun(
|
|
10739
|
+
payload.task_id,
|
|
10740
|
+
payload.run_id
|
|
10741
|
+
);
|
|
10742
|
+
} catch (error) {
|
|
10743
|
+
this.logger.warn(
|
|
10744
|
+
"Failed to fetch task run for initial prompt override",
|
|
10745
|
+
{
|
|
10746
|
+
taskId: payload.task_id,
|
|
10747
|
+
runId: payload.run_id,
|
|
10748
|
+
error
|
|
10749
|
+
}
|
|
10750
|
+
);
|
|
10751
|
+
}
|
|
10752
|
+
}
|
|
10753
|
+
const initialPromptOverride = taskRun ? this.getInitialPromptOverride(taskRun) : null;
|
|
10754
|
+
const initialPrompt = initialPromptOverride ?? task.description;
|
|
10755
|
+
if (!initialPrompt) {
|
|
10666
10756
|
this.logger.warn("Task has no description, skipping initial message");
|
|
10667
10757
|
return;
|
|
10668
10758
|
}
|
|
10669
10759
|
this.logger.info("Sending initial task message", {
|
|
10670
10760
|
taskId: payload.task_id,
|
|
10671
|
-
descriptionLength:
|
|
10761
|
+
descriptionLength: initialPrompt.length,
|
|
10762
|
+
usedInitialPromptOverride: !!initialPromptOverride
|
|
10672
10763
|
});
|
|
10673
10764
|
const result = await this.session.clientConnection.prompt({
|
|
10674
10765
|
sessionId: this.session.acpSessionId,
|
|
10675
|
-
prompt: [{ type: "text", text:
|
|
10766
|
+
prompt: [{ type: "text", text: initialPrompt }]
|
|
10676
10767
|
});
|
|
10677
10768
|
this.logger.info("Initial task message completed", {
|
|
10678
10769
|
stopReason: result.stopReason
|
|
10679
10770
|
});
|
|
10771
|
+
if (result.stopReason === "end_turn") {
|
|
10772
|
+
await this.relayAgentResponse(payload);
|
|
10773
|
+
}
|
|
10680
10774
|
} catch (error) {
|
|
10681
10775
|
this.logger.error("Failed to send initial task message", error);
|
|
10682
10776
|
if (this.session) {
|
|
@@ -10685,7 +10779,33 @@ var AgentServer = class {
|
|
|
10685
10779
|
await this.signalTaskComplete(payload, "error");
|
|
10686
10780
|
}
|
|
10687
10781
|
}
|
|
10688
|
-
|
|
10782
|
+
getInitialPromptOverride(taskRun) {
|
|
10783
|
+
const state = taskRun.state;
|
|
10784
|
+
const override = state?.initial_prompt_override;
|
|
10785
|
+
if (typeof override !== "string") {
|
|
10786
|
+
return null;
|
|
10787
|
+
}
|
|
10788
|
+
const trimmed2 = override.trim();
|
|
10789
|
+
return trimmed2.length > 0 ? trimmed2 : null;
|
|
10790
|
+
}
|
|
10791
|
+
buildCloudSystemPrompt(prUrl) {
|
|
10792
|
+
if (prUrl) {
|
|
10793
|
+
return `
|
|
10794
|
+
# Cloud Task Execution
|
|
10795
|
+
|
|
10796
|
+
This task already has an open pull request: ${prUrl}
|
|
10797
|
+
|
|
10798
|
+
After completing the requested changes:
|
|
10799
|
+
1. Check out the existing PR branch with \`gh pr checkout ${prUrl}\`
|
|
10800
|
+
2. Stage and commit all changes with a clear commit message
|
|
10801
|
+
3. Push to the existing PR branch
|
|
10802
|
+
|
|
10803
|
+
Important:
|
|
10804
|
+
- Do NOT create a new branch or a new pull request.
|
|
10805
|
+
- Do NOT add "Co-Authored-By" trailers to commit messages.
|
|
10806
|
+
- Do NOT add "Generated with [Claude Code]" or similar attribution lines to PR descriptions.
|
|
10807
|
+
`;
|
|
10808
|
+
}
|
|
10689
10809
|
return `
|
|
10690
10810
|
# Cloud Task Execution
|
|
10691
10811
|
|
|
@@ -10755,19 +10875,34 @@ Important:
|
|
|
10755
10875
|
}
|
|
10756
10876
|
createCloudClient(payload) {
|
|
10757
10877
|
const mode = this.getEffectiveMode(payload);
|
|
10878
|
+
const interactionOrigin = process.env.TWIG_INTERACTION_ORIGIN;
|
|
10758
10879
|
return {
|
|
10759
10880
|
requestPermission: async (params) => {
|
|
10760
10881
|
this.logger.debug("Permission request", {
|
|
10761
10882
|
mode,
|
|
10883
|
+
interactionOrigin,
|
|
10762
10884
|
options: params.options
|
|
10763
10885
|
});
|
|
10764
10886
|
const allowOption = params.options.find(
|
|
10765
10887
|
(o) => o.kind === "allow_once" || o.kind === "allow_always"
|
|
10766
10888
|
);
|
|
10889
|
+
const selectedOptionId = allowOption?.optionId ?? params.options[0].optionId;
|
|
10890
|
+
if (interactionOrigin === "slack") {
|
|
10891
|
+
const twigToolKind = params.toolCall?._meta?.twigToolKind;
|
|
10892
|
+
if (twigToolKind === "question") {
|
|
10893
|
+
this.relaySlackQuestion(payload, params.toolCall?._meta);
|
|
10894
|
+
return {
|
|
10895
|
+
outcome: { outcome: "cancelled" },
|
|
10896
|
+
_meta: {
|
|
10897
|
+
message: "This question has been relayed to the Slack thread where this task originated. The user will reply there. Do NOT re-ask the question or pick an answer yourself. Simply let the user know you are waiting for their reply."
|
|
10898
|
+
}
|
|
10899
|
+
};
|
|
10900
|
+
}
|
|
10901
|
+
}
|
|
10767
10902
|
return {
|
|
10768
10903
|
outcome: {
|
|
10769
10904
|
outcome: "selected",
|
|
10770
|
-
optionId:
|
|
10905
|
+
optionId: selectedOptionId
|
|
10771
10906
|
}
|
|
10772
10907
|
};
|
|
10773
10908
|
},
|
|
@@ -10786,6 +10921,97 @@ Important:
|
|
|
10786
10921
|
}
|
|
10787
10922
|
};
|
|
10788
10923
|
}
|
|
10924
|
+
async relayAgentResponse(payload) {
|
|
10925
|
+
if (!this.session) {
|
|
10926
|
+
return;
|
|
10927
|
+
}
|
|
10928
|
+
if (this.questionRelayedToSlack) {
|
|
10929
|
+
this.questionRelayedToSlack = false;
|
|
10930
|
+
return;
|
|
10931
|
+
}
|
|
10932
|
+
try {
|
|
10933
|
+
await this.session.logWriter.flush(payload.run_id);
|
|
10934
|
+
} catch (error) {
|
|
10935
|
+
this.logger.warn("Failed to flush logs before Slack relay", {
|
|
10936
|
+
taskId: payload.task_id,
|
|
10937
|
+
runId: payload.run_id,
|
|
10938
|
+
error
|
|
10939
|
+
});
|
|
10940
|
+
}
|
|
10941
|
+
const message = this.session.logWriter.getLastAgentMessage(payload.run_id);
|
|
10942
|
+
if (!message) {
|
|
10943
|
+
this.logger.warn("No agent message found for Slack relay", {
|
|
10944
|
+
taskId: payload.task_id,
|
|
10945
|
+
runId: payload.run_id,
|
|
10946
|
+
sessionRegistered: this.session.logWriter.isRegistered(payload.run_id)
|
|
10947
|
+
});
|
|
10948
|
+
return;
|
|
10949
|
+
}
|
|
10950
|
+
try {
|
|
10951
|
+
await this.posthogAPI.relayMessage(
|
|
10952
|
+
payload.task_id,
|
|
10953
|
+
payload.run_id,
|
|
10954
|
+
message
|
|
10955
|
+
);
|
|
10956
|
+
} catch (error) {
|
|
10957
|
+
this.logger.warn("Failed to relay initial agent response to Slack", {
|
|
10958
|
+
taskId: payload.task_id,
|
|
10959
|
+
runId: payload.run_id,
|
|
10960
|
+
error
|
|
10961
|
+
});
|
|
10962
|
+
}
|
|
10963
|
+
}
|
|
10964
|
+
relaySlackQuestion(payload, toolMeta2) {
|
|
10965
|
+
const firstQuestion = this.getFirstQuestionMeta(toolMeta2);
|
|
10966
|
+
if (!this.isQuestionMeta(firstQuestion)) {
|
|
10967
|
+
return;
|
|
10968
|
+
}
|
|
10969
|
+
let message = `*${firstQuestion.question}*
|
|
10970
|
+
|
|
10971
|
+
`;
|
|
10972
|
+
if (firstQuestion.options?.length) {
|
|
10973
|
+
firstQuestion.options.forEach(
|
|
10974
|
+
(opt, i) => {
|
|
10975
|
+
message += `${i + 1}. *${opt.label}*`;
|
|
10976
|
+
if (opt.description) message += ` \u2014 ${opt.description}`;
|
|
10977
|
+
message += "\n";
|
|
10978
|
+
}
|
|
10979
|
+
);
|
|
10980
|
+
}
|
|
10981
|
+
message += "\nReply in this thread with your choice.";
|
|
10982
|
+
this.questionRelayedToSlack = true;
|
|
10983
|
+
this.posthogAPI.relayMessage(payload.task_id, payload.run_id, message).catch(
|
|
10984
|
+
(err) => this.logger.warn("Failed to relay question to Slack", { err })
|
|
10985
|
+
);
|
|
10986
|
+
}
|
|
10987
|
+
getFirstQuestionMeta(toolMeta2) {
|
|
10988
|
+
if (!toolMeta2) {
|
|
10989
|
+
return null;
|
|
10990
|
+
}
|
|
10991
|
+
const questionsValue = toolMeta2.questions;
|
|
10992
|
+
if (!Array.isArray(questionsValue) || questionsValue.length === 0) {
|
|
10993
|
+
return null;
|
|
10994
|
+
}
|
|
10995
|
+
return questionsValue[0];
|
|
10996
|
+
}
|
|
10997
|
+
isQuestionMeta(value) {
|
|
10998
|
+
if (!value || typeof value !== "object") {
|
|
10999
|
+
return false;
|
|
11000
|
+
}
|
|
11001
|
+
const candidate = value;
|
|
11002
|
+
if (typeof candidate.question !== "string") {
|
|
11003
|
+
return false;
|
|
11004
|
+
}
|
|
11005
|
+
if (candidate.options === void 0) {
|
|
11006
|
+
return true;
|
|
11007
|
+
}
|
|
11008
|
+
if (!Array.isArray(candidate.options)) {
|
|
11009
|
+
return false;
|
|
11010
|
+
}
|
|
11011
|
+
return candidate.options.every(
|
|
11012
|
+
(option) => !!option && typeof option === "object" && typeof option.label === "string"
|
|
11013
|
+
);
|
|
11014
|
+
}
|
|
10789
11015
|
detectAndAttachPrUrl(payload, update) {
|
|
10790
11016
|
try {
|
|
10791
11017
|
const meta = update?._meta?.claudeCode;
|
|
@@ -10816,6 +11042,7 @@ Important:
|
|
|
10816
11042
|
);
|
|
10817
11043
|
if (!prUrlMatch) return;
|
|
10818
11044
|
const prUrl = prUrlMatch[0];
|
|
11045
|
+
this.detectedPrUrl = prUrl;
|
|
10819
11046
|
this.logger.info("Detected PR URL in bash output", {
|
|
10820
11047
|
runId: payload.run_id,
|
|
10821
11048
|
prUrl
|