@posthog/agent 2.3.520 → 2.3.524

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.
@@ -0,0 +1,54 @@
1
+ // src/adapters/codex/structured-output-mcp-server.ts
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+
6
+ // src/adapters/codex/structured-output-constants.ts
7
+ var STRUCTURED_OUTPUT_MCP_NAME = "posthog_output";
8
+ var STRUCTURED_OUTPUT_TOOL_NAME = "create_output";
9
+
10
+ // src/adapters/codex/structured-output-mcp-server.ts
11
+ function die(message) {
12
+ process.stderr.write(`[structured-output-mcp-server] ${message}
13
+ `);
14
+ process.exit(1);
15
+ }
16
+ var schemaEnv = process.env.POSTHOG_OUTPUT_SCHEMA;
17
+ if (!schemaEnv) {
18
+ die("POSTHOG_OUTPUT_SCHEMA env var is required");
19
+ }
20
+ var jsonSchema;
21
+ try {
22
+ jsonSchema = JSON.parse(Buffer.from(schemaEnv, "base64").toString("utf-8"));
23
+ } catch (err) {
24
+ die(`Failed to parse POSTHOG_OUTPUT_SCHEMA as base64-encoded JSON: ${err}`);
25
+ }
26
+ var zodType = z.fromJSONSchema(jsonSchema);
27
+ if (!(zodType instanceof z.ZodObject)) {
28
+ die(
29
+ `POSTHOG_OUTPUT_SCHEMA must describe a JSON object schema (got ${zodType.constructor.name})`
30
+ );
31
+ }
32
+ var zodShape = { ...zodType.shape };
33
+ var server = new McpServer({
34
+ name: STRUCTURED_OUTPUT_MCP_NAME,
35
+ version: "1.0.0"
36
+ });
37
+ server.tool(
38
+ STRUCTURED_OUTPUT_TOOL_NAME,
39
+ "Submit the structured output for this task. Call this tool with the required fields to deliver your final result.",
40
+ zodShape,
41
+ async () => {
42
+ return {
43
+ content: [
44
+ {
45
+ type: "text",
46
+ text: "Output submitted successfully."
47
+ }
48
+ ]
49
+ };
50
+ }
51
+ );
52
+ var transport = new StdioServerTransport();
53
+ await server.connect(transport);
54
+ //# sourceMappingURL=structured-output-mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/codex/structured-output-mcp-server.ts","../../../src/adapters/codex/structured-output-constants.ts"],"sourcesContent":["/**\n * Standalone stdio MCP server for structured output in the Codex adapter.\n *\n * Spawned by codex-acp as an MCP server process. Reads the JSON schema\n * from the POSTHOG_OUTPUT_SCHEMA env var (base64-encoded) and registers\n * a tool whose Zod shape McpServer.tool() validates on each call.\n *\n * Usage:\n * POSTHOG_OUTPUT_SCHEMA=<base64> node structured-output-mcp-server.js\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport {\n STRUCTURED_OUTPUT_MCP_NAME,\n STRUCTURED_OUTPUT_TOOL_NAME,\n} from \"./structured-output-constants\";\n\nfunction die(message: string): never {\n process.stderr.write(`[structured-output-mcp-server] ${message}\\n`);\n process.exit(1);\n}\n\nconst schemaEnv = process.env.POSTHOG_OUTPUT_SCHEMA;\nif (!schemaEnv) {\n die(\"POSTHOG_OUTPUT_SCHEMA env var is required\");\n}\n\nlet jsonSchema: Record<string, unknown>;\ntry {\n jsonSchema = JSON.parse(Buffer.from(schemaEnv, \"base64\").toString(\"utf-8\"));\n} catch (err) {\n die(`Failed to parse POSTHOG_OUTPUT_SCHEMA as base64-encoded JSON: ${err}`);\n}\n\nconst zodType = z.fromJSONSchema(jsonSchema);\nif (!(zodType instanceof z.ZodObject)) {\n die(\n `POSTHOG_OUTPUT_SCHEMA must describe a JSON object schema (got ${zodType.constructor.name})`,\n );\n}\n// McpServer.tool() expects a mutable ZodRawShape\nconst zodShape = { ...zodType.shape } as z.ZodRawShape;\n\nconst server = new McpServer({\n name: STRUCTURED_OUTPUT_MCP_NAME,\n version: \"1.0.0\",\n});\n\nserver.tool(\n STRUCTURED_OUTPUT_TOOL_NAME,\n \"Submit the structured output for this task. Call this tool with the required fields to deliver your final result.\",\n zodShape,\n async () => {\n // McpServer.tool() validates `args` against `zodShape` before invoking\n // this handler, so reaching this point means the input is valid. The\n // parent process captures the validated output by intercepting the\n // tool call in the ACP stream.\n return {\n content: [\n {\n type: \"text\" as const,\n text: \"Output submitted successfully.\",\n },\n ],\n };\n },\n);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n","/**\n * Shared identifiers for the injected structured-output MCP server.\n * Imported by codex-agent.ts (server config), codex-client.ts (tool-call\n * matching), and structured-output-mcp-server.ts (tool registration) so the\n * three stay in sync.\n */\n\nexport const STRUCTURED_OUTPUT_MCP_NAME = \"posthog_output\";\nexport const STRUCTURED_OUTPUT_TOOL_NAME = \"create_output\";\n"],"mappings":";AAWA,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,SAAS;;;ACNX,IAAM,6BAA6B;AACnC,IAAM,8BAA8B;;;ADW3C,SAAS,IAAI,SAAwB;AACnC,UAAQ,OAAO,MAAM,kCAAkC,OAAO;AAAA,CAAI;AAClE,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,YAAY,QAAQ,IAAI;AAC9B,IAAI,CAAC,WAAW;AACd,MAAI,2CAA2C;AACjD;AAEA,IAAI;AACJ,IAAI;AACF,eAAa,KAAK,MAAM,OAAO,KAAK,WAAW,QAAQ,EAAE,SAAS,OAAO,CAAC;AAC5E,SAAS,KAAK;AACZ,MAAI,iEAAiE,GAAG,EAAE;AAC5E;AAEA,IAAM,UAAU,EAAE,eAAe,UAAU;AAC3C,IAAI,EAAE,mBAAmB,EAAE,YAAY;AACrC;AAAA,IACE,iEAAiE,QAAQ,YAAY,IAAI;AAAA,EAC3F;AACF;AAEA,IAAM,WAAW,EAAE,GAAG,QAAQ,MAAM;AAEpC,IAAM,SAAS,IAAI,UAAU;AAAA,EAC3B,MAAM;AAAA,EACN,SAAS;AACX,CAAC;AAED,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAKV,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAM,YAAY,IAAI,qBAAqB;AAC3C,MAAM,OAAO,QAAQ,SAAS;","names":[]}
package/dist/agent.js CHANGED
@@ -4030,7 +4030,7 @@ import { v7 as uuidv7 } from "uuid";
4030
4030
  // package.json
4031
4031
  var package_default = {
4032
4032
  name: "@posthog/agent",
4033
- version: "2.3.520",
4033
+ version: "2.3.524",
4034
4034
  repository: "https://github.com/PostHog/code",
4035
4035
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
4036
4036
  exports: {
@@ -4147,7 +4147,6 @@ var package_default = {
4147
4147
  },
4148
4148
  dependencies: {
4149
4149
  "@agentclientprotocol/sdk": "0.19.0",
4150
- ajv: "^8.17.1",
4151
4150
  "@anthropic-ai/claude-agent-sdk": "0.2.112",
4152
4151
  "@anthropic-ai/sdk": "0.89.0",
4153
4152
  "@hono/node-server": "^1.19.9",
@@ -4161,6 +4160,7 @@ var package_default = {
4161
4160
  hono: "^4.11.7",
4162
4161
  jsonwebtoken: "^9.0.2",
4163
4162
  minimatch: "^10.0.3",
4163
+ "@modelcontextprotocol/sdk": "1.29.0",
4164
4164
  tar: "^7.5.0",
4165
4165
  uuid: "13.0.0",
4166
4166
  "yoga-wasm-web": "^0.3.3",
@@ -17808,13 +17808,30 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17808
17808
  };
17809
17809
 
17810
17810
  // src/adapters/codex/codex-agent.ts
17811
+ import { existsSync as existsSync5 } from "fs";
17812
+ import { resolve as resolvePath } from "path";
17811
17813
  import {
17812
17814
  ClientSideConnection,
17813
17815
  ndJsonStream,
17814
17816
  RequestError as RequestError3
17815
17817
  } from "@agentclientprotocol/sdk";
17816
17818
 
17819
+ // src/adapters/codex/structured-output-constants.ts
17820
+ var STRUCTURED_OUTPUT_MCP_NAME = "posthog_output";
17821
+ var STRUCTURED_OUTPUT_TOOL_NAME = "create_output";
17822
+
17817
17823
  // src/adapters/codex/codex-client.ts
17824
+ function isStructuredOutputToolCall(title) {
17825
+ if (!title) return false;
17826
+ if (title === STRUCTURED_OUTPUT_TOOL_NAME) return true;
17827
+ return title.includes(STRUCTURED_OUTPUT_MCP_NAME) && title.includes(STRUCTURED_OUTPUT_TOOL_NAME);
17828
+ }
17829
+ function toRecord(value) {
17830
+ if (value && typeof value === "object" && !Array.isArray(value)) {
17831
+ return value;
17832
+ }
17833
+ return null;
17834
+ }
17818
17835
  var AUTO_APPROVED_KINDS = {
17819
17836
  default: /* @__PURE__ */ new Set(["read", "search", "fetch", "think"]),
17820
17837
  acceptEdits: /* @__PURE__ */ new Set(["read", "edit", "search", "fetch", "think"]),
@@ -17853,6 +17870,7 @@ function shouldAutoApprove(mode, kind) {
17853
17870
  }
17854
17871
  function createCodexClient(upstreamClient, logger, sessionState, callbacks) {
17855
17872
  const terminalHandles = /* @__PURE__ */ new Map();
17873
+ const structuredOutputState = /* @__PURE__ */ new Map();
17856
17874
  return {
17857
17875
  async requestPermission(params) {
17858
17876
  const kind = params.toolCall?.kind;
@@ -17876,6 +17894,26 @@ function createCodexClient(upstreamClient, logger, sessionState, callbacks) {
17876
17894
  },
17877
17895
  async sessionUpdate(params) {
17878
17896
  const update = params.update;
17897
+ if (callbacks?.onStructuredOutput && (update?.sessionUpdate === "tool_call" || update?.sessionUpdate === "tool_call_update")) {
17898
+ const toolCallId = update.toolCallId;
17899
+ const title = update.title;
17900
+ if (toolCallId && isStructuredOutputToolCall(title)) {
17901
+ const entry = structuredOutputState.get(toolCallId) ?? {
17902
+ fired: false
17903
+ };
17904
+ const rawInput = toRecord(update.rawInput);
17905
+ if (rawInput) entry.rawInput = rawInput;
17906
+ structuredOutputState.set(toolCallId, entry);
17907
+ if (update.status === "completed" && !entry.fired && entry.rawInput) {
17908
+ entry.fired = true;
17909
+ try {
17910
+ await callbacks.onStructuredOutput(entry.rawInput);
17911
+ } catch (err2) {
17912
+ logger.warn("onStructuredOutput callback threw", { error: err2 });
17913
+ }
17914
+ }
17915
+ }
17916
+ }
17879
17917
  if (update?.sessionUpdate === "usage_update") {
17880
17918
  const used = update.used;
17881
17919
  const size = update.size;
@@ -18237,6 +18275,33 @@ function getCurrentPermissionMode(currentModeId, fallbackMode) {
18237
18275
  }
18238
18276
  return toCodexPermissionMode(fallbackMode);
18239
18277
  }
18278
+ var STRUCTURED_OUTPUT_INSTRUCTIONS = `
18279
+
18280
+ When you have completed the task, call the \`${STRUCTURED_OUTPUT_TOOL_NAME}\` tool with the final structured result. The tool's input schema matches the required output format for this task. Do not describe the result in a plain message \u2014 submitting it via the tool is required for the task to be considered complete.`;
18281
+ function resolveStructuredOutputMcpScript() {
18282
+ const rel = "adapters/codex/structured-output-mcp-server.js";
18283
+ let dir = import.meta.dirname ?? __dirname;
18284
+ for (let i2 = 0; i2 < 5; i2++) {
18285
+ const candidate = resolvePath(dir, rel);
18286
+ if (existsSync5(candidate)) return candidate;
18287
+ dir = resolvePath(dir, "..");
18288
+ }
18289
+ throw new Error(
18290
+ `Could not locate ${rel} relative to ${import.meta.dirname ?? __dirname}.`
18291
+ );
18292
+ }
18293
+ function buildStructuredOutputMcpServer(jsonSchema) {
18294
+ const scriptPath = resolveStructuredOutputMcpScript();
18295
+ const schemaBase64 = Buffer.from(JSON.stringify(jsonSchema)).toString(
18296
+ "base64"
18297
+ );
18298
+ return {
18299
+ name: STRUCTURED_OUTPUT_MCP_NAME,
18300
+ command: process.execPath,
18301
+ args: [scriptPath],
18302
+ env: [{ name: "POSTHOG_OUTPUT_SCHEMA", value: schemaBase64 }]
18303
+ };
18304
+ }
18240
18305
  var CodexAcpAgent = class extends BaseAcpAgent {
18241
18306
  adapterName = "codex";
18242
18307
  codexProcess;
@@ -18255,6 +18320,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18255
18320
  promptMutex = Promise.resolve();
18256
18321
  codexProcessOptions;
18257
18322
  processCallbacks;
18323
+ onStructuredOutput;
18258
18324
  // Snapshot of the initialize() request so refreshSession can replay the
18259
18325
  // same handshake against a respawned codex-acp subprocess.
18260
18326
  lastInitRequest;
@@ -18266,6 +18332,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18266
18332
  const settingsManager = new CodexSettingsManager(cwd);
18267
18333
  this.codexProcessOptions = options.codexProcessOptions;
18268
18334
  this.processCallbacks = options.processCallbacks;
18335
+ this.onStructuredOutput = options.onStructuredOutput;
18269
18336
  this.codexProcess = spawnCodexProcess({
18270
18337
  ...options.codexProcessOptions,
18271
18338
  settings: settingsManager.getSettings(),
@@ -18287,7 +18354,8 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18287
18354
  this.enrichment = createEnrichment(options.posthogApiConfig, this.logger);
18288
18355
  this.codexConnection = new ClientSideConnection(
18289
18356
  (_agent) => createCodexClient(this.client, this.logger, this.sessionState, {
18290
- enrichmentDeps: this.enrichment?.deps
18357
+ enrichmentDeps: this.enrichment?.deps,
18358
+ onStructuredOutput: this.onStructuredOutput
18291
18359
  }),
18292
18360
  codexStream
18293
18361
  );
@@ -18321,7 +18389,8 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18321
18389
  async newSession(params) {
18322
18390
  const meta = params._meta;
18323
18391
  const requestedPermissionMode = toCodexPermissionMode(meta?.permissionMode);
18324
- const response = await this.codexConnection.newSession(params);
18392
+ const injectedParams = this.applyStructuredOutput(params, meta);
18393
+ const response = await this.codexConnection.newSession(injectedParams);
18325
18394
  response.configOptions = normalizeCodexConfigOptions(
18326
18395
  response.configOptions
18327
18396
  );
@@ -18353,11 +18422,12 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18353
18422
  return response;
18354
18423
  }
18355
18424
  async loadSession(params) {
18356
- const response = await this.codexConnection.loadSession(params);
18425
+ const meta = params._meta;
18426
+ const injectedParams = this.applyStructuredOutput(params, meta);
18427
+ const response = await this.codexConnection.loadSession(injectedParams);
18357
18428
  response.configOptions = normalizeCodexConfigOptions(
18358
18429
  response.configOptions
18359
18430
  );
18360
- const meta = params._meta;
18361
18431
  const currentPermissionMode = getCurrentPermissionMode(
18362
18432
  response.modes?.currentModeId,
18363
18433
  meta?.permissionMode
@@ -18380,15 +18450,20 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18380
18450
  return response;
18381
18451
  }
18382
18452
  async unstable_resumeSession(params) {
18383
- const loadResponse = await this.codexConnection.loadSession({
18384
- sessionId: params.sessionId,
18385
- cwd: params.cwd,
18386
- mcpServers: params.mcpServers ?? []
18387
- });
18453
+ const meta = params._meta;
18454
+ const injectedParams = this.applyStructuredOutput(
18455
+ {
18456
+ sessionId: params.sessionId,
18457
+ cwd: params.cwd,
18458
+ mcpServers: params.mcpServers ?? [],
18459
+ _meta: params._meta
18460
+ },
18461
+ meta
18462
+ );
18463
+ const loadResponse = await this.codexConnection.loadSession(injectedParams);
18388
18464
  loadResponse.configOptions = normalizeCodexConfigOptions(
18389
18465
  loadResponse.configOptions
18390
18466
  );
18391
- const meta = params._meta;
18392
18467
  const currentPermissionMode = getCurrentPermissionMode(
18393
18468
  loadResponse.modes?.currentModeId,
18394
18469
  meta?.permissionMode
@@ -18415,15 +18490,19 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18415
18490
  };
18416
18491
  }
18417
18492
  async unstable_forkSession(params) {
18418
- const newResponse = await this.codexConnection.newSession({
18419
- cwd: params.cwd,
18420
- mcpServers: params.mcpServers ?? [],
18421
- _meta: params._meta
18422
- });
18493
+ const meta = params._meta;
18494
+ const injectedParams = this.applyStructuredOutput(
18495
+ {
18496
+ cwd: params.cwd,
18497
+ mcpServers: params.mcpServers ?? [],
18498
+ _meta: params._meta
18499
+ },
18500
+ meta
18501
+ );
18502
+ const newResponse = await this.codexConnection.newSession(injectedParams);
18423
18503
  newResponse.configOptions = normalizeCodexConfigOptions(
18424
18504
  newResponse.configOptions
18425
18505
  );
18426
- const meta = params._meta;
18427
18506
  const requestedPermissionMode = toCodexPermissionMode(meta?.permissionMode);
18428
18507
  this.sessionState = createSessionState(newResponse.sessionId, params.cwd, {
18429
18508
  taskRunId: meta?.taskRunId,
@@ -18440,6 +18519,30 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18440
18519
  );
18441
18520
  return newResponse;
18442
18521
  }
18522
+ /**
18523
+ * When the caller wires up `onStructuredOutput` and provides a JSON schema
18524
+ * via `_meta.jsonSchema`, inject the stdio MCP server that exposes
18525
+ * `create_output` and append instructions telling the model to use it.
18526
+ *
18527
+ * Codex has no native equivalent of Claude's `outputFormat`, so we lean on
18528
+ * MCP tool-calling to get validated structured output back.
18529
+ */
18530
+ applyStructuredOutput(request, meta) {
18531
+ if (!meta?.jsonSchema || !this.onStructuredOutput) {
18532
+ return request;
18533
+ }
18534
+ const mcpServer = buildStructuredOutputMcpServer(meta.jsonSchema);
18535
+ const existingMeta = request._meta ?? {};
18536
+ const existingSystemPrompt = typeof existingMeta.systemPrompt === "string" ? existingMeta.systemPrompt : "";
18537
+ return {
18538
+ ...request,
18539
+ mcpServers: [...request.mcpServers ?? [], mcpServer],
18540
+ _meta: {
18541
+ ...existingMeta,
18542
+ systemPrompt: existingSystemPrompt + STRUCTURED_OUTPUT_INSTRUCTIONS
18543
+ }
18544
+ };
18545
+ }
18443
18546
  async applyInitialPermissionMode(sessionId, permissionMode, currentModeId) {
18444
18547
  if (!permissionMode) {
18445
18548
  return;
@@ -18598,7 +18701,9 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18598
18701
  const codexStream = ndJsonStream(codexWritable, codexReadable);
18599
18702
  const newAbortController = new AbortController();
18600
18703
  const newConnection = new ClientSideConnection(
18601
- (_agent) => createCodexClient(this.client, this.logger, this.sessionState),
18704
+ (_agent) => createCodexClient(this.client, this.logger, this.sessionState, {
18705
+ onStructuredOutput: this.onStructuredOutput
18706
+ }),
18602
18707
  codexStream
18603
18708
  );
18604
18709
  const initRequest = this.lastInitRequest ?? {
@@ -18778,7 +18883,8 @@ function createCodexConnection(config) {
18778
18883
  agent = new CodexAcpAgent(client, {
18779
18884
  codexProcessOptions: config.codexOptions ?? {},
18780
18885
  processCallbacks: config.processCallbacks,
18781
- posthogApiConfig: resolveEnricherApiConfig(config)
18886
+ posthogApiConfig: resolveEnricherApiConfig(config),
18887
+ onStructuredOutput: config.onStructuredOutput
18782
18888
  });
18783
18889
  return agent;
18784
18890
  }, agentStream);