@posthog/agent 2.3.663 → 2.3.675

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/agent",
3
- "version": "2.3.663",
3
+ "version": "2.3.675",
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": {
@@ -107,8 +107,8 @@
107
107
  "typescript": "^5.5.0",
108
108
  "vitest": "^2.1.8",
109
109
  "@posthog/shared": "1.0.0",
110
- "@posthog/git": "1.0.0",
111
- "@posthog/enricher": "1.0.0"
110
+ "@posthog/enricher": "1.0.0",
111
+ "@posthog/git": "1.0.0"
112
112
  },
113
113
  "dependencies": {
114
114
  "@agentclientprotocol/sdk": "0.19.0",
@@ -29,7 +29,7 @@ describe("createLocalToolsMcpServer", () => {
29
29
  it("exposes git_signed_commit over MCP in a cloud run with a token", async () => {
30
30
  const server = createLocalToolsMcpServer(
31
31
  { cwd: "/repo", token: "ghs_x" },
32
- { taskRunId: "run-1" },
32
+ { environment: "cloud" },
33
33
  );
34
34
  if (!server) {
35
35
  throw new Error("expected the local-tools server to be registered");
@@ -121,6 +121,7 @@ export type SDKMessageFilter = {
121
121
  export type NewSessionMeta = {
122
122
  taskRunId?: string;
123
123
  taskId?: string;
124
+ environment?: "local" | "cloud";
124
125
  disableBuiltInTools?: boolean;
125
126
  systemPrompt?: unknown;
126
127
  sessionId?: string;
@@ -97,6 +97,7 @@ export {
97
97
  interface NewSessionMeta {
98
98
  taskRunId?: string;
99
99
  taskId?: string;
100
+ environment?: "local" | "cloud";
100
101
  systemPrompt?: string;
101
102
  permissionMode?: string;
102
103
  model?: string;
@@ -10,7 +10,7 @@ describe("local-tools registry", () => {
10
10
  const savedSandbox = process.env.IS_SANDBOX;
11
11
 
12
12
  beforeEach(() => {
13
- // isCloudRun also keys off IS_SANDBOX; clear it so meta.taskRunId is the
13
+ // isCloudRun also keys off IS_SANDBOX; clear it so meta.environment is the
14
14
  // only cloud signal under test.
15
15
  delete process.env.IS_SANDBOX;
16
16
  });
@@ -35,23 +35,41 @@ describe("local-tools registry", () => {
35
35
  });
36
36
 
37
37
  it.each([
38
- { name: "cloud run with a token", taskRunId: "run-1", token: "ghs_x" },
39
- { name: "cloud run without a token", taskRunId: "run-1", token: undefined },
40
- { name: "desktop run with a token", taskRunId: undefined, token: "ghs_x" },
41
38
  {
42
- name: "desktop run without a token",
43
- taskRunId: undefined,
39
+ name: "cloud run with a token",
40
+ meta: { environment: "cloud" as const },
41
+ token: "ghs_x",
42
+ expected: true,
43
+ },
44
+ {
45
+ name: "cloud run without a token (resolved lazily at call time)",
46
+ meta: { environment: "cloud" as const },
44
47
  token: undefined,
48
+ expected: true,
45
49
  },
46
- ])(
47
- "exposes git_signed_commit only in $name when cloud+token",
48
- ({ taskRunId, token }) => {
49
- const tools = enabledLocalTools(
50
- { cwd: "/repo", token },
51
- taskRunId ? { taskRunId } : undefined,
52
- );
53
- const hasSignedCommit = tools.some((t) => t.name === "git_signed_commit");
54
- expect(hasSignedCommit).toBe(Boolean(taskRunId) && Boolean(token));
50
+ {
51
+ name: "desktop run with a token",
52
+ meta: { environment: "local" as const },
53
+ token: "ghs_x",
54
+ expected: false,
55
55
  },
56
- );
56
+ {
57
+ name: "desktop run without a token",
58
+ meta: { environment: "local" as const },
59
+ token: undefined,
60
+ expected: false,
61
+ },
62
+ ])("exposes git_signed_commit in $name", ({ meta, token, expected }) => {
63
+ const tools = enabledLocalTools({ cwd: "/repo", token }, meta);
64
+ const hasSignedCommit = tools.some((t) => t.name === "git_signed_commit");
65
+ expect(hasSignedCommit).toBe(expected);
66
+ });
67
+
68
+ it("does not treat legacy taskRunId-only metadata as cloud", () => {
69
+ const tools = enabledLocalTools({ cwd: "/repo", token: undefined }, {
70
+ taskRunId: "run-1",
71
+ } as unknown as { environment?: "local" | "cloud" });
72
+ const hasSignedCommit = tools.some((t) => t.name === "git_signed_commit");
73
+ expect(hasSignedCommit).toBe(false);
74
+ });
57
75
  });
@@ -19,7 +19,7 @@ export interface LocalToolCtx {
19
19
 
20
20
  /** Minimal session-meta shape needed to gate tools (e.g. cloud-only). */
21
21
  export interface LocalToolGateMeta {
22
- taskRunId?: string;
22
+ environment?: "local" | "cloud";
23
23
  }
24
24
 
25
25
  /**
@@ -1,4 +1,4 @@
1
- import { isCloudRun } from "../../../utils/common";
1
+ import { isCloudRun, resolveGithubToken } from "../../../utils/common";
2
2
  import {
3
3
  runSignedCommitTool,
4
4
  SIGNED_COMMIT_TOOL_DESCRIPTION,
@@ -8,19 +8,34 @@ import {
8
8
  import { defineLocalTool } from "../registry";
9
9
 
10
10
  /**
11
- * `git_signed_commit` as a local tool. Cloud runs only, and only when a GitHub
12
- * token is available (the commit is created via GitHub's API, which also signs
13
- * it). Committing is core to cloud tasks, so keep it visible past ToolSearch.
11
+ * `git_signed_commit` as a local tool. Cloud-run only; the token is resolved
12
+ * lazily at call time so the tool stays visible even when the GitHub token
13
+ * lands in `process.env` after the session was created (e.g. an orchestrator
14
+ * injecting it post-spawn). Committing is core to cloud tasks, so keep it
15
+ * exposed past ToolSearch via `alwaysLoad`.
14
16
  */
15
17
  export const signedCommitTool = defineLocalTool({
16
18
  name: SIGNED_COMMIT_TOOL_NAME,
17
19
  description: SIGNED_COMMIT_TOOL_DESCRIPTION,
18
20
  schema: signedCommitToolSchema,
19
21
  alwaysLoad: true,
20
- isEnabled: (ctx, meta) => isCloudRun(meta) && !!ctx.token,
21
- handler: (ctx, args) =>
22
- runSignedCommitTool(
23
- { cwd: ctx.cwd, token: ctx.token ?? "", taskId: ctx.taskId },
22
+ isEnabled: (_ctx, meta) => isCloudRun(meta),
23
+ handler: (ctx, args) => {
24
+ const token = ctx.token ?? resolveGithubToken();
25
+ if (!token) {
26
+ return Promise.resolve({
27
+ content: [
28
+ {
29
+ type: "text" as const,
30
+ text: `${SIGNED_COMMIT_TOOL_NAME} failed: no GitHub token in env (GH_TOKEN/GITHUB_TOKEN)`,
31
+ },
32
+ ],
33
+ isError: true,
34
+ });
35
+ }
36
+ return runSignedCommitTool(
37
+ { cwd: ctx.cwd, token, taskId: ctx.taskId },
24
38
  args,
25
- ),
39
+ );
40
+ },
26
41
  });
@@ -976,6 +976,7 @@ export class AgentServer {
976
976
  sessionId: payload.run_id,
977
977
  taskRunId: payload.run_id,
978
978
  taskId: payload.task_id,
979
+ environment: "cloud",
979
980
  systemPrompt: sessionSystemPrompt,
980
981
  ...(this.config.model && { model: this.config.model }),
981
982
  allowedDomains: this.config.allowedDomains,
@@ -27,11 +27,16 @@ export const IS_ROOT =
27
27
  export const ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;
28
28
 
29
29
  /**
30
- * A cloud sandbox run, as opposed to a local desktop session. Cloud sandboxes
31
- * always set IS_SANDBOX and carry a taskRunId; desktop sessions have neither.
30
+ * A cloud sandbox run, as opposed to a local desktop session. `taskRunId` is
31
+ * used by both desktop and cloud for persistence, so it must not imply cloud.
32
32
  */
33
- export function isCloudRun(meta: { taskRunId?: string } | undefined): boolean {
34
- return !!process.env.IS_SANDBOX || !!meta?.taskRunId;
33
+ export function isCloudRun(
34
+ meta: { environment?: "local" | "cloud" } | undefined,
35
+ ): boolean {
36
+ if (meta?.environment) {
37
+ return meta.environment === "cloud";
38
+ }
39
+ return !!process.env.IS_SANDBOX;
35
40
  }
36
41
 
37
42
  /** The GitHub token available to the sandbox, if any. */