@posthog/agent 2.3.22 → 2.3.31
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/session/jsonl-hydration.js +14 -1
- package/dist/adapters/claude/session/jsonl-hydration.js.map +1 -1
- package/dist/agent.js +86 -12
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.d.ts +13 -0
- package/dist/server/agent-server.js +118 -13
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +150 -35
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/claude/claude-agent.ts +67 -12
- package/src/adapters/claude/session/jsonl-hydration.ts +6 -1
- package/src/adapters/claude/session/models.ts +50 -0
- package/src/server/agent-server.ts +30 -1
- package/src/server/bin.ts +40 -23
- package/src/server/schemas.ts +16 -0
- package/src/server/types.ts +8 -0
package/package.json
CHANGED
|
@@ -59,7 +59,12 @@ import { fetchMcpToolMetadata } from "./mcp/tool-metadata";
|
|
|
59
59
|
import { canUseTool } from "./permissions/permission-handlers";
|
|
60
60
|
import { getAvailableSlashCommands } from "./session/commands";
|
|
61
61
|
import { parseMcpServers } from "./session/mcp-config";
|
|
62
|
-
import {
|
|
62
|
+
import {
|
|
63
|
+
DEFAULT_MODEL,
|
|
64
|
+
getDefaultContextWindow,
|
|
65
|
+
getEffortOptions,
|
|
66
|
+
toSdkModelId,
|
|
67
|
+
} from "./session/models";
|
|
63
68
|
import {
|
|
64
69
|
buildSessionOptions,
|
|
65
70
|
buildSystemPrompt,
|
|
@@ -337,7 +342,9 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
337
342
|
(m) => m.contextWindow,
|
|
338
343
|
);
|
|
339
344
|
const contextWindowSize =
|
|
340
|
-
contextWindows.length > 0
|
|
345
|
+
contextWindows.length > 0
|
|
346
|
+
? Math.min(...contextWindows)
|
|
347
|
+
: getDefaultContextWindow(this.session.modelId ?? "");
|
|
341
348
|
|
|
342
349
|
// Send usage_update notification
|
|
343
350
|
if (lastAssistantTotalUsage !== null) {
|
|
@@ -509,6 +516,7 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
509
516
|
const sdkModelId = toSdkModelId(params.modelId);
|
|
510
517
|
await this.session.query.setModel(sdkModelId);
|
|
511
518
|
this.session.modelId = params.modelId;
|
|
519
|
+
this.rebuildEffortConfigOption(params.modelId);
|
|
512
520
|
await this.updateConfigOption("model", params.modelId);
|
|
513
521
|
return {};
|
|
514
522
|
}
|
|
@@ -559,6 +567,7 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
559
567
|
const sdkModelId = toSdkModelId(params.value);
|
|
560
568
|
await this.session.query.setModel(sdkModelId);
|
|
561
569
|
this.session.modelId = params.value;
|
|
570
|
+
this.rebuildEffortConfigOption(params.value);
|
|
562
571
|
} else if (params.configId === "effort") {
|
|
563
572
|
const newEffort = params.value as EffortLevel;
|
|
564
573
|
this.session.effort = newEffort;
|
|
@@ -865,7 +874,7 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
865
874
|
description: mode.description ?? undefined,
|
|
866
875
|
}));
|
|
867
876
|
|
|
868
|
-
|
|
877
|
+
const configOptions: SessionConfigOption[] = [
|
|
869
878
|
{
|
|
870
879
|
id: "mode",
|
|
871
880
|
name: "Approval Preset",
|
|
@@ -885,21 +894,67 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
885
894
|
category: "model" as SessionConfigOptionCategory,
|
|
886
895
|
description: "Choose which model Claude should use",
|
|
887
896
|
},
|
|
888
|
-
|
|
897
|
+
];
|
|
898
|
+
|
|
899
|
+
const effortOptions = getEffortOptions(modelOptions.currentModelId);
|
|
900
|
+
if (effortOptions) {
|
|
901
|
+
configOptions.push({
|
|
889
902
|
id: "effort",
|
|
890
903
|
name: "Effort",
|
|
891
904
|
type: "select",
|
|
892
905
|
currentValue: currentEffort,
|
|
893
|
-
options:
|
|
894
|
-
{ value: "low", name: "Low" },
|
|
895
|
-
{ value: "medium", name: "Medium" },
|
|
896
|
-
{ value: "high", name: "High" },
|
|
897
|
-
{ value: "max", name: "Max" },
|
|
898
|
-
],
|
|
906
|
+
options: effortOptions,
|
|
899
907
|
category: "thought_level" as SessionConfigOptionCategory,
|
|
900
908
|
description: "Controls how much effort Claude puts into its response",
|
|
901
|
-
}
|
|
902
|
-
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
return configOptions;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
private rebuildEffortConfigOption(modelId: string): void {
|
|
916
|
+
const effortOptions = getEffortOptions(modelId);
|
|
917
|
+
const existingEffort = this.session.configOptions.find(
|
|
918
|
+
(o) => o.id === "effort",
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
if (!effortOptions) {
|
|
922
|
+
this.session.configOptions = this.session.configOptions.filter(
|
|
923
|
+
(o) => o.id !== "effort",
|
|
924
|
+
);
|
|
925
|
+
if (this.session.effort) {
|
|
926
|
+
this.session.effort = undefined;
|
|
927
|
+
this.session.queryOptions.effort = undefined;
|
|
928
|
+
}
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const currentValue = existingEffort?.currentValue ?? "high";
|
|
933
|
+
const isValidValue = effortOptions.some((o) => o.value === currentValue);
|
|
934
|
+
const resolvedValue = isValidValue ? currentValue : "high";
|
|
935
|
+
|
|
936
|
+
if (resolvedValue !== currentValue && this.session.effort) {
|
|
937
|
+
this.session.effort = resolvedValue as EffortLevel;
|
|
938
|
+
this.session.queryOptions.effort = resolvedValue as EffortLevel;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
const effortConfig: SessionConfigOption = {
|
|
942
|
+
id: "effort",
|
|
943
|
+
name: "Effort",
|
|
944
|
+
type: "select",
|
|
945
|
+
currentValue: resolvedValue,
|
|
946
|
+
options: effortOptions,
|
|
947
|
+
category: "thought_level" as SessionConfigOptionCategory,
|
|
948
|
+
description: "Controls how much effort Claude puts into its response",
|
|
949
|
+
};
|
|
950
|
+
|
|
951
|
+
if (existingEffort) {
|
|
952
|
+
this.session.configOptions = this.session.configOptions.map((o) =>
|
|
953
|
+
o.id === "effort" ? effortConfig : o,
|
|
954
|
+
);
|
|
955
|
+
} else {
|
|
956
|
+
this.session.configOptions.push(effortConfig);
|
|
957
|
+
}
|
|
903
958
|
}
|
|
904
959
|
|
|
905
960
|
private async sendAvailableCommandsUpdate(): Promise<void> {
|
|
@@ -5,6 +5,7 @@ import * as path from "node:path";
|
|
|
5
5
|
import type { ContentBlock } from "@agentclientprotocol/sdk";
|
|
6
6
|
import type { PostHogAPIClient } from "../../../posthog-api";
|
|
7
7
|
import type { StoredEntry } from "../../../types";
|
|
8
|
+
import { supports1MContext } from "./models";
|
|
8
9
|
|
|
9
10
|
interface ConversationTurn {
|
|
10
11
|
role: "user" | "assistant";
|
|
@@ -188,6 +189,7 @@ export function rebuildConversation(
|
|
|
188
189
|
|
|
189
190
|
const CHARS_PER_TOKEN = 4;
|
|
190
191
|
const DEFAULT_MAX_TOKENS = 150_000;
|
|
192
|
+
const LARGE_CONTEXT_MAX_TOKENS = 800_000;
|
|
191
193
|
|
|
192
194
|
function estimateTurnTokens(turn: ConversationTurn): number {
|
|
193
195
|
let chars = 0;
|
|
@@ -546,7 +548,10 @@ export async function hydrateSessionJsonl(params: {
|
|
|
546
548
|
return;
|
|
547
549
|
}
|
|
548
550
|
|
|
549
|
-
const
|
|
551
|
+
const maxTokens = supports1MContext(params.model ?? "")
|
|
552
|
+
? LARGE_CONTEXT_MAX_TOKENS
|
|
553
|
+
: DEFAULT_MAX_TOKENS;
|
|
554
|
+
const conversation = selectRecentTurns(allTurns, maxTokens);
|
|
550
555
|
log.info("Selected recent turns for hydration", {
|
|
551
556
|
totalTurns: allTurns.length,
|
|
552
557
|
selectedTurns: conversation.length,
|
|
@@ -11,3 +11,53 @@ const GATEWAY_TO_SDK_MODEL: Record<string, string> = {
|
|
|
11
11
|
export function toSdkModelId(modelId: string): string {
|
|
12
12
|
return GATEWAY_TO_SDK_MODEL[modelId] ?? modelId;
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
const MODELS_WITH_1M_CONTEXT = new Set([
|
|
16
|
+
"claude-opus-4-6",
|
|
17
|
+
"claude-sonnet-4-6",
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
export function supports1MContext(modelId: string): boolean {
|
|
21
|
+
return MODELS_WITH_1M_CONTEXT.has(modelId);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getDefaultContextWindow(modelId: string): number {
|
|
25
|
+
return supports1MContext(modelId) ? 1_000_000 : 200_000;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const MODELS_WITH_EFFORT = new Set([
|
|
29
|
+
"claude-opus-4-5",
|
|
30
|
+
"claude-opus-4-6",
|
|
31
|
+
"claude-sonnet-4-6",
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
const MODELS_WITH_MAX_EFFORT = new Set(["claude-opus-4-6"]);
|
|
35
|
+
|
|
36
|
+
export function supportsEffort(modelId: string): boolean {
|
|
37
|
+
return MODELS_WITH_EFFORT.has(modelId);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function supportsMaxEffort(modelId: string): boolean {
|
|
41
|
+
return MODELS_WITH_MAX_EFFORT.has(modelId);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface EffortOption {
|
|
45
|
+
value: string;
|
|
46
|
+
name: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getEffortOptions(modelId: string): EffortOption[] | null {
|
|
50
|
+
if (!supportsEffort(modelId)) return null;
|
|
51
|
+
|
|
52
|
+
const options: EffortOption[] = [
|
|
53
|
+
{ value: "low", name: "Low" },
|
|
54
|
+
{ value: "medium", name: "Medium" },
|
|
55
|
+
{ value: "high", name: "High" },
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
if (supportsMaxEffort(modelId)) {
|
|
59
|
+
options.push({ value: "max", name: "Max" });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return options;
|
|
63
|
+
}
|
|
@@ -639,7 +639,14 @@ export class AgentServer {
|
|
|
639
639
|
_meta: {
|
|
640
640
|
sessionId: payload.run_id,
|
|
641
641
|
taskRunId: payload.run_id,
|
|
642
|
-
systemPrompt:
|
|
642
|
+
systemPrompt: this.buildSessionSystemPrompt(prUrl),
|
|
643
|
+
...(this.config.claudeCode?.plugins?.length && {
|
|
644
|
+
claudeCode: {
|
|
645
|
+
options: {
|
|
646
|
+
plugins: this.config.claudeCode.plugins,
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
}),
|
|
643
650
|
},
|
|
644
651
|
});
|
|
645
652
|
|
|
@@ -944,6 +951,28 @@ export class AgentServer {
|
|
|
944
951
|
: null;
|
|
945
952
|
}
|
|
946
953
|
|
|
954
|
+
private buildSessionSystemPrompt(
|
|
955
|
+
prUrl?: string | null,
|
|
956
|
+
): string | { append: string } {
|
|
957
|
+
const cloudAppend = this.buildCloudSystemPrompt(prUrl);
|
|
958
|
+
const userPrompt = this.config.claudeCode?.systemPrompt;
|
|
959
|
+
|
|
960
|
+
// String override: combine user prompt with cloud instructions
|
|
961
|
+
if (typeof userPrompt === "string") {
|
|
962
|
+
return [userPrompt, cloudAppend].join("\n\n");
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// Preset with append: merge user append with cloud instructions
|
|
966
|
+
if (typeof userPrompt === "object") {
|
|
967
|
+
return {
|
|
968
|
+
append: [userPrompt.append, cloudAppend].filter(Boolean).join("\n\n"),
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// Default: just cloud instructions
|
|
973
|
+
return { append: cloudAppend };
|
|
974
|
+
}
|
|
975
|
+
|
|
947
976
|
private buildCloudSystemPrompt(prUrl?: string | null): string {
|
|
948
977
|
if (prUrl) {
|
|
949
978
|
return `
|
package/src/server/bin.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { AgentServer } from "./agent-server";
|
|
5
|
-
import { mcpServersSchema } from "./schemas";
|
|
5
|
+
import { claudeCodeConfigSchema, mcpServersSchema } from "./schemas";
|
|
6
6
|
|
|
7
7
|
const envSchema = z.object({
|
|
8
8
|
JWT_PUBLIC_KEY: z
|
|
@@ -34,6 +34,30 @@ const envSchema = z.object({
|
|
|
34
34
|
|
|
35
35
|
const program = new Command();
|
|
36
36
|
|
|
37
|
+
function parseJsonOption<S extends z.ZodTypeAny>(
|
|
38
|
+
raw: string | undefined,
|
|
39
|
+
schema: S,
|
|
40
|
+
flag: string,
|
|
41
|
+
): z.output<S> | undefined {
|
|
42
|
+
if (!raw) return undefined;
|
|
43
|
+
|
|
44
|
+
let parsed: unknown;
|
|
45
|
+
try {
|
|
46
|
+
parsed = JSON.parse(raw);
|
|
47
|
+
} catch {
|
|
48
|
+
program.error(`${flag} must be valid JSON`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const result = schema.safeParse(parsed);
|
|
52
|
+
if (!result.success) {
|
|
53
|
+
const errors = result.error.issues
|
|
54
|
+
.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`)
|
|
55
|
+
.join("\n");
|
|
56
|
+
program.error(`${flag} validation failed:\n${errors}`);
|
|
57
|
+
}
|
|
58
|
+
return result.data;
|
|
59
|
+
}
|
|
60
|
+
|
|
37
61
|
program
|
|
38
62
|
.name("agent-server")
|
|
39
63
|
.description("PostHog cloud agent server - runs in sandbox environments")
|
|
@@ -51,6 +75,10 @@ program
|
|
|
51
75
|
"MCP servers config as JSON array (ACP McpServer[] format)",
|
|
52
76
|
)
|
|
53
77
|
.option("--baseBranch <branch>", "Base branch for PR creation")
|
|
78
|
+
.option(
|
|
79
|
+
"--claudeCodeConfig <json>",
|
|
80
|
+
"Claude Code config as JSON (systemPrompt, systemPromptAppend, plugins)",
|
|
81
|
+
)
|
|
54
82
|
.action(async (options) => {
|
|
55
83
|
const envResult = envSchema.safeParse(process.env);
|
|
56
84
|
|
|
@@ -66,28 +94,16 @@ program
|
|
|
66
94
|
|
|
67
95
|
const mode = options.mode === "background" ? "background" : "interactive";
|
|
68
96
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const result = mcpServersSchema.safeParse(parsed);
|
|
80
|
-
if (!result.success) {
|
|
81
|
-
const errors = result.error.issues
|
|
82
|
-
.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`)
|
|
83
|
-
.join("\n");
|
|
84
|
-
program.error(
|
|
85
|
-
`--mcpServers validation failed (only remote http/sse servers are supported):\n${errors}`,
|
|
86
|
-
);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
mcpServers = result.data;
|
|
90
|
-
}
|
|
97
|
+
const mcpServers = parseJsonOption(
|
|
98
|
+
options.mcpServers,
|
|
99
|
+
mcpServersSchema,
|
|
100
|
+
"--mcpServers",
|
|
101
|
+
);
|
|
102
|
+
const claudeCode = parseJsonOption(
|
|
103
|
+
options.claudeCodeConfig,
|
|
104
|
+
claudeCodeConfigSchema,
|
|
105
|
+
"--claudeCodeConfig",
|
|
106
|
+
);
|
|
91
107
|
|
|
92
108
|
const server = new AgentServer({
|
|
93
109
|
port: parseInt(options.port, 10),
|
|
@@ -101,6 +117,7 @@ program
|
|
|
101
117
|
runId: options.runId,
|
|
102
118
|
mcpServers,
|
|
103
119
|
baseBranch: options.baseBranch,
|
|
120
|
+
claudeCode,
|
|
104
121
|
});
|
|
105
122
|
|
|
106
123
|
process.on("SIGINT", async () => {
|
package/src/server/schemas.ts
CHANGED
|
@@ -16,6 +16,22 @@ export const mcpServersSchema = z.array(remoteMcpServerSchema);
|
|
|
16
16
|
|
|
17
17
|
export type RemoteMcpServer = z.infer<typeof remoteMcpServerSchema>;
|
|
18
18
|
|
|
19
|
+
export const claudeCodeConfigSchema = z.object({
|
|
20
|
+
systemPrompt: z
|
|
21
|
+
.union([
|
|
22
|
+
z.string(),
|
|
23
|
+
z.object({
|
|
24
|
+
type: z.literal("preset"),
|
|
25
|
+
preset: z.literal("claude_code"),
|
|
26
|
+
append: z.string().optional(),
|
|
27
|
+
}),
|
|
28
|
+
])
|
|
29
|
+
.optional(),
|
|
30
|
+
plugins: z
|
|
31
|
+
.array(z.object({ type: z.literal("local"), path: z.string() }))
|
|
32
|
+
.optional(),
|
|
33
|
+
});
|
|
34
|
+
|
|
19
35
|
export const jsonRpcRequestSchema = z.object({
|
|
20
36
|
jsonrpc: z.literal("2.0"),
|
|
21
37
|
method: z.string(),
|
package/src/server/types.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { AgentMode } from "../types";
|
|
2
2
|
import type { RemoteMcpServer } from "./schemas";
|
|
3
3
|
|
|
4
|
+
export interface ClaudeCodeConfig {
|
|
5
|
+
systemPrompt?:
|
|
6
|
+
| string
|
|
7
|
+
| { type: "preset"; preset: "claude_code"; append?: string };
|
|
8
|
+
plugins?: { type: "local"; path: string }[];
|
|
9
|
+
}
|
|
10
|
+
|
|
4
11
|
export interface AgentServerConfig {
|
|
5
12
|
port: number;
|
|
6
13
|
repositoryPath?: string;
|
|
@@ -14,4 +21,5 @@ export interface AgentServerConfig {
|
|
|
14
21
|
version?: string;
|
|
15
22
|
mcpServers?: RemoteMcpServer[];
|
|
16
23
|
baseBranch?: string;
|
|
24
|
+
claudeCode?: ClaudeCodeConfig;
|
|
17
25
|
}
|