@posthog/agent 2.3.454 → 2.3.465
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 +1 -1
- package/dist/agent.js.map +1 -1
- package/dist/handoff-checkpoint.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 +6 -4
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +6 -4
- 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/handoff-checkpoint.ts +1 -1
- package/src/server/agent-server.configure-environment.test.ts +97 -0
- package/src/server/agent-server.ts +11 -6
- package/src/types.ts +1 -0
package/dist/types.d.ts
CHANGED
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 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 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}\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 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}\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":";AA8MO,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.465",
|
|
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": {
|
|
@@ -103,8 +103,8 @@
|
|
|
103
103
|
"typescript": "^5.5.0",
|
|
104
104
|
"vitest": "^2.1.8",
|
|
105
105
|
"@posthog/shared": "1.0.0",
|
|
106
|
-
"@posthog/
|
|
107
|
-
"@posthog/
|
|
106
|
+
"@posthog/git": "1.0.0",
|
|
107
|
+
"@posthog/enricher": "1.0.0"
|
|
108
108
|
},
|
|
109
109
|
"dependencies": {
|
|
110
110
|
"@agentclientprotocol/sdk": "0.19.0",
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { AgentServer } from "./agent-server";
|
|
3
|
+
|
|
4
|
+
interface TestableServer {
|
|
5
|
+
configureEnvironment(args?: { isInternal?: boolean }): void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const ENV_KEYS_UNDER_TEST = [
|
|
9
|
+
"LLM_GATEWAY_URL",
|
|
10
|
+
"ANTHROPIC_BASE_URL",
|
|
11
|
+
"OPENAI_BASE_URL",
|
|
12
|
+
] as const;
|
|
13
|
+
|
|
14
|
+
describe("AgentServer.configureEnvironment", () => {
|
|
15
|
+
const originalEnv: Partial<Record<string, string | undefined>> = {};
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
for (const key of ENV_KEYS_UNDER_TEST) {
|
|
19
|
+
originalEnv[key] = process.env[key];
|
|
20
|
+
delete process.env[key];
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
for (const key of ENV_KEYS_UNDER_TEST) {
|
|
26
|
+
const value = originalEnv[key];
|
|
27
|
+
if (value === undefined) {
|
|
28
|
+
delete process.env[key];
|
|
29
|
+
} else {
|
|
30
|
+
process.env[key] = value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const buildServer = (mode: "background" | "interactive"): TestableServer =>
|
|
36
|
+
new AgentServer({
|
|
37
|
+
port: 0,
|
|
38
|
+
jwtPublicKey: "test-key",
|
|
39
|
+
apiUrl: "https://us.posthog.com",
|
|
40
|
+
apiKey: "test-api-key",
|
|
41
|
+
projectId: 1,
|
|
42
|
+
mode,
|
|
43
|
+
taskId: "test-task-id",
|
|
44
|
+
runId: "test-run-id",
|
|
45
|
+
}) as unknown as TestableServer;
|
|
46
|
+
|
|
47
|
+
it("tags as background_agents when the task is internal", () => {
|
|
48
|
+
buildServer("interactive").configureEnvironment({ isInternal: true });
|
|
49
|
+
|
|
50
|
+
expect(process.env.LLM_GATEWAY_URL).toBe(
|
|
51
|
+
"https://gateway.us.posthog.com/background_agents",
|
|
52
|
+
);
|
|
53
|
+
expect(process.env.ANTHROPIC_BASE_URL).toBe(
|
|
54
|
+
"https://gateway.us.posthog.com/background_agents",
|
|
55
|
+
);
|
|
56
|
+
expect(process.env.OPENAI_BASE_URL).toBe(
|
|
57
|
+
"https://gateway.us.posthog.com/background_agents/v1",
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("tags as posthog_code when the task is not internal", () => {
|
|
62
|
+
buildServer("background").configureEnvironment({ isInternal: false });
|
|
63
|
+
|
|
64
|
+
expect(process.env.LLM_GATEWAY_URL).toBe(
|
|
65
|
+
"https://gateway.us.posthog.com/posthog_code",
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("tags as posthog_code when isInternal is omitted (getTask failure fallback)", () => {
|
|
70
|
+
buildServer("background").configureEnvironment();
|
|
71
|
+
|
|
72
|
+
expect(process.env.LLM_GATEWAY_URL).toBe(
|
|
73
|
+
"https://gateway.us.posthog.com/posthog_code",
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("ignores mode when picking the gateway product", () => {
|
|
78
|
+
buildServer("background").configureEnvironment({ isInternal: false });
|
|
79
|
+
const fromBackground = process.env.LLM_GATEWAY_URL;
|
|
80
|
+
|
|
81
|
+
buildServer("interactive").configureEnvironment({ isInternal: false });
|
|
82
|
+
const fromInteractive = process.env.LLM_GATEWAY_URL;
|
|
83
|
+
|
|
84
|
+
expect(fromBackground).toBe(fromInteractive);
|
|
85
|
+
expect(fromBackground).toBe("https://gateway.us.posthog.com/posthog_code");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("respects the LLM_GATEWAY_URL override regardless of internal flag", () => {
|
|
89
|
+
process.env.LLM_GATEWAY_URL = "http://ngrok.test/proxy";
|
|
90
|
+
|
|
91
|
+
buildServer("background").configureEnvironment({ isInternal: true });
|
|
92
|
+
|
|
93
|
+
expect(process.env.LLM_GATEWAY_URL).toBe("http://ngrok.test/proxy");
|
|
94
|
+
expect(process.env.ANTHROPIC_BASE_URL).toBe("http://ngrok.test/proxy");
|
|
95
|
+
expect(process.env.OPENAI_BASE_URL).toBe("http://ngrok.test/proxy/v1");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -46,7 +46,7 @@ import type {
|
|
|
46
46
|
} from "../types";
|
|
47
47
|
import { resourceLink } from "../utils/acp-content";
|
|
48
48
|
import { AsyncMutex } from "../utils/async-mutex";
|
|
49
|
-
import { getLlmGatewayUrl } from "../utils/gateway";
|
|
49
|
+
import { type GatewayProduct, getLlmGatewayUrl } from "../utils/gateway";
|
|
50
50
|
import { Logger } from "../utils/logger";
|
|
51
51
|
import { logAgentshRuntimeInfo } from "./agentsh-runtime";
|
|
52
52
|
import {
|
|
@@ -778,8 +778,6 @@ export class AgentServer {
|
|
|
778
778
|
name: process.env.HOSTNAME || "cloud-sandbox",
|
|
779
779
|
};
|
|
780
780
|
|
|
781
|
-
this.configureEnvironment();
|
|
782
|
-
|
|
783
781
|
const [preTaskRun, preTask] = await Promise.all([
|
|
784
782
|
this.posthogAPI
|
|
785
783
|
.getTaskRun(payload.task_id, payload.run_id)
|
|
@@ -800,6 +798,8 @@ export class AgentServer {
|
|
|
800
798
|
}),
|
|
801
799
|
]);
|
|
802
800
|
|
|
801
|
+
this.configureEnvironment({ isInternal: preTask?.internal === true });
|
|
802
|
+
|
|
803
803
|
const prUrl = getTaskRunStateString(preTaskRun, "slack_notified_pr_url");
|
|
804
804
|
|
|
805
805
|
if (prUrl) {
|
|
@@ -1710,10 +1710,15 @@ ${attributionInstructions}
|
|
|
1710
1710
|
}
|
|
1711
1711
|
}
|
|
1712
1712
|
|
|
1713
|
-
private configureEnvironment(
|
|
1713
|
+
private configureEnvironment({
|
|
1714
|
+
isInternal = false,
|
|
1715
|
+
}: {
|
|
1716
|
+
isInternal?: boolean;
|
|
1717
|
+
} = {}): void {
|
|
1714
1718
|
const { apiKey, apiUrl, projectId } = this.config;
|
|
1715
|
-
const product =
|
|
1716
|
-
|
|
1719
|
+
const product: GatewayProduct = isInternal
|
|
1720
|
+
? "background_agents"
|
|
1721
|
+
: "posthog_code";
|
|
1717
1722
|
const gatewayUrl =
|
|
1718
1723
|
process.env.LLM_GATEWAY_URL || getLlmGatewayUrl(apiUrl, product);
|
|
1719
1724
|
const openaiBaseUrl = gatewayUrl.endsWith("/v1")
|
package/src/types.ts
CHANGED
|
@@ -41,6 +41,7 @@ export interface Task {
|
|
|
41
41
|
github_integration?: number | null;
|
|
42
42
|
repository: string; // Format: "organization/repository" (e.g., "posthog/posthog-js")
|
|
43
43
|
json_schema?: Record<string, unknown> | null; // JSON schema for task output validation
|
|
44
|
+
internal?: boolean;
|
|
44
45
|
created_at: string;
|
|
45
46
|
updated_at: string;
|
|
46
47
|
created_by?: {
|