@posthog/agent 2.3.727 → 2.3.735
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/agent.js +21 -3
- 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.js +21 -3
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +21 -3
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +3 -3
- package/src/adapters/claude/UPSTREAM.md +1 -0
- package/src/adapters/claude/claude-agent.slash-command.test.ts +22 -2
- package/src/adapters/claude/claude-agent.ts +31 -1
- package/src/adapters/claude/types.ts +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/agent",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.735",
|
|
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/
|
|
111
|
-
"@posthog/
|
|
110
|
+
"@posthog/enricher": "1.0.0",
|
|
111
|
+
"@posthog/git": "1.0.0"
|
|
112
112
|
},
|
|
113
113
|
"dependencies": {
|
|
114
114
|
"@agentclientprotocol/sdk": "0.19.0",
|
|
@@ -53,6 +53,7 @@ Fork of `@anthropic-ai/claude-agent-acp`. Upstream repo: https://github.com/anth
|
|
|
53
53
|
| Auth methods | `claude-ai-login` + `console-login` | Returns empty `authMethods` | Auth handled externally |
|
|
54
54
|
| Session fingerprinting | Implicit teardown on cwd/mcp change | Explicit `refreshSession()` | Caller-initiated is more predictable |
|
|
55
55
|
| Shutdown on ACP close | Process exits | No standalone process | Agent is embedded in server |
|
|
56
|
+
| Unsupported slash commands | Loops silently on early idle | Emits "Unsupported slash command" chunk, gated on `initializationResult().commands` so plugin/skill commands (e.g. `/skills-store`) whose echoes use a fresh uuid are not false-flagged | The SDK consumes some slash commands without producing output (e.g. `/plugin` in non-interactive mode); without this we hang. The known-commands gate avoids racing plugin/skill loads where idle can arrive before the transformed user-message echo. |
|
|
56
57
|
|
|
57
58
|
## Changes Ported in v0.30.0 Sync
|
|
58
59
|
|
|
@@ -34,7 +34,11 @@ function makeAgent(): { agent: Agent; client: ClientMocks } {
|
|
|
34
34
|
return { agent, client };
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function installFakeSession(
|
|
37
|
+
function installFakeSession(
|
|
38
|
+
agent: Agent,
|
|
39
|
+
sessionId: string,
|
|
40
|
+
knownSlashCommands?: Set<string>,
|
|
41
|
+
): MockQuery {
|
|
38
42
|
const query = createMockQuery();
|
|
39
43
|
const input = new Pushable();
|
|
40
44
|
const abortController = new AbortController();
|
|
@@ -63,6 +67,7 @@ function installFakeSession(agent: Agent, sessionId: string): MockQuery {
|
|
|
63
67
|
taskRunId: "run-1",
|
|
64
68
|
lastContextWindowSize: 200_000,
|
|
65
69
|
modelId: "claude-sonnet-4-6",
|
|
70
|
+
knownSlashCommands,
|
|
66
71
|
};
|
|
67
72
|
|
|
68
73
|
(agent as unknown as { session: typeof session }).session = session;
|
|
@@ -99,6 +104,7 @@ describe("ClaudeAcpAgent.prompt — early idle handling", () => {
|
|
|
99
104
|
label: "unsupported slash command surfaces error and ends turn",
|
|
100
105
|
sessionId: "s-slash",
|
|
101
106
|
prompt: "/plugin install slack",
|
|
107
|
+
knownCommands: undefined,
|
|
102
108
|
expectsUnsupportedChunk: true,
|
|
103
109
|
commandInMessage: "/plugin",
|
|
104
110
|
},
|
|
@@ -106,6 +112,16 @@ describe("ClaudeAcpAgent.prompt — early idle handling", () => {
|
|
|
106
112
|
label: "non-slash prompt with early idle is silently skipped",
|
|
107
113
|
sessionId: "s-regular",
|
|
108
114
|
prompt: "hello",
|
|
115
|
+
knownCommands: undefined,
|
|
116
|
+
expectsUnsupportedChunk: false,
|
|
117
|
+
commandInMessage: null,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
label:
|
|
121
|
+
"known plugin/skill command with early idle is not flagged as unsupported",
|
|
122
|
+
sessionId: "s-skill",
|
|
123
|
+
prompt: "/skills-store use my address pr review skill",
|
|
124
|
+
knownCommands: new Set(["skills-store"]),
|
|
109
125
|
expectsUnsupportedChunk: false,
|
|
110
126
|
commandInMessage: null,
|
|
111
127
|
},
|
|
@@ -113,7 +129,11 @@ describe("ClaudeAcpAgent.prompt — early idle handling", () => {
|
|
|
113
129
|
|
|
114
130
|
it.each(cases)("$label", async (tc) => {
|
|
115
131
|
const { agent, client } = makeAgent();
|
|
116
|
-
const query = installFakeSession(
|
|
132
|
+
const query = installFakeSession(
|
|
133
|
+
agent,
|
|
134
|
+
tc.sessionId,
|
|
135
|
+
tc.knownCommands as Set<string> | undefined,
|
|
136
|
+
);
|
|
117
137
|
|
|
118
138
|
const promptPromise = agent.prompt({
|
|
119
139
|
sessionId: tc.sessionId,
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
type Query,
|
|
44
44
|
query,
|
|
45
45
|
type SDKUserMessage,
|
|
46
|
+
type SlashCommand,
|
|
46
47
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
47
48
|
import { v7 as uuidv7 } from "uuid";
|
|
48
49
|
import packageJson from "../../../package.json" with { type: "json" };
|
|
@@ -143,6 +144,17 @@ function readClaudeMdQuietly(cwd: string, logger: Logger): string | undefined {
|
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
146
|
|
|
147
|
+
function collectKnownSlashCommands(
|
|
148
|
+
commands: SlashCommand[] | undefined,
|
|
149
|
+
): Set<string> {
|
|
150
|
+
const names = new Set<string>();
|
|
151
|
+
if (!commands) return names;
|
|
152
|
+
for (const cmd of commands) {
|
|
153
|
+
if (cmd.name) names.add(cmd.name);
|
|
154
|
+
}
|
|
155
|
+
return names;
|
|
156
|
+
}
|
|
157
|
+
|
|
146
158
|
function sanitizeTitle(text: string): string {
|
|
147
159
|
const sanitized = text
|
|
148
160
|
.replace(/[\r\n]+/g, " ")
|
|
@@ -500,7 +512,17 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
500
512
|
// and produced no output (e.g. /plugin in a non-interactive
|
|
501
513
|
// context). Without this branch we would loop forever waiting
|
|
502
514
|
// for an echo that never comes; surface a clear error instead.
|
|
503
|
-
|
|
515
|
+
//
|
|
516
|
+
// Only fire for commands the SDK does NOT recognize. Plugin
|
|
517
|
+
// and skill commands (e.g. /skills-store) produce a fresh
|
|
518
|
+
// user-message echo with a new uuid that our replay check
|
|
519
|
+
// can't match, so an early idle here is a race, not a real
|
|
520
|
+
// "unsupported" — fall through and let the loop continue.
|
|
521
|
+
const cmdName = commandMatch?.[1].slice(1);
|
|
522
|
+
const known =
|
|
523
|
+
cmdName !== undefined &&
|
|
524
|
+
this.session.knownSlashCommands?.has(cmdName) === true;
|
|
525
|
+
if (commandMatch && !known) {
|
|
504
526
|
const cmd = commandMatch[1];
|
|
505
527
|
this.logger.warn(
|
|
506
528
|
"Slash command produced no output; treating as unsupported",
|
|
@@ -520,6 +542,8 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
520
542
|
}
|
|
521
543
|
this.logger.debug("Skipping idle state before prompt replay", {
|
|
522
544
|
sessionId: params.sessionId,
|
|
545
|
+
command: commandMatch?.[1],
|
|
546
|
+
known,
|
|
523
547
|
});
|
|
524
548
|
break;
|
|
525
549
|
}
|
|
@@ -1305,6 +1329,9 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
1305
1329
|
`Session ${forkSession ? "fork" : "resumption"} timed out for sessionId=${sessionId}`,
|
|
1306
1330
|
);
|
|
1307
1331
|
}
|
|
1332
|
+
session.knownSlashCommands = collectKnownSlashCommands(
|
|
1333
|
+
result.value.commands,
|
|
1334
|
+
);
|
|
1308
1335
|
} catch (err) {
|
|
1309
1336
|
settingsManager.dispose();
|
|
1310
1337
|
if (
|
|
@@ -1356,6 +1383,9 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
1356
1383
|
`Session initialization timed out for sessionId=${sessionId}`,
|
|
1357
1384
|
);
|
|
1358
1385
|
}
|
|
1386
|
+
session.knownSlashCommands = collectKnownSlashCommands(
|
|
1387
|
+
initResult.value.commands,
|
|
1388
|
+
);
|
|
1359
1389
|
} catch (err) {
|
|
1360
1390
|
settingsManager.dispose();
|
|
1361
1391
|
this.logger.error("Session initialization failed", {
|
|
@@ -68,6 +68,13 @@ export type Session = BaseSession & {
|
|
|
68
68
|
emitRawSDKMessages: boolean | SDKMessageFilter[];
|
|
69
69
|
/** Refreshed at session init and on MCP/skill changes. */
|
|
70
70
|
contextBreakdownBaseline?: ContextBreakdownBaseline;
|
|
71
|
+
/**
|
|
72
|
+
* Slash command names (without leading slash) the SDK recognizes for this
|
|
73
|
+
* session — built-ins plus plugin/skill commands. Captured from the SDK's
|
|
74
|
+
* init response. Used to distinguish "command produced no output" from
|
|
75
|
+
* "command is genuinely unknown" when the session goes idle without an echo.
|
|
76
|
+
*/
|
|
77
|
+
knownSlashCommands?: Set<string>;
|
|
71
78
|
};
|
|
72
79
|
|
|
73
80
|
export type ToolUseCache = {
|