assistant-cloud 0.2.1 → 0.2.2
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/README.md +23 -7
- package/dist/AssistantCloud.d.ts +1 -2
- package/dist/AssistantCloud.d.ts.map +1 -1
- package/dist/AssistantCloudAPI.d.ts +5 -6
- package/dist/AssistantCloudAPI.d.ts.map +1 -1
- package/dist/AssistantCloudAuthStrategy.d.ts +6 -7
- package/dist/AssistantCloudAuthStrategy.d.ts.map +1 -1
- package/dist/AssistantCloudAuthTokens.d.ts +1 -2
- package/dist/AssistantCloudAuthTokens.d.ts.map +1 -1
- package/dist/AssistantCloudEvents.d.ts +3 -4
- package/dist/AssistantCloudEvents.d.ts.map +1 -1
- package/dist/AssistantCloudEvents.js +1 -1
- package/dist/AssistantCloudEvents.js.map +1 -1
- package/dist/AssistantCloudFiles.d.ts +2 -3
- package/dist/AssistantCloudFiles.d.ts.map +1 -1
- package/dist/AssistantCloudProjectThreadMessages.d.ts +1 -2
- package/dist/AssistantCloudProjectThreadMessages.d.ts.map +1 -1
- package/dist/AssistantCloudProjectThreads.d.ts +1 -2
- package/dist/AssistantCloudProjectThreads.d.ts.map +1 -1
- package/dist/AssistantCloudProjects.d.ts +1 -2
- package/dist/AssistantCloudProjects.d.ts.map +1 -1
- package/dist/AssistantCloudRuns.d.ts +2 -3
- package/dist/AssistantCloudRuns.d.ts.map +1 -1
- package/dist/AssistantCloudScores.d.ts +3 -4
- package/dist/AssistantCloudScores.d.ts.map +1 -1
- package/dist/AssistantCloudThreadMessages.d.ts +7 -6
- package/dist/AssistantCloudThreadMessages.d.ts.map +1 -1
- package/dist/AssistantCloudThreadMessages.js +7 -2
- package/dist/AssistantCloudThreadMessages.js.map +1 -1
- package/dist/AssistantCloudThreads.d.ts +3 -4
- package/dist/AssistantCloudThreads.d.ts.map +1 -1
- package/dist/CloudEngagementReporter.d.ts +3 -4
- package/dist/CloudEngagementReporter.d.ts.map +1 -1
- package/dist/CloudMessagePersistence.d.ts +1 -2
- package/dist/CloudMessagePersistence.d.ts.map +1 -1
- package/dist/CloudRunReporter.d.ts +4 -5
- package/dist/CloudRunReporter.d.ts.map +1 -1
- package/dist/CloudRunReporter.js +13 -4
- package/dist/CloudRunReporter.js.map +1 -1
- package/dist/FormattedCloudPersistence.d.ts +2 -3
- package/dist/FormattedCloudPersistence.d.ts.map +1 -1
- package/dist/ai-sdk/index.d.ts +4 -5
- package/dist/ai-sdk/index.d.ts.map +1 -1
- package/dist/cloudResponse.d.ts +12 -13
- package/dist/cloudResponse.d.ts.map +1 -1
- package/dist/generateThreadTitle.d.ts +1 -2
- package/dist/generateThreadTitle.d.ts.map +1 -1
- package/dist/instrumentMcpSampling.d.ts +6 -7
- package/dist/instrumentMcpSampling.d.ts.map +1 -1
- package/dist/runTelemetry.d.ts +15 -16
- package/dist/runTelemetry.d.ts.map +1 -1
- package/dist/telemetry/index.d.ts +8 -9
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/version.d.ts +1 -2
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +10 -9
- package/src/AssistantCloudEvents.test.ts +41 -0
- package/src/AssistantCloudEvents.ts +1 -0
- package/src/AssistantCloudThreadMessages.test.ts +53 -2
- package/src/AssistantCloudThreadMessages.ts +13 -1
- package/src/CloudRunReporter.ts +16 -4
- package/src/tests/CloudRunReporter.test.ts +35 -0
|
@@ -49,11 +49,13 @@ const MESSAGE_FEEDBACK_TYPES = ["positive", "negative"] as const;
|
|
|
49
49
|
|
|
50
50
|
export type AssistantCloudThreadMessageFeedbackBody = {
|
|
51
51
|
type: "positive" | "negative";
|
|
52
|
+
comment?: string;
|
|
52
53
|
};
|
|
53
54
|
|
|
54
55
|
export type AssistantCloudThreadMessageFeedbackResponse = {
|
|
55
56
|
feedback_id: string;
|
|
56
57
|
type: "positive" | "negative";
|
|
58
|
+
comment?: string | null;
|
|
57
59
|
};
|
|
58
60
|
|
|
59
61
|
export const decodeCloudMessage = (
|
|
@@ -132,10 +134,17 @@ export class AssistantCloudThreadMessages {
|
|
|
132
134
|
messageId: string,
|
|
133
135
|
body: AssistantCloudThreadMessageFeedbackBody,
|
|
134
136
|
): Promise<AssistantCloudThreadMessageFeedbackResponse> {
|
|
137
|
+
const comment = body.comment?.trim();
|
|
135
138
|
const response = readCloudRecord(
|
|
136
139
|
await this.cloud.makeRequest(
|
|
137
140
|
`/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/feedback`,
|
|
138
|
-
{
|
|
141
|
+
{
|
|
142
|
+
method: "POST",
|
|
143
|
+
body: {
|
|
144
|
+
type: body.type,
|
|
145
|
+
...(comment ? { comment } : undefined),
|
|
146
|
+
},
|
|
147
|
+
},
|
|
139
148
|
),
|
|
140
149
|
"thread message feedback response",
|
|
141
150
|
);
|
|
@@ -143,6 +152,9 @@ export class AssistantCloudThreadMessages {
|
|
|
143
152
|
return {
|
|
144
153
|
feedback_id: readCloudString(response.feedback_id, "feedback_id"),
|
|
145
154
|
type: readCloudEnum(response.type, "type", MESSAGE_FEEDBACK_TYPES),
|
|
155
|
+
...("comment" in response
|
|
156
|
+
? { comment: readCloudNullableString(response.comment, "comment") }
|
|
157
|
+
: undefined),
|
|
146
158
|
};
|
|
147
159
|
}
|
|
148
160
|
}
|
package/src/CloudRunReporter.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AssistantCloud } from "./AssistantCloud";
|
|
2
|
+
import { CloudAPIError } from "./AssistantCloudAPI";
|
|
2
3
|
import { createRunReport, type RunReportInit } from "./runTelemetry";
|
|
3
4
|
|
|
4
5
|
export type CloudRunReportInit = Omit<RunReportInit, "telemetry">;
|
|
@@ -7,8 +8,8 @@ export type CloudRunReportInit = Omit<RunReportInit, "telemetry">;
|
|
|
7
8
|
* Sends run reports the way every client integration has to: nothing while
|
|
8
9
|
* telemetry is off, the cloud's environment, release and tags on every report,
|
|
9
10
|
* the `beforeReport` hook applied last, and a failed send that never surfaces.
|
|
10
|
-
* A report
|
|
11
|
-
* the
|
|
11
|
+
* A keyed report is deduplicated while in flight and after an attempt. A
|
|
12
|
+
* rate-limited attempt releases the key so a later observation can try again.
|
|
12
13
|
*/
|
|
13
14
|
export class CloudRunReporter {
|
|
14
15
|
private readonly reported = new Set<string>();
|
|
@@ -19,6 +20,7 @@ export class CloudRunReporter {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
public async report(init: CloudRunReportInit, key?: string): Promise<void> {
|
|
23
|
+
let claimedKey: string | undefined;
|
|
22
24
|
try {
|
|
23
25
|
const cloud = this.getCloud();
|
|
24
26
|
if (!cloud.telemetry.enabled) return;
|
|
@@ -29,10 +31,20 @@ export class CloudRunReporter {
|
|
|
29
31
|
const report = beforeReport ? beforeReport(initial) : initial;
|
|
30
32
|
if (!report) return;
|
|
31
33
|
|
|
32
|
-
if (key !== undefined)
|
|
34
|
+
if (key !== undefined) {
|
|
35
|
+
this.reported.add(key);
|
|
36
|
+
claimedKey = key;
|
|
37
|
+
}
|
|
33
38
|
await cloud.runs.report(report);
|
|
34
|
-
} catch {
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (claimedKey !== undefined && isRetryableReportError(error)) {
|
|
41
|
+
this.reported.delete(claimedKey);
|
|
42
|
+
}
|
|
35
43
|
return;
|
|
36
44
|
}
|
|
37
45
|
}
|
|
38
46
|
}
|
|
47
|
+
|
|
48
|
+
const isRetryableReportError = (error: unknown): boolean => {
|
|
49
|
+
return error instanceof CloudAPIError && error.status === 429;
|
|
50
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
2
|
import type { AssistantCloud } from "../AssistantCloud";
|
|
3
|
+
import { CloudAPIError } from "../AssistantCloudAPI";
|
|
3
4
|
import { CloudRunReporter } from "../CloudRunReporter";
|
|
5
|
+
import { CloudResponseError } from "../cloudResponse";
|
|
4
6
|
|
|
5
7
|
const createCloud = (telemetry: AssistantCloud["telemetry"]) => {
|
|
6
8
|
const report = vi.fn().mockResolvedValue({ run_id: "run_1" });
|
|
@@ -69,6 +71,39 @@ describe("CloudRunReporter", () => {
|
|
|
69
71
|
expect(report).toHaveBeenCalledTimes(3);
|
|
70
72
|
});
|
|
71
73
|
|
|
74
|
+
it("allows a keyed run to retry after rate limiting", async () => {
|
|
75
|
+
const { cloud, report } = createCloud({ enabled: true });
|
|
76
|
+
report.mockRejectedValueOnce(new CloudAPIError("rate limited", 429));
|
|
77
|
+
const reporter = new CloudRunReporter(cloud);
|
|
78
|
+
|
|
79
|
+
await reporter.report({ threadId: "t", status: "completed" }, "t:m");
|
|
80
|
+
await reporter.report({ threadId: "t", status: "completed" }, "t:m");
|
|
81
|
+
await reporter.report({ threadId: "t", status: "completed" }, "t:m");
|
|
82
|
+
|
|
83
|
+
expect(report).toHaveBeenCalledTimes(2);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it.each([
|
|
87
|
+
["a transport failure", new Error("offline")],
|
|
88
|
+
["a request timeout", new CloudAPIError("timeout", 408)],
|
|
89
|
+
["a server error", new CloudAPIError("unavailable", 503)],
|
|
90
|
+
[
|
|
91
|
+
"a successful response with an invalid body",
|
|
92
|
+
new CloudResponseError("invalid response"),
|
|
93
|
+
],
|
|
94
|
+
["a successful response with invalid JSON", new SyntaxError("invalid")],
|
|
95
|
+
["a permanent client error", new CloudAPIError("invalid report", 400)],
|
|
96
|
+
])("does not retry after %s", async (_name, error) => {
|
|
97
|
+
const { cloud, report } = createCloud({ enabled: true });
|
|
98
|
+
report.mockRejectedValueOnce(error);
|
|
99
|
+
const reporter = new CloudRunReporter(cloud);
|
|
100
|
+
|
|
101
|
+
await reporter.report({ threadId: "t", status: "completed" }, "t:m");
|
|
102
|
+
await reporter.report({ threadId: "t", status: "completed" }, "t:m");
|
|
103
|
+
|
|
104
|
+
expect(report).toHaveBeenCalledOnce();
|
|
105
|
+
});
|
|
106
|
+
|
|
72
107
|
it("swallows a failed send and reads the cloud through a getter", async () => {
|
|
73
108
|
const { cloud } = createCloud({ enabled: true });
|
|
74
109
|
(cloud.runs.report as ReturnType<typeof vi.fn>).mockRejectedValue(
|