@posthog/agent 2.3.678 → 2.3.703
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/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
- package/dist/adapters/claude/mcp/tool-metadata.d.ts +4 -1
- package/dist/adapters/claude/mcp/tool-metadata.js +4 -0
- package/dist/adapters/claude/mcp/tool-metadata.js.map +1 -1
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/agent.js +287 -28
- package/dist/agent.js.map +1 -1
- package/dist/handoff-checkpoint.js +70 -0
- package/dist/handoff-checkpoint.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/resume.js +70 -0
- package/dist/resume.js.map +1 -1
- package/dist/server/agent-server.js +436 -179
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +429 -172
- package/dist/server/bin.cjs.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 +84 -1
- package/src/adapters/claude/context-breakdown.test.ts +130 -0
- package/src/adapters/claude/context-breakdown.ts +127 -0
- package/src/adapters/claude/conversion/acp-to-sdk.test.ts +39 -0
- package/src/adapters/claude/conversion/acp-to-sdk.ts +20 -24
- package/src/adapters/claude/mcp/tool-metadata.ts +6 -0
- package/src/adapters/claude/types.ts +3 -0
- package/src/adapters/codex/codex-agent.ts +46 -5
- package/src/adapters/codex/codex-client.test.ts +49 -1
- package/src/adapters/codex/session-state.ts +36 -5
package/dist/server/bin.cjs
CHANGED
|
@@ -9471,7 +9471,7 @@ var import_zod4 = require("zod");
|
|
|
9471
9471
|
// package.json
|
|
9472
9472
|
var package_default = {
|
|
9473
9473
|
name: "@posthog/agent",
|
|
9474
|
-
version: "2.3.
|
|
9474
|
+
version: "2.3.703",
|
|
9475
9475
|
repository: "https://github.com/PostHog/code",
|
|
9476
9476
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
9477
9477
|
exports: {
|
|
@@ -14668,22 +14668,314 @@ function resolveTaskId(meta) {
|
|
|
14668
14668
|
return meta?.taskId ?? meta?.persistence?.taskId;
|
|
14669
14669
|
}
|
|
14670
14670
|
|
|
14671
|
+
// src/adapters/claude/context-breakdown.ts
|
|
14672
|
+
var CLAUDE_PRESET_ESTIMATE_TOKENS = 4e3;
|
|
14673
|
+
var CHARS_PER_TOKEN = 4;
|
|
14674
|
+
function estimateTokens(text2) {
|
|
14675
|
+
if (!text2) return 0;
|
|
14676
|
+
return Math.max(0, Math.round(text2.length / CHARS_PER_TOKEN));
|
|
14677
|
+
}
|
|
14678
|
+
function estimateJsonTokens(value) {
|
|
14679
|
+
try {
|
|
14680
|
+
return estimateTokens(JSON.stringify(value));
|
|
14681
|
+
} catch {
|
|
14682
|
+
return 0;
|
|
14683
|
+
}
|
|
14684
|
+
}
|
|
14685
|
+
function estimateSkillsTokens(commands) {
|
|
14686
|
+
if (!commands.length) return 0;
|
|
14687
|
+
return estimateJsonTokens(
|
|
14688
|
+
commands.map((c) => ({
|
|
14689
|
+
name: c.name,
|
|
14690
|
+
description: c.description,
|
|
14691
|
+
hint: c.input?.hint
|
|
14692
|
+
}))
|
|
14693
|
+
);
|
|
14694
|
+
}
|
|
14695
|
+
function estimateMcpTokens(tools) {
|
|
14696
|
+
if (!tools.length) return 0;
|
|
14697
|
+
return estimateJsonTokens(
|
|
14698
|
+
tools.map((t) => ({ name: t.name, description: t.description }))
|
|
14699
|
+
);
|
|
14700
|
+
}
|
|
14701
|
+
function estimateRulesTokens(rules) {
|
|
14702
|
+
return estimateTokens(rules);
|
|
14703
|
+
}
|
|
14704
|
+
function emptyBaseline() {
|
|
14705
|
+
return {
|
|
14706
|
+
systemPrompt: 0,
|
|
14707
|
+
tools: 0,
|
|
14708
|
+
rules: 0,
|
|
14709
|
+
skills: 0,
|
|
14710
|
+
mcp: 0,
|
|
14711
|
+
subagents: 0
|
|
14712
|
+
};
|
|
14713
|
+
}
|
|
14714
|
+
function estimateSystemPrompt(systemPrompt) {
|
|
14715
|
+
if (!systemPrompt) return CLAUDE_PRESET_ESTIMATE_TOKENS;
|
|
14716
|
+
if (typeof systemPrompt === "string") return estimateTokens(systemPrompt);
|
|
14717
|
+
if (typeof systemPrompt === "object") {
|
|
14718
|
+
const obj = systemPrompt;
|
|
14719
|
+
const appendTokens = typeof obj.append === "string" ? estimateTokens(obj.append) : 0;
|
|
14720
|
+
if (obj.type === "preset") {
|
|
14721
|
+
return CLAUDE_PRESET_ESTIMATE_TOKENS + appendTokens;
|
|
14722
|
+
}
|
|
14723
|
+
return appendTokens;
|
|
14724
|
+
}
|
|
14725
|
+
return 0;
|
|
14726
|
+
}
|
|
14727
|
+
function buildBreakdown(baseline, currentInputTokens) {
|
|
14728
|
+
const stableSum = baseline.systemPrompt + baseline.tools + baseline.rules + baseline.skills + baseline.mcp + baseline.subagents;
|
|
14729
|
+
const conversation = Math.max(0, currentInputTokens - stableSum);
|
|
14730
|
+
return {
|
|
14731
|
+
systemPrompt: baseline.systemPrompt,
|
|
14732
|
+
tools: baseline.tools,
|
|
14733
|
+
rules: baseline.rules,
|
|
14734
|
+
skills: baseline.skills,
|
|
14735
|
+
mcp: baseline.mcp,
|
|
14736
|
+
subagents: baseline.subagents,
|
|
14737
|
+
conversation
|
|
14738
|
+
};
|
|
14739
|
+
}
|
|
14740
|
+
|
|
14671
14741
|
// src/adapters/claude/conversion/acp-to-sdk.ts
|
|
14672
14742
|
var path6 = __toESM(require("path"), 1);
|
|
14673
14743
|
var import_node_url = require("url");
|
|
14674
|
-
|
|
14675
|
-
|
|
14676
|
-
|
|
14677
|
-
"
|
|
14678
|
-
"jpeg",
|
|
14679
|
-
"
|
|
14680
|
-
"
|
|
14681
|
-
"
|
|
14682
|
-
"
|
|
14683
|
-
"
|
|
14684
|
-
"
|
|
14685
|
-
"tiff"
|
|
14744
|
+
|
|
14745
|
+
// ../shared/dist/index.js
|
|
14746
|
+
var IMAGE_MIME_TYPES = {
|
|
14747
|
+
png: "image/png",
|
|
14748
|
+
jpg: "image/jpeg",
|
|
14749
|
+
jpeg: "image/jpeg",
|
|
14750
|
+
gif: "image/gif",
|
|
14751
|
+
webp: "image/webp",
|
|
14752
|
+
bmp: "image/bmp",
|
|
14753
|
+
ico: "image/x-icon",
|
|
14754
|
+
tiff: "image/tiff",
|
|
14755
|
+
tif: "image/tiff",
|
|
14756
|
+
svg: "image/svg+xml",
|
|
14757
|
+
heic: "image/heic",
|
|
14758
|
+
heif: "image/heif",
|
|
14759
|
+
avif: "image/avif"
|
|
14760
|
+
};
|
|
14761
|
+
var IMAGE_EXTENSIONS = new Set(
|
|
14762
|
+
Object.keys(IMAGE_MIME_TYPES)
|
|
14763
|
+
);
|
|
14764
|
+
var CLAUDE_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
14765
|
+
"image/jpeg",
|
|
14766
|
+
"image/png",
|
|
14767
|
+
"image/gif",
|
|
14768
|
+
"image/webp"
|
|
14769
|
+
]);
|
|
14770
|
+
function isClaudeImageMimeType(mimeType) {
|
|
14771
|
+
return CLAUDE_IMAGE_MIME_TYPES.has(mimeType.toLowerCase());
|
|
14772
|
+
}
|
|
14773
|
+
var MAX_DATA_URL_LENGTH = 20 * 1024 * 1024;
|
|
14774
|
+
var MAX_IMAGE_BASE64_LENGTH = 15 * 1024 * 1024;
|
|
14775
|
+
function extensionOf(filename) {
|
|
14776
|
+
const slash = Math.max(filename.lastIndexOf("/"), filename.lastIndexOf("\\"));
|
|
14777
|
+
const basename4 = slash >= 0 ? filename.slice(slash + 1) : filename;
|
|
14778
|
+
const cleanBasename = basename4.split(/[?#]/)[0];
|
|
14779
|
+
const dot = cleanBasename.lastIndexOf(".");
|
|
14780
|
+
return dot > 0 ? cleanBasename.slice(dot + 1).toLowerCase() : "";
|
|
14781
|
+
}
|
|
14782
|
+
function isImageFile(filename) {
|
|
14783
|
+
const ext = extensionOf(filename);
|
|
14784
|
+
return ext.length > 0 && IMAGE_EXTENSIONS.has(ext);
|
|
14785
|
+
}
|
|
14786
|
+
var AUDIO_VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
14787
|
+
"mp3",
|
|
14788
|
+
"mp4",
|
|
14789
|
+
"wav",
|
|
14790
|
+
"avi",
|
|
14791
|
+
"mov",
|
|
14792
|
+
"mkv",
|
|
14793
|
+
"webm",
|
|
14794
|
+
"mpg",
|
|
14795
|
+
"mpeg",
|
|
14796
|
+
"flac",
|
|
14797
|
+
"ogg",
|
|
14798
|
+
"m4a",
|
|
14799
|
+
"aac"
|
|
14800
|
+
]);
|
|
14801
|
+
var ARCHIVE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
14802
|
+
"zip",
|
|
14803
|
+
"tar",
|
|
14804
|
+
"gz",
|
|
14805
|
+
"tgz",
|
|
14806
|
+
"bz2",
|
|
14807
|
+
"xz",
|
|
14808
|
+
"rar",
|
|
14809
|
+
"7z"
|
|
14686
14810
|
]);
|
|
14811
|
+
var EXECUTABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
14812
|
+
"exe",
|
|
14813
|
+
"dll",
|
|
14814
|
+
"so",
|
|
14815
|
+
"dylib",
|
|
14816
|
+
"wasm",
|
|
14817
|
+
"bin",
|
|
14818
|
+
"o"
|
|
14819
|
+
]);
|
|
14820
|
+
var FONT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
14821
|
+
"ttf",
|
|
14822
|
+
"otf",
|
|
14823
|
+
"woff",
|
|
14824
|
+
"woff2",
|
|
14825
|
+
"eot"
|
|
14826
|
+
]);
|
|
14827
|
+
var DOCUMENT_BINARY_EXTENSIONS = /* @__PURE__ */ new Set(["pdf"]);
|
|
14828
|
+
var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
14829
|
+
...Object.keys(IMAGE_MIME_TYPES).filter((ext) => ext !== "svg"),
|
|
14830
|
+
...AUDIO_VIDEO_EXTENSIONS,
|
|
14831
|
+
...ARCHIVE_EXTENSIONS,
|
|
14832
|
+
...EXECUTABLE_EXTENSIONS,
|
|
14833
|
+
...FONT_EXTENSIONS,
|
|
14834
|
+
...DOCUMENT_BINARY_EXTENSIONS
|
|
14835
|
+
]);
|
|
14836
|
+
var CLOUD_PROMPT_PREFIX = "__twig_cloud_prompt_v1__:";
|
|
14837
|
+
function deserializeCloudPrompt(value) {
|
|
14838
|
+
const trimmed2 = value.trim();
|
|
14839
|
+
if (!trimmed2) {
|
|
14840
|
+
return [];
|
|
14841
|
+
}
|
|
14842
|
+
if (!trimmed2.startsWith(CLOUD_PROMPT_PREFIX)) {
|
|
14843
|
+
return [{ type: "text", text: trimmed2 }];
|
|
14844
|
+
}
|
|
14845
|
+
try {
|
|
14846
|
+
const parsed = JSON.parse(trimmed2.slice(CLOUD_PROMPT_PREFIX.length));
|
|
14847
|
+
if (Array.isArray(parsed.blocks) && parsed.blocks.length > 0) {
|
|
14848
|
+
return parsed.blocks;
|
|
14849
|
+
}
|
|
14850
|
+
} catch {
|
|
14851
|
+
}
|
|
14852
|
+
return [{ type: "text", text: trimmed2 }];
|
|
14853
|
+
}
|
|
14854
|
+
function promptBlocksToText(blocks) {
|
|
14855
|
+
return blocks.filter((b) => b.type === "text").map((block) => block.text).join("").trim();
|
|
14856
|
+
}
|
|
14857
|
+
var consoleLogger = {
|
|
14858
|
+
info: (_message, _data) => {
|
|
14859
|
+
},
|
|
14860
|
+
debug: (_message, _data) => {
|
|
14861
|
+
},
|
|
14862
|
+
error: (_message, _data) => {
|
|
14863
|
+
},
|
|
14864
|
+
warn: (_message, _data) => {
|
|
14865
|
+
}
|
|
14866
|
+
};
|
|
14867
|
+
var Saga = class {
|
|
14868
|
+
completedSteps = [];
|
|
14869
|
+
currentStepName = "unknown";
|
|
14870
|
+
stepTimings = [];
|
|
14871
|
+
log;
|
|
14872
|
+
constructor(logger) {
|
|
14873
|
+
this.log = logger ?? consoleLogger;
|
|
14874
|
+
}
|
|
14875
|
+
/**
|
|
14876
|
+
* Run the saga with the given input.
|
|
14877
|
+
* Returns a discriminated union result - either success with data or failure with error details.
|
|
14878
|
+
*/
|
|
14879
|
+
async run(input) {
|
|
14880
|
+
this.completedSteps = [];
|
|
14881
|
+
this.currentStepName = "unknown";
|
|
14882
|
+
this.stepTimings = [];
|
|
14883
|
+
const sagaStart = performance.now();
|
|
14884
|
+
try {
|
|
14885
|
+
const result = await this.execute(input);
|
|
14886
|
+
const totalDuration = performance.now() - sagaStart;
|
|
14887
|
+
this.log.debug("Saga completed successfully", {
|
|
14888
|
+
sagaName: this.sagaName,
|
|
14889
|
+
stepsCompleted: this.completedSteps.length,
|
|
14890
|
+
totalDurationMs: Math.round(totalDuration),
|
|
14891
|
+
stepTimings: this.stepTimings
|
|
14892
|
+
});
|
|
14893
|
+
return { success: true, data: result };
|
|
14894
|
+
} catch (error) {
|
|
14895
|
+
this.log.error("Saga failed, initiating rollback", {
|
|
14896
|
+
sagaName: this.sagaName,
|
|
14897
|
+
failedStep: this.currentStepName,
|
|
14898
|
+
error: error instanceof Error ? error.message : String(error),
|
|
14899
|
+
completedStepTimings: this.stepTimings
|
|
14900
|
+
});
|
|
14901
|
+
await this.rollback();
|
|
14902
|
+
return {
|
|
14903
|
+
success: false,
|
|
14904
|
+
error: error instanceof Error ? error.message : String(error),
|
|
14905
|
+
failedStep: this.currentStepName
|
|
14906
|
+
};
|
|
14907
|
+
}
|
|
14908
|
+
}
|
|
14909
|
+
/**
|
|
14910
|
+
* Execute a step with its rollback action.
|
|
14911
|
+
* If the step succeeds, its rollback action is stored for potential rollback.
|
|
14912
|
+
* The step name is automatically tracked for error reporting.
|
|
14913
|
+
*
|
|
14914
|
+
* @param config - Step configuration with name, execute, and rollback functions
|
|
14915
|
+
* @returns The result of the execute function
|
|
14916
|
+
* @throws Re-throws any error from the execute function (triggers rollback)
|
|
14917
|
+
*/
|
|
14918
|
+
async step(config) {
|
|
14919
|
+
this.currentStepName = config.name;
|
|
14920
|
+
const stepStart = performance.now();
|
|
14921
|
+
const result = await config.execute();
|
|
14922
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
14923
|
+
this.stepTimings.push({ name: config.name, durationMs });
|
|
14924
|
+
this.completedSteps.push({
|
|
14925
|
+
name: config.name,
|
|
14926
|
+
rollback: () => config.rollback(result)
|
|
14927
|
+
});
|
|
14928
|
+
return result;
|
|
14929
|
+
}
|
|
14930
|
+
/**
|
|
14931
|
+
* Execute a step that doesn't need rollback.
|
|
14932
|
+
* Useful for read-only operations or operations that are idempotent.
|
|
14933
|
+
* The step name is automatically tracked for error reporting.
|
|
14934
|
+
*
|
|
14935
|
+
* @param name - Step name for logging and error tracking
|
|
14936
|
+
* @param execute - The action to execute
|
|
14937
|
+
* @returns The result of the execute function
|
|
14938
|
+
*/
|
|
14939
|
+
async readOnlyStep(name2, execute) {
|
|
14940
|
+
this.currentStepName = name2;
|
|
14941
|
+
const stepStart = performance.now();
|
|
14942
|
+
const result = await execute();
|
|
14943
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
14944
|
+
this.stepTimings.push({ name: name2, durationMs });
|
|
14945
|
+
return result;
|
|
14946
|
+
}
|
|
14947
|
+
/**
|
|
14948
|
+
* Roll back all completed steps in reverse order.
|
|
14949
|
+
* Rollback errors are logged but don't stop the rollback of other steps.
|
|
14950
|
+
*/
|
|
14951
|
+
async rollback() {
|
|
14952
|
+
this.log.info("Rolling back saga", {
|
|
14953
|
+
stepsToRollback: this.completedSteps.length
|
|
14954
|
+
});
|
|
14955
|
+
const stepsReversed = [...this.completedSteps].reverse();
|
|
14956
|
+
for (const step of stepsReversed) {
|
|
14957
|
+
try {
|
|
14958
|
+
await step.rollback();
|
|
14959
|
+
} catch (error) {
|
|
14960
|
+
this.log.error(`Failed to rollback step: ${step.name}`, {
|
|
14961
|
+
error: error instanceof Error ? error.message : String(error)
|
|
14962
|
+
});
|
|
14963
|
+
}
|
|
14964
|
+
}
|
|
14965
|
+
this.log.info("Rollback completed", {
|
|
14966
|
+
stepsAttempted: this.completedSteps.length
|
|
14967
|
+
});
|
|
14968
|
+
}
|
|
14969
|
+
/**
|
|
14970
|
+
* Get the number of completed steps (useful for testing)
|
|
14971
|
+
*/
|
|
14972
|
+
getCompletedStepCount() {
|
|
14973
|
+
return this.completedSteps.length;
|
|
14974
|
+
}
|
|
14975
|
+
};
|
|
14976
|
+
|
|
14977
|
+
// src/adapters/claude/conversion/acp-to-sdk.ts
|
|
14978
|
+
var PDF_EXTENSIONS = /* @__PURE__ */ new Set(["pdf"]);
|
|
14687
14979
|
var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
14688
14980
|
"mp4",
|
|
14689
14981
|
"mov",
|
|
@@ -14712,7 +15004,7 @@ function readToolGuidanceForPath(filePath) {
|
|
|
14712
15004
|
if (PDF_EXTENSIONS.has(ext)) {
|
|
14713
15005
|
return 'Optional `pages` string (e.g. "1-5") per Read call instead of loading the entire PDF.';
|
|
14714
15006
|
}
|
|
14715
|
-
if (
|
|
15007
|
+
if (isImageFile(filePath) || VIDEO_EXTENSIONS.has(ext)) {
|
|
14716
15008
|
return "Binary file \u2014 use Read with `file_path`; prefer bounded reads where supported.";
|
|
14717
15009
|
}
|
|
14718
15010
|
return "Large text \u2014 use multiple Read calls with optional `offset` and `limit`.";
|
|
@@ -14778,14 +15070,22 @@ ${chunk.resource.text}
|
|
|
14778
15070
|
break;
|
|
14779
15071
|
case "image":
|
|
14780
15072
|
if (chunk.data) {
|
|
14781
|
-
|
|
14782
|
-
|
|
14783
|
-
|
|
14784
|
-
|
|
14785
|
-
|
|
14786
|
-
|
|
14787
|
-
|
|
14788
|
-
|
|
15073
|
+
if (isClaudeImageMimeType(chunk.mimeType)) {
|
|
15074
|
+
content.push({
|
|
15075
|
+
type: "image",
|
|
15076
|
+
source: {
|
|
15077
|
+
type: "base64",
|
|
15078
|
+
data: chunk.data,
|
|
15079
|
+
media_type: chunk.mimeType
|
|
15080
|
+
}
|
|
15081
|
+
});
|
|
15082
|
+
} else {
|
|
15083
|
+
content.push(
|
|
15084
|
+
sdkText(
|
|
15085
|
+
`[Unsupported image MIME type: ${chunk.mimeType}. Supported: image/jpeg, image/png, image/gif, image/webp.]`
|
|
15086
|
+
)
|
|
15087
|
+
);
|
|
15088
|
+
}
|
|
14789
15089
|
} else if (chunk.uri?.startsWith("http")) {
|
|
14790
15090
|
content.push({
|
|
14791
15091
|
type: "image",
|
|
@@ -15254,6 +15554,9 @@ function getConnectedMcpServerNames() {
|
|
|
15254
15554
|
}
|
|
15255
15555
|
return [...names];
|
|
15256
15556
|
}
|
|
15557
|
+
function getCachedMcpTools() {
|
|
15558
|
+
return [...mcpToolMetadataCache.values()];
|
|
15559
|
+
}
|
|
15257
15560
|
function getMcpToolApprovalState(toolName) {
|
|
15258
15561
|
return mcpToolMetadataCache.get(toolName)?.approvalState;
|
|
15259
15562
|
}
|
|
@@ -18085,6 +18388,19 @@ var SettingsManager = class {
|
|
|
18085
18388
|
var SESSION_VALIDATION_TIMEOUT_MS = 3e4;
|
|
18086
18389
|
var MAX_TITLE_LENGTH = 256;
|
|
18087
18390
|
var LOCAL_ONLY_COMMANDS = /* @__PURE__ */ new Set(["/context", "/heapdump", "/extra-usage"]);
|
|
18391
|
+
function readClaudeMdQuietly(cwd, logger) {
|
|
18392
|
+
try {
|
|
18393
|
+
return fs10.readFileSync(path12.join(cwd, "CLAUDE.md"), "utf-8");
|
|
18394
|
+
} catch (err2) {
|
|
18395
|
+
if (err2?.code !== "ENOENT") {
|
|
18396
|
+
logger.warn("Failed to read CLAUDE.md for context breakdown", {
|
|
18397
|
+
cwd,
|
|
18398
|
+
error: err2 instanceof Error ? err2.message : String(err2)
|
|
18399
|
+
});
|
|
18400
|
+
}
|
|
18401
|
+
return void 0;
|
|
18402
|
+
}
|
|
18403
|
+
}
|
|
18088
18404
|
function sanitizeTitle(text2) {
|
|
18089
18405
|
const sanitized = text2.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
|
|
18090
18406
|
if (sanitized.length <= MAX_TITLE_LENGTH) {
|
|
@@ -18350,6 +18666,24 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18350
18666
|
}
|
|
18351
18667
|
if (message.subtype === "session_state_changed" && message.state === "idle") {
|
|
18352
18668
|
if (!promptReplayed) {
|
|
18669
|
+
if (commandMatch) {
|
|
18670
|
+
const cmd = commandMatch[1];
|
|
18671
|
+
this.logger.warn(
|
|
18672
|
+
"Slash command produced no output; treating as unsupported",
|
|
18673
|
+
{ sessionId: params.sessionId, command: cmd }
|
|
18674
|
+
);
|
|
18675
|
+
await this.client.sessionUpdate({
|
|
18676
|
+
sessionId: params.sessionId,
|
|
18677
|
+
update: {
|
|
18678
|
+
sessionUpdate: "agent_message_chunk",
|
|
18679
|
+
content: {
|
|
18680
|
+
type: "text",
|
|
18681
|
+
text: `Unsupported slash command: \`${cmd}\`. PostHog Code does not implement this command.`
|
|
18682
|
+
}
|
|
18683
|
+
}
|
|
18684
|
+
});
|
|
18685
|
+
return { stopReason: "end_turn" };
|
|
18686
|
+
}
|
|
18353
18687
|
this.logger.debug("Skipping idle state before prompt replay", {
|
|
18354
18688
|
sessionId: params.sessionId
|
|
18355
18689
|
});
|
|
@@ -18412,6 +18746,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18412
18746
|
}
|
|
18413
18747
|
});
|
|
18414
18748
|
}
|
|
18749
|
+
const breakdownInputTokens = lastStreamUsage.input_tokens + lastStreamUsage.cache_read_input_tokens + lastStreamUsage.cache_creation_input_tokens;
|
|
18415
18750
|
await this.client.extNotification(
|
|
18416
18751
|
POSTHOG_NOTIFICATIONS.USAGE_UPDATE,
|
|
18417
18752
|
{
|
|
@@ -18422,7 +18757,11 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18422
18757
|
cachedReadTokens: message.usage.cache_read_input_tokens,
|
|
18423
18758
|
cachedWriteTokens: message.usage.cache_creation_input_tokens
|
|
18424
18759
|
},
|
|
18425
|
-
cost: message.total_cost_usd
|
|
18760
|
+
cost: message.total_cost_usd,
|
|
18761
|
+
breakdown: buildBreakdown(
|
|
18762
|
+
this.session.contextBreakdownBaseline ?? emptyBaseline(),
|
|
18763
|
+
breakdownInputTokens
|
|
18764
|
+
)
|
|
18426
18765
|
}
|
|
18427
18766
|
);
|
|
18428
18767
|
const usage = {
|
|
@@ -18873,6 +19212,11 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
18873
19212
|
pendingMessages: /* @__PURE__ */ new Map(),
|
|
18874
19213
|
nextPendingOrder: 0,
|
|
18875
19214
|
emitRawSDKMessages: meta?.claudeCode?.emitRawSDKMessages ?? false,
|
|
19215
|
+
contextBreakdownBaseline: {
|
|
19216
|
+
...emptyBaseline(),
|
|
19217
|
+
systemPrompt: estimateSystemPrompt(systemPrompt),
|
|
19218
|
+
rules: estimateRulesTokens(readClaudeMdQuietly(cwd, this.logger))
|
|
19219
|
+
},
|
|
18876
19220
|
// Custom properties
|
|
18877
19221
|
cwd,
|
|
18878
19222
|
notificationHistory: [],
|
|
@@ -19130,13 +19474,26 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
19130
19474
|
}
|
|
19131
19475
|
async sendAvailableCommandsUpdate() {
|
|
19132
19476
|
const commands = await this.session.query.supportedCommands();
|
|
19477
|
+
const available = getAvailableSlashCommands(commands);
|
|
19133
19478
|
await this.client.sessionUpdate({
|
|
19134
19479
|
sessionId: this.sessionId,
|
|
19135
19480
|
update: {
|
|
19136
19481
|
sessionUpdate: "available_commands_update",
|
|
19137
|
-
availableCommands:
|
|
19482
|
+
availableCommands: available
|
|
19138
19483
|
}
|
|
19139
19484
|
});
|
|
19485
|
+
this.updateBreakdownCategory("skills", estimateSkillsTokens(available));
|
|
19486
|
+
}
|
|
19487
|
+
/** Update one category of the context-breakdown baseline so the next
|
|
19488
|
+
* `_posthog/usage_update` carries fresher numbers. No-op when the baseline
|
|
19489
|
+
* hasn't been initialized yet (e.g. in a unit-test session). */
|
|
19490
|
+
updateBreakdownCategory(key, tokens) {
|
|
19491
|
+
if (!this.session?.contextBreakdownBaseline) return;
|
|
19492
|
+
if (this.session.contextBreakdownBaseline[key] === tokens) return;
|
|
19493
|
+
this.session.contextBreakdownBaseline = {
|
|
19494
|
+
...this.session.contextBreakdownBaseline,
|
|
19495
|
+
[key]: tokens
|
|
19496
|
+
};
|
|
19140
19497
|
}
|
|
19141
19498
|
async replaySessionHistory(sessionId) {
|
|
19142
19499
|
try {
|
|
@@ -19185,6 +19542,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
19185
19542
|
() => this.sendAvailableCommandsUpdate()
|
|
19186
19543
|
),
|
|
19187
19544
|
fetchMcpToolMetadata(q, this.logger).then(() => {
|
|
19545
|
+
this.updateBreakdownCategory(
|
|
19546
|
+
"mcp",
|
|
19547
|
+
estimateMcpTokens(getCachedMcpTools())
|
|
19548
|
+
);
|
|
19188
19549
|
const serverNames = getConnectedMcpServerNames();
|
|
19189
19550
|
if (serverNames.length > 0) {
|
|
19190
19551
|
this.options?.onMcpServersReady?.(serverNames);
|
|
@@ -19411,6 +19772,25 @@ function createSessionState(sessionId, cwd, opts) {
|
|
|
19411
19772
|
taskId: opts?.taskId
|
|
19412
19773
|
};
|
|
19413
19774
|
}
|
|
19775
|
+
function resetSessionState(state, sessionId, cwd, opts) {
|
|
19776
|
+
state.sessionId = sessionId;
|
|
19777
|
+
state.cwd = cwd;
|
|
19778
|
+
state.modeId = opts?.modeId ?? "auto";
|
|
19779
|
+
state.modelId = opts?.modelId;
|
|
19780
|
+
state.configOptions = [];
|
|
19781
|
+
state.accumulatedUsage = {
|
|
19782
|
+
inputTokens: 0,
|
|
19783
|
+
outputTokens: 0,
|
|
19784
|
+
cachedReadTokens: 0,
|
|
19785
|
+
cachedWriteTokens: 0
|
|
19786
|
+
};
|
|
19787
|
+
state.contextSize = void 0;
|
|
19788
|
+
state.contextUsed = void 0;
|
|
19789
|
+
state.contextBreakdownBaseline = void 0;
|
|
19790
|
+
state.permissionMode = opts?.permissionMode ?? "auto";
|
|
19791
|
+
state.taskRunId = opts?.taskRunId;
|
|
19792
|
+
state.taskId = opts?.taskId;
|
|
19793
|
+
}
|
|
19414
19794
|
function resetUsage(state) {
|
|
19415
19795
|
state.accumulatedUsage = {
|
|
19416
19796
|
inputTokens: 0,
|
|
@@ -19633,6 +20013,12 @@ function classifyPromptError(error) {
|
|
|
19633
20013
|
message
|
|
19634
20014
|
);
|
|
19635
20015
|
}
|
|
20016
|
+
var CODEX_BASELINE_TOKENS = 12e3;
|
|
20017
|
+
function buildCodexBaseline(meta) {
|
|
20018
|
+
const baseline = emptyBaseline();
|
|
20019
|
+
baseline.systemPrompt = CODEX_BASELINE_TOKENS + estimateTokens(meta?.systemPrompt);
|
|
20020
|
+
return baseline;
|
|
20021
|
+
}
|
|
19636
20022
|
var CODEX_NATIVE_MODE = {
|
|
19637
20023
|
auto: "auto",
|
|
19638
20024
|
default: "auto",
|
|
@@ -19802,7 +20188,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
19802
20188
|
response.configOptions = normalizeCodexConfigOptions(
|
|
19803
20189
|
response.configOptions
|
|
19804
20190
|
);
|
|
19805
|
-
this.sessionState
|
|
20191
|
+
resetSessionState(this.sessionState, response.sessionId, params.cwd, {
|
|
19806
20192
|
taskRunId: meta?.taskRunId,
|
|
19807
20193
|
taskId: resolveTaskId(meta),
|
|
19808
20194
|
modeId: response.modes?.currentModeId ?? "auto",
|
|
@@ -19811,6 +20197,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
19811
20197
|
});
|
|
19812
20198
|
this.sessionId = response.sessionId;
|
|
19813
20199
|
this.sessionState.configOptions = response.configOptions ?? [];
|
|
20200
|
+
this.sessionState.contextBreakdownBaseline = buildCodexBaseline(meta);
|
|
19814
20201
|
await this.applyInitialPermissionMode(
|
|
19815
20202
|
response.sessionId,
|
|
19816
20203
|
meta?.permissionMode,
|
|
@@ -19843,7 +20230,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
19843
20230
|
response.modes?.currentModeId,
|
|
19844
20231
|
meta?.permissionMode
|
|
19845
20232
|
);
|
|
19846
|
-
this.sessionState
|
|
20233
|
+
resetSessionState(this.sessionState, params.sessionId, params.cwd, {
|
|
19847
20234
|
taskRunId: meta?.taskRunId,
|
|
19848
20235
|
taskId: resolveTaskId(meta),
|
|
19849
20236
|
modeId: response.modes?.currentModeId ?? "auto",
|
|
@@ -19851,6 +20238,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
19851
20238
|
});
|
|
19852
20239
|
this.sessionId = params.sessionId;
|
|
19853
20240
|
this.sessionState.configOptions = response.configOptions ?? [];
|
|
20241
|
+
this.sessionState.contextBreakdownBaseline = buildCodexBaseline(meta);
|
|
19854
20242
|
if (meta?.taskRunId) {
|
|
19855
20243
|
await this.client.extNotification(POSTHOG_NOTIFICATIONS.SDK_SESSION, {
|
|
19856
20244
|
taskRunId: meta.taskRunId,
|
|
@@ -19882,7 +20270,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
19882
20270
|
loadResponse.modes?.currentModeId,
|
|
19883
20271
|
meta?.permissionMode
|
|
19884
20272
|
);
|
|
19885
|
-
this.sessionState
|
|
20273
|
+
resetSessionState(this.sessionState, params.sessionId, params.cwd, {
|
|
19886
20274
|
taskRunId: meta?.taskRunId,
|
|
19887
20275
|
taskId: resolveTaskId(meta),
|
|
19888
20276
|
modeId: loadResponse.modes?.currentModeId ?? "auto",
|
|
@@ -19890,6 +20278,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
19890
20278
|
});
|
|
19891
20279
|
this.sessionId = params.sessionId;
|
|
19892
20280
|
this.sessionState.configOptions = loadResponse.configOptions ?? [];
|
|
20281
|
+
this.sessionState.contextBreakdownBaseline = buildCodexBaseline(meta);
|
|
19893
20282
|
if (meta?.taskRunId) {
|
|
19894
20283
|
await this.client.extNotification(POSTHOG_NOTIFICATIONS.SDK_SESSION, {
|
|
19895
20284
|
taskRunId: meta.taskRunId,
|
|
@@ -19921,7 +20310,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
19921
20310
|
newResponse.configOptions
|
|
19922
20311
|
);
|
|
19923
20312
|
const requestedPermissionMode = toCodexPermissionMode(meta?.permissionMode);
|
|
19924
|
-
this.sessionState
|
|
20313
|
+
resetSessionState(this.sessionState, newResponse.sessionId, params.cwd, {
|
|
19925
20314
|
taskRunId: meta?.taskRunId,
|
|
19926
20315
|
taskId: resolveTaskId(meta),
|
|
19927
20316
|
modeId: newResponse.modes?.currentModeId ?? "auto",
|
|
@@ -19929,6 +20318,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
19929
20318
|
});
|
|
19930
20319
|
this.sessionId = newResponse.sessionId;
|
|
19931
20320
|
this.sessionState.configOptions = newResponse.configOptions ?? [];
|
|
20321
|
+
this.sessionState.contextBreakdownBaseline = buildCodexBaseline(meta);
|
|
19932
20322
|
await this.applyInitialPermissionMode(
|
|
19933
20323
|
newResponse.sessionId,
|
|
19934
20324
|
meta?.permissionMode,
|
|
@@ -20065,6 +20455,15 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
20065
20455
|
});
|
|
20066
20456
|
}
|
|
20067
20457
|
}
|
|
20458
|
+
if (this.sessionState.contextUsed !== void 0) {
|
|
20459
|
+
await this.client.extNotification(POSTHOG_NOTIFICATIONS.USAGE_UPDATE, {
|
|
20460
|
+
sessionId: params.sessionId,
|
|
20461
|
+
breakdown: buildBreakdown(
|
|
20462
|
+
this.sessionState.contextBreakdownBaseline ?? emptyBaseline(),
|
|
20463
|
+
this.sessionState.contextUsed
|
|
20464
|
+
)
|
|
20465
|
+
});
|
|
20466
|
+
}
|
|
20068
20467
|
return response;
|
|
20069
20468
|
}
|
|
20070
20469
|
async interrupt() {
|
|
@@ -20381,148 +20780,6 @@ var import_node_crypto2 = require("crypto");
|
|
|
20381
20780
|
var fs12 = __toESM(require("fs/promises"), 1);
|
|
20382
20781
|
var path14 = __toESM(require("path"), 1);
|
|
20383
20782
|
|
|
20384
|
-
// ../shared/dist/index.js
|
|
20385
|
-
var CLOUD_PROMPT_PREFIX = "__twig_cloud_prompt_v1__:";
|
|
20386
|
-
function deserializeCloudPrompt(value) {
|
|
20387
|
-
const trimmed2 = value.trim();
|
|
20388
|
-
if (!trimmed2) {
|
|
20389
|
-
return [];
|
|
20390
|
-
}
|
|
20391
|
-
if (!trimmed2.startsWith(CLOUD_PROMPT_PREFIX)) {
|
|
20392
|
-
return [{ type: "text", text: trimmed2 }];
|
|
20393
|
-
}
|
|
20394
|
-
try {
|
|
20395
|
-
const parsed = JSON.parse(trimmed2.slice(CLOUD_PROMPT_PREFIX.length));
|
|
20396
|
-
if (Array.isArray(parsed.blocks) && parsed.blocks.length > 0) {
|
|
20397
|
-
return parsed.blocks;
|
|
20398
|
-
}
|
|
20399
|
-
} catch {
|
|
20400
|
-
}
|
|
20401
|
-
return [{ type: "text", text: trimmed2 }];
|
|
20402
|
-
}
|
|
20403
|
-
function promptBlocksToText(blocks) {
|
|
20404
|
-
return blocks.filter((b) => b.type === "text").map((block) => block.text).join("").trim();
|
|
20405
|
-
}
|
|
20406
|
-
var consoleLogger = {
|
|
20407
|
-
info: (_message, _data) => {
|
|
20408
|
-
},
|
|
20409
|
-
debug: (_message, _data) => {
|
|
20410
|
-
},
|
|
20411
|
-
error: (_message, _data) => {
|
|
20412
|
-
},
|
|
20413
|
-
warn: (_message, _data) => {
|
|
20414
|
-
}
|
|
20415
|
-
};
|
|
20416
|
-
var Saga = class {
|
|
20417
|
-
completedSteps = [];
|
|
20418
|
-
currentStepName = "unknown";
|
|
20419
|
-
stepTimings = [];
|
|
20420
|
-
log;
|
|
20421
|
-
constructor(logger) {
|
|
20422
|
-
this.log = logger ?? consoleLogger;
|
|
20423
|
-
}
|
|
20424
|
-
/**
|
|
20425
|
-
* Run the saga with the given input.
|
|
20426
|
-
* Returns a discriminated union result - either success with data or failure with error details.
|
|
20427
|
-
*/
|
|
20428
|
-
async run(input) {
|
|
20429
|
-
this.completedSteps = [];
|
|
20430
|
-
this.currentStepName = "unknown";
|
|
20431
|
-
this.stepTimings = [];
|
|
20432
|
-
const sagaStart = performance.now();
|
|
20433
|
-
try {
|
|
20434
|
-
const result = await this.execute(input);
|
|
20435
|
-
const totalDuration = performance.now() - sagaStart;
|
|
20436
|
-
this.log.debug("Saga completed successfully", {
|
|
20437
|
-
sagaName: this.sagaName,
|
|
20438
|
-
stepsCompleted: this.completedSteps.length,
|
|
20439
|
-
totalDurationMs: Math.round(totalDuration),
|
|
20440
|
-
stepTimings: this.stepTimings
|
|
20441
|
-
});
|
|
20442
|
-
return { success: true, data: result };
|
|
20443
|
-
} catch (error) {
|
|
20444
|
-
this.log.error("Saga failed, initiating rollback", {
|
|
20445
|
-
sagaName: this.sagaName,
|
|
20446
|
-
failedStep: this.currentStepName,
|
|
20447
|
-
error: error instanceof Error ? error.message : String(error),
|
|
20448
|
-
completedStepTimings: this.stepTimings
|
|
20449
|
-
});
|
|
20450
|
-
await this.rollback();
|
|
20451
|
-
return {
|
|
20452
|
-
success: false,
|
|
20453
|
-
error: error instanceof Error ? error.message : String(error),
|
|
20454
|
-
failedStep: this.currentStepName
|
|
20455
|
-
};
|
|
20456
|
-
}
|
|
20457
|
-
}
|
|
20458
|
-
/**
|
|
20459
|
-
* Execute a step with its rollback action.
|
|
20460
|
-
* If the step succeeds, its rollback action is stored for potential rollback.
|
|
20461
|
-
* The step name is automatically tracked for error reporting.
|
|
20462
|
-
*
|
|
20463
|
-
* @param config - Step configuration with name, execute, and rollback functions
|
|
20464
|
-
* @returns The result of the execute function
|
|
20465
|
-
* @throws Re-throws any error from the execute function (triggers rollback)
|
|
20466
|
-
*/
|
|
20467
|
-
async step(config) {
|
|
20468
|
-
this.currentStepName = config.name;
|
|
20469
|
-
const stepStart = performance.now();
|
|
20470
|
-
const result = await config.execute();
|
|
20471
|
-
const durationMs = Math.round(performance.now() - stepStart);
|
|
20472
|
-
this.stepTimings.push({ name: config.name, durationMs });
|
|
20473
|
-
this.completedSteps.push({
|
|
20474
|
-
name: config.name,
|
|
20475
|
-
rollback: () => config.rollback(result)
|
|
20476
|
-
});
|
|
20477
|
-
return result;
|
|
20478
|
-
}
|
|
20479
|
-
/**
|
|
20480
|
-
* Execute a step that doesn't need rollback.
|
|
20481
|
-
* Useful for read-only operations or operations that are idempotent.
|
|
20482
|
-
* The step name is automatically tracked for error reporting.
|
|
20483
|
-
*
|
|
20484
|
-
* @param name - Step name for logging and error tracking
|
|
20485
|
-
* @param execute - The action to execute
|
|
20486
|
-
* @returns The result of the execute function
|
|
20487
|
-
*/
|
|
20488
|
-
async readOnlyStep(name2, execute) {
|
|
20489
|
-
this.currentStepName = name2;
|
|
20490
|
-
const stepStart = performance.now();
|
|
20491
|
-
const result = await execute();
|
|
20492
|
-
const durationMs = Math.round(performance.now() - stepStart);
|
|
20493
|
-
this.stepTimings.push({ name: name2, durationMs });
|
|
20494
|
-
return result;
|
|
20495
|
-
}
|
|
20496
|
-
/**
|
|
20497
|
-
* Roll back all completed steps in reverse order.
|
|
20498
|
-
* Rollback errors are logged but don't stop the rollback of other steps.
|
|
20499
|
-
*/
|
|
20500
|
-
async rollback() {
|
|
20501
|
-
this.log.info("Rolling back saga", {
|
|
20502
|
-
stepsToRollback: this.completedSteps.length
|
|
20503
|
-
});
|
|
20504
|
-
const stepsReversed = [...this.completedSteps].reverse();
|
|
20505
|
-
for (const step of stepsReversed) {
|
|
20506
|
-
try {
|
|
20507
|
-
await step.rollback();
|
|
20508
|
-
} catch (error) {
|
|
20509
|
-
this.log.error(`Failed to rollback step: ${step.name}`, {
|
|
20510
|
-
error: error instanceof Error ? error.message : String(error)
|
|
20511
|
-
});
|
|
20512
|
-
}
|
|
20513
|
-
}
|
|
20514
|
-
this.log.info("Rollback completed", {
|
|
20515
|
-
stepsAttempted: this.completedSteps.length
|
|
20516
|
-
});
|
|
20517
|
-
}
|
|
20518
|
-
/**
|
|
20519
|
-
* Get the number of completed steps (useful for testing)
|
|
20520
|
-
*/
|
|
20521
|
-
getCompletedStepCount() {
|
|
20522
|
-
return this.completedSteps.length;
|
|
20523
|
-
}
|
|
20524
|
-
};
|
|
20525
|
-
|
|
20526
20783
|
// ../git/dist/git-saga.js
|
|
20527
20784
|
var GitSaga = class extends Saga {
|
|
20528
20785
|
_git = null;
|
|
@@ -21758,7 +22015,7 @@ var import_node_crypto3 = require("crypto");
|
|
|
21758
22015
|
var fs13 = __toESM(require("fs/promises"), 1);
|
|
21759
22016
|
var os8 = __toESM(require("os"), 1);
|
|
21760
22017
|
var path16 = __toESM(require("path"), 1);
|
|
21761
|
-
var
|
|
22018
|
+
var CHARS_PER_TOKEN2 = 4;
|
|
21762
22019
|
var DEFAULT_MAX_TOKENS = 15e4;
|
|
21763
22020
|
function estimateTurnTokens(turn) {
|
|
21764
22021
|
let chars = 0;
|
|
@@ -21775,7 +22032,7 @@ function estimateTurnTokens(turn) {
|
|
|
21775
22032
|
}
|
|
21776
22033
|
}
|
|
21777
22034
|
}
|
|
21778
|
-
return Math.ceil(chars /
|
|
22035
|
+
return Math.ceil(chars / CHARS_PER_TOKEN2);
|
|
21779
22036
|
}
|
|
21780
22037
|
function selectRecentTurns(turns, maxTokens = DEFAULT_MAX_TOKENS) {
|
|
21781
22038
|
let budget = maxTokens;
|