@posthog/agent 2.3.696 → 2.3.709
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 +19 -1
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +22 -1
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +22 -1
- package/dist/server/bin.cjs.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
- package/src/adapters/claude/claude-agent.slash-command.test.ts +153 -0
- package/src/adapters/claude/claude-agent.ts +22 -0
- package/src/server/agent-server.configure-environment.test.ts +14 -0
- package/src/server/agent-server.ts +4 -0
- package/src/types.ts +1 -0
package/dist/types.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ interface Task {
|
|
|
27
27
|
title: string;
|
|
28
28
|
description: string;
|
|
29
29
|
origin_product: "error_tracking" | "eval_clusters" | "user_created" | "support_queue" | "session_summaries" | "signal_report";
|
|
30
|
+
signal_report?: string | null;
|
|
30
31
|
github_integration?: number | null;
|
|
31
32
|
repository: string;
|
|
32
33
|
json_schema?: Record<string, unknown> | null;
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n GitHandoffCheckpoint,\n HandoffLocalGitState as GitHandoffLocalGitState,\n} from \"@posthog/git/handoff\";\n\n/**\n * Stored custom notification following ACP extensibility model.\n * Custom notifications use underscore-prefixed methods (e.g., `_posthog/phase_start`).\n * See: https://agentclientprotocol.com/docs/extensibility\n */\nexport interface StoredNotification {\n type: \"notification\";\n /** When this notification was stored */\n timestamp: string;\n /** JSON-RPC 2.0 notification (no id field = notification, not request) */\n notification: {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n };\n}\n\n/**\n * Type alias for stored log entries.\n */\nexport type StoredEntry = StoredNotification;\n\n// PostHog Task model (matches PostHog Code's OpenAPI schema)\nexport interface Task {\n id: string;\n task_number?: number;\n slug?: string;\n title: string;\n description: string;\n origin_product:\n | \"error_tracking\"\n | \"eval_clusters\"\n | \"user_created\"\n | \"support_queue\"\n | \"session_summaries\"\n | \"signal_report\";\n github_integration?: number | null;\n repository: string; // Format: \"organization/repository\" (e.g., \"posthog/posthog-js\")\n json_schema?: Record<string, unknown> | null; // JSON schema for task output validation\n internal?: boolean;\n created_at: string;\n updated_at: string;\n created_by?: {\n id: number;\n uuid: string;\n distinct_id: string;\n first_name: string;\n email: string;\n };\n latest_run?: TaskRun;\n}\n\n// Log entry structure for TaskRun.log\n\nexport type ArtifactType =\n | \"plan\"\n | \"context\"\n | \"reference\"\n | \"output\"\n | \"artifact\"\n | \"user_attachment\";\n\nexport interface TaskRunArtifact {\n id?: string;\n name: string;\n type: ArtifactType;\n source?: string;\n size?: number;\n content_type?: string;\n storage_path?: string;\n uploaded_at?: string;\n}\n\nexport type TaskRunStatus =\n | \"not_started\"\n | \"queued\"\n | \"in_progress\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\nexport type TaskRunEnvironment = \"local\" | \"cloud\";\n\n// TaskRun model - represents individual execution runs of tasks\nexport interface TaskRun {\n id: string;\n task: string; // Task ID\n team: number;\n branch: string | null;\n stage: string | null; // Current stage (e.g., 'research', 'plan', 'build')\n environment: TaskRunEnvironment;\n status: TaskRunStatus;\n log_url: string;\n error_message: string | null;\n output: Record<string, unknown> | null; // Structured output (PR URL, commit SHA, etc.)\n state: Record<string, unknown>; // Intermediate run state (defaults to {}, never null)\n artifacts?: TaskRunArtifact[];\n created_at: string;\n updated_at: string;\n completed_at: string | null;\n}\n\nexport interface ProcessSpawnedCallback {\n onProcessSpawned?: (info: {\n pid: number;\n command: string;\n sessionId?: string;\n }) => void;\n onProcessExited?: (pid: number) => void;\n onMcpServersReady?: (serverNames: string[]) => void;\n}\n\nexport interface TaskExecutionOptions {\n repositoryPath?: string;\n adapter?: \"claude\" | \"codex\";\n model?: string;\n gatewayUrl?: string;\n codexBinaryPath?: string;\n instructions?: string;\n processCallbacks?: ProcessSpawnedCallback;\n /** Callback invoked when the agent calls the create_output tool for structured output */\n onStructuredOutput?: (output: Record<string, unknown>) => Promise<void>;\n /** Additional directories the agent process can access beyond cwd. */\n additionalDirectories?: string[];\n}\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport type OnLogCallback = (\n level: LogLevel,\n scope: string,\n message: string,\n data?: unknown,\n) => void;\n\nexport interface PostHogAPIConfig {\n apiUrl: string;\n getApiKey: () => string | Promise<string>;\n refreshApiKey?: () => string | Promise<string>;\n projectId: number;\n userAgent?: string;\n}\n\nexport interface OtelTransportConfig {\n /** PostHog ingest host, e.g., \"https://us.i.posthog.com\" */\n host: string;\n /** Project API key */\n apiKey: string;\n /** Override the logs endpoint path (default: /i/v1/logs) */\n logsPath?: string;\n}\n\nexport interface AgentConfig {\n posthog?: PostHogAPIConfig;\n /** OTEL transport config for shipping logs to PostHog Logs */\n otelTransport?: OtelTransportConfig;\n /** Skip session log persistence (e.g. for preview sessions with no real task) */\n skipLogPersistence?: boolean;\n /** Local cache path for instant log loading (e.g., ~/.posthog-code) */\n localCachePath?: string;\n /**\n * Annotate files the agent reads with PostHog enrichment (event volume,\n * flag rollout/staleness, experiment links). Defaults to enabled when\n * `posthog` config is present; set `{ enabled: false }` to opt out.\n */\n enricher?: { enabled?: boolean };\n debug?: boolean;\n onLog?: OnLogCallback;\n}\n\n// Device info for tracking where work happens\nexport interface DeviceInfo {\n type: \"local\" | \"cloud\";\n name?: string;\n}\n\n// Agent execution mode - for tracking interactive vs background runs, when backgrounded an agent will continue working without asking questions\nexport type AgentMode = \"interactive\" | \"background\";\n\n// Git file status codes\nexport type FileStatus = \"A\" | \"M\" | \"D\";\n\nexport interface FileChange {\n path: string;\n status: FileStatus;\n}\n\nexport type HandoffLocalGitState = GitHandoffLocalGitState;\n\nexport interface GitCheckpoint extends GitHandoffCheckpoint {\n artifactPath?: string;\n indexArtifactPath?: string;\n}\n\nexport interface GitCheckpointEvent extends GitCheckpoint {\n device?: DeviceInfo;\n}\n\n/**\n * Keeps the emitted `@posthog/agent/types` entrypoint as a runtime ESM module.\n *\n * `export {}` is stripped by tsup in this package, which leaves `dist/types.js`\n * empty and breaks downstream type resolution for the exported subpath.\n */\nexport const AGENT_TYPES_MODULE = true;\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n GitHandoffCheckpoint,\n HandoffLocalGitState as GitHandoffLocalGitState,\n} from \"@posthog/git/handoff\";\n\n/**\n * Stored custom notification following ACP extensibility model.\n * Custom notifications use underscore-prefixed methods (e.g., `_posthog/phase_start`).\n * See: https://agentclientprotocol.com/docs/extensibility\n */\nexport interface StoredNotification {\n type: \"notification\";\n /** When this notification was stored */\n timestamp: string;\n /** JSON-RPC 2.0 notification (no id field = notification, not request) */\n notification: {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n };\n}\n\n/**\n * Type alias for stored log entries.\n */\nexport type StoredEntry = StoredNotification;\n\n// PostHog Task model (matches PostHog Code's OpenAPI schema)\nexport interface Task {\n id: string;\n task_number?: number;\n slug?: string;\n title: string;\n description: string;\n origin_product:\n | \"error_tracking\"\n | \"eval_clusters\"\n | \"user_created\"\n | \"support_queue\"\n | \"session_summaries\"\n | \"signal_report\";\n signal_report?: string | null; // Inbox report UUID when origin_product is \"signal_report\"\n github_integration?: number | null;\n repository: string; // Format: \"organization/repository\" (e.g., \"posthog/posthog-js\")\n json_schema?: Record<string, unknown> | null; // JSON schema for task output validation\n internal?: boolean;\n created_at: string;\n updated_at: string;\n created_by?: {\n id: number;\n uuid: string;\n distinct_id: string;\n first_name: string;\n email: string;\n };\n latest_run?: TaskRun;\n}\n\n// Log entry structure for TaskRun.log\n\nexport type ArtifactType =\n | \"plan\"\n | \"context\"\n | \"reference\"\n | \"output\"\n | \"artifact\"\n | \"user_attachment\";\n\nexport interface TaskRunArtifact {\n id?: string;\n name: string;\n type: ArtifactType;\n source?: string;\n size?: number;\n content_type?: string;\n storage_path?: string;\n uploaded_at?: string;\n}\n\nexport type TaskRunStatus =\n | \"not_started\"\n | \"queued\"\n | \"in_progress\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\nexport type TaskRunEnvironment = \"local\" | \"cloud\";\n\n// TaskRun model - represents individual execution runs of tasks\nexport interface TaskRun {\n id: string;\n task: string; // Task ID\n team: number;\n branch: string | null;\n stage: string | null; // Current stage (e.g., 'research', 'plan', 'build')\n environment: TaskRunEnvironment;\n status: TaskRunStatus;\n log_url: string;\n error_message: string | null;\n output: Record<string, unknown> | null; // Structured output (PR URL, commit SHA, etc.)\n state: Record<string, unknown>; // Intermediate run state (defaults to {}, never null)\n artifacts?: TaskRunArtifact[];\n created_at: string;\n updated_at: string;\n completed_at: string | null;\n}\n\nexport interface ProcessSpawnedCallback {\n onProcessSpawned?: (info: {\n pid: number;\n command: string;\n sessionId?: string;\n }) => void;\n onProcessExited?: (pid: number) => void;\n onMcpServersReady?: (serverNames: string[]) => void;\n}\n\nexport interface TaskExecutionOptions {\n repositoryPath?: string;\n adapter?: \"claude\" | \"codex\";\n model?: string;\n gatewayUrl?: string;\n codexBinaryPath?: string;\n instructions?: string;\n processCallbacks?: ProcessSpawnedCallback;\n /** Callback invoked when the agent calls the create_output tool for structured output */\n onStructuredOutput?: (output: Record<string, unknown>) => Promise<void>;\n /** Additional directories the agent process can access beyond cwd. */\n additionalDirectories?: string[];\n}\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport type OnLogCallback = (\n level: LogLevel,\n scope: string,\n message: string,\n data?: unknown,\n) => void;\n\nexport interface PostHogAPIConfig {\n apiUrl: string;\n getApiKey: () => string | Promise<string>;\n refreshApiKey?: () => string | Promise<string>;\n projectId: number;\n userAgent?: string;\n}\n\nexport interface OtelTransportConfig {\n /** PostHog ingest host, e.g., \"https://us.i.posthog.com\" */\n host: string;\n /** Project API key */\n apiKey: string;\n /** Override the logs endpoint path (default: /i/v1/logs) */\n logsPath?: string;\n}\n\nexport interface AgentConfig {\n posthog?: PostHogAPIConfig;\n /** OTEL transport config for shipping logs to PostHog Logs */\n otelTransport?: OtelTransportConfig;\n /** Skip session log persistence (e.g. for preview sessions with no real task) */\n skipLogPersistence?: boolean;\n /** Local cache path for instant log loading (e.g., ~/.posthog-code) */\n localCachePath?: string;\n /**\n * Annotate files the agent reads with PostHog enrichment (event volume,\n * flag rollout/staleness, experiment links). Defaults to enabled when\n * `posthog` config is present; set `{ enabled: false }` to opt out.\n */\n enricher?: { enabled?: boolean };\n debug?: boolean;\n onLog?: OnLogCallback;\n}\n\n// Device info for tracking where work happens\nexport interface DeviceInfo {\n type: \"local\" | \"cloud\";\n name?: string;\n}\n\n// Agent execution mode - for tracking interactive vs background runs, when backgrounded an agent will continue working without asking questions\nexport type AgentMode = \"interactive\" | \"background\";\n\n// Git file status codes\nexport type FileStatus = \"A\" | \"M\" | \"D\";\n\nexport interface FileChange {\n path: string;\n status: FileStatus;\n}\n\nexport type HandoffLocalGitState = GitHandoffLocalGitState;\n\nexport interface GitCheckpoint extends GitHandoffCheckpoint {\n artifactPath?: string;\n indexArtifactPath?: string;\n}\n\nexport interface GitCheckpointEvent extends GitCheckpoint {\n device?: DeviceInfo;\n}\n\n/**\n * Keeps the emitted `@posthog/agent/types` entrypoint as a runtime ESM module.\n *\n * `export {}` is stripped by tsup in this package, which leaves `dist/types.js`\n * empty and breaks downstream type resolution for the exported subpath.\n */\nexport const AGENT_TYPES_MODULE = true;\n"],"mappings":";AAkNO,IAAM,qBAAqB;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/agent",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.709",
|
|
4
4
|
"repository": "https://github.com/PostHog/code",
|
|
5
5
|
"description": "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
6
6
|
"exports": {
|
|
@@ -106,9 +106,9 @@
|
|
|
106
106
|
"tsx": "^4.20.6",
|
|
107
107
|
"typescript": "^5.5.0",
|
|
108
108
|
"vitest": "^2.1.8",
|
|
109
|
-
"@posthog/enricher": "1.0.0",
|
|
110
109
|
"@posthog/shared": "1.0.0",
|
|
111
|
-
"@posthog/git": "1.0.0"
|
|
110
|
+
"@posthog/git": "1.0.0",
|
|
111
|
+
"@posthog/enricher": "1.0.0"
|
|
112
112
|
},
|
|
113
113
|
"dependencies": {
|
|
114
114
|
"@agentclientprotocol/sdk": "0.19.0",
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { AgentSideConnection } from "@agentclientprotocol/sdk";
|
|
2
|
+
import type { SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { createMockQuery, type MockQuery } from "../../test/mocks/claude-sdk";
|
|
5
|
+
import { Pushable } from "../../utils/streams";
|
|
6
|
+
|
|
7
|
+
vi.mock("@anthropic-ai/claude-agent-sdk", () => ({
|
|
8
|
+
query: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
vi.mock("./mcp/tool-metadata", () => ({
|
|
12
|
+
fetchMcpToolMetadata: vi.fn().mockResolvedValue(undefined),
|
|
13
|
+
getConnectedMcpServerNames: vi.fn().mockReturnValue([]),
|
|
14
|
+
setMcpToolApprovalStates: vi.fn(),
|
|
15
|
+
isMcpToolReadOnly: vi.fn().mockReturnValue(false),
|
|
16
|
+
getMcpToolMetadata: vi.fn().mockReturnValue(undefined),
|
|
17
|
+
getMcpToolApprovalState: vi.fn().mockReturnValue(undefined),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
const { ClaudeAcpAgent } = await import("./claude-agent");
|
|
21
|
+
type Agent = InstanceType<typeof ClaudeAcpAgent>;
|
|
22
|
+
|
|
23
|
+
interface ClientMocks {
|
|
24
|
+
sessionUpdate: ReturnType<typeof vi.fn>;
|
|
25
|
+
extNotification: ReturnType<typeof vi.fn>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function makeAgent(): { agent: Agent; client: ClientMocks } {
|
|
29
|
+
const client: ClientMocks = {
|
|
30
|
+
sessionUpdate: vi.fn().mockResolvedValue(undefined),
|
|
31
|
+
extNotification: vi.fn().mockResolvedValue(undefined),
|
|
32
|
+
};
|
|
33
|
+
const agent = new ClaudeAcpAgent(client as unknown as AgentSideConnection);
|
|
34
|
+
return { agent, client };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function installFakeSession(agent: Agent, sessionId: string): MockQuery {
|
|
38
|
+
const query = createMockQuery();
|
|
39
|
+
const input = new Pushable();
|
|
40
|
+
const abortController = new AbortController();
|
|
41
|
+
|
|
42
|
+
const session = {
|
|
43
|
+
query,
|
|
44
|
+
queryOptions: { sessionId, cwd: "/tmp/repo", abortController },
|
|
45
|
+
input,
|
|
46
|
+
cancelled: false,
|
|
47
|
+
interruptReason: undefined,
|
|
48
|
+
settingsManager: { dispose: vi.fn(), getRepoRoot: () => "/tmp/repo" },
|
|
49
|
+
permissionMode: "default" as const,
|
|
50
|
+
abortController,
|
|
51
|
+
accumulatedUsage: {
|
|
52
|
+
inputTokens: 0,
|
|
53
|
+
outputTokens: 0,
|
|
54
|
+
cachedReadTokens: 0,
|
|
55
|
+
cachedWriteTokens: 0,
|
|
56
|
+
},
|
|
57
|
+
configOptions: [],
|
|
58
|
+
promptRunning: false,
|
|
59
|
+
pendingMessages: new Map(),
|
|
60
|
+
nextPendingOrder: 0,
|
|
61
|
+
cwd: "/tmp/repo",
|
|
62
|
+
notificationHistory: [] as unknown[],
|
|
63
|
+
taskRunId: "run-1",
|
|
64
|
+
lastContextWindowSize: 200_000,
|
|
65
|
+
modelId: "claude-sonnet-4-6",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
(agent as unknown as { session: typeof session }).session = session;
|
|
69
|
+
(agent as unknown as { sessionId: string }).sessionId = sessionId;
|
|
70
|
+
|
|
71
|
+
return query;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function findUnsupportedChunkText(
|
|
75
|
+
calls: ClientMocks["sessionUpdate"]["mock"]["calls"],
|
|
76
|
+
): string | undefined {
|
|
77
|
+
const match = calls.find(([call]) => {
|
|
78
|
+
const update = (
|
|
79
|
+
call as {
|
|
80
|
+
update?: { sessionUpdate?: string; content?: { text?: string } };
|
|
81
|
+
}
|
|
82
|
+
).update;
|
|
83
|
+
return (
|
|
84
|
+
update?.sessionUpdate === "agent_message_chunk" &&
|
|
85
|
+
update?.content?.text?.toLowerCase().includes("unsupported")
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
return (match?.[0] as { update: { content: { text: string } } } | undefined)
|
|
89
|
+
?.update.content.text;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
describe("ClaudeAcpAgent.prompt — early idle handling", () => {
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
vi.clearAllMocks();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const cases = [
|
|
98
|
+
{
|
|
99
|
+
label: "unsupported slash command surfaces error and ends turn",
|
|
100
|
+
sessionId: "s-slash",
|
|
101
|
+
prompt: "/plugin install slack",
|
|
102
|
+
expectsUnsupportedChunk: true,
|
|
103
|
+
commandInMessage: "/plugin",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
label: "non-slash prompt with early idle is silently skipped",
|
|
107
|
+
sessionId: "s-regular",
|
|
108
|
+
prompt: "hello",
|
|
109
|
+
expectsUnsupportedChunk: false,
|
|
110
|
+
commandInMessage: null,
|
|
111
|
+
},
|
|
112
|
+
] as const;
|
|
113
|
+
|
|
114
|
+
it.each(cases)("$label", async (tc) => {
|
|
115
|
+
const { agent, client } = makeAgent();
|
|
116
|
+
const query = installFakeSession(agent, tc.sessionId);
|
|
117
|
+
|
|
118
|
+
const promptPromise = agent.prompt({
|
|
119
|
+
sessionId: tc.sessionId,
|
|
120
|
+
prompt: [{ type: "text", text: tc.prompt }],
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Let the prompt loop start awaiting the first SDK message.
|
|
124
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
125
|
+
|
|
126
|
+
query._mockHelpers.sendMessage({
|
|
127
|
+
type: "system",
|
|
128
|
+
subtype: "session_state_changed",
|
|
129
|
+
state: "idle",
|
|
130
|
+
} as unknown as SDKMessage);
|
|
131
|
+
query._mockHelpers.complete();
|
|
132
|
+
|
|
133
|
+
if (tc.expectsUnsupportedChunk) {
|
|
134
|
+
const result = await promptPromise;
|
|
135
|
+
expect(result.stopReason).toBe("end_turn");
|
|
136
|
+
|
|
137
|
+
const text = findUnsupportedChunkText(client.sessionUpdate.mock.calls);
|
|
138
|
+
expect(text).toBeDefined();
|
|
139
|
+
if (tc.commandInMessage) {
|
|
140
|
+
expect(text).toContain(tc.commandInMessage);
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
// No unsupported chunk; loop falls through to the existing
|
|
144
|
+
// "Session did not end in result" failure path.
|
|
145
|
+
await expect(promptPromise).rejects.toThrow(
|
|
146
|
+
/Session did not end in result/,
|
|
147
|
+
);
|
|
148
|
+
expect(
|
|
149
|
+
findUnsupportedChunkText(client.sessionUpdate.mock.calls),
|
|
150
|
+
).toBeUndefined();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -496,6 +496,28 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
496
496
|
(message as Record<string, unknown>).state === "idle"
|
|
497
497
|
) {
|
|
498
498
|
if (!promptReplayed) {
|
|
499
|
+
// The SDK consumed a slash command we do not handle locally
|
|
500
|
+
// and produced no output (e.g. /plugin in a non-interactive
|
|
501
|
+
// context). Without this branch we would loop forever waiting
|
|
502
|
+
// for an echo that never comes; surface a clear error instead.
|
|
503
|
+
if (commandMatch) {
|
|
504
|
+
const cmd = commandMatch[1];
|
|
505
|
+
this.logger.warn(
|
|
506
|
+
"Slash command produced no output; treating as unsupported",
|
|
507
|
+
{ sessionId: params.sessionId, command: cmd },
|
|
508
|
+
);
|
|
509
|
+
await this.client.sessionUpdate({
|
|
510
|
+
sessionId: params.sessionId,
|
|
511
|
+
update: {
|
|
512
|
+
sessionUpdate: "agent_message_chunk",
|
|
513
|
+
content: {
|
|
514
|
+
type: "text",
|
|
515
|
+
text: `Unsupported slash command: \`${cmd}\`. PostHog Code does not implement this command.`,
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
});
|
|
519
|
+
return { stopReason: "end_turn" };
|
|
520
|
+
}
|
|
499
521
|
this.logger.debug("Skipping idle state before prompt replay", {
|
|
500
522
|
sessionId: params.sessionId,
|
|
501
523
|
});
|
|
@@ -5,6 +5,7 @@ interface TestableServer {
|
|
|
5
5
|
configureEnvironment(args?: {
|
|
6
6
|
isInternal?: boolean;
|
|
7
7
|
originProduct?: string | null;
|
|
8
|
+
signalReportId?: string | null;
|
|
8
9
|
taskId?: string | null;
|
|
9
10
|
taskRunId?: string | null;
|
|
10
11
|
taskUserId?: number | null;
|
|
@@ -124,6 +125,7 @@ describe("AgentServer.configureEnvironment", () => {
|
|
|
124
125
|
buildServer("background").configureEnvironment({
|
|
125
126
|
isInternal: true,
|
|
126
127
|
originProduct: "signal_report",
|
|
128
|
+
signalReportId: "report-123",
|
|
127
129
|
taskId: "task-abc",
|
|
128
130
|
taskRunId: "run-xyz",
|
|
129
131
|
taskUserId: 42,
|
|
@@ -133,6 +135,7 @@ describe("AgentServer.configureEnvironment", () => {
|
|
|
133
135
|
[
|
|
134
136
|
"x-posthog-property-task_origin_product: signal_report",
|
|
135
137
|
"x-posthog-property-task_internal: true",
|
|
138
|
+
"x-posthog-property-signal_report_id: report-123",
|
|
136
139
|
"x-posthog-property-task_id: task-abc",
|
|
137
140
|
"x-posthog-property-task_run_id: run-xyz",
|
|
138
141
|
"x-posthog-property-task_user_id: 42",
|
|
@@ -140,6 +143,17 @@ describe("AgentServer.configureEnvironment", () => {
|
|
|
140
143
|
);
|
|
141
144
|
});
|
|
142
145
|
|
|
146
|
+
it("omits signal_report_id from ANTHROPIC_CUSTOM_HEADERS for non-report tasks", () => {
|
|
147
|
+
buildServer("background").configureEnvironment({
|
|
148
|
+
isInternal: false,
|
|
149
|
+
taskId: "task-abc",
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(process.env.ANTHROPIC_CUSTOM_HEADERS).not.toContain(
|
|
153
|
+
"signal_report_id",
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
|
|
143
157
|
it("omits optional task metadata from ANTHROPIC_CUSTOM_HEADERS when not provided", () => {
|
|
144
158
|
buildServer("background").configureEnvironment({ isInternal: false });
|
|
145
159
|
|
|
@@ -867,6 +867,7 @@ export class AgentServer {
|
|
|
867
867
|
this.configureEnvironment({
|
|
868
868
|
isInternal: preTask?.internal === true,
|
|
869
869
|
originProduct: preTask?.origin_product,
|
|
870
|
+
signalReportId: preTask?.signal_report,
|
|
870
871
|
taskId: payload.task_id,
|
|
871
872
|
taskRunId: payload.run_id,
|
|
872
873
|
taskUserId: payload.user_id,
|
|
@@ -1853,12 +1854,14 @@ ${signedCommitInstructions}
|
|
|
1853
1854
|
private configureEnvironment({
|
|
1854
1855
|
isInternal = false,
|
|
1855
1856
|
originProduct,
|
|
1857
|
+
signalReportId,
|
|
1856
1858
|
taskId,
|
|
1857
1859
|
taskRunId,
|
|
1858
1860
|
taskUserId,
|
|
1859
1861
|
}: {
|
|
1860
1862
|
isInternal?: boolean;
|
|
1861
1863
|
originProduct?: string | null;
|
|
1864
|
+
signalReportId?: string | null;
|
|
1862
1865
|
taskId?: string | null;
|
|
1863
1866
|
taskRunId?: string | null;
|
|
1864
1867
|
taskUserId?: number | null;
|
|
@@ -1877,6 +1880,7 @@ ${signedCommitInstructions}
|
|
|
1877
1880
|
const customHeaders = buildGatewayPropertyHeaders({
|
|
1878
1881
|
task_origin_product: originProduct,
|
|
1879
1882
|
task_internal: isInternal,
|
|
1883
|
+
signal_report_id: signalReportId,
|
|
1880
1884
|
task_id: taskId,
|
|
1881
1885
|
task_run_id: taskRunId,
|
|
1882
1886
|
task_user_id: taskUserId,
|
package/src/types.ts
CHANGED
|
@@ -39,6 +39,7 @@ export interface Task {
|
|
|
39
39
|
| "support_queue"
|
|
40
40
|
| "session_summaries"
|
|
41
41
|
| "signal_report";
|
|
42
|
+
signal_report?: string | null; // Inbox report UUID when origin_product is "signal_report"
|
|
42
43
|
github_integration?: number | null;
|
|
43
44
|
repository: string; // Format: "organization/repository" (e.g., "posthog/posthog-js")
|
|
44
45
|
json_schema?: Record<string, unknown> | null; // JSON schema for task output validation
|