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.
Files changed (63) hide show
  1. package/README.md +23 -7
  2. package/dist/AssistantCloud.d.ts +1 -2
  3. package/dist/AssistantCloud.d.ts.map +1 -1
  4. package/dist/AssistantCloudAPI.d.ts +5 -6
  5. package/dist/AssistantCloudAPI.d.ts.map +1 -1
  6. package/dist/AssistantCloudAuthStrategy.d.ts +6 -7
  7. package/dist/AssistantCloudAuthStrategy.d.ts.map +1 -1
  8. package/dist/AssistantCloudAuthTokens.d.ts +1 -2
  9. package/dist/AssistantCloudAuthTokens.d.ts.map +1 -1
  10. package/dist/AssistantCloudEvents.d.ts +3 -4
  11. package/dist/AssistantCloudEvents.d.ts.map +1 -1
  12. package/dist/AssistantCloudEvents.js +1 -1
  13. package/dist/AssistantCloudEvents.js.map +1 -1
  14. package/dist/AssistantCloudFiles.d.ts +2 -3
  15. package/dist/AssistantCloudFiles.d.ts.map +1 -1
  16. package/dist/AssistantCloudProjectThreadMessages.d.ts +1 -2
  17. package/dist/AssistantCloudProjectThreadMessages.d.ts.map +1 -1
  18. package/dist/AssistantCloudProjectThreads.d.ts +1 -2
  19. package/dist/AssistantCloudProjectThreads.d.ts.map +1 -1
  20. package/dist/AssistantCloudProjects.d.ts +1 -2
  21. package/dist/AssistantCloudProjects.d.ts.map +1 -1
  22. package/dist/AssistantCloudRuns.d.ts +2 -3
  23. package/dist/AssistantCloudRuns.d.ts.map +1 -1
  24. package/dist/AssistantCloudScores.d.ts +3 -4
  25. package/dist/AssistantCloudScores.d.ts.map +1 -1
  26. package/dist/AssistantCloudThreadMessages.d.ts +7 -6
  27. package/dist/AssistantCloudThreadMessages.d.ts.map +1 -1
  28. package/dist/AssistantCloudThreadMessages.js +7 -2
  29. package/dist/AssistantCloudThreadMessages.js.map +1 -1
  30. package/dist/AssistantCloudThreads.d.ts +3 -4
  31. package/dist/AssistantCloudThreads.d.ts.map +1 -1
  32. package/dist/CloudEngagementReporter.d.ts +3 -4
  33. package/dist/CloudEngagementReporter.d.ts.map +1 -1
  34. package/dist/CloudMessagePersistence.d.ts +1 -2
  35. package/dist/CloudMessagePersistence.d.ts.map +1 -1
  36. package/dist/CloudRunReporter.d.ts +4 -5
  37. package/dist/CloudRunReporter.d.ts.map +1 -1
  38. package/dist/CloudRunReporter.js +13 -4
  39. package/dist/CloudRunReporter.js.map +1 -1
  40. package/dist/FormattedCloudPersistence.d.ts +2 -3
  41. package/dist/FormattedCloudPersistence.d.ts.map +1 -1
  42. package/dist/ai-sdk/index.d.ts +4 -5
  43. package/dist/ai-sdk/index.d.ts.map +1 -1
  44. package/dist/cloudResponse.d.ts +12 -13
  45. package/dist/cloudResponse.d.ts.map +1 -1
  46. package/dist/generateThreadTitle.d.ts +1 -2
  47. package/dist/generateThreadTitle.d.ts.map +1 -1
  48. package/dist/instrumentMcpSampling.d.ts +6 -7
  49. package/dist/instrumentMcpSampling.d.ts.map +1 -1
  50. package/dist/runTelemetry.d.ts +15 -16
  51. package/dist/runTelemetry.d.ts.map +1 -1
  52. package/dist/telemetry/index.d.ts +8 -9
  53. package/dist/telemetry/index.d.ts.map +1 -1
  54. package/dist/version.d.ts +1 -2
  55. package/dist/version.d.ts.map +1 -1
  56. package/dist/version.js +1 -1
  57. package/package.json +10 -9
  58. package/src/AssistantCloudEvents.test.ts +41 -0
  59. package/src/AssistantCloudEvents.ts +1 -0
  60. package/src/AssistantCloudThreadMessages.test.ts +53 -2
  61. package/src/AssistantCloudThreadMessages.ts +13 -1
  62. package/src/CloudRunReporter.ts +16 -4
  63. 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
- { method: "POST", body },
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
  }
@@ -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 given a key is sent once per key, so an integration that observes
11
- * the same finished run twice reports it once.
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) this.reported.add(key);
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(