@posthog/agent 2.1.71 → 2.1.83
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.d.ts +22 -2
- package/dist/adapters/claude/permissions/permission-options.d.ts +3 -1
- package/dist/adapters/claude/permissions/permission-options.js +5 -2
- package/dist/adapters/claude/permissions/permission-options.js.map +1 -1
- package/dist/adapters/claude/questions/utils.d.ts +1 -0
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/agent.d.ts +30 -5
- package/dist/agent.js +22 -12
- package/dist/agent.js.map +1 -1
- package/dist/gateway-models.d.ts +1 -2
- package/dist/gateway-models.js +0 -5
- package/dist/gateway-models.js.map +1 -1
- package/dist/index.d.ts +1 -257
- package/dist/index.js +1 -10532
- package/dist/index.js.map +1 -1
- package/dist/server/agent-server.js +31 -17
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +31 -17
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -4
- package/src/acp-extensions.ts +0 -98
- package/src/adapters/acp-connection.ts +6 -5
- package/src/adapters/claude/claude-agent.ts +1 -1
- package/src/adapters/claude/conversion/sdk-to-acp.ts +6 -3
- package/src/adapters/claude/mcp/tool-metadata.ts +8 -5
- package/src/adapters/claude/permissions/permission-handlers.ts +2 -1
- package/src/adapters/claude/permissions/permission-options.ts +10 -1
- package/src/adapters/claude/session/options.ts +11 -2
- package/src/agent.ts +2 -2
- package/src/gateway-models.ts +0 -7
- package/src/index.ts +1 -79
- package/src/sagas/apply-snapshot-saga.ts +6 -3
- package/src/sagas/capture-tree-saga.test.ts +1 -1
- package/src/test/mocks/msw-handlers.ts +0 -3
- package/dist/agent-DK1apkaG.d.ts +0 -133
- package/dist/logger-DDBiMOOD.d.ts +0 -24
- package/src/adapters/claude/tool-meta.ts +0 -143
- package/src/test/assertions.ts +0 -114
- package/src/test/controllers/sse-controller.ts +0 -107
- package/src/test/fixtures/notifications.ts +0 -92
- package/src/test/setup.ts +0 -114
- package/src/test/wait.ts +0 -41
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
const QuestionOptionSchema = z.object({
|
|
4
|
-
label: z.string(),
|
|
5
|
-
description: z.string().optional(),
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
const QuestionItemSchema = z.object({
|
|
9
|
-
question: z.string(),
|
|
10
|
-
header: z.string().optional(),
|
|
11
|
-
options: z.array(QuestionOptionSchema),
|
|
12
|
-
multiSelect: z.boolean().optional(),
|
|
13
|
-
completed: z.boolean().optional(),
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
export const QuestionMetaSchema = z.object({
|
|
17
|
-
questions: z.array(QuestionItemSchema),
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
export type QuestionOption = z.infer<typeof QuestionOptionSchema>;
|
|
21
|
-
export type QuestionItem = z.infer<typeof QuestionItemSchema>;
|
|
22
|
-
export type QuestionMeta = z.infer<typeof QuestionMetaSchema>;
|
|
23
|
-
|
|
24
|
-
const toolSchemas = {
|
|
25
|
-
bash: z.object({
|
|
26
|
-
command: z.string(),
|
|
27
|
-
description: z.string().optional(),
|
|
28
|
-
}),
|
|
29
|
-
edit: z.object({
|
|
30
|
-
file_path: z.string(),
|
|
31
|
-
old_string: z.string(),
|
|
32
|
-
new_string: z.string(),
|
|
33
|
-
replace_all: z.boolean().optional(),
|
|
34
|
-
}),
|
|
35
|
-
write: z.object({
|
|
36
|
-
file_path: z.string(),
|
|
37
|
-
content: z.string(),
|
|
38
|
-
}),
|
|
39
|
-
read: z.object({
|
|
40
|
-
file_path: z.string(),
|
|
41
|
-
offset: z.number().optional(),
|
|
42
|
-
limit: z.number().optional(),
|
|
43
|
-
}),
|
|
44
|
-
switch_mode: z.object({
|
|
45
|
-
plan: z.string().optional(),
|
|
46
|
-
}),
|
|
47
|
-
} as const;
|
|
48
|
-
|
|
49
|
-
type ToolKind = keyof typeof toolSchemas;
|
|
50
|
-
const _toolKinds = Object.keys(toolSchemas) as ToolKind[];
|
|
51
|
-
|
|
52
|
-
const sdkToolNameToKind: Record<string, ToolKind> = {
|
|
53
|
-
Bash: "bash",
|
|
54
|
-
Edit: "edit",
|
|
55
|
-
Write: "write",
|
|
56
|
-
Read: "read",
|
|
57
|
-
ExitPlanMode: "switch_mode",
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const BaseTwigToolMetaSchema = z.object({
|
|
61
|
-
claudeCode: z
|
|
62
|
-
.object({
|
|
63
|
-
toolName: z.string(),
|
|
64
|
-
toolResponse: z.unknown().optional(),
|
|
65
|
-
})
|
|
66
|
-
.optional(),
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
type BaseMeta = z.infer<typeof BaseTwigToolMetaSchema>;
|
|
70
|
-
|
|
71
|
-
type ToolMeta<K extends ToolKind> = BaseMeta & {
|
|
72
|
-
twigToolKind: K;
|
|
73
|
-
} & { [P in K]: z.infer<(typeof toolSchemas)[K]> };
|
|
74
|
-
|
|
75
|
-
export type BashToolMeta = ToolMeta<"bash">;
|
|
76
|
-
export type EditToolMeta = ToolMeta<"edit">;
|
|
77
|
-
export type WriteToolMeta = ToolMeta<"write">;
|
|
78
|
-
export type ReadToolMeta = ToolMeta<"read">;
|
|
79
|
-
export type SwitchModeToolMeta = ToolMeta<"switch_mode">;
|
|
80
|
-
export type QuestionToolMeta = BaseMeta & {
|
|
81
|
-
twigToolKind: "question";
|
|
82
|
-
questions: QuestionItem[];
|
|
83
|
-
};
|
|
84
|
-
export type GenericToolMeta = BaseMeta & { twigToolKind?: undefined };
|
|
85
|
-
|
|
86
|
-
export type TwigToolMeta =
|
|
87
|
-
| BashToolMeta
|
|
88
|
-
| EditToolMeta
|
|
89
|
-
| WriteToolMeta
|
|
90
|
-
| ReadToolMeta
|
|
91
|
-
| SwitchModeToolMeta
|
|
92
|
-
| QuestionToolMeta
|
|
93
|
-
| GenericToolMeta;
|
|
94
|
-
|
|
95
|
-
export function isBashToolMeta(meta: TwigToolMeta): meta is BashToolMeta {
|
|
96
|
-
return meta.twigToolKind === "bash";
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function isEditToolMeta(meta: TwigToolMeta): meta is EditToolMeta {
|
|
100
|
-
return meta.twigToolKind === "edit";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function isWriteToolMeta(meta: TwigToolMeta): meta is WriteToolMeta {
|
|
104
|
-
return meta.twigToolKind === "write";
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function isReadToolMeta(meta: TwigToolMeta): meta is ReadToolMeta {
|
|
108
|
-
return meta.twigToolKind === "read";
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function isSwitchModeToolMeta(
|
|
112
|
-
meta: TwigToolMeta,
|
|
113
|
-
): meta is SwitchModeToolMeta {
|
|
114
|
-
return meta.twigToolKind === "switch_mode";
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function isQuestionToolMeta(
|
|
118
|
-
meta: TwigToolMeta,
|
|
119
|
-
): meta is QuestionToolMeta {
|
|
120
|
-
return meta.twigToolKind === "question";
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export function buildToolMeta(
|
|
124
|
-
toolName: string,
|
|
125
|
-
input: Record<string, unknown>,
|
|
126
|
-
): TwigToolMeta {
|
|
127
|
-
const kind = sdkToolNameToKind[toolName];
|
|
128
|
-
if (!kind) {
|
|
129
|
-
return { claudeCode: { toolName } };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const schema = toolSchemas[kind];
|
|
133
|
-
const result = schema.safeParse(input);
|
|
134
|
-
if (!result.success) {
|
|
135
|
-
return { claudeCode: { toolName } };
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
claudeCode: { toolName },
|
|
140
|
-
twigToolKind: kind,
|
|
141
|
-
[kind]: result.data,
|
|
142
|
-
} as TwigToolMeta;
|
|
143
|
-
}
|
package/src/test/assertions.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { expect } from "vitest";
|
|
2
|
-
|
|
3
|
-
export interface NotificationEntry {
|
|
4
|
-
notification?: {
|
|
5
|
-
method?: string;
|
|
6
|
-
params?: {
|
|
7
|
-
sessionId?: string;
|
|
8
|
-
update?: {
|
|
9
|
-
sessionUpdate?: string;
|
|
10
|
-
content?: {
|
|
11
|
-
type?: string;
|
|
12
|
-
text?: string;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface NotificationMatcher {
|
|
20
|
-
method?: string;
|
|
21
|
-
text?: string;
|
|
22
|
-
sessionId?: string;
|
|
23
|
-
sessionUpdate?: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function entryMatchesNotification(
|
|
27
|
-
entry: unknown,
|
|
28
|
-
matcher: NotificationMatcher,
|
|
29
|
-
): boolean {
|
|
30
|
-
const notification = (entry as NotificationEntry).notification;
|
|
31
|
-
if (!notification) return false;
|
|
32
|
-
|
|
33
|
-
if (matcher.method && notification.method !== matcher.method) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
if (
|
|
37
|
-
matcher.sessionId &&
|
|
38
|
-
notification.params?.sessionId !== matcher.sessionId
|
|
39
|
-
) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
if (
|
|
43
|
-
matcher.sessionUpdate &&
|
|
44
|
-
notification.params?.update?.sessionUpdate !== matcher.sessionUpdate
|
|
45
|
-
) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
if (matcher.text) {
|
|
49
|
-
const text = notification.params?.update?.content?.text;
|
|
50
|
-
if (!text || !text.includes(matcher.text)) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function findNotification(
|
|
58
|
-
appendLogCalls: unknown[][],
|
|
59
|
-
matcher: NotificationMatcher,
|
|
60
|
-
): NotificationEntry | undefined {
|
|
61
|
-
for (const entries of appendLogCalls) {
|
|
62
|
-
for (const entry of entries) {
|
|
63
|
-
if (entryMatchesNotification(entry, matcher)) {
|
|
64
|
-
return entry as NotificationEntry;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function hasNotification(
|
|
72
|
-
appendLogCalls: unknown[][],
|
|
73
|
-
matcher: NotificationMatcher,
|
|
74
|
-
): boolean {
|
|
75
|
-
return findNotification(appendLogCalls, matcher) !== undefined;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function expectNotification(
|
|
79
|
-
appendLogCalls: unknown[][],
|
|
80
|
-
matcher: NotificationMatcher,
|
|
81
|
-
): NotificationEntry {
|
|
82
|
-
const found = findNotification(appendLogCalls, matcher);
|
|
83
|
-
expect(
|
|
84
|
-
found,
|
|
85
|
-
`Expected notification matching ${JSON.stringify(matcher)}`,
|
|
86
|
-
).toBeDefined();
|
|
87
|
-
return found!;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function expectNoNotification(
|
|
91
|
-
appendLogCalls: unknown[][],
|
|
92
|
-
matcher: NotificationMatcher,
|
|
93
|
-
): void {
|
|
94
|
-
const found = findNotification(appendLogCalls, matcher);
|
|
95
|
-
expect(
|
|
96
|
-
found,
|
|
97
|
-
`Expected no notification matching ${JSON.stringify(matcher)}`,
|
|
98
|
-
).toBeUndefined();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function countNotifications(
|
|
102
|
-
appendLogCalls: unknown[][],
|
|
103
|
-
matcher: NotificationMatcher,
|
|
104
|
-
): number {
|
|
105
|
-
let count = 0;
|
|
106
|
-
for (const entries of appendLogCalls) {
|
|
107
|
-
for (const entry of entries) {
|
|
108
|
-
if (entryMatchesNotification(entry, matcher)) {
|
|
109
|
-
count++;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return count;
|
|
114
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
type SseState = "idle" | "streaming" | "closing" | "closed";
|
|
2
|
-
|
|
3
|
-
export interface EventOptions {
|
|
4
|
-
id?: string;
|
|
5
|
-
event?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export class SseController {
|
|
9
|
-
private encoder = new TextEncoder();
|
|
10
|
-
private controller: ReadableStreamDefaultController<Uint8Array> | null = null;
|
|
11
|
-
private state: SseState = "idle";
|
|
12
|
-
|
|
13
|
-
createStream(): ReadableStream<Uint8Array> {
|
|
14
|
-
return new ReadableStream({
|
|
15
|
-
start: (controller) => {
|
|
16
|
-
this.controller = controller;
|
|
17
|
-
this.state = "streaming";
|
|
18
|
-
},
|
|
19
|
-
cancel: () => {
|
|
20
|
-
this.state = "closed";
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
sendEvent(data: unknown, options: EventOptions = {}): boolean {
|
|
26
|
-
if (
|
|
27
|
-
this.state === "closed" ||
|
|
28
|
-
this.state === "closing" ||
|
|
29
|
-
!this.controller
|
|
30
|
-
) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const lines: string[] = [];
|
|
35
|
-
if (options.id) {
|
|
36
|
-
lines.push(`id: ${options.id}`);
|
|
37
|
-
}
|
|
38
|
-
if (options.event) {
|
|
39
|
-
lines.push(`event: ${options.event}`);
|
|
40
|
-
}
|
|
41
|
-
lines.push(`data: ${JSON.stringify(data)}`);
|
|
42
|
-
lines.push("");
|
|
43
|
-
lines.push("");
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
this.controller.enqueue(this.encoder.encode(lines.join("\n")));
|
|
47
|
-
return true;
|
|
48
|
-
} catch {
|
|
49
|
-
this.state = "closed";
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
sendRaw(rawData: string): boolean {
|
|
55
|
-
if (
|
|
56
|
-
this.state === "closed" ||
|
|
57
|
-
this.state === "closing" ||
|
|
58
|
-
!this.controller
|
|
59
|
-
) {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
try {
|
|
63
|
-
this.controller.enqueue(this.encoder.encode(rawData));
|
|
64
|
-
return true;
|
|
65
|
-
} catch {
|
|
66
|
-
this.state = "closed";
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
sendPartial(partialData: string): boolean {
|
|
72
|
-
return this.sendRaw(partialData);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
error(err: Error): void {
|
|
76
|
-
if (this.state !== "streaming" || !this.controller) return;
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
this.state = "closed";
|
|
80
|
-
this.controller.error(err);
|
|
81
|
-
} catch {
|
|
82
|
-
// Already errored or closed
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
close(): void {
|
|
87
|
-
if (this.state === "closed") return;
|
|
88
|
-
|
|
89
|
-
this.state = "closing";
|
|
90
|
-
if (this.controller) {
|
|
91
|
-
try {
|
|
92
|
-
this.controller.close();
|
|
93
|
-
} catch {
|
|
94
|
-
// Already closed
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
this.state = "closed";
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
get closed(): boolean {
|
|
101
|
-
return this.state === "closed";
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
get currentState(): SseState {
|
|
105
|
-
return this.state;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { POSTHOG_NOTIFICATIONS } from "../../acp-extensions.js";
|
|
2
|
-
import type { StoredNotification } from "../../types.js";
|
|
3
|
-
|
|
4
|
-
export function createNotification(
|
|
5
|
-
method: string,
|
|
6
|
-
params: Record<string, unknown>,
|
|
7
|
-
): StoredNotification {
|
|
8
|
-
return {
|
|
9
|
-
type: "notification",
|
|
10
|
-
timestamp: new Date().toISOString(),
|
|
11
|
-
notification: {
|
|
12
|
-
jsonrpc: "2.0",
|
|
13
|
-
method,
|
|
14
|
-
params,
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function createUserMessage(content: string): StoredNotification {
|
|
20
|
-
return createNotification("session/update", {
|
|
21
|
-
update: {
|
|
22
|
-
sessionUpdate: "user_message",
|
|
23
|
-
content: { type: "text", text: content },
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function createAgentChunk(text: string): StoredNotification {
|
|
29
|
-
return createNotification("session/update", {
|
|
30
|
-
update: {
|
|
31
|
-
sessionUpdate: "agent_message_chunk",
|
|
32
|
-
content: { type: "text", text },
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function createToolCall(
|
|
38
|
-
toolCallId: string,
|
|
39
|
-
toolName: string,
|
|
40
|
-
toolInput: unknown,
|
|
41
|
-
): StoredNotification {
|
|
42
|
-
return createNotification("session/update", {
|
|
43
|
-
update: {
|
|
44
|
-
sessionUpdate: "tool_call",
|
|
45
|
-
_meta: {
|
|
46
|
-
claudeCode: { toolCallId, toolName, toolInput },
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function createToolResult(
|
|
53
|
-
toolCallId: string,
|
|
54
|
-
toolResponse: unknown,
|
|
55
|
-
): StoredNotification {
|
|
56
|
-
return createNotification("session/update", {
|
|
57
|
-
update: {
|
|
58
|
-
sessionUpdate: "tool_result",
|
|
59
|
-
_meta: {
|
|
60
|
-
claudeCode: { toolCallId, toolResponse },
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function createTreeSnapshotNotification(
|
|
67
|
-
treeHash: string,
|
|
68
|
-
archiveUrl?: string,
|
|
69
|
-
options: { interrupted?: boolean; device?: { type: "local" | "cloud" } } = {},
|
|
70
|
-
): StoredNotification {
|
|
71
|
-
return createNotification(POSTHOG_NOTIFICATIONS.TREE_SNAPSHOT, {
|
|
72
|
-
treeHash,
|
|
73
|
-
baseCommit: "abc123",
|
|
74
|
-
archiveUrl,
|
|
75
|
-
changes: [{ path: "file.ts", status: "A" }],
|
|
76
|
-
timestamp: new Date().toISOString(),
|
|
77
|
-
...options,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function createStatusNotification(
|
|
82
|
-
status: "connected" | "disconnected" | "error",
|
|
83
|
-
message?: string,
|
|
84
|
-
): StoredNotification {
|
|
85
|
-
return createNotification("session/update", {
|
|
86
|
-
update: {
|
|
87
|
-
sessionUpdate: "status",
|
|
88
|
-
status,
|
|
89
|
-
message,
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
}
|
package/src/test/setup.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { type SetupServerApi, setupServer } from "msw/node";
|
|
2
|
-
import { AgentServer } from "../server/agent-server.js";
|
|
3
|
-
import { SseController } from "./controllers/sse-controller.js";
|
|
4
|
-
import { createTestRepo, type TestRepo } from "./fixtures/api.js";
|
|
5
|
-
import {
|
|
6
|
-
type AgentServerConfig,
|
|
7
|
-
createAgentServerConfig,
|
|
8
|
-
} from "./fixtures/config.js";
|
|
9
|
-
import { createPostHogHandlers } from "./mocks/msw-handlers.js";
|
|
10
|
-
|
|
11
|
-
export interface TestContext {
|
|
12
|
-
repo: TestRepo;
|
|
13
|
-
sseController: SseController;
|
|
14
|
-
appendLogCalls: unknown[][];
|
|
15
|
-
server: SetupServerApi;
|
|
16
|
-
agentServer: AgentServer;
|
|
17
|
-
config: AgentServerConfig;
|
|
18
|
-
createAgentServer: (overrides?: Partial<AgentServerConfig>) => AgentServer;
|
|
19
|
-
resetSseController: () => SseController;
|
|
20
|
-
cleanup: () => Promise<void>;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface CreateTestContextOptions {
|
|
24
|
-
configOverrides?: Partial<AgentServerConfig>;
|
|
25
|
-
autoStart?: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function createTestContext(
|
|
29
|
-
options: CreateTestContextOptions = {},
|
|
30
|
-
): Promise<TestContext> {
|
|
31
|
-
const repo = await createTestRepo("agent-server");
|
|
32
|
-
let sseController = new SseController();
|
|
33
|
-
const appendLogCalls: unknown[][] = [];
|
|
34
|
-
|
|
35
|
-
const server = setupServer(
|
|
36
|
-
...createPostHogHandlers({
|
|
37
|
-
baseUrl: "http://localhost:8000",
|
|
38
|
-
onAppendLog: (entries) => appendLogCalls.push(entries),
|
|
39
|
-
}),
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
server.listen({ onUnhandledRequest: "bypass" });
|
|
43
|
-
|
|
44
|
-
const config = createAgentServerConfig(repo, options.configOverrides);
|
|
45
|
-
|
|
46
|
-
const agentServer = new AgentServer(config);
|
|
47
|
-
|
|
48
|
-
const createAgentServer = (overrides: Partial<AgentServerConfig> = {}) => {
|
|
49
|
-
return new AgentServer({
|
|
50
|
-
...config,
|
|
51
|
-
...overrides,
|
|
52
|
-
});
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const resetSseController = () => {
|
|
56
|
-
sseController.close();
|
|
57
|
-
sseController = new SseController();
|
|
58
|
-
return sseController;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const cleanup = async () => {
|
|
62
|
-
sseController.close();
|
|
63
|
-
server.close();
|
|
64
|
-
await repo.cleanup();
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
repo,
|
|
69
|
-
sseController,
|
|
70
|
-
appendLogCalls,
|
|
71
|
-
server,
|
|
72
|
-
agentServer,
|
|
73
|
-
config,
|
|
74
|
-
createAgentServer,
|
|
75
|
-
resetSseController,
|
|
76
|
-
cleanup,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export {
|
|
81
|
-
expectNoNotification,
|
|
82
|
-
expectNotification,
|
|
83
|
-
findNotification,
|
|
84
|
-
hasNotification,
|
|
85
|
-
} from "./assertions.js";
|
|
86
|
-
export {
|
|
87
|
-
createMockApiClient,
|
|
88
|
-
createTaskRun,
|
|
89
|
-
createTestRepo,
|
|
90
|
-
type TestRepo,
|
|
91
|
-
} from "./fixtures/api.js";
|
|
92
|
-
export { createAgentServerConfig } from "./fixtures/config.js";
|
|
93
|
-
export {
|
|
94
|
-
createAgentChunk,
|
|
95
|
-
createNotification,
|
|
96
|
-
createStatusNotification,
|
|
97
|
-
createToolCall,
|
|
98
|
-
createToolResult,
|
|
99
|
-
createTreeSnapshotNotification,
|
|
100
|
-
createUserMessage,
|
|
101
|
-
} from "./fixtures/notifications.js";
|
|
102
|
-
export {
|
|
103
|
-
createErrorResult,
|
|
104
|
-
createInitMessage,
|
|
105
|
-
createMockQuery,
|
|
106
|
-
createSuccessResult,
|
|
107
|
-
type MockQuery,
|
|
108
|
-
} from "./mocks/claude-sdk.js";
|
|
109
|
-
export { createPostHogHandlers, SseController } from "./mocks/msw-handlers.js";
|
|
110
|
-
export {
|
|
111
|
-
waitForArrayLength,
|
|
112
|
-
waitForCallCount,
|
|
113
|
-
waitForCondition,
|
|
114
|
-
} from "./wait.js";
|
package/src/test/wait.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export interface WaitOptions {
|
|
2
|
-
timeout?: number;
|
|
3
|
-
interval?: number;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export async function waitForCondition(
|
|
7
|
-
condition: () => boolean | Promise<boolean>,
|
|
8
|
-
options: WaitOptions = {},
|
|
9
|
-
): Promise<void> {
|
|
10
|
-
const { timeout = 1000, interval = 20 } = options;
|
|
11
|
-
const start = Date.now();
|
|
12
|
-
|
|
13
|
-
while (true) {
|
|
14
|
-
const result = await condition();
|
|
15
|
-
if (result) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (Date.now() - start > timeout) {
|
|
20
|
-
throw new Error(`Condition not met within ${timeout}ms`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
await new Promise((r) => setTimeout(r, interval));
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function waitForArrayLength<T>(
|
|
28
|
-
getArray: () => T[],
|
|
29
|
-
minLength: number,
|
|
30
|
-
options: WaitOptions = {},
|
|
31
|
-
): Promise<void> {
|
|
32
|
-
await waitForCondition(() => getArray().length >= minLength, options);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export async function waitForCallCount(
|
|
36
|
-
mockFn: { mock: { calls: unknown[][] } },
|
|
37
|
-
minCalls: number,
|
|
38
|
-
options: WaitOptions = {},
|
|
39
|
-
): Promise<void> {
|
|
40
|
-
await waitForCondition(() => mockFn.mock.calls.length >= minCalls, options);
|
|
41
|
-
}
|