assistant-cloud 0.1.34 → 0.1.36

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 (74) hide show
  1. package/dist/AssistantCloud.d.ts +2 -1
  2. package/dist/AssistantCloud.d.ts.map +1 -1
  3. package/dist/AssistantCloud.js +4 -1
  4. package/dist/AssistantCloud.js.map +1 -1
  5. package/dist/AssistantCloudAPI.d.ts +5 -2
  6. package/dist/AssistantCloudAPI.d.ts.map +1 -1
  7. package/dist/AssistantCloudAPI.js +21 -11
  8. package/dist/AssistantCloudAPI.js.map +1 -1
  9. package/dist/AssistantCloudAuthStrategy.d.ts +2 -0
  10. package/dist/AssistantCloudAuthStrategy.d.ts.map +1 -1
  11. package/dist/AssistantCloudAuthStrategy.js +51 -10
  12. package/dist/AssistantCloudAuthStrategy.js.map +1 -1
  13. package/dist/AssistantCloudAuthTokens.d.ts +0 -1
  14. package/dist/AssistantCloudAuthTokens.d.ts.map +1 -1
  15. package/dist/AssistantCloudFiles.d.ts +0 -1
  16. package/dist/AssistantCloudFiles.d.ts.map +1 -1
  17. package/dist/AssistantCloudProjectThreadMessages.d.ts +19 -0
  18. package/dist/AssistantCloudProjectThreadMessages.d.ts.map +1 -0
  19. package/dist/AssistantCloudProjectThreadMessages.js +16 -0
  20. package/dist/AssistantCloudProjectThreadMessages.js.map +1 -0
  21. package/dist/AssistantCloudProjectThreads.d.ts +21 -0
  22. package/dist/AssistantCloudProjectThreads.d.ts.map +1 -0
  23. package/dist/AssistantCloudProjectThreads.js +22 -0
  24. package/dist/AssistantCloudProjectThreads.js.map +1 -0
  25. package/dist/AssistantCloudProjects.d.ts +10 -0
  26. package/dist/AssistantCloudProjects.d.ts.map +1 -0
  27. package/dist/AssistantCloudProjects.js +12 -0
  28. package/dist/AssistantCloudProjects.js.map +1 -0
  29. package/dist/AssistantCloudRuns.d.ts +0 -1
  30. package/dist/AssistantCloudRuns.d.ts.map +1 -1
  31. package/dist/AssistantCloudThreadMessages.d.ts +2 -2
  32. package/dist/AssistantCloudThreadMessages.d.ts.map +1 -1
  33. package/dist/AssistantCloudThreadMessages.js +15 -2
  34. package/dist/AssistantCloudThreadMessages.js.map +1 -1
  35. package/dist/AssistantCloudThreads.d.ts +2 -2
  36. package/dist/AssistantCloudThreads.d.ts.map +1 -1
  37. package/dist/AssistantCloudThreads.js +20 -3
  38. package/dist/AssistantCloudThreads.js.map +1 -1
  39. package/dist/CloudMessagePersistence.d.ts +2 -2
  40. package/dist/CloudMessagePersistence.d.ts.map +1 -1
  41. package/dist/CloudMessagePersistence.js +11 -6
  42. package/dist/CloudMessagePersistence.js.map +1 -1
  43. package/dist/FormattedCloudPersistence.d.ts +0 -1
  44. package/dist/FormattedCloudPersistence.d.ts.map +1 -1
  45. package/dist/cloudResponse.d.ts +16 -0
  46. package/dist/cloudResponse.d.ts.map +1 -0
  47. package/dist/cloudResponse.js +43 -0
  48. package/dist/cloudResponse.js.map +1 -0
  49. package/dist/index.d.ts +3 -2
  50. package/dist/index.js +3 -1
  51. package/dist/instrumentMcpSampling.d.ts.map +1 -1
  52. package/dist/tests/setup.d.ts +1 -1
  53. package/dist/tests/setup.js +2 -4
  54. package/dist/tests/setup.js.map +1 -1
  55. package/package.json +5 -5
  56. package/src/AssistantCloud.ts +3 -0
  57. package/src/AssistantCloudAPI.ts +31 -13
  58. package/src/AssistantCloudAuthStrategy.ts +68 -24
  59. package/src/AssistantCloudProjectThreadMessages.ts +40 -0
  60. package/src/AssistantCloudProjectThreads.ts +47 -0
  61. package/src/AssistantCloudProjects.ts +10 -0
  62. package/src/AssistantCloudThreadMessages.test.ts +41 -0
  63. package/src/AssistantCloudThreadMessages.ts +38 -3
  64. package/src/AssistantCloudThreads.test.ts +74 -0
  65. package/src/AssistantCloudThreads.ts +51 -3
  66. package/src/CloudMessagePersistence.ts +18 -5
  67. package/src/cloudResponse.test.ts +28 -0
  68. package/src/cloudResponse.ts +72 -0
  69. package/src/index.ts +2 -0
  70. package/src/tests/AssistantCloudAPI.test.ts +147 -8
  71. package/src/tests/AssistantCloudAuthStrategy.test.ts +191 -0
  72. package/src/tests/AssistantCloudProjects.test.ts +121 -0
  73. package/src/tests/CloudMessagePersistence.test.ts +40 -0
  74. package/src/tests/setup.ts +2 -9
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantCloudThreadMessages.js","names":[],"sources":["../src/AssistantCloudThreadMessages.ts"],"sourcesContent":["import type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport type { AssistantCloudAPI } from \"./AssistantCloudAPI\";\n\nexport type CloudMessage = {\n id: string;\n parent_id: string | null;\n height: number;\n created_at: Date;\n updated_at: Date;\n format: \"aui/v0\" | string;\n content: ReadonlyJSONObject;\n};\n\ntype AssistantCloudThreadMessageListQuery = {\n format?: string;\n};\n\ntype AssistantCloudThreadMessageListResponse = {\n messages: CloudMessage[];\n};\n\ntype AssistantCloudThreadMessageCreateBody = {\n parent_id: string | null;\n format: \"aui/v0\" | string;\n content: ReadonlyJSONObject;\n};\n\ntype AssistantCloudMessageCreateResponse = {\n message_id: string;\n};\n\ntype AssistantCloudThreadMessageUpdateBody = {\n content: ReadonlyJSONObject;\n};\n\nexport class AssistantCloudThreadMessages {\n constructor(private cloud: AssistantCloudAPI) {}\n\n public async list(\n threadId: string,\n query?: AssistantCloudThreadMessageListQuery,\n ): Promise<AssistantCloudThreadMessageListResponse> {\n return this.cloud.makeRequest(\n `/threads/${encodeURIComponent(threadId)}/messages`,\n { query },\n );\n }\n\n public async create(\n threadId: string,\n body: AssistantCloudThreadMessageCreateBody,\n ): Promise<AssistantCloudMessageCreateResponse> {\n return this.cloud.makeRequest(\n `/threads/${encodeURIComponent(threadId)}/messages`,\n { method: \"POST\", body },\n );\n }\n\n public async update(\n threadId: string,\n messageId: string,\n body: AssistantCloudThreadMessageUpdateBody,\n ): Promise<void> {\n return this.cloud.makeRequest(\n `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}`,\n { method: \"PUT\", body },\n );\n }\n}\n"],"mappings":";AAmCA,IAAa,+BAAb,MAA0C;CACpB;CAApB,YAAY,OAAkC;EAA1B,KAAA,QAAA;CAA2B;CAE/C,MAAa,KACX,UACA,OACkD;EAClD,OAAO,KAAK,MAAM,YAChB,YAAY,mBAAmB,QAAQ,EAAE,YACzC,EAAE,MAAM,CACV;CACF;CAEA,MAAa,OACX,UACA,MAC8C;EAC9C,OAAO,KAAK,MAAM,YAChB,YAAY,mBAAmB,QAAQ,EAAE,YACzC;GAAE,QAAQ;GAAQ;EAAK,CACzB;CACF;CAEA,MAAa,OACX,UACA,WACA,MACe;EACf,OAAO,KAAK,MAAM,YAChB,YAAY,mBAAmB,QAAQ,EAAE,YAAY,mBAAmB,SAAS,KACjF;GAAE,QAAQ;GAAO;EAAK,CACxB;CACF;AACF"}
1
+ {"version":3,"file":"AssistantCloudThreadMessages.js","names":[],"sources":["../src/AssistantCloudThreadMessages.ts"],"sourcesContent":["import type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport type { AssistantCloudAPI } from \"./AssistantCloudAPI\";\nimport {\n readCloudArray,\n readCloudInteger,\n readCloudJSONObject,\n readCloudNullableString,\n readCloudRecord,\n readCloudString,\n readCloudTimestamp,\n} from \"./cloudResponse\";\n\nexport type CloudMessage = {\n id: string;\n parent_id: string | null;\n height: number;\n created_at: Date;\n updated_at: Date;\n format: \"aui/v0\" | string;\n content: ReadonlyJSONObject;\n};\n\ntype AssistantCloudThreadMessageListQuery = {\n format?: string;\n};\n\ntype AssistantCloudThreadMessageListResponse = {\n messages: CloudMessage[];\n};\n\ntype AssistantCloudThreadMessageCreateBody = {\n parent_id: string | null;\n format: \"aui/v0\" | string;\n content: ReadonlyJSONObject;\n};\n\ntype AssistantCloudMessageCreateResponse = {\n message_id: string;\n};\n\ntype AssistantCloudThreadMessageUpdateBody = {\n content: ReadonlyJSONObject;\n};\n\nexport const decodeCloudMessage = (\n value: unknown,\n field: string,\n): CloudMessage => {\n const message = readCloudRecord(value, field);\n return {\n id: readCloudString(message.id, `${field}.id`),\n parent_id: readCloudNullableString(message.parent_id, `${field}.parent_id`),\n height: readCloudInteger(message.height, `${field}.height`),\n created_at: readCloudTimestamp(message.created_at, `${field}.created_at`),\n updated_at: readCloudTimestamp(message.updated_at, `${field}.updated_at`),\n format: readCloudString(message.format, `${field}.format`),\n content: readCloudJSONObject(message.content, `${field}.content`),\n };\n};\n\nexport class AssistantCloudThreadMessages {\n constructor(private cloud: AssistantCloudAPI) {}\n\n public async list(\n threadId: string,\n query?: AssistantCloudThreadMessageListQuery,\n ): Promise<AssistantCloudThreadMessageListResponse> {\n const response = readCloudRecord(\n await this.cloud.makeRequest(\n `/threads/${encodeURIComponent(threadId)}/messages`,\n { query },\n ),\n \"thread message list response\",\n );\n const messages = readCloudArray(response.messages, \"messages\");\n\n return {\n messages: messages.map((message, index) =>\n decodeCloudMessage(message, `messages[${index}]`),\n ),\n };\n }\n\n public async create(\n threadId: string,\n body: AssistantCloudThreadMessageCreateBody,\n ): Promise<AssistantCloudMessageCreateResponse> {\n return this.cloud.makeRequest(\n `/threads/${encodeURIComponent(threadId)}/messages`,\n { method: \"POST\", body },\n );\n }\n\n public async update(\n threadId: string,\n messageId: string,\n body: AssistantCloudThreadMessageUpdateBody,\n ): Promise<void> {\n return this.cloud.makeRequest(\n `/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}`,\n { method: \"PUT\", body },\n );\n }\n}\n"],"mappings":";;AA4CA,MAAa,sBACX,OACA,UACiB;CACjB,MAAM,UAAU,gBAAgB,OAAO,KAAK;CAC5C,OAAO;EACL,IAAI,gBAAgB,QAAQ,IAAI,GAAG,MAAM,IAAI;EAC7C,WAAW,wBAAwB,QAAQ,WAAW,GAAG,MAAM,WAAW;EAC1E,QAAQ,iBAAiB,QAAQ,QAAQ,GAAG,MAAM,QAAQ;EAC1D,YAAY,mBAAmB,QAAQ,YAAY,GAAG,MAAM,YAAY;EACxE,YAAY,mBAAmB,QAAQ,YAAY,GAAG,MAAM,YAAY;EACxE,QAAQ,gBAAgB,QAAQ,QAAQ,GAAG,MAAM,QAAQ;EACzD,SAAS,oBAAoB,QAAQ,SAAS,GAAG,MAAM,SAAS;CAClE;AACF;AAEA,IAAa,+BAAb,MAA0C;CACpB;CAApB,YAAY,OAAkC;EAA1B,KAAA,QAAA;CAA2B;CAE/C,MAAa,KACX,UACA,OACkD;EAUlD,OAAO,EACL,UAHe,eAPA,gBACf,MAAM,KAAK,MAAM,YACf,YAAY,mBAAmB,QAAQ,EAAE,YACzC,EAAE,MAAM,CACV,GACA,8BAEqC,CAAC,CAAC,UAAU,UAGhC,CAAC,CAAC,KAAK,SAAS,UAC/B,mBAAmB,SAAS,YAAY,MAAM,EAAE,CAClD,EACF;CACF;CAEA,MAAa,OACX,UACA,MAC8C;EAC9C,OAAO,KAAK,MAAM,YAChB,YAAY,mBAAmB,QAAQ,EAAE,YACzC;GAAE,QAAQ;GAAQ;EAAK,CACzB;CACF;CAEA,MAAa,OACX,UACA,WACA,MACe;EACf,OAAO,KAAK,MAAM,YAChB,YAAY,mBAAmB,QAAQ,EAAE,YAAY,mBAAmB,SAAS,KACjF;GAAE,QAAQ;GAAO;EAAK,CACxB;CACF;AACF"}
@@ -1,6 +1,5 @@
1
1
  import { AssistantCloudAPI } from "./AssistantCloudAPI.js";
2
2
  import { AssistantCloudThreadMessages } from "./AssistantCloudThreadMessages.js";
3
-
4
3
  //#region src/AssistantCloudThreads.d.ts
5
4
  type AssistantCloudThreadsListQuery = {
6
5
  is_archived?: boolean;
@@ -37,6 +36,7 @@ type AssistantCloudThreadsUpdateBody = {
37
36
  metadata?: unknown | undefined;
38
37
  is_archived?: boolean | undefined;
39
38
  };
39
+ declare const decodeCloudThread: (value: unknown, field: string) => CloudThread;
40
40
  declare class AssistantCloudThreads {
41
41
  private cloud;
42
42
  readonly messages: AssistantCloudThreadMessages;
@@ -48,5 +48,5 @@ declare class AssistantCloudThreads {
48
48
  delete(threadId: string): Promise<void>;
49
49
  }
50
50
  //#endregion
51
- export { AssistantCloudThreads };
51
+ export { AssistantCloudThreads, CloudThread, decodeCloudThread };
52
52
  //# sourceMappingURL=AssistantCloudThreads.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantCloudThreads.d.ts","names":[],"sources":["../src/AssistantCloudThreads.ts"],"mappings":";;;;KAGK,8BAAA;EACH,WAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,KAGG,WAAA;EACH,KAAA;EACA,eAAA,EAAiB,IAAA;EACjB,QAAA;EACA,WAAA;EACA,EAAA;EACA,UAAA;EACA,UAAA,EAAY,IAAA;EACZ,UAAA,EAAY,IAAA;EACZ,YAAA;EACA,WAAA;AAAA;AAAA,KAGG,iCAAA;EACH,OAAA,EAAS,WAAW;AAAA;AAAA,KAGjB,+BAAA;EACH,KAAA;EACA,eAAA,EAAiB,IAAI;EACrB,QAAA;EACA,WAAA;AAAA;AAAA,KAGG,mCAAA;EACH,SAAS;AAAA;AAAA,KAGN,+BAAA;EACH,KAAA;EACA,eAAA,GAAkB,IAAI;EACtB,QAAA;EACA,WAAA;AAAA;AAAA,cAGW,qBAAA;EAAA,QAGS,KAAA;EAAA,SAFJ,QAAA,EAAU,4BAAA;cAEN,KAAA,EAAO,iBAAA;EAId,IAAA,CACX,KAAA,GAAQ,8BAAA,GACP,OAAA,CAAQ,iCAAA;EAIE,GAAA,CAAI,QAAA,WAAmB,OAAA,CAAQ,WAAA;EAI/B,MAAA,CACX,IAAA,EAAM,+BAAA,GACL,OAAA,CAAQ,mCAAA;EAIE,MAAA,CACX,QAAA,UACA,IAAA,EAAM,+BAAA,GACL,OAAA;EAOU,MAAA,CAAO,QAAA,WAAmB,OAAA;AAAA"}
1
+ {"version":3,"file":"AssistantCloudThreads.d.ts","names":[],"sources":["../src/AssistantCloudThreads.ts"],"mappings":";;;KAWK;EACH;EACA;EACA;;KAGU;EACV;EACA,iBAAiB;EACjB;EACA;EACA;EACA;EACA,YAAY;EACZ,YAAY;EACZ;EACA;;KAGG;EACH,SAAS;;KAGN;EACH;EACA,iBAAiB;EACjB;EACA;;KAGG;EACH;;KAGG;EACH;EACA,kBAAkB;EAClB;EACA;;cAGW,oBACX,gBACA,kBACC;cAsBU;UAGS;WAFJ,UAAU;EAEN,YAAA,OAAO;EAId,KACX,QAAQ,iCACP,QAAQ;EAcE,IAAI,mBAAmB,QAAQ;EAS/B,OACX,MAAM,kCACL,QAAQ;EAIE,OACX,kBACA,MAAM,kCACL;EAOU,OAAO,mBAAmB"}
@@ -1,5 +1,21 @@
1
+ import { readCloudArray, readCloudBoolean, readCloudNullableString, readCloudRecord, readCloudString, readCloudTimestamp } from "./cloudResponse.js";
1
2
  import { AssistantCloudThreadMessages } from "./AssistantCloudThreadMessages.js";
2
3
  //#region src/AssistantCloudThreads.ts
4
+ const decodeCloudThread = (value, field) => {
5
+ const thread = readCloudRecord(value, field);
6
+ return {
7
+ title: readCloudNullableString(thread.title, `${field}.title`) ?? "",
8
+ last_message_at: readCloudTimestamp(thread.last_message_at, `${field}.last_message_at`),
9
+ metadata: thread.metadata,
10
+ external_id: readCloudNullableString(thread.external_id, `${field}.external_id`),
11
+ id: readCloudString(thread.id, `${field}.id`),
12
+ project_id: readCloudString(thread.project_id, `${field}.project_id`),
13
+ created_at: readCloudTimestamp(thread.created_at, `${field}.created_at`),
14
+ updated_at: readCloudTimestamp(thread.updated_at, `${field}.updated_at`),
15
+ workspace_id: readCloudString(thread.workspace_id, `${field}.workspace_id`),
16
+ is_archived: readCloudBoolean(thread.is_archived, `${field}.is_archived`)
17
+ };
18
+ };
3
19
  var AssistantCloudThreads = class {
4
20
  cloud;
5
21
  messages;
@@ -8,10 +24,11 @@ var AssistantCloudThreads = class {
8
24
  this.messages = new AssistantCloudThreadMessages(cloud);
9
25
  }
10
26
  async list(query) {
11
- return this.cloud.makeRequest("/threads", { query });
27
+ return { threads: readCloudArray(readCloudRecord(await this.cloud.makeRequest("/threads", { query }), "thread list response").threads, "threads").map((thread, index) => decodeCloudThread(thread, `threads[${index}]`)) };
12
28
  }
13
29
  async get(threadId) {
14
- return this.cloud.makeRequest(`/threads/${encodeURIComponent(threadId)}`);
30
+ const response = readCloudRecord(await this.cloud.makeRequest(`/threads/${encodeURIComponent(threadId)}`), "thread response");
31
+ return decodeCloudThread(response.thread, "thread");
15
32
  }
16
33
  async create(body) {
17
34
  return this.cloud.makeRequest("/threads", {
@@ -30,6 +47,6 @@ var AssistantCloudThreads = class {
30
47
  }
31
48
  };
32
49
  //#endregion
33
- export { AssistantCloudThreads };
50
+ export { AssistantCloudThreads, decodeCloudThread };
34
51
 
35
52
  //# sourceMappingURL=AssistantCloudThreads.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantCloudThreads.js","names":[],"sources":["../src/AssistantCloudThreads.ts"],"sourcesContent":["import type { AssistantCloudAPI } from \"./AssistantCloudAPI\";\nimport { AssistantCloudThreadMessages } from \"./AssistantCloudThreadMessages\";\n\ntype AssistantCloudThreadsListQuery = {\n is_archived?: boolean;\n limit?: number;\n after?: string;\n};\n\ntype CloudThread = {\n title: string;\n last_message_at: Date;\n metadata: unknown;\n external_id: string | null;\n id: string;\n project_id: string;\n created_at: Date;\n updated_at: Date;\n workspace_id: string;\n is_archived: boolean;\n};\n\ntype AssistantCloudThreadsListResponse = {\n threads: CloudThread[];\n};\n\ntype AssistantCloudThreadsCreateBody = {\n title?: string | undefined;\n last_message_at: Date;\n metadata?: unknown | undefined;\n external_id?: string | undefined;\n};\n\ntype AssistantCloudThreadsCreateResponse = {\n thread_id: string;\n};\n\ntype AssistantCloudThreadsUpdateBody = {\n title?: string | undefined;\n last_message_at?: Date | undefined;\n metadata?: unknown | undefined;\n is_archived?: boolean | undefined;\n};\n\nexport class AssistantCloudThreads {\n public readonly messages: AssistantCloudThreadMessages;\n\n constructor(private cloud: AssistantCloudAPI) {\n this.messages = new AssistantCloudThreadMessages(cloud);\n }\n\n public async list(\n query?: AssistantCloudThreadsListQuery,\n ): Promise<AssistantCloudThreadsListResponse> {\n return this.cloud.makeRequest(\"/threads\", { query });\n }\n\n public async get(threadId: string): Promise<CloudThread> {\n return this.cloud.makeRequest(`/threads/${encodeURIComponent(threadId)}`);\n }\n\n public async create(\n body: AssistantCloudThreadsCreateBody,\n ): Promise<AssistantCloudThreadsCreateResponse> {\n return this.cloud.makeRequest(\"/threads\", { method: \"POST\", body });\n }\n\n public async update(\n threadId: string,\n body: AssistantCloudThreadsUpdateBody,\n ): Promise<void> {\n return this.cloud.makeRequest(`/threads/${encodeURIComponent(threadId)}`, {\n method: \"PUT\",\n body,\n });\n }\n\n public async delete(threadId: string): Promise<void> {\n return this.cloud.makeRequest(`/threads/${encodeURIComponent(threadId)}`, {\n method: \"DELETE\",\n });\n }\n}\n"],"mappings":";;AA4CA,IAAa,wBAAb,MAAmC;CAGb;CAFpB;CAEA,YAAY,OAAkC;EAA1B,KAAA,QAAA;EAClB,KAAK,WAAW,IAAI,6BAA6B,KAAK;CACxD;CAEA,MAAa,KACX,OAC4C;EAC5C,OAAO,KAAK,MAAM,YAAY,YAAY,EAAE,MAAM,CAAC;CACrD;CAEA,MAAa,IAAI,UAAwC;EACvD,OAAO,KAAK,MAAM,YAAY,YAAY,mBAAmB,QAAQ,GAAG;CAC1E;CAEA,MAAa,OACX,MAC8C;EAC9C,OAAO,KAAK,MAAM,YAAY,YAAY;GAAE,QAAQ;GAAQ;EAAK,CAAC;CACpE;CAEA,MAAa,OACX,UACA,MACe;EACf,OAAO,KAAK,MAAM,YAAY,YAAY,mBAAmB,QAAQ,KAAK;GACxE,QAAQ;GACR;EACF,CAAC;CACH;CAEA,MAAa,OAAO,UAAiC;EACnD,OAAO,KAAK,MAAM,YAAY,YAAY,mBAAmB,QAAQ,KAAK,EACxE,QAAQ,SACV,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"AssistantCloudThreads.js","names":[],"sources":["../src/AssistantCloudThreads.ts"],"sourcesContent":["import type { AssistantCloudAPI } from \"./AssistantCloudAPI\";\nimport { AssistantCloudThreadMessages } from \"./AssistantCloudThreadMessages\";\nimport {\n readCloudArray,\n readCloudBoolean,\n readCloudNullableString,\n readCloudRecord,\n readCloudString,\n readCloudTimestamp,\n} from \"./cloudResponse\";\n\ntype AssistantCloudThreadsListQuery = {\n is_archived?: boolean;\n limit?: number;\n after?: string;\n};\n\nexport type CloudThread = {\n title: string;\n last_message_at: Date;\n metadata: unknown;\n external_id: string | null;\n id: string;\n project_id: string;\n created_at: Date;\n updated_at: Date;\n workspace_id: string;\n is_archived: boolean;\n};\n\ntype AssistantCloudThreadsListResponse = {\n threads: CloudThread[];\n};\n\ntype AssistantCloudThreadsCreateBody = {\n title?: string | undefined;\n last_message_at: Date;\n metadata?: unknown | undefined;\n external_id?: string | undefined;\n};\n\ntype AssistantCloudThreadsCreateResponse = {\n thread_id: string;\n};\n\ntype AssistantCloudThreadsUpdateBody = {\n title?: string | undefined;\n last_message_at?: Date | undefined;\n metadata?: unknown | undefined;\n is_archived?: boolean | undefined;\n};\n\nexport const decodeCloudThread = (\n value: unknown,\n field: string,\n): CloudThread => {\n const thread = readCloudRecord(value, field);\n return {\n title: readCloudNullableString(thread.title, `${field}.title`) ?? \"\",\n last_message_at: readCloudTimestamp(\n thread.last_message_at,\n `${field}.last_message_at`,\n ),\n metadata: thread.metadata,\n external_id: readCloudNullableString(\n thread.external_id,\n `${field}.external_id`,\n ),\n id: readCloudString(thread.id, `${field}.id`),\n project_id: readCloudString(thread.project_id, `${field}.project_id`),\n created_at: readCloudTimestamp(thread.created_at, `${field}.created_at`),\n updated_at: readCloudTimestamp(thread.updated_at, `${field}.updated_at`),\n workspace_id: readCloudString(thread.workspace_id, `${field}.workspace_id`),\n is_archived: readCloudBoolean(thread.is_archived, `${field}.is_archived`),\n };\n};\n\nexport class AssistantCloudThreads {\n public readonly messages: AssistantCloudThreadMessages;\n\n constructor(private cloud: AssistantCloudAPI) {\n this.messages = new AssistantCloudThreadMessages(cloud);\n }\n\n public async list(\n query?: AssistantCloudThreadsListQuery,\n ): Promise<AssistantCloudThreadsListResponse> {\n const response = readCloudRecord(\n await this.cloud.makeRequest(\"/threads\", { query }),\n \"thread list response\",\n );\n const threads = readCloudArray(response.threads, \"threads\");\n\n return {\n threads: threads.map((thread, index) =>\n decodeCloudThread(thread, `threads[${index}]`),\n ),\n };\n }\n\n public async get(threadId: string): Promise<CloudThread> {\n const response = readCloudRecord(\n await this.cloud.makeRequest(`/threads/${encodeURIComponent(threadId)}`),\n \"thread response\",\n );\n\n return decodeCloudThread(response.thread, \"thread\");\n }\n\n public async create(\n body: AssistantCloudThreadsCreateBody,\n ): Promise<AssistantCloudThreadsCreateResponse> {\n return this.cloud.makeRequest(\"/threads\", { method: \"POST\", body });\n }\n\n public async update(\n threadId: string,\n body: AssistantCloudThreadsUpdateBody,\n ): Promise<void> {\n return this.cloud.makeRequest(`/threads/${encodeURIComponent(threadId)}`, {\n method: \"PUT\",\n body,\n });\n }\n\n public async delete(threadId: string): Promise<void> {\n return this.cloud.makeRequest(`/threads/${encodeURIComponent(threadId)}`, {\n method: \"DELETE\",\n });\n }\n}\n"],"mappings":";;;AAoDA,MAAa,qBACX,OACA,UACgB;CAChB,MAAM,SAAS,gBAAgB,OAAO,KAAK;CAC3C,OAAO;EACL,OAAO,wBAAwB,OAAO,OAAO,GAAG,MAAM,OAAO,KAAK;EAClE,iBAAiB,mBACf,OAAO,iBACP,GAAG,MAAM,iBACX;EACA,UAAU,OAAO;EACjB,aAAa,wBACX,OAAO,aACP,GAAG,MAAM,aACX;EACA,IAAI,gBAAgB,OAAO,IAAI,GAAG,MAAM,IAAI;EAC5C,YAAY,gBAAgB,OAAO,YAAY,GAAG,MAAM,YAAY;EACpE,YAAY,mBAAmB,OAAO,YAAY,GAAG,MAAM,YAAY;EACvE,YAAY,mBAAmB,OAAO,YAAY,GAAG,MAAM,YAAY;EACvE,cAAc,gBAAgB,OAAO,cAAc,GAAG,MAAM,cAAc;EAC1E,aAAa,iBAAiB,OAAO,aAAa,GAAG,MAAM,aAAa;CAC1E;AACF;AAEA,IAAa,wBAAb,MAAmC;CAGb;CAFpB;CAEA,YAAY,OAAkC;EAA1B,KAAA,QAAA;EAClB,KAAK,WAAW,IAAI,6BAA6B,KAAK;CACxD;CAEA,MAAa,KACX,OAC4C;EAO5C,OAAO,EACL,SAHc,eAJC,gBACf,MAAM,KAAK,MAAM,YAAY,YAAY,EAAE,MAAM,CAAC,GAClD,sBAEoC,CAAC,CAAC,SAAS,SAGhC,CAAC,CAAC,KAAK,QAAQ,UAC5B,kBAAkB,QAAQ,WAAW,MAAM,EAAE,CAC/C,EACF;CACF;CAEA,MAAa,IAAI,UAAwC;EACvD,MAAM,WAAW,gBACf,MAAM,KAAK,MAAM,YAAY,YAAY,mBAAmB,QAAQ,GAAG,GACvE,iBACF;EAEA,OAAO,kBAAkB,SAAS,QAAQ,QAAQ;CACpD;CAEA,MAAa,OACX,MAC8C;EAC9C,OAAO,KAAK,MAAM,YAAY,YAAY;GAAE,QAAQ;GAAQ;EAAK,CAAC;CACpE;CAEA,MAAa,OACX,UACA,MACe;EACf,OAAO,KAAK,MAAM,YAAY,YAAY,mBAAmB,QAAQ,KAAK;GACxE,QAAQ;GACR;EACF,CAAC;CACH;CAEA,MAAa,OAAO,UAAiC;EACnD,OAAO,KAAK,MAAM,YAAY,YAAY,mBAAmB,QAAQ,KAAK,EACxE,QAAQ,SACV,CAAC;CACH;AACF"}
@@ -1,7 +1,6 @@
1
1
  import { CloudMessage } from "./AssistantCloudThreadMessages.js";
2
2
  import { AssistantCloud } from "./AssistantCloud.js";
3
3
  import { ReadonlyJSONObject } from "assistant-stream/utils";
4
-
5
4
  //#region src/CloudMessagePersistence.d.ts
6
5
  /**
7
6
  * Shared persistence logic for cloud message storage.
@@ -15,9 +14,10 @@ import { ReadonlyJSONObject } from "assistant-stream/utils";
15
14
  * to get its remote ID before creating B.
16
15
  */
17
16
  declare class CloudMessagePersistence {
18
- private cloud;
19
17
  private idMapping;
18
+ private getCloud;
20
19
  constructor(cloud: AssistantCloud);
20
+ constructor(getCloud: () => AssistantCloud);
21
21
  /**
22
22
  * Persist a message to the cloud.
23
23
  *
@@ -1 +1 @@
1
- {"version":3,"file":"CloudMessagePersistence.d.ts","names":[],"sources":["../src/CloudMessagePersistence.ts"],"mappings":";;;;;;;;AAcA;;;;;;;;cAAa,uBAAA;EAAA,QAGS,KAAA;EAAA,QAFZ,SAAA;cAEY,KAAA,EAAO,cAAA;EAuFiB;;;;;;;;;EA5EtC,MAAA,CACJ,QAAA,UACA,SAAA,UACA,QAAA,iBACA,MAAA,UACA,OAAA,EAAS,kBAAA,GACR,OAAA;EAFD;;;EAkCI,MAAA,CACJ,QAAA,UACA,SAAA,UACA,OAAA,UACA,OAAA,EAAS,kBAAA,GACR,OAAA;EALG;;;EAcN,WAAA,CAAY,SAAA;EAVD;;;;EAkBL,WAAA,CAAY,SAAA,WAAoB,OAAA;EAAhC;;;;;;;;;;EAgBA,IAAA,CAAK,QAAA,UAAkB,MAAA,YAAe,OAAA,CAhBC,YAAA;;;;EA+B7C,KAAA;AAAA"}
1
+ {"version":3,"file":"CloudMessagePersistence.d.ts","names":[],"sources":["../src/CloudMessagePersistence.ts"],"mappings":";;;;;;;;;;;;;;;cAca;UACH;UACA;EAEI,YAAA,OAAO;EACP,YAAA,gBAAgB;;;;;;;;;;EActB,OACJ,kBACA,mBACA,yBACA,gBACA,SAAS,qBACR;;;;EAiCG,OACJ,kBACA,mBACA,iBACA,SAAS,qBACR;;;;EAeH,YAAY;;;;;EAQN,YAAY,oBAAoB;;;;;;;;;;;EAgBhC,KAAK,kBAAkB,kBAAe,QAhBN;;;;EAgCtC"}
@@ -11,10 +11,10 @@
11
11
  * to get its remote ID before creating B.
12
12
  */
13
13
  var CloudMessagePersistence = class {
14
- cloud;
15
14
  idMapping = {};
15
+ getCloud;
16
16
  constructor(cloud) {
17
- this.cloud = cloud;
17
+ this.getCloud = typeof cloud === "function" ? cloud : () => cloud;
18
18
  }
19
19
  /**
20
20
  * Persist a message to the cloud.
@@ -26,8 +26,9 @@ var CloudMessagePersistence = class {
26
26
  * @param content - Message content (format-specific)
27
27
  */
28
28
  async append(threadId, messageId, parentId, format, content) {
29
+ const cloud = this.getCloud();
29
30
  const resolvedParentId = parentId ? await this.idMapping[parentId] ?? parentId : null;
30
- const task = this.cloud.threads.messages.create(threadId, {
31
+ const task = cloud.threads.messages.create(threadId, {
31
32
  parent_id: resolvedParentId,
32
33
  format,
33
34
  content
@@ -45,9 +46,13 @@ var CloudMessagePersistence = class {
45
46
  * Update an already-persisted message in the cloud.
46
47
  */
47
48
  async update(threadId, messageId, _format, content) {
49
+ const cloud = this.getCloud();
48
50
  const remoteId = await this.getRemoteId(messageId);
49
- if (!remoteId) return;
50
- await this.cloud.threads.messages.update(threadId, remoteId, { content });
51
+ if (!remoteId) {
52
+ console.warn(`Skipping update for message ${messageId}: no remote id is mapped.`);
53
+ return;
54
+ }
55
+ await cloud.threads.messages.update(threadId, remoteId, { content });
51
56
  }
52
57
  /**
53
58
  * Check if a message has been persisted (or is currently being persisted).
@@ -75,7 +80,7 @@ var CloudMessagePersistence = class {
75
80
  * @returns Array of cloud messages
76
81
  */
77
82
  async load(threadId, format) {
78
- const { messages } = await this.cloud.threads.messages.list(threadId, format ? { format } : void 0);
83
+ const { messages } = await this.getCloud().threads.messages.list(threadId, format ? { format } : void 0);
79
84
  for (const m of messages) this.idMapping[m.id] = m.id;
80
85
  return messages;
81
86
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CloudMessagePersistence.js","names":[],"sources":["../src/CloudMessagePersistence.ts"],"sourcesContent":["import type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport type { AssistantCloud } from \"./AssistantCloud\";\n\n/**\n * Shared persistence logic for cloud message storage.\n *\n * Handles ID mapping (local → remote) and parent_id chaining for both:\n * - AssistantCloudThreadHistoryAdapter (assistant-ui runtime)\n * - useCloudChat (standalone AI SDK hook)\n *\n * The promise-based ID resolution handles concurrent appends — if message B's\n * parent is message A, and A is still being created, we await A's promise\n * to get its remote ID before creating B.\n */\nexport class CloudMessagePersistence {\n private idMapping: Record<string, string | Promise<string>> = {};\n\n constructor(private cloud: AssistantCloud) {}\n\n /**\n * Persist a message to the cloud.\n *\n * @param threadId - Remote thread ID\n * @param messageId - Local message ID (used for tracking)\n * @param parentId - Local parent message ID (or null for first message)\n * @param format - Message format (e.g., \"aui/v0\", \"ai-sdk/v6\")\n * @param content - Message content (format-specific)\n */\n async append(\n threadId: string,\n messageId: string,\n parentId: string | null,\n format: string,\n content: ReadonlyJSONObject,\n ): Promise<void> {\n // Resolve parent's remote ID if it exists (may be a promise if concurrent)\n const resolvedParentId = parentId\n ? ((await this.idMapping[parentId]) ?? parentId)\n : null;\n\n const task = this.cloud.threads.messages\n .create(threadId, {\n parent_id: resolvedParentId,\n format,\n content,\n })\n .then(({ message_id }) => {\n this.idMapping[messageId] = message_id;\n return message_id;\n })\n .catch((err) => {\n // Only delete if we're still the active task (avoids clobbering a retry)\n if (this.idMapping[messageId] === task) {\n delete this.idMapping[messageId];\n }\n throw err;\n });\n\n // Store the promise immediately so concurrent appends can await it\n this.idMapping[messageId] = task;\n return task.then(() => {});\n }\n\n /**\n * Update an already-persisted message in the cloud.\n */\n async update(\n threadId: string,\n messageId: string,\n _format: string,\n content: ReadonlyJSONObject,\n ): Promise<void> {\n const remoteId = await this.getRemoteId(messageId);\n if (!remoteId) return; // not persisted yet, skip\n await this.cloud.threads.messages.update(threadId, remoteId, { content });\n }\n\n /**\n * Check if a message has been persisted (or is currently being persisted).\n */\n isPersisted(messageId: string): boolean {\n return messageId in this.idMapping;\n }\n\n /**\n * Get the remote ID for a local message ID (resolved).\n * Returns undefined if not persisted.\n */\n async getRemoteId(messageId: string): Promise<string | undefined> {\n const entry = this.idMapping[messageId];\n if (!entry) return undefined;\n return entry;\n }\n\n /**\n * Load messages from the cloud and populate the ID mapping.\n *\n * The ID mapping is populated so that `isPersisted()` returns true for\n * loaded messages, preventing re-persistence of already-stored messages.\n *\n * @param threadId - Remote thread ID\n * @param format - Optional format filter\n * @returns Array of cloud messages\n */\n async load(threadId: string, format?: string) {\n const { messages } = await this.cloud.threads.messages.list(\n threadId,\n format ? { format } : undefined,\n );\n // Populate ID mapping so isPersisted() recognizes loaded messages\n for (const m of messages) {\n this.idMapping[m.id] = m.id;\n }\n return messages;\n }\n\n /**\n * Reset the ID mapping (call when switching threads).\n */\n reset() {\n this.idMapping = {};\n }\n}\n"],"mappings":";;;;;;;;;;;;AAcA,IAAa,0BAAb,MAAqC;CAGf;CAFpB,YAA8D,CAAC;CAE/D,YAAY,OAA+B;EAAvB,KAAA,QAAA;CAAwB;;;;;;;;;;CAW5C,MAAM,OACJ,UACA,WACA,UACA,QACA,SACe;EAEf,MAAM,mBAAmB,WACnB,MAAM,KAAK,UAAU,aAAc,WACrC;EAEJ,MAAM,OAAO,KAAK,MAAM,QAAQ,SAC7B,OAAO,UAAU;GAChB,WAAW;GACX;GACA;EACF,CAAC,CAAC,CACD,MAAM,EAAE,iBAAiB;GACxB,KAAK,UAAU,aAAa;GAC5B,OAAO;EACT,CAAC,CAAC,CACD,OAAO,QAAQ;GAEd,IAAI,KAAK,UAAU,eAAe,MAChC,OAAO,KAAK,UAAU;GAExB,MAAM;EACR,CAAC;EAGH,KAAK,UAAU,aAAa;EAC5B,OAAO,KAAK,WAAW,CAAC,CAAC;CAC3B;;;;CAKA,MAAM,OACJ,UACA,WACA,SACA,SACe;EACf,MAAM,WAAW,MAAM,KAAK,YAAY,SAAS;EACjD,IAAI,CAAC,UAAU;EACf,MAAM,KAAK,MAAM,QAAQ,SAAS,OAAO,UAAU,UAAU,EAAE,QAAQ,CAAC;CAC1E;;;;CAKA,YAAY,WAA4B;EACtC,OAAO,aAAa,KAAK;CAC3B;;;;;CAMA,MAAM,YAAY,WAAgD;EAChE,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,OAAO,OAAO,KAAA;EACnB,OAAO;CACT;;;;;;;;;;;CAYA,MAAM,KAAK,UAAkB,QAAiB;EAC5C,MAAM,EAAE,aAAa,MAAM,KAAK,MAAM,QAAQ,SAAS,KACrD,UACA,SAAS,EAAE,OAAO,IAAI,KAAA,CACxB;EAEA,KAAK,MAAM,KAAK,UACd,KAAK,UAAU,EAAE,MAAM,EAAE;EAE3B,OAAO;CACT;;;;CAKA,QAAQ;EACN,KAAK,YAAY,CAAC;CACpB;AACF"}
1
+ {"version":3,"file":"CloudMessagePersistence.js","names":[],"sources":["../src/CloudMessagePersistence.ts"],"sourcesContent":["import type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport type { AssistantCloud } from \"./AssistantCloud\";\n\n/**\n * Shared persistence logic for cloud message storage.\n *\n * Handles ID mapping (local → remote) and parent_id chaining for both:\n * - AssistantCloudThreadHistoryAdapter (assistant-ui runtime)\n * - useCloudChat (standalone AI SDK hook)\n *\n * The promise-based ID resolution handles concurrent appends — if message B's\n * parent is message A, and A is still being created, we await A's promise\n * to get its remote ID before creating B.\n */\nexport class CloudMessagePersistence {\n private idMapping: Record<string, string | Promise<string>> = {};\n private getCloud: () => AssistantCloud;\n\n constructor(cloud: AssistantCloud);\n constructor(getCloud: () => AssistantCloud);\n constructor(cloud: AssistantCloud | (() => AssistantCloud)) {\n this.getCloud = typeof cloud === \"function\" ? cloud : () => cloud;\n }\n\n /**\n * Persist a message to the cloud.\n *\n * @param threadId - Remote thread ID\n * @param messageId - Local message ID (used for tracking)\n * @param parentId - Local parent message ID (or null for first message)\n * @param format - Message format (e.g., \"aui/v0\", \"ai-sdk/v6\")\n * @param content - Message content (format-specific)\n */\n async append(\n threadId: string,\n messageId: string,\n parentId: string | null,\n format: string,\n content: ReadonlyJSONObject,\n ): Promise<void> {\n const cloud = this.getCloud();\n // Resolve parent's remote ID if it exists (may be a promise if concurrent)\n const resolvedParentId = parentId\n ? ((await this.idMapping[parentId]) ?? parentId)\n : null;\n\n const task = cloud.threads.messages\n .create(threadId, {\n parent_id: resolvedParentId,\n format,\n content,\n })\n .then(({ message_id }) => {\n this.idMapping[messageId] = message_id;\n return message_id;\n })\n .catch((err) => {\n // Only delete if we're still the active task (avoids clobbering a retry)\n if (this.idMapping[messageId] === task) {\n delete this.idMapping[messageId];\n }\n throw err;\n });\n\n // Store the promise immediately so concurrent appends can await it\n this.idMapping[messageId] = task;\n return task.then(() => {});\n }\n\n /**\n * Update an already-persisted message in the cloud.\n */\n async update(\n threadId: string,\n messageId: string,\n _format: string,\n content: ReadonlyJSONObject,\n ): Promise<void> {\n const cloud = this.getCloud();\n const remoteId = await this.getRemoteId(messageId);\n if (!remoteId) {\n console.warn(\n `Skipping update for message ${messageId}: no remote id is mapped.`,\n );\n return;\n }\n await cloud.threads.messages.update(threadId, remoteId, { content });\n }\n\n /**\n * Check if a message has been persisted (or is currently being persisted).\n */\n isPersisted(messageId: string): boolean {\n return messageId in this.idMapping;\n }\n\n /**\n * Get the remote ID for a local message ID (resolved).\n * Returns undefined if not persisted.\n */\n async getRemoteId(messageId: string): Promise<string | undefined> {\n const entry = this.idMapping[messageId];\n if (!entry) return undefined;\n return entry;\n }\n\n /**\n * Load messages from the cloud and populate the ID mapping.\n *\n * The ID mapping is populated so that `isPersisted()` returns true for\n * loaded messages, preventing re-persistence of already-stored messages.\n *\n * @param threadId - Remote thread ID\n * @param format - Optional format filter\n * @returns Array of cloud messages\n */\n async load(threadId: string, format?: string) {\n const cloud = this.getCloud();\n const { messages } = await cloud.threads.messages.list(\n threadId,\n format ? { format } : undefined,\n );\n // Populate ID mapping so isPersisted() recognizes loaded messages\n for (const m of messages) {\n this.idMapping[m.id] = m.id;\n }\n return messages;\n }\n\n /**\n * Reset the ID mapping (call when switching threads).\n */\n reset() {\n this.idMapping = {};\n }\n}\n"],"mappings":";;;;;;;;;;;;AAcA,IAAa,0BAAb,MAAqC;CACnC,YAA8D,CAAC;CAC/D;CAIA,YAAY,OAAgD;EAC1D,KAAK,WAAW,OAAO,UAAU,aAAa,cAAc;CAC9D;;;;;;;;;;CAWA,MAAM,OACJ,UACA,WACA,UACA,QACA,SACe;EACf,MAAM,QAAQ,KAAK,SAAS;EAE5B,MAAM,mBAAmB,WACnB,MAAM,KAAK,UAAU,aAAc,WACrC;EAEJ,MAAM,OAAO,MAAM,QAAQ,SACxB,OAAO,UAAU;GAChB,WAAW;GACX;GACA;EACF,CAAC,CAAC,CACD,MAAM,EAAE,iBAAiB;GACxB,KAAK,UAAU,aAAa;GAC5B,OAAO;EACT,CAAC,CAAC,CACD,OAAO,QAAQ;GAEd,IAAI,KAAK,UAAU,eAAe,MAChC,OAAO,KAAK,UAAU;GAExB,MAAM;EACR,CAAC;EAGH,KAAK,UAAU,aAAa;EAC5B,OAAO,KAAK,WAAW,CAAC,CAAC;CAC3B;;;;CAKA,MAAM,OACJ,UACA,WACA,SACA,SACe;EACf,MAAM,QAAQ,KAAK,SAAS;EAC5B,MAAM,WAAW,MAAM,KAAK,YAAY,SAAS;EACjD,IAAI,CAAC,UAAU;GACb,QAAQ,KACN,+BAA+B,UAAU,0BAC3C;GACA;EACF;EACA,MAAM,MAAM,QAAQ,SAAS,OAAO,UAAU,UAAU,EAAE,QAAQ,CAAC;CACrE;;;;CAKA,YAAY,WAA4B;EACtC,OAAO,aAAa,KAAK;CAC3B;;;;;CAMA,MAAM,YAAY,WAAgD;EAChE,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,OAAO,OAAO,KAAA;EACnB,OAAO;CACT;;;;;;;;;;;CAYA,MAAM,KAAK,UAAkB,QAAiB;EAE5C,MAAM,EAAE,aAAa,MADP,KAAK,SACY,CAAC,CAAC,QAAQ,SAAS,KAChD,UACA,SAAS,EAAE,OAAO,IAAI,KAAA,CACxB;EAEA,KAAK,MAAM,KAAK,UACd,KAAK,UAAU,EAAE,MAAM,EAAE;EAE3B,OAAO;CACT;;;;CAKA,QAAQ;EACN,KAAK,YAAY,CAAC;CACpB;AACF"}
@@ -1,5 +1,4 @@
1
1
  import { ReadonlyJSONObject } from "assistant-stream/utils";
2
-
3
2
  //#region src/FormattedCloudPersistence.d.ts
4
3
  /**
5
4
  * Format adapter shape — structurally identical to the MessageFormatAdapter
@@ -1 +1 @@
1
- {"version":3,"file":"FormattedCloudPersistence.d.ts","names":[],"sources":["../src/FormattedCloudPersistence.ts"],"mappings":";;;;;AAOA;;;KAAY,oBAAA;EACV,MAAA;EACA,MAAA,CAAO,IAAA;IAAQ,QAAA;IAAyB,OAAA,EAAS,QAAA;EAAA,IAAa,cAAA;EAC9D,MAAA,CAAO,MAAA;IACL,EAAA;IACA,SAAA;IACA,MAAA;IACA,OAAA,EAAS,cAAA;EAAA;IACL,QAAA;IAAyB,OAAA,EAAS,QAAA;EAAA;EACxC,KAAA,CAAM,OAAA,EAAS,QAAA;AAAA;;;;;;;;;;;cAaJ,0BAAA,6BACX,WAAA;EACE,MAAA,GACE,QAAA,UACA,SAAA,UACA,QAAA,iBACA,MAAA,UACA,OAAA,EAAS,kBAAA,KACN,OAAA;EACL,IAAA,GAAO,QAAA,UAAkB,MAAA,cAAoB,OAAA;EAC7C,WAAA,GAAc,SAAA;EACd,MAAA,IACE,QAAA,UACA,SAAA,UACA,MAAA,UACA,OAAA,EAAS,kBAAA,KACN,OAAA;AAAA,GAEP,OAAA,EAAS,oBAAA,CAAqB,QAAA,EAAU,cAAA;6BAGtB,IAAA;IACR,QAAA;IAAyB,OAAA,EAAS,QAAA;EAAA,MACzC,OAAA;8BAamB,IAAA;IACR,QAAA;IAAyB,OAAA,EAAS,QAAA;EAAA,GAAU,SAAA,aAEnD,OAAA;8BAUsB,OAAA"}
1
+ {"version":3,"file":"FormattedCloudPersistence.d.ts","names":[],"sources":["../src/FormattedCloudPersistence.ts"],"mappings":";;;;;;;KAOY,qBAAqB,UAAU;EACzC;EACA,OAAO;IAAQ;IAAyB,SAAS;MAAa;EAC9D,OAAO;IACL;IACA;IACA;IACA,SAAS;;IACL;IAAyB,SAAS;;EACxC,MAAM,SAAS;;;;;;;;;;;;cAaJ,6BAA8B,UAAU,gBACnD;EACE,SACE,kBACA,mBACA,yBACA,gBACA,SAAS,uBACN;EACL,OAAO,kBAAkB,oBAAoB;EAC7C,cAAc;EACd,UACE,kBACA,mBACA,gBACA,SAAS,uBACN;GAEP,SAAS,qBAAqB,UAAU;EAG5B,SAAA,kBAAM;IACR;IAAyB,SAAS;QACzC;EAaa,UAAA,kBAAM;IACR;IAAyB,SAAS;KAAU,sBAEnD;EAUgB,OAAA,qBAAM;;MA/Db;;;;EA+ES,cAAA"}
@@ -0,0 +1,16 @@
1
+ import { ReadonlyJSONObject } from "assistant-stream/utils";
2
+ //#region src/cloudResponse.d.ts
3
+ declare class CloudResponseError extends Error {
4
+ constructor(message: string);
5
+ }
6
+ declare const readCloudRecord: (value: unknown, field: string) => Record<string, unknown>;
7
+ declare const readCloudArray: (value: unknown, field: string) => unknown[];
8
+ declare const readCloudString: (value: unknown, field: string) => string;
9
+ declare const readCloudNullableString: (value: unknown, field: string) => string | null;
10
+ declare const readCloudBoolean: (value: unknown, field: string) => boolean;
11
+ declare const readCloudInteger: (value: unknown, field: string) => number;
12
+ declare const readCloudTimestamp: (value: unknown, field: string) => Date;
13
+ declare const readCloudJSONObject: (value: unknown, field: string) => ReadonlyJSONObject;
14
+ //#endregion
15
+ export { CloudResponseError, readCloudArray, readCloudBoolean, readCloudInteger, readCloudJSONObject, readCloudNullableString, readCloudRecord, readCloudString, readCloudTimestamp };
16
+ //# sourceMappingURL=cloudResponse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudResponse.d.ts","names":[],"sources":["../src/cloudResponse.ts"],"mappings":";;cAEa,2BAA2B;EAC1B,YAAA;;cAWD,kBACX,gBACA,kBACC;cAOU,iBAAkB,gBAAgB;cAKlC,kBAAmB,gBAAgB;cAKnC,0BACX,gBACA;cAMW,mBAAoB,gBAAgB;cAOpC,mBAAoB,gBAAgB;cAKpC,qBAAsB,gBAAgB,kBAAgB;cActD,sBACX,gBACA,kBACC"}
@@ -0,0 +1,43 @@
1
+ //#region src/cloudResponse.ts
2
+ var CloudResponseError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "CloudResponseError";
6
+ }
7
+ };
8
+ const invalidCloudResponse = (field, expected) => new CloudResponseError(`Invalid Assistant Cloud response for "${field}": expected ${expected}`);
9
+ const readCloudRecord = (value, field) => {
10
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw invalidCloudResponse(field, "an object");
11
+ return value;
12
+ };
13
+ const readCloudArray = (value, field) => {
14
+ if (!Array.isArray(value)) throw invalidCloudResponse(field, "an array");
15
+ return value;
16
+ };
17
+ const readCloudString = (value, field) => {
18
+ if (typeof value !== "string") throw invalidCloudResponse(field, "a string");
19
+ return value;
20
+ };
21
+ const readCloudNullableString = (value, field) => {
22
+ if (value === null) return null;
23
+ return readCloudString(value, field);
24
+ };
25
+ const readCloudBoolean = (value, field) => {
26
+ if (typeof value !== "boolean") throw invalidCloudResponse(field, "a boolean");
27
+ return value;
28
+ };
29
+ const readCloudInteger = (value, field) => {
30
+ if (!Number.isInteger(value)) throw invalidCloudResponse(field, "an integer");
31
+ return value;
32
+ };
33
+ const readCloudTimestamp = (value, field) => {
34
+ if (typeof value !== "string") throw invalidCloudResponse(field, "a canonical ISO timestamp");
35
+ const date = new Date(value);
36
+ if (Number.isNaN(date.getTime()) || date.toISOString() !== value) throw invalidCloudResponse(field, "a canonical ISO timestamp");
37
+ return date;
38
+ };
39
+ const readCloudJSONObject = (value, field) => readCloudRecord(value, field);
40
+ //#endregion
41
+ export { CloudResponseError, readCloudArray, readCloudBoolean, readCloudInteger, readCloudJSONObject, readCloudNullableString, readCloudRecord, readCloudString, readCloudTimestamp };
42
+
43
+ //# sourceMappingURL=cloudResponse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudResponse.js","names":[],"sources":["../src/cloudResponse.ts"],"sourcesContent":["import type { ReadonlyJSONObject } from \"assistant-stream/utils\";\n\nexport class CloudResponseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CloudResponseError\";\n }\n}\n\nconst invalidCloudResponse = (field: string, expected: string) =>\n new CloudResponseError(\n `Invalid Assistant Cloud response for \"${field}\": expected ${expected}`,\n );\n\nexport const readCloudRecord = (\n value: unknown,\n field: string,\n): Record<string, unknown> => {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw invalidCloudResponse(field, \"an object\");\n }\n return value as Record<string, unknown>;\n};\n\nexport const readCloudArray = (value: unknown, field: string): unknown[] => {\n if (!Array.isArray(value)) throw invalidCloudResponse(field, \"an array\");\n return value;\n};\n\nexport const readCloudString = (value: unknown, field: string): string => {\n if (typeof value !== \"string\") throw invalidCloudResponse(field, \"a string\");\n return value;\n};\n\nexport const readCloudNullableString = (\n value: unknown,\n field: string,\n): string | null => {\n if (value === null) return null;\n return readCloudString(value, field);\n};\n\nexport const readCloudBoolean = (value: unknown, field: string): boolean => {\n if (typeof value !== \"boolean\") {\n throw invalidCloudResponse(field, \"a boolean\");\n }\n return value;\n};\n\nexport const readCloudInteger = (value: unknown, field: string): number => {\n if (!Number.isInteger(value)) throw invalidCloudResponse(field, \"an integer\");\n return value as number;\n};\n\nexport const readCloudTimestamp = (value: unknown, field: string): Date => {\n if (typeof value !== \"string\") {\n throw invalidCloudResponse(field, \"a canonical ISO timestamp\");\n }\n\n const date = new Date(value);\n // The round trip pins the backend DTO's Date#toISOString() wire contract.\n if (Number.isNaN(date.getTime()) || date.toISOString() !== value) {\n throw invalidCloudResponse(field, \"a canonical ISO timestamp\");\n }\n\n return date;\n};\n\nexport const readCloudJSONObject = (\n value: unknown,\n field: string,\n): ReadonlyJSONObject => readCloudRecord(value, field) as ReadonlyJSONObject;\n"],"mappings":";AAEA,IAAa,qBAAb,cAAwC,MAAM;CAC5C,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;AAEA,MAAM,wBAAwB,OAAe,aAC3C,IAAI,mBACF,yCAAyC,MAAM,cAAc,UAC/D;AAEF,MAAa,mBACX,OACA,UAC4B;CAC5B,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GACpE,MAAM,qBAAqB,OAAO,WAAW;CAE/C,OAAO;AACT;AAEA,MAAa,kBAAkB,OAAgB,UAA6B;CAC1E,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,MAAM,qBAAqB,OAAO,UAAU;CACvE,OAAO;AACT;AAEA,MAAa,mBAAmB,OAAgB,UAA0B;CACxE,IAAI,OAAO,UAAU,UAAU,MAAM,qBAAqB,OAAO,UAAU;CAC3E,OAAO;AACT;AAEA,MAAa,2BACX,OACA,UACkB;CAClB,IAAI,UAAU,MAAM,OAAO;CAC3B,OAAO,gBAAgB,OAAO,KAAK;AACrC;AAEA,MAAa,oBAAoB,OAAgB,UAA2B;CAC1E,IAAI,OAAO,UAAU,WACnB,MAAM,qBAAqB,OAAO,WAAW;CAE/C,OAAO;AACT;AAEA,MAAa,oBAAoB,OAAgB,UAA0B;CACzE,IAAI,CAAC,OAAO,UAAU,KAAK,GAAG,MAAM,qBAAqB,OAAO,YAAY;CAC5E,OAAO;AACT;AAEA,MAAa,sBAAsB,OAAgB,UAAwB;CACzE,IAAI,OAAO,UAAU,UACnB,MAAM,qBAAqB,OAAO,2BAA2B;CAG/D,MAAM,OAAO,IAAI,KAAK,KAAK;CAE3B,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,KAAK,KAAK,YAAY,MAAM,OACzD,MAAM,qBAAqB,OAAO,2BAA2B;CAG/D,OAAO;AACT;AAEA,MAAa,uBACX,OACA,UACuB,gBAAgB,OAAO,KAAK"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { McpSamplingHandler, SamplingCallData, createSamplingCollector, wrapSamplingHandler } from "./instrumentMcpSampling.js";
2
2
  import { AssistantCloudRunReport } from "./AssistantCloudRuns.js";
3
- import { AssistantCloudTelemetryConfig } from "./AssistantCloudAPI.js";
3
+ import { AssistantCloudTelemetryConfig, CloudAPIError } from "./AssistantCloudAPI.js";
4
4
  import { CloudMessage } from "./AssistantCloudThreadMessages.js";
5
5
  import { AssistantCloud } from "./AssistantCloud.js";
6
6
  import { CloudMessagePersistence } from "./CloudMessagePersistence.js";
7
7
  import { MessageFormatAdapter, createFormattedPersistence } from "./FormattedCloudPersistence.js";
8
- export { AssistantCloud, type AssistantCloudRunReport, type AssistantCloudTelemetryConfig, type CloudMessage, CloudMessagePersistence, type McpSamplingHandler, type MessageFormatAdapter, type SamplingCallData, createFormattedPersistence, createSamplingCollector, wrapSamplingHandler };
8
+ import { CloudResponseError } from "./cloudResponse.js";
9
+ export { AssistantCloud, type AssistantCloudRunReport, type AssistantCloudTelemetryConfig, CloudAPIError, type CloudMessage, CloudMessagePersistence, CloudResponseError, type McpSamplingHandler, type MessageFormatAdapter, type SamplingCallData, createFormattedPersistence, createSamplingCollector, wrapSamplingHandler };
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { CloudAPIError } from "./AssistantCloudAPI.js";
2
+ import { CloudResponseError } from "./cloudResponse.js";
1
3
  import { AssistantCloud } from "./AssistantCloud.js";
2
4
  import { CloudMessagePersistence } from "./CloudMessagePersistence.js";
3
5
  import { createFormattedPersistence } from "./FormattedCloudPersistence.js";
4
6
  import { createSamplingCollector, wrapSamplingHandler } from "./instrumentMcpSampling.js";
5
- export { AssistantCloud, CloudMessagePersistence, createFormattedPersistence, createSamplingCollector, wrapSamplingHandler };
7
+ export { AssistantCloud, CloudAPIError, CloudMessagePersistence, CloudResponseError, createFormattedPersistence, createSamplingCollector, wrapSamplingHandler };
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentMcpSampling.d.ts","names":[],"sources":["../src/instrumentMcpSampling.ts"],"mappings":";;AAQA;;;;;;KAAY,gBAAA;EACV,QAAA;EACA,YAAA;EACA,aAAA;EACA,gBAAA;EACA,mBAAA;EACA,WAAA;AAAA;AAAA,KAGU,kBAAA,IACV,OAAA,EAAS,kBAAA,KACN,OAAA,CAAQ,mBAAA;AAAA,KAED,kBAAA;EACV,MAAA;EACA,MAAA;IACE,QAAA;IACA,gBAAA;MAAqB,KAAA;QAAU,IAAA;MAAA;IAAA;IAC/B,SAAA;IAAA,CACC,GAAA;EAAA;AAAA;AAAA,KAIO,mBAAA;EACV,KAAA;EACA,OAAA;EACA,KAAA;IACE,WAAA;IACA,YAAA;IACA,YAAA;IACA,gBAAA;IACA,eAAA;IACA,iBAAA;EAAA;EAAA,CAED,GAAA;AAAA;;;;;;;;;;;;;;;AAAW;AAqBd;;;iBAAgB,mBAAA,CACd,OAAA,EAAS,kBAAA,EACT,cAAA,GAAiB,IAAA,EAAM,gBAAA,YACtB,kBAAA;;;;;;;;;;;;AAAkB;iBA6CL,uBAAA;kBAGI,gBAAA;kBAAA,gBAAA"}
1
+ {"version":3,"file":"instrumentMcpSampling.d.ts","names":[],"sources":["../src/instrumentMcpSampling.ts"],"mappings":";;;;;;;;KAQY;EACV;EACA;EACA;EACA;EACA;EACA;;KAGU,sBACV,SAAS,uBACN,QAAQ;KAED;EACV;EACA;IACE;IACA;MAAqB;QAAU;;;IAC/B;KACC;;;KAIO;EACV;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;;GAED;;;;;;;;;;;;;;;;;;;;iBAqBa,oBACd,SAAS,oBACT,iBAAiB,MAAM,4BACtB;;;;;;;;;;;;;iBA6Ca;EAGI,UAAA,MAAA;kBAAA"}
@@ -1 +1 @@
1
- export { };
1
+ export {}
@@ -1,9 +1,7 @@
1
1
  import { vi } from "vitest";
2
2
  //#region src/tests/setup.ts
3
- const OriginalDate = globalThis.Date;
4
- const fixedDate = new OriginalDate("2023-01-01");
5
- globalThis.Date = vi.fn(() => fixedDate);
6
- globalThis.Date.now = vi.fn(() => fixedDate.getTime());
3
+ vi.useFakeTimers({ toFake: ["Date"] });
4
+ vi.setSystemTime(/* @__PURE__ */ new Date("2023-01-01T00:00:00.000Z"));
7
5
  //#endregion
8
6
 
9
7
  //# sourceMappingURL=setup.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","names":[],"sources":["../../src/tests/setup.ts"],"sourcesContent":["// This file contains setup code for tests\nimport { vi } from \"vitest\";\n\n// Set up globalThis mocks if needed\n// Using a fixed date to avoid recursive calls\nconst OriginalDate = globalThis.Date;\nconst fixedDate = new OriginalDate(\"2023-01-01\");\nglobalThis.Date = vi.fn(() => fixedDate) as any;\nglobalThis.Date.now = vi.fn(() => fixedDate.getTime());\n\n// Add any other globalThis setup needed for tests\n"],"mappings":";;AAKA,MAAM,eAAe,WAAW;AAChC,MAAM,YAAY,IAAI,aAAa,YAAY;AAC/C,WAAW,OAAO,GAAG,SAAS,SAAS;AACvC,WAAW,KAAK,MAAM,GAAG,SAAS,UAAU,QAAQ,CAAC"}
1
+ {"version":3,"file":"setup.js","names":[],"sources":["../../src/tests/setup.ts"],"sourcesContent":["import { vi } from \"vitest\";\n\nvi.useFakeTimers({ toFake: [\"Date\"] });\nvi.setSystemTime(new Date(\"2023-01-01T00:00:00.000Z\"));\n"],"mappings":";;AAEA,GAAG,cAAc,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AACrC,GAAG,8BAAc,IAAI,KAAK,0BAA0B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assistant-cloud",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "Cloud integration for assistant-ui",
5
5
  "keywords": [
6
6
  "assistant",
@@ -27,12 +27,12 @@
27
27
  ],
28
28
  "sideEffects": false,
29
29
  "dependencies": {
30
- "assistant-stream": "^0.3.24"
30
+ "assistant-stream": "^0.3.27"
31
31
  },
32
32
  "devDependencies": {
33
- "@types/node": "^26.0.0",
34
- "vitest": "^4.1.9",
35
- "@assistant-ui/x-buildutils": "0.0.16"
33
+ "@types/node": "^26.1.1",
34
+ "vitest": "^4.1.10",
35
+ "@assistant-ui/x-buildutils": "0.0.19"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public",
@@ -4,12 +4,14 @@ import {
4
4
  type AssistantCloudTelemetryConfig,
5
5
  } from "./AssistantCloudAPI";
6
6
  import { AssistantCloudAuthTokens } from "./AssistantCloudAuthTokens";
7
+ import { AssistantCloudProjects } from "./AssistantCloudProjects";
7
8
  import { AssistantCloudRuns } from "./AssistantCloudRuns";
8
9
  import { AssistantCloudThreads } from "./AssistantCloudThreads";
9
10
  import { AssistantCloudFiles } from "./AssistantCloudFiles";
10
11
 
11
12
  export class AssistantCloud {
12
13
  public readonly threads;
14
+ public readonly projects;
13
15
  public readonly auth;
14
16
  public readonly runs;
15
17
  public readonly files;
@@ -18,6 +20,7 @@ export class AssistantCloud {
18
20
  constructor(config: AssistantCloudConfig) {
19
21
  const api = new AssistantCloudAPI(config);
20
22
  this.threads = new AssistantCloudThreads(api);
23
+ this.projects = new AssistantCloudProjects(api);
21
24
  this.auth = {
22
25
  tokens: new AssistantCloudAuthTokens(api),
23
26
  };
@@ -48,10 +48,13 @@ export type AssistantCloudConfig = (
48
48
  telemetry?: boolean | AssistantCloudTelemetryConfig;
49
49
  };
50
50
 
51
- class CloudAPIError extends Error {
52
- constructor(message: string) {
51
+ export class CloudAPIError extends Error {
52
+ constructor(
53
+ message: string,
54
+ public readonly status: number,
55
+ ) {
53
56
  super(message);
54
- this.name = "APIError";
57
+ this.name = "CloudAPIError";
55
58
  }
56
59
  }
57
60
 
@@ -62,26 +65,31 @@ type MakeRequestOptions = {
62
65
  body?: object | undefined;
63
66
  };
64
67
 
68
+ const normalizeBaseUrl = (baseUrl: string) => {
69
+ if (!baseUrl || !baseUrl.endsWith("/")) return baseUrl;
70
+ return baseUrl.slice(0, -1);
71
+ };
72
+
65
73
  export class AssistantCloudAPI {
66
74
  public _auth: AssistantCloudAuthStrategy;
67
75
  public _baseUrl;
68
76
 
69
77
  constructor(config: AssistantCloudConfig) {
70
78
  if ("authToken" in config) {
71
- this._baseUrl = config.baseUrl;
79
+ this._baseUrl = normalizeBaseUrl(config.baseUrl);
72
80
  this._auth = new AssistantCloudJWTAuthStrategy(config.authToken);
73
81
  } else if ("apiKey" in config) {
74
- this._baseUrl = (
75
- config.baseUrl ?? "https://backend.assistant-api.com"
76
- ).replace(/\/$/, "");
82
+ this._baseUrl = normalizeBaseUrl(
83
+ config.baseUrl ?? "https://backend.assistant-api.com",
84
+ );
77
85
  this._auth = new AssistantCloudAPIKeyAuthStrategy(
78
86
  config.apiKey,
79
87
  config.userId,
80
88
  config.workspaceId,
81
89
  );
82
90
  } else if ("anonymous" in config) {
83
- this._baseUrl = config.baseUrl;
84
- this._auth = new AssistantCloudAnonymousAuthStrategy(config.baseUrl);
91
+ this._baseUrl = normalizeBaseUrl(config.baseUrl);
92
+ this._auth = new AssistantCloudAnonymousAuthStrategy(this._baseUrl);
85
93
  } else {
86
94
  throw new Error(
87
95
  "Invalid configuration: Must provide authToken, apiKey, or anonymous configuration",
@@ -90,7 +98,7 @@ export class AssistantCloudAPI {
90
98
  }
91
99
 
92
100
  public async initializeAuth() {
93
- return !!this._auth.getAuthHeaders();
101
+ return !!(await this._auth.getAuthHeaders());
94
102
  }
95
103
 
96
104
  public async makeRawRequest(
@@ -133,11 +141,12 @@ export class AssistantCloudAPI {
133
141
  const text = await response.text();
134
142
  try {
135
143
  const body = JSON.parse(text);
136
- throw new CloudAPIError(body.message);
144
+ throw new CloudAPIError(body.message, response.status);
137
145
  } catch (error) {
138
146
  if (error instanceof CloudAPIError) throw error;
139
- throw new Error(
147
+ throw new CloudAPIError(
140
148
  `Request failed with status ${response.status}, ${text}`,
149
+ response.status,
141
150
  );
142
151
  }
143
152
  }
@@ -147,6 +156,15 @@ export class AssistantCloudAPI {
147
156
 
148
157
  public async makeRequest(endpoint: string, options: MakeRequestOptions = {}) {
149
158
  const response = await this.makeRawRequest(endpoint, options);
150
- return response.json();
159
+ if (
160
+ response.status === 204 ||
161
+ response.headers.get("content-length") === "0"
162
+ )
163
+ return undefined;
164
+
165
+ const text = await response.text();
166
+ if (text.trim() === "") return undefined;
167
+
168
+ return JSON.parse(text);
151
169
  }
152
170
  }