forked from github/copilot-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsdkTestHelper.ts
More file actions
108 lines (99 loc) · 3.8 KB
/
Copy pathsdkTestHelper.ts
File metadata and controls
108 lines (99 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------------------------------------------*/
import { AssistantMessageEvent } from "@github/copilot/sdk";
import { CopilotSession } from "../../../src";
export async function getFinalAssistantMessage(
session: CopilotSession
): Promise<AssistantMessageEvent> {
// We don't know whether the answer has already arrived or not, so race both possibilities
return new Promise<AssistantMessageEvent>(async (resolve, reject) => {
getFutureFinalResponse(session).then(resolve).catch(reject);
getExistingFinalResponse(session)
.then((msg) => {
if (msg) {
resolve(msg);
}
})
.catch(reject);
});
}
function getExistingFinalResponse(
session: CopilotSession
): Promise<AssistantMessageEvent | undefined> {
return new Promise<AssistantMessageEvent | undefined>(async (resolve, reject) => {
const messages = await session.getMessages();
const finalUserMessageIndex = messages.findLastIndex((m) => m.type === "user.message");
const currentTurnMessages =
finalUserMessageIndex < 0 ? messages : messages.slice(finalUserMessageIndex);
const currentTurnError = currentTurnMessages.find((m) => m.type === "session.error");
if (currentTurnError) {
const error = new Error(currentTurnError.data.message);
error.stack = currentTurnError.data.stack;
reject(error);
return;
}
const sessionIdleMessageIndex = currentTurnMessages.findIndex(
(m) => m.type === "session.idle"
);
if (sessionIdleMessageIndex !== -1) {
const lastAssistantMessage = currentTurnMessages
.slice(0, sessionIdleMessageIndex)
.findLast((m) => m.type === "assistant.message");
resolve(lastAssistantMessage as AssistantMessageEvent | undefined);
return;
}
resolve(undefined);
});
}
function getFutureFinalResponse(session: CopilotSession): Promise<AssistantMessageEvent> {
return new Promise<AssistantMessageEvent | undefined>((resolve, reject) => {
let finalAssistantMessage: AssistantMessageEvent | undefined;
session.on((event) => {
if (event.type === "assistant.message") {
finalAssistantMessage = event;
} else if (event.type === "session.idle") {
resolve(finalAssistantMessage);
} else if (event.type === "session.error") {
const error = new Error(event.data.message);
error.stack = event.data.stack;
reject(error);
}
});
});
}
export async function retry(
message: string,
fn: () => Promise<void>,
maxTries: number = 100,
delay: number = 100
) {
let failedAttempts = 0;
while (true) {
try {
await fn();
return;
} catch (error: unknown) {
failedAttempts++;
if (failedAttempts >= maxTries) {
throw new Error(
`Failed to ${message} after ${maxTries} attempts\n${formatError(error)}`
);
}
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}
export function formatError(error: unknown): string {
if (error instanceof Error) {
return String(error);
} else if (typeof error === "object" && error !== null) {
try {
return JSON.stringify(error);
} catch {
return "[object with circular reference]";
}
} else {
return String(error);
}
}