@posthog/agent 2.3.263 → 2.3.267

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.
@@ -896,6 +896,125 @@ var require_dist2 = __commonJS({
896
896
  var import_commander = require("commander");
897
897
  var import_v42 = require("zod/v4");
898
898
 
899
+ // src/adapters/claude/session/models.ts
900
+ var DEFAULT_MODEL = "opus";
901
+ var GATEWAY_TO_SDK_MODEL = {
902
+ "claude-opus-4-5": "opus",
903
+ "claude-opus-4-6": "opus",
904
+ "claude-sonnet-4-5": "sonnet",
905
+ "claude-sonnet-4-6": "sonnet",
906
+ "claude-haiku-4-5": "haiku"
907
+ };
908
+ function toSdkModelId(modelId) {
909
+ return GATEWAY_TO_SDK_MODEL[modelId] ?? modelId;
910
+ }
911
+ var MODELS_WITH_1M_CONTEXT = /* @__PURE__ */ new Set([
912
+ "claude-opus-4-6",
913
+ "claude-sonnet-4-6"
914
+ ]);
915
+ function supports1MContext(modelId) {
916
+ return MODELS_WITH_1M_CONTEXT.has(modelId);
917
+ }
918
+ var MODELS_WITH_EFFORT = /* @__PURE__ */ new Set([
919
+ "claude-opus-4-5",
920
+ "claude-opus-4-6",
921
+ "claude-sonnet-4-6"
922
+ ]);
923
+ var MODELS_WITH_MAX_EFFORT = /* @__PURE__ */ new Set(["claude-opus-4-6"]);
924
+ function supportsEffort(modelId) {
925
+ return MODELS_WITH_EFFORT.has(modelId);
926
+ }
927
+ function supportsMaxEffort(modelId) {
928
+ return MODELS_WITH_MAX_EFFORT.has(modelId);
929
+ }
930
+ var MODELS_TO_EXCLUDE_MCP_TOOLS = /* @__PURE__ */ new Set(["claude-haiku-4-5"]);
931
+ function supportsMcpInjection(modelId) {
932
+ return !MODELS_TO_EXCLUDE_MCP_TOOLS.has(modelId);
933
+ }
934
+ function getEffortOptions(modelId) {
935
+ if (!supportsEffort(modelId)) return null;
936
+ const options = [
937
+ { value: "low", name: "Low" },
938
+ { value: "medium", name: "Medium" },
939
+ { value: "high", name: "High" }
940
+ ];
941
+ if (supportsMaxEffort(modelId)) {
942
+ options.push({ value: "max", name: "Max" });
943
+ }
944
+ return options;
945
+ }
946
+ var MODEL_CONTEXT_HINT_PATTERN = /\[(\d+m)\]$/i;
947
+ function tokenizeModelPreference(model) {
948
+ const lower = model.trim().toLowerCase();
949
+ const contextHint = lower.match(MODEL_CONTEXT_HINT_PATTERN)?.[1]?.toLowerCase();
950
+ const normalized = lower.replace(MODEL_CONTEXT_HINT_PATTERN, " $1 ");
951
+ const rawTokens = normalized.split(/[^a-z0-9]+/).filter(Boolean);
952
+ const tokens = rawTokens.map((token) => {
953
+ if (token === "opusplan") return "opus";
954
+ if (token === "best" || token === "default") return "";
955
+ return token;
956
+ }).filter((token) => token && token !== "claude").filter((token) => /[a-z]/.test(token) || token.endsWith("m"));
957
+ return { tokens, contextHint };
958
+ }
959
+ function scoreModelMatch(model, tokens, contextHint) {
960
+ const haystack = `${model.value} ${model.name ?? ""}`.toLowerCase();
961
+ let score = 0;
962
+ for (const token of tokens) {
963
+ if (haystack.includes(token)) {
964
+ score += token === contextHint ? 3 : 1;
965
+ }
966
+ }
967
+ return score;
968
+ }
969
+ function resolveModelPreference(preference, options) {
970
+ const trimmed2 = preference.trim();
971
+ if (!trimmed2) return null;
972
+ const lower = trimmed2.toLowerCase();
973
+ const directMatch = options.find(
974
+ (o) => o.value === trimmed2 || o.value.toLowerCase() === lower || o.name && o.name.toLowerCase() === lower
975
+ );
976
+ if (directMatch) return directMatch.value;
977
+ const includesMatch = options.find((o) => {
978
+ const value = o.value.toLowerCase();
979
+ const display = (o.name ?? "").toLowerCase();
980
+ return value.includes(lower) || display.includes(lower) || lower.includes(value);
981
+ });
982
+ if (includesMatch) return includesMatch.value;
983
+ const { tokens, contextHint } = tokenizeModelPreference(trimmed2);
984
+ if (tokens.length === 0) return null;
985
+ let bestMatch = null;
986
+ let bestScore = 0;
987
+ for (const model of options) {
988
+ const score = scoreModelMatch(model, tokens, contextHint);
989
+ if (0 < score && (!bestMatch || bestScore < score)) {
990
+ bestMatch = model;
991
+ bestScore = score;
992
+ }
993
+ }
994
+ return bestMatch?.value ?? null;
995
+ }
996
+
997
+ // src/adapters/codex/models.ts
998
+ var CODEX_REASONING_EFFORT_OPTIONS = [
999
+ { value: "low", name: "Low" },
1000
+ { value: "medium", name: "Medium" },
1001
+ { value: "high", name: "High" }
1002
+ ];
1003
+ function getReasoningEffortOptions(_modelId) {
1004
+ return CODEX_REASONING_EFFORT_OPTIONS;
1005
+ }
1006
+
1007
+ // src/adapters/reasoning-effort.ts
1008
+ function getReasoningEffortOptions2(adapter, modelId) {
1009
+ const options = adapter === "codex" ? getReasoningEffortOptions(modelId) : getEffortOptions(modelId);
1010
+ return options;
1011
+ }
1012
+ function isSupportedReasoningEffort(adapter, modelId, value) {
1013
+ return getReasoningEffortOptions2(adapter, modelId)?.some(
1014
+ (option) => option.value === value
1015
+ ) ?? false;
1016
+ }
1017
+
899
1018
  // src/server/agent-server.ts
900
1019
  var import_sdk5 = require("@agentclientprotocol/sdk");
901
1020
  var import_node_server = require("@hono/node-server");
@@ -5683,7 +5802,7 @@ var import_hono = require("hono");
5683
5802
  // package.json
5684
5803
  var package_default = {
5685
5804
  name: "@posthog/agent",
5686
- version: "2.3.263",
5805
+ version: "2.3.267",
5687
5806
  repository: "https://github.com/PostHog/code",
5688
5807
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
5689
5808
  exports: {
@@ -5731,6 +5850,10 @@ var package_default = {
5731
5850
  types: "./dist/adapters/claude/session/models.d.ts",
5732
5851
  import: "./dist/adapters/claude/session/models.js"
5733
5852
  },
5853
+ "./adapters/reasoning-effort": {
5854
+ types: "./dist/adapters/reasoning-effort.d.ts",
5855
+ import: "./dist/adapters/reasoning-effort.js"
5856
+ },
5734
5857
  "./execution-mode": {
5735
5858
  types: "./dist/execution-mode.d.ts",
5736
5859
  import: "./dist/execution-mode.js"
@@ -6115,6 +6238,7 @@ function unreachable(value, logger) {
6115
6238
 
6116
6239
  // src/gateway-models.ts
6117
6240
  var DEFAULT_GATEWAY_MODEL = "claude-opus-4-6";
6241
+ var DEFAULT_CODEX_MODEL = "gpt-5.4";
6118
6242
  var BLOCKED_MODELS = /* @__PURE__ */ new Set(["gpt-5-mini", "openai/gpt-5-mini"]);
6119
6243
  var CACHE_TTL = 10 * 60 * 1e3;
6120
6244
  var gatewayModelsCache = null;
@@ -8346,104 +8470,6 @@ function parseMcpServers(params) {
8346
8470
  return mcpServers;
8347
8471
  }
8348
8472
 
8349
- // src/adapters/claude/session/models.ts
8350
- var DEFAULT_MODEL = "opus";
8351
- var GATEWAY_TO_SDK_MODEL = {
8352
- "claude-opus-4-5": "opus",
8353
- "claude-opus-4-6": "opus",
8354
- "claude-sonnet-4-5": "sonnet",
8355
- "claude-sonnet-4-6": "sonnet",
8356
- "claude-haiku-4-5": "haiku"
8357
- };
8358
- function toSdkModelId(modelId) {
8359
- return GATEWAY_TO_SDK_MODEL[modelId] ?? modelId;
8360
- }
8361
- var MODELS_WITH_1M_CONTEXT = /* @__PURE__ */ new Set([
8362
- "claude-opus-4-6",
8363
- "claude-sonnet-4-6"
8364
- ]);
8365
- function supports1MContext(modelId) {
8366
- return MODELS_WITH_1M_CONTEXT.has(modelId);
8367
- }
8368
- var MODELS_WITH_EFFORT = /* @__PURE__ */ new Set([
8369
- "claude-opus-4-5",
8370
- "claude-opus-4-6",
8371
- "claude-sonnet-4-6"
8372
- ]);
8373
- var MODELS_WITH_MAX_EFFORT = /* @__PURE__ */ new Set(["claude-opus-4-6"]);
8374
- function supportsEffort(modelId) {
8375
- return MODELS_WITH_EFFORT.has(modelId);
8376
- }
8377
- function supportsMaxEffort(modelId) {
8378
- return MODELS_WITH_MAX_EFFORT.has(modelId);
8379
- }
8380
- var MODELS_TO_EXCLUDE_MCP_TOOLS = /* @__PURE__ */ new Set(["claude-haiku-4-5"]);
8381
- function supportsMcpInjection(modelId) {
8382
- return !MODELS_TO_EXCLUDE_MCP_TOOLS.has(modelId);
8383
- }
8384
- function getEffortOptions(modelId) {
8385
- if (!supportsEffort(modelId)) return null;
8386
- const options = [
8387
- { value: "low", name: "Low" },
8388
- { value: "medium", name: "Medium" },
8389
- { value: "high", name: "High" }
8390
- ];
8391
- if (supportsMaxEffort(modelId)) {
8392
- options.push({ value: "max", name: "Max" });
8393
- }
8394
- return options;
8395
- }
8396
- var MODEL_CONTEXT_HINT_PATTERN = /\[(\d+m)\]$/i;
8397
- function tokenizeModelPreference(model) {
8398
- const lower = model.trim().toLowerCase();
8399
- const contextHint = lower.match(MODEL_CONTEXT_HINT_PATTERN)?.[1]?.toLowerCase();
8400
- const normalized = lower.replace(MODEL_CONTEXT_HINT_PATTERN, " $1 ");
8401
- const rawTokens = normalized.split(/[^a-z0-9]+/).filter(Boolean);
8402
- const tokens = rawTokens.map((token) => {
8403
- if (token === "opusplan") return "opus";
8404
- if (token === "best" || token === "default") return "";
8405
- return token;
8406
- }).filter((token) => token && token !== "claude").filter((token) => /[a-z]/.test(token) || token.endsWith("m"));
8407
- return { tokens, contextHint };
8408
- }
8409
- function scoreModelMatch(model, tokens, contextHint) {
8410
- const haystack = `${model.value} ${model.name ?? ""}`.toLowerCase();
8411
- let score = 0;
8412
- for (const token of tokens) {
8413
- if (haystack.includes(token)) {
8414
- score += token === contextHint ? 3 : 1;
8415
- }
8416
- }
8417
- return score;
8418
- }
8419
- function resolveModelPreference(preference, options) {
8420
- const trimmed2 = preference.trim();
8421
- if (!trimmed2) return null;
8422
- const lower = trimmed2.toLowerCase();
8423
- const directMatch = options.find(
8424
- (o) => o.value === trimmed2 || o.value.toLowerCase() === lower || o.name && o.name.toLowerCase() === lower
8425
- );
8426
- if (directMatch) return directMatch.value;
8427
- const includesMatch = options.find((o) => {
8428
- const value = o.value.toLowerCase();
8429
- const display = (o.name ?? "").toLowerCase();
8430
- return value.includes(lower) || display.includes(lower) || lower.includes(value);
8431
- });
8432
- if (includesMatch) return includesMatch.value;
8433
- const { tokens, contextHint } = tokenizeModelPreference(trimmed2);
8434
- if (tokens.length === 0) return null;
8435
- let bestMatch = null;
8436
- let bestScore = 0;
8437
- for (const model of options) {
8438
- const score = scoreModelMatch(model, tokens, contextHint);
8439
- if (0 < score && (!bestMatch || bestScore < score)) {
8440
- bestMatch = model;
8441
- bestScore = score;
8442
- }
8443
- }
8444
- return bestMatch?.value ?? null;
8445
- }
8446
-
8447
8473
  // src/adapters/claude/session/options.ts
8448
8474
  var import_node_child_process2 = require("child_process");
8449
8475
  var fs4 = __toESM(require("fs"), 1);
@@ -10092,6 +10118,9 @@ function buildConfigArgs(options) {
10092
10118
  if (options.model) {
10093
10119
  args.push("-c", `model="${options.model}"`);
10094
10120
  }
10121
+ if (options.reasoningEffort) {
10122
+ args.push("-c", `model_reasoning_effort="${options.reasoningEffort}"`);
10123
+ }
10095
10124
  if (options.instructions) {
10096
10125
  const escaped = options.instructions.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/"/g, '\\"');
10097
10126
  args.push("-c", `instructions="${escaped}"`);
@@ -12346,6 +12375,14 @@ function createTappedWritableStream2(underlying, onMessage, logger) {
12346
12375
  }
12347
12376
  });
12348
12377
  }
12378
+ function getTaskRunStateString(taskRun, key) {
12379
+ const state = taskRun?.state;
12380
+ if (!state || typeof state !== "object") {
12381
+ return null;
12382
+ }
12383
+ const value = state[key];
12384
+ return typeof value === "string" ? value : null;
12385
+ }
12349
12386
  var AgentServer = class _AgentServer {
12350
12387
  config;
12351
12388
  logger;
@@ -12398,6 +12435,9 @@ var AgentServer = class _AgentServer {
12398
12435
  });
12399
12436
  this.app = this.createApp();
12400
12437
  }
12438
+ getRuntimeAdapter() {
12439
+ return this.config.runtimeAdapter ?? "claude";
12440
+ }
12401
12441
  getEffectiveMode(payload) {
12402
12442
  return payload.mode ?? this.config.mode;
12403
12443
  }
@@ -12764,6 +12804,30 @@ var AgentServer = class _AgentServer {
12764
12804
  name: process.env.HOSTNAME || "cloud-sandbox"
12765
12805
  };
12766
12806
  this.configureEnvironment();
12807
+ const [preTaskRun, preTask] = await Promise.all([
12808
+ this.posthogAPI.getTaskRun(payload.task_id, payload.run_id).catch((err) => {
12809
+ this.logger.warn("Failed to fetch task run for session context", {
12810
+ taskId: payload.task_id,
12811
+ runId: payload.run_id,
12812
+ error: err
12813
+ });
12814
+ return null;
12815
+ }),
12816
+ this.posthogAPI.getTask(payload.task_id).catch((err) => {
12817
+ this.logger.warn("Failed to fetch task for session context", {
12818
+ taskId: payload.task_id,
12819
+ error: err
12820
+ });
12821
+ return null;
12822
+ })
12823
+ ]);
12824
+ const prUrl = getTaskRunStateString(preTaskRun, "slack_notified_pr_url");
12825
+ if (prUrl) {
12826
+ this.detectedPrUrl = prUrl;
12827
+ }
12828
+ const runtimeAdapter = this.getRuntimeAdapter();
12829
+ const sessionSystemPrompt = this.buildSessionSystemPrompt(prUrl);
12830
+ const codexInstructions = runtimeAdapter === "codex" ? this.buildCodexInstructions(sessionSystemPrompt) : void 0;
12767
12831
  const posthogAPI = new PostHogAPIClient({
12768
12832
  apiUrl: this.config.apiUrl,
12769
12833
  projectId: this.config.projectId,
@@ -12782,10 +12846,20 @@ var AgentServer = class _AgentServer {
12782
12846
  logger: new Logger({ debug: true, prefix: "[SessionLogWriter]" })
12783
12847
  });
12784
12848
  const acpConnection = createAcpConnection({
12849
+ adapter: runtimeAdapter,
12785
12850
  taskRunId: payload.run_id,
12786
12851
  taskId: payload.task_id,
12787
12852
  deviceType: deviceInfo.type,
12788
12853
  logWriter,
12854
+ logger: this.logger,
12855
+ codexOptions: runtimeAdapter === "codex" ? {
12856
+ cwd: this.config.repositoryPath ?? "/tmp/workspace",
12857
+ apiBaseUrl: process.env.OPENAI_BASE_URL,
12858
+ apiKey: this.config.apiKey,
12859
+ model: this.config.model ?? DEFAULT_CODEX_MODEL,
12860
+ reasoningEffort: this.config.reasoningEffort,
12861
+ instructions: codexInstructions
12862
+ } : void 0,
12789
12863
  onStructuredOutput: async (output) => {
12790
12864
  await this.posthogAPI.setTaskRunOutput(
12791
12865
  payload.task_id,
@@ -12822,27 +12896,6 @@ var AgentServer = class _AgentServer {
12822
12896
  protocolVersion: import_sdk5.PROTOCOL_VERSION,
12823
12897
  clientCapabilities: {}
12824
12898
  });
12825
- const [preTaskRun, preTask] = await Promise.all([
12826
- this.posthogAPI.getTaskRun(payload.task_id, payload.run_id).catch((err) => {
12827
- this.logger.warn("Failed to fetch task run for session context", {
12828
- taskId: payload.task_id,
12829
- runId: payload.run_id,
12830
- error: err
12831
- });
12832
- return null;
12833
- }),
12834
- this.posthogAPI.getTask(payload.task_id).catch((err) => {
12835
- this.logger.warn("Failed to fetch task for session context", {
12836
- taskId: payload.task_id,
12837
- error: err
12838
- });
12839
- return null;
12840
- })
12841
- ]);
12842
- const prUrl = typeof preTaskRun?.state?.slack_notified_pr_url === "string" ? (preTaskRun?.state).slack_notified_pr_url : null;
12843
- if (prUrl) {
12844
- this.detectedPrUrl = prUrl;
12845
- }
12846
12899
  const runState = preTaskRun?.state;
12847
12900
  const initialPermissionMode = typeof runState?.initial_permission_mode === "string" ? runState.initial_permission_mode : "bypassPermissions";
12848
12901
  const sessionResponse = await clientConnection.newSession({
@@ -12851,14 +12904,20 @@ var AgentServer = class _AgentServer {
12851
12904
  _meta: {
12852
12905
  sessionId: payload.run_id,
12853
12906
  taskRunId: payload.run_id,
12854
- systemPrompt: this.buildSessionSystemPrompt(prUrl),
12907
+ systemPrompt: sessionSystemPrompt,
12908
+ ...this.config.model && { model: this.config.model },
12855
12909
  allowedDomains: this.config.allowedDomains,
12856
12910
  jsonSchema: preTask?.json_schema ?? null,
12857
12911
  permissionMode: initialPermissionMode,
12858
12912
  ...this.config.claudeCode?.plugins?.length && {
12859
12913
  claudeCode: {
12860
12914
  options: {
12861
- plugins: this.config.claudeCode.plugins
12915
+ ...this.config.claudeCode?.plugins?.length && {
12916
+ plugins: this.config.claudeCode.plugins
12917
+ },
12918
+ ...runtimeAdapter === "claude" && this.config.reasoningEffort && {
12919
+ effort: this.config.reasoningEffort
12920
+ }
12862
12921
  }
12863
12922
  }
12864
12923
  }
@@ -13143,6 +13202,9 @@ ${toolSummary}`);
13143
13202
  }
13144
13203
  return { append: cloudAppend };
13145
13204
  }
13205
+ buildCodexInstructions(systemPrompt) {
13206
+ return typeof systemPrompt === "string" ? systemPrompt : systemPrompt.append;
13207
+ }
13146
13208
  getCloudInteractionOrigin() {
13147
13209
  return process.env.POSTHOG_CODE_INTERACTION_ORIGIN ?? process.env.CODE_INTERACTION_ORIGIN ?? process.env.TWIG_INTERACTION_ORIGIN;
13148
13210
  }
@@ -13749,7 +13811,10 @@ var envSchema = import_v42.z.object({
13749
13811
  }).min(1, "POSTHOG_PERSONAL_API_KEY cannot be empty"),
13750
13812
  POSTHOG_PROJECT_ID: import_v42.z.string({
13751
13813
  error: "POSTHOG_PROJECT_ID is required for routing requests to the correct project"
13752
- }).regex(/^\d+$/, "POSTHOG_PROJECT_ID must be a numeric string").transform((val) => parseInt(val, 10))
13814
+ }).regex(/^\d+$/, "POSTHOG_PROJECT_ID must be a numeric string").transform((val) => parseInt(val, 10)),
13815
+ POSTHOG_CODE_RUNTIME_ADAPTER: import_v42.z.enum(["claude", "codex"]).optional(),
13816
+ POSTHOG_CODE_MODEL: import_v42.z.string().optional(),
13817
+ POSTHOG_CODE_REASONING_EFFORT: import_v42.z.enum(["low", "medium", "high", "max"]).optional()
13753
13818
  });
13754
13819
  var program = new import_commander.Command();
13755
13820
  function parseBooleanOption(raw, flag) {
@@ -13809,6 +13874,15 @@ ${errors}`);
13809
13874
  "--claudeCodeConfig"
13810
13875
  );
13811
13876
  const allowedDomains = options.allowedDomains ? options.allowedDomains.split(",").map((d) => d.trim()).filter(Boolean) : void 0;
13877
+ if (env.POSTHOG_CODE_RUNTIME_ADAPTER && env.POSTHOG_CODE_MODEL && env.POSTHOG_CODE_REASONING_EFFORT && !isSupportedReasoningEffort(
13878
+ env.POSTHOG_CODE_RUNTIME_ADAPTER,
13879
+ env.POSTHOG_CODE_MODEL,
13880
+ env.POSTHOG_CODE_REASONING_EFFORT
13881
+ )) {
13882
+ program.error(
13883
+ `POSTHOG_CODE_REASONING_EFFORT '${env.POSTHOG_CODE_REASONING_EFFORT}' is not supported for ${env.POSTHOG_CODE_RUNTIME_ADAPTER} model '${env.POSTHOG_CODE_MODEL}'.`
13884
+ );
13885
+ }
13812
13886
  const server = new AgentServer({
13813
13887
  port: parseInt(options.port, 10),
13814
13888
  jwtPublicKey: env.JWT_PUBLIC_KEY,
@@ -13823,7 +13897,10 @@ ${errors}`);
13823
13897
  mcpServers,
13824
13898
  baseBranch: options.baseBranch,
13825
13899
  claudeCode,
13826
- allowedDomains
13900
+ allowedDomains,
13901
+ runtimeAdapter: env.POSTHOG_CODE_RUNTIME_ADAPTER,
13902
+ model: env.POSTHOG_CODE_MODEL,
13903
+ reasoningEffort: env.POSTHOG_CODE_REASONING_EFFORT
13827
13904
  });
13828
13905
  process.on("SIGINT", async () => {
13829
13906
  await server.stop();