assistant-cloud 0.2.0 → 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 +48 -6
- package/dist/AssistantCloud.d.ts +3 -3
- package/dist/AssistantCloud.d.ts.map +1 -1
- package/dist/AssistantCloud.js +2 -0
- package/dist/AssistantCloud.js.map +1 -1
- package/dist/AssistantCloudAPI.d.ts +14 -6
- package/dist/AssistantCloudAPI.d.ts.map +1 -1
- package/dist/AssistantCloudAPI.js +17 -1
- package/dist/AssistantCloudAPI.js.map +1 -1
- package/dist/AssistantCloudAuthStrategy.d.ts +6 -7
- package/dist/AssistantCloudAuthStrategy.d.ts.map +1 -1
- package/dist/AssistantCloudAuthStrategy.js +4 -2
- package/dist/AssistantCloudAuthStrategy.js.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 +5 -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 +3 -3
- package/dist/AssistantCloudRuns.d.ts.map +1 -1
- package/dist/AssistantCloudRuns.js +2 -1
- package/dist/AssistantCloudRuns.js.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 +73 -0
- package/dist/CloudEngagementReporter.d.ts.map +1 -0
- package/dist/CloudEngagementReporter.js +132 -0
- package/dist/CloudEngagementReporter.js.map +1 -0
- package/dist/CloudMessagePersistence.d.ts +9 -11
- package/dist/CloudMessagePersistence.d.ts.map +1 -1
- package/dist/CloudMessagePersistence.js +18 -11
- package/dist/CloudMessagePersistence.js.map +1 -1
- package/dist/CloudRunReporter.d.ts +19 -0
- package/dist/CloudRunReporter.d.ts.map +1 -0
- package/dist/CloudRunReporter.js +47 -0
- package/dist/CloudRunReporter.js.map +1 -0
- package/dist/FormattedCloudPersistence.d.ts +5 -11
- package/dist/FormattedCloudPersistence.d.ts.map +1 -1
- package/dist/FormattedCloudPersistence.js +3 -8
- package/dist/FormattedCloudPersistence.js.map +1 -1
- package/dist/ai-sdk/index.d.ts +32 -0
- package/dist/ai-sdk/index.d.ts.map +1 -0
- package/dist/ai-sdk/index.js +147 -0
- package/dist/ai-sdk/index.js.map +1 -0
- 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/generateThreadTitle.js +1 -0
- package/dist/generateThreadTitle.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -2
- package/dist/instrumentMcpSampling.d.ts +6 -7
- package/dist/instrumentMcpSampling.d.ts.map +1 -1
- package/dist/instrumentMcpSampling.js +12 -2
- package/dist/instrumentMcpSampling.js.map +1 -1
- package/dist/runTelemetry.d.ts +30 -15
- package/dist/runTelemetry.d.ts.map +1 -1
- package/dist/runTelemetry.js.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 +4 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/package.json +24 -10
- package/src/AssistantCloud.ts +3 -0
- package/src/AssistantCloudAPI.ts +31 -1
- package/src/AssistantCloudAuthStrategy.ts +4 -2
- package/src/AssistantCloudEvents.test.ts +68 -2
- package/src/AssistantCloudEvents.ts +6 -0
- package/src/AssistantCloudRuns.ts +1 -0
- package/src/AssistantCloudThreadMessages.test.ts +53 -2
- package/src/AssistantCloudThreadMessages.ts +13 -1
- package/src/CloudEngagementReporter.ts +231 -0
- package/src/CloudMessagePersistence.ts +24 -13
- package/src/CloudRunReporter.ts +50 -0
- package/src/FormattedCloudPersistence.ts +3 -8
- package/src/ai-sdk/index.test.ts +258 -0
- package/src/ai-sdk/index.ts +222 -0
- package/src/generateThreadTitle.test.ts +32 -0
- package/src/generateThreadTitle.ts +1 -0
- package/src/index.ts +11 -1
- package/src/instrumentMcpSampling.test.ts +102 -0
- package/src/instrumentMcpSampling.ts +16 -2
- package/src/runTelemetry.ts +17 -0
- package/src/tests/AssistantCloud.test.ts +33 -1
- package/src/tests/AssistantCloudAPI.test.ts +51 -0
- package/src/tests/AssistantCloudAuthStrategy.test.ts +22 -0
- package/src/tests/AssistantCloudProjects.test.ts +1 -5
- package/src/tests/CloudEngagementReporter.test.ts +184 -0
- package/src/tests/CloudMessagePersistence.test.ts +235 -0
- package/src/tests/CloudRunReporter.test.ts +135 -0
- package/src/version.ts +4 -0
|
@@ -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\";\nimport type { CloudMessage } from \"./AssistantCloudThreadMessages\";\n\nconst CLOUD_MESSAGE_PAGE_SIZE = 200;\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"CloudMessagePersistence.js","names":[],"sources":["../src/CloudMessagePersistence.ts"],"sourcesContent":["import type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport type { AssistantCloud } from \"./AssistantCloud\";\nimport type { CloudMessage } from \"./AssistantCloudThreadMessages\";\n\nconst CLOUD_MESSAGE_PAGE_SIZE = 200;\n\n/**\n * Appends, updates and loads cloud messages while mapping local ids to cloud\n * ids and chaining parent_id. A parent that is still being created is awaited,\n * so concurrent appends land under the right parent.\n */\nexport class CloudMessagePersistence {\n private idMapping = new Map<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 const existing = this.idMapping.get(messageId);\n if (existing instanceof Promise) {\n await existing;\n return;\n }\n\n const task = (async () => {\n const parentEntry = parentId ? this.idMapping.get(parentId) : undefined;\n const resolvedParentId = parentId\n ? ((await parentEntry) ?? parentId)\n : null;\n const { message_id } = await cloud.threads.messages.create(threadId, {\n parent_id: resolvedParentId,\n format,\n content,\n });\n return message_id;\n })();\n\n this.idMapping.set(messageId, task);\n try {\n const remoteId = await task;\n if (this.idMapping.get(messageId) === task) {\n this.idMapping.set(messageId, remoteId);\n }\n } catch (err) {\n if (this.idMapping.get(messageId) === task) {\n this.idMapping.delete(messageId);\n }\n throw err;\n }\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 this.idMapping.has(messageId);\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.get(messageId);\n if (!entry) return undefined;\n return entry;\n }\n\n getResolvedRemoteId(messageId: string): string | undefined {\n const entry = this.idMapping.get(messageId);\n return typeof entry === \"string\" ? entry : undefined;\n }\n\n /**\n * Load messages from the cloud and populate the ID mapping.\n *\n * The list endpoint caps a response at 200 rows, so pages are followed by\n * message ID cursor until a short page and concatenated in server order.\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 * A loaded ID that an append already maps keeps the remote ID from that append, and falls back to the loaded ID if the append fails.\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 idMapping = this.idMapping;\n const cloud = this.getCloud();\n const messages: CloudMessage[] = [];\n const seen = new Set<string>();\n let after: string | undefined;\n\n while (true) {\n const page = await cloud.threads.messages.list(threadId, {\n ...(format ? { format } : undefined),\n limit: CLOUD_MESSAGE_PAGE_SIZE,\n ...(after ? { after } : undefined),\n });\n const last = page.messages.at(-1);\n if (!last) break;\n\n // A cursor the server cannot resolve drops the keyset filter and replays\n // an earlier page, so already-seen rows end the walk instead of repeating.\n const fresh = page.messages.filter((m) => !seen.has(m.id));\n if (fresh.length === 0) break;\n for (const m of fresh) seen.add(m.id);\n\n messages.push(...fresh);\n if (page.messages.length < CLOUD_MESSAGE_PAGE_SIZE) break;\n after = last.id;\n }\n\n if (this.idMapping === idMapping) {\n for (const m of messages) {\n const entry = idMapping.get(m.id);\n if (entry === undefined) {\n idMapping.set(m.id, m.id);\n } else if (entry instanceof Promise) {\n void entry.catch(() => {\n const current = idMapping.get(m.id);\n if (current === undefined || current === entry) {\n idMapping.set(m.id, m.id);\n }\n });\n }\n }\n }\n return messages;\n }\n\n /**\n * Reset the ID mapping (call when switching threads).\n *\n * Pending `load()` and `append()` calls are not cancelled and still settle\n * normally, but their results no longer populate the ID mapping.\n */\n reset() {\n this.idMapping = new Map();\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RunReportInit } from "./runTelemetry.js";
|
|
2
|
+
import { AssistantCloud } from "./AssistantCloud.js";
|
|
3
|
+
//#region src/CloudRunReporter.d.ts
|
|
4
|
+
export type CloudRunReportInit = Omit<RunReportInit, "telemetry">;
|
|
5
|
+
/**
|
|
6
|
+
* Sends run reports the way every client integration has to: nothing while
|
|
7
|
+
* telemetry is off, the cloud's environment, release and tags on every report,
|
|
8
|
+
* the `beforeReport` hook applied last, and a failed send that never surfaces.
|
|
9
|
+
* A keyed report is deduplicated while in flight and after an attempt. A
|
|
10
|
+
* rate-limited attempt releases the key so a later observation can try again.
|
|
11
|
+
*/
|
|
12
|
+
export declare class CloudRunReporter {
|
|
13
|
+
private readonly reported;
|
|
14
|
+
private readonly getCloud;
|
|
15
|
+
constructor(cloud: AssistantCloud | (() => AssistantCloud));
|
|
16
|
+
report(init: CloudRunReportInit, key?: string): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//# sourceMappingURL=CloudRunReporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CloudRunReporter.d.ts","names":[],"sources":["../src/CloudRunReporter.ts"],"mappings":";;;YAIY,qBAAqB,KAAK;;;;;;;;qBASzB;mBACM;mBACA;EAEL,YAAA,OAAO,wBAAwB;EAI9B,OAAO,MAAM,oBAAoB,eAAe"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { CloudAPIError } from "./AssistantCloudAPI.js";
|
|
2
|
+
import { createRunReport } from "./runTelemetry.js";
|
|
3
|
+
//#region src/CloudRunReporter.ts
|
|
4
|
+
/**
|
|
5
|
+
* Sends run reports the way every client integration has to: nothing while
|
|
6
|
+
* telemetry is off, the cloud's environment, release and tags on every report,
|
|
7
|
+
* the `beforeReport` hook applied last, and a failed send that never surfaces.
|
|
8
|
+
* A keyed report is deduplicated while in flight and after an attempt. A
|
|
9
|
+
* rate-limited attempt releases the key so a later observation can try again.
|
|
10
|
+
*/
|
|
11
|
+
var CloudRunReporter = class {
|
|
12
|
+
reported = /* @__PURE__ */ new Set();
|
|
13
|
+
getCloud;
|
|
14
|
+
constructor(cloud) {
|
|
15
|
+
this.getCloud = typeof cloud === "function" ? cloud : () => cloud;
|
|
16
|
+
}
|
|
17
|
+
async report(init, key) {
|
|
18
|
+
let claimedKey;
|
|
19
|
+
try {
|
|
20
|
+
const cloud = this.getCloud();
|
|
21
|
+
if (!cloud.telemetry.enabled) return;
|
|
22
|
+
if (key !== void 0 && this.reported.has(key)) return;
|
|
23
|
+
const initial = createRunReport({
|
|
24
|
+
...init,
|
|
25
|
+
telemetry: cloud.telemetry
|
|
26
|
+
});
|
|
27
|
+
const { beforeReport } = cloud.telemetry;
|
|
28
|
+
const report = beforeReport ? beforeReport(initial) : initial;
|
|
29
|
+
if (!report) return;
|
|
30
|
+
if (key !== void 0) {
|
|
31
|
+
this.reported.add(key);
|
|
32
|
+
claimedKey = key;
|
|
33
|
+
}
|
|
34
|
+
await cloud.runs.report(report);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (claimedKey !== void 0 && isRetryableReportError(error)) this.reported.delete(claimedKey);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const isRetryableReportError = (error) => {
|
|
42
|
+
return error instanceof CloudAPIError && error.status === 429;
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { CloudRunReporter };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=CloudRunReporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CloudRunReporter.js","names":[],"sources":["../src/CloudRunReporter.ts"],"sourcesContent":["import type { AssistantCloud } from \"./AssistantCloud\";\nimport { CloudAPIError } from \"./AssistantCloudAPI\";\nimport { createRunReport, type RunReportInit } from \"./runTelemetry\";\n\nexport type CloudRunReportInit = Omit<RunReportInit, \"telemetry\">;\n\n/**\n * Sends run reports the way every client integration has to: nothing while\n * telemetry is off, the cloud's environment, release and tags on every report,\n * the `beforeReport` hook applied last, and a failed send that never surfaces.\n * A keyed report is deduplicated while in flight and after an attempt. A\n * rate-limited attempt releases the key so a later observation can try again.\n */\nexport class CloudRunReporter {\n private readonly reported = new Set<string>();\n private readonly getCloud: () => AssistantCloud;\n\n constructor(cloud: AssistantCloud | (() => AssistantCloud)) {\n this.getCloud = typeof cloud === \"function\" ? cloud : () => cloud;\n }\n\n public async report(init: CloudRunReportInit, key?: string): Promise<void> {\n let claimedKey: string | undefined;\n try {\n const cloud = this.getCloud();\n if (!cloud.telemetry.enabled) return;\n if (key !== undefined && this.reported.has(key)) return;\n\n const initial = createRunReport({ ...init, telemetry: cloud.telemetry });\n const { beforeReport } = cloud.telemetry;\n const report = beforeReport ? beforeReport(initial) : initial;\n if (!report) return;\n\n if (key !== undefined) {\n this.reported.add(key);\n claimedKey = key;\n }\n await cloud.runs.report(report);\n } catch (error) {\n if (claimedKey !== undefined && isRetryableReportError(error)) {\n this.reported.delete(claimedKey);\n }\n return;\n }\n }\n}\n\nconst isRetryableReportError = (error: unknown): boolean => {\n return error instanceof CloudAPIError && error.status === 429;\n};\n"],"mappings":";;;;;;;;;;AAaA,IAAa,mBAAb,MAA8B;CAC5B,2BAA4B,IAAI,IAAY;CAC5C;CAEA,YAAY,OAAgD;EAC1D,KAAK,WAAW,OAAO,UAAU,aAAa,cAAc;CAC9D;CAEA,MAAa,OAAO,MAA0B,KAA6B;EACzE,IAAI;EACJ,IAAI;GACF,MAAM,QAAQ,KAAK,SAAS;GAC5B,IAAI,CAAC,MAAM,UAAU,SAAS;GAC9B,IAAI,QAAQ,KAAA,KAAa,KAAK,SAAS,IAAI,GAAG,GAAG;GAEjD,MAAM,UAAU,gBAAgB;IAAE,GAAG;IAAM,WAAW,MAAM;GAAU,CAAC;GACvE,MAAM,EAAE,iBAAiB,MAAM;GAC/B,MAAM,SAAS,eAAe,aAAa,OAAO,IAAI;GACtD,IAAI,CAAC,QAAQ;GAEb,IAAI,QAAQ,KAAA,GAAW;IACrB,KAAK,SAAS,IAAI,GAAG;IACrB,aAAa;GACf;GACA,MAAM,MAAM,KAAK,OAAO,MAAM;EAChC,SAAS,OAAO;GACd,IAAI,eAAe,KAAA,KAAa,uBAAuB,KAAK,GAC1D,KAAK,SAAS,OAAO,UAAU;GAEjC;EACF;CACF;AACF;AAEA,MAAM,0BAA0B,UAA4B;CAC1D,OAAO,iBAAiB,iBAAiB,MAAM,WAAW;AAC5D"}
|
|
@@ -5,7 +5,7 @@ import { ReadonlyJSONObject } from "assistant-stream/utils";
|
|
|
5
5
|
* in @assistant-ui/react, but defined here to avoid cross-package type moves.
|
|
6
6
|
* TypeScript's structural typing ensures these are interchangeable.
|
|
7
7
|
*/
|
|
8
|
-
type MessageFormatAdapter<TMessage, TStorageFormat> = {
|
|
8
|
+
export type MessageFormatAdapter<TMessage, TStorageFormat> = {
|
|
9
9
|
format: string;
|
|
10
10
|
encode(item: {
|
|
11
11
|
parentId: string | null;
|
|
@@ -23,16 +23,11 @@ type MessageFormatAdapter<TMessage, TStorageFormat> = {
|
|
|
23
23
|
getId(message: TMessage): string;
|
|
24
24
|
};
|
|
25
25
|
/**
|
|
26
|
-
* Wraps a CloudMessagePersistence
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* - useCloudChat (standalone AI SDK hook)
|
|
30
|
-
* - AssistantCloudThreadHistoryAdapter.withFormat() (assistant-ui runtime)
|
|
31
|
-
*
|
|
32
|
-
* The persistence parameter is typed structurally (not by class) so callers
|
|
33
|
-
* don't need to import CloudMessagePersistence directly.
|
|
26
|
+
* Wraps a CloudMessagePersistence with a MessageFormatAdapter's encode and
|
|
27
|
+
* decode. The persistence parameter is typed structurally, so a caller does
|
|
28
|
+
* not need to import the class.
|
|
34
29
|
*/
|
|
35
|
-
declare const createFormattedPersistence: <TMessage, TStorageFormat>(persistence: {
|
|
30
|
+
export declare const createFormattedPersistence: <TMessage, TStorageFormat>(persistence: {
|
|
36
31
|
append: (threadId: string, messageId: string, parentId: string | null, format: string, content: ReadonlyJSONObject) => Promise<void>;
|
|
37
32
|
load: (threadId: string, format?: string) => Promise<any[]>;
|
|
38
33
|
isPersisted: (messageId: string) => boolean;
|
|
@@ -55,5 +50,4 @@ declare const createFormattedPersistence: <TMessage, TStorageFormat>(persistence
|
|
|
55
50
|
isPersisted: (messageId: string) => boolean;
|
|
56
51
|
};
|
|
57
52
|
//#endregion
|
|
58
|
-
export { MessageFormatAdapter, createFormattedPersistence };
|
|
59
53
|
//# sourceMappingURL=FormattedCloudPersistence.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormattedCloudPersistence.d.ts","names":[],"sources":["../src/FormattedCloudPersistence.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"FormattedCloudPersistence.d.ts","names":[],"sources":["../src/FormattedCloudPersistence.ts"],"mappings":";;;;;;;YAOY,qBAAqB,UAAU;EACzC;EACA,OAAO;IAAQ;IAAyB,SAAS;MAAa;EAC9D,OAAO;IACL;IACA;IACA;IACA,SAAS;;IACL;IAAyB,SAAS;;EACxC,MAAM,SAAS;;;;;;;qBAQJ,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;;MA1Db;;;;EA0ES,cAAA"}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
//#region src/FormattedCloudPersistence.ts
|
|
2
2
|
/**
|
|
3
|
-
* Wraps a CloudMessagePersistence
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - useCloudChat (standalone AI SDK hook)
|
|
7
|
-
* - AssistantCloudThreadHistoryAdapter.withFormat() (assistant-ui runtime)
|
|
8
|
-
*
|
|
9
|
-
* The persistence parameter is typed structurally (not by class) so callers
|
|
10
|
-
* don't need to import CloudMessagePersistence directly.
|
|
3
|
+
* Wraps a CloudMessagePersistence with a MessageFormatAdapter's encode and
|
|
4
|
+
* decode. The persistence parameter is typed structurally, so a caller does
|
|
5
|
+
* not need to import the class.
|
|
11
6
|
*/
|
|
12
7
|
const createFormattedPersistence = (persistence, adapter) => ({
|
|
13
8
|
append: async (threadId, item) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormattedCloudPersistence.js","names":[],"sources":["../src/FormattedCloudPersistence.ts"],"sourcesContent":["import type { ReadonlyJSONObject } from \"assistant-stream/utils\";\n\n/**\n * Format adapter shape — structurally identical to the MessageFormatAdapter\n * in @assistant-ui/react, but defined here to avoid cross-package type moves.\n * TypeScript's structural typing ensures these are interchangeable.\n */\nexport type MessageFormatAdapter<TMessage, TStorageFormat> = {\n format: string;\n encode(item: { parentId: string | null; message: TMessage }): TStorageFormat;\n decode(stored: {\n id: string;\n parent_id: string | null;\n format: string;\n content: TStorageFormat;\n }): { parentId: string | null; message: TMessage };\n getId(message: TMessage): string;\n};\n\n/**\n * Wraps a CloudMessagePersistence
|
|
1
|
+
{"version":3,"file":"FormattedCloudPersistence.js","names":[],"sources":["../src/FormattedCloudPersistence.ts"],"sourcesContent":["import type { ReadonlyJSONObject } from \"assistant-stream/utils\";\n\n/**\n * Format adapter shape — structurally identical to the MessageFormatAdapter\n * in @assistant-ui/react, but defined here to avoid cross-package type moves.\n * TypeScript's structural typing ensures these are interchangeable.\n */\nexport type MessageFormatAdapter<TMessage, TStorageFormat> = {\n format: string;\n encode(item: { parentId: string | null; message: TMessage }): TStorageFormat;\n decode(stored: {\n id: string;\n parent_id: string | null;\n format: string;\n content: TStorageFormat;\n }): { parentId: string | null; message: TMessage };\n getId(message: TMessage): string;\n};\n\n/**\n * Wraps a CloudMessagePersistence with a MessageFormatAdapter's encode and\n * decode. The persistence parameter is typed structurally, so a caller does\n * not need to import the class.\n */\nexport const createFormattedPersistence = <TMessage, TStorageFormat>(\n persistence: {\n append: (\n threadId: string,\n messageId: string,\n parentId: string | null,\n format: string,\n content: ReadonlyJSONObject,\n ) => Promise<void>;\n load: (threadId: string, format?: string) => Promise<any[]>;\n isPersisted: (messageId: string) => boolean;\n update?: (\n threadId: string,\n messageId: string,\n format: string,\n content: ReadonlyJSONObject,\n ) => Promise<void>;\n },\n adapter: MessageFormatAdapter<TMessage, TStorageFormat>,\n) => ({\n append: async (\n threadId: string,\n item: { parentId: string | null; message: TMessage },\n ): Promise<void> => {\n const messageId = adapter.getId(item.message);\n const encoded = adapter.encode(item);\n return persistence.append(\n threadId,\n messageId,\n item.parentId,\n adapter.format,\n encoded as ReadonlyJSONObject,\n );\n },\n update: persistence.update\n ? async (\n threadId: string,\n item: { parentId: string | null; message: TMessage },\n messageId: string,\n ): Promise<void> => {\n const encoded = adapter.encode(item);\n return persistence.update!(\n threadId,\n messageId,\n adapter.format,\n encoded as ReadonlyJSONObject,\n );\n }\n : undefined,\n load: async (threadId: string) => {\n const messages = await persistence.load(threadId, adapter.format);\n return {\n messages: messages\n .filter((m) => m.format === adapter.format)\n .map((m) =>\n adapter.decode({\n id: m.id,\n parent_id: m.parent_id,\n format: m.format,\n content: m.content as TStorageFormat,\n }),\n )\n .reverse(),\n };\n },\n isPersisted: (messageId: string) => persistence.isPersisted(messageId),\n});\n"],"mappings":";;;;;;AAwBA,MAAa,8BACX,aAiBA,aACI;CACJ,QAAQ,OACN,UACA,SACkB;EAClB,MAAM,YAAY,QAAQ,MAAM,KAAK,OAAO;EAC5C,MAAM,UAAU,QAAQ,OAAO,IAAI;EACnC,OAAO,YAAY,OACjB,UACA,WACA,KAAK,UACL,QAAQ,QACR,OACF;CACF;CACA,QAAQ,YAAY,SAChB,OACE,UACA,MACA,cACkB;EAClB,MAAM,UAAU,QAAQ,OAAO,IAAI;EACnC,OAAO,YAAY,OACjB,UACA,WACA,QAAQ,QACR,OACF;CACF,IACA,KAAA;CACJ,MAAM,OAAO,aAAqB;EAEhC,OAAO,EACL,WAAU,MAFW,YAAY,KAAK,UAAU,QAAQ,MAAM,EAAA,CAG3D,QAAQ,MAAM,EAAE,WAAW,QAAQ,MAAM,CAAC,CAC1C,KAAK,MACJ,QAAQ,OAAO;GACb,IAAI,EAAE;GACN,WAAW,EAAE;GACb,QAAQ,EAAE;GACV,SAAS,EAAE;EACb,CAAC,CACH,CAAC,CACA,QAAQ,EACb;CACF;CACA,cAAc,cAAsB,YAAY,YAAY,SAAS;AACvE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { RunMessageTelemetry } from "../runTelemetry.js";
|
|
2
|
+
import { MessageFormatAdapter } from "../FormattedCloudPersistence.js";
|
|
3
|
+
import { UIMessage } from "ai";
|
|
4
|
+
//#region src/ai-sdk/index.d.ts
|
|
5
|
+
export type AISDKStorageFormat = Omit<UIMessage, "id">;
|
|
6
|
+
/** The stored form of an AI SDK message: the message without its id. */
|
|
7
|
+
export declare const aiSDKV6FormatAdapter: MessageFormatAdapter<UIMessage, AISDKStorageFormat>;
|
|
8
|
+
/**
|
|
9
|
+
* A message as an AI SDK integration holds it, or as the cloud stored it under
|
|
10
|
+
* the ai-sdk/v6 format, which drops the id. Parts are typed by their `type`
|
|
11
|
+
* alone, so this shape and the telemetry read from it need nothing from `ai`.
|
|
12
|
+
*/
|
|
13
|
+
export type AISDKMessageLike = {
|
|
14
|
+
id?: string | undefined;
|
|
15
|
+
role: string;
|
|
16
|
+
parts: readonly {
|
|
17
|
+
type: string;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}[];
|
|
20
|
+
metadata?: unknown;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Reads the run report fields out of the assistant messages of one run. A run
|
|
24
|
+
* the AI SDK streamed as one message is one element; a run the cloud stored as
|
|
25
|
+
* several assistant rows is aggregated, step by step, in order. Returns null
|
|
26
|
+
* when no assistant message is present. Status reads completed when the run
|
|
27
|
+
* produced text or tool calls, as a live finish with reason `tool-calls` does;
|
|
28
|
+
* an integration that observed the finish event overrides it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function extractAISDKRunTelemetry(messages: readonly AISDKMessageLike[]): RunMessageTelemetry | null;
|
|
31
|
+
//#endregion
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/ai-sdk/index.ts"],"mappings":";;;;YAeY,qBAAqB,KAAK;;qBAGzB,sBAAsB,qBACjC,WACA;;;;;;YAgBU;EACV;EACA;EACA;IAAkB;KAAe;;EACjC;;;;;;;;;;wBAgHc,yBACd,mBAAmB,qBAClB"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { createRunTelemetryToolCall, extractRunTelemetryModelId, normalizeRunTelemetryUsage, truncateRunTelemetryText } from "../runTelemetry.js";
|
|
2
|
+
//#region src/ai-sdk/index.ts
|
|
3
|
+
/** The stored form of an AI SDK message: the message without its id. */
|
|
4
|
+
const aiSDKV6FormatAdapter = {
|
|
5
|
+
format: "ai-sdk/v6",
|
|
6
|
+
encode: ({ message: { id: _id, ...message } }) => message,
|
|
7
|
+
decode: (stored) => ({
|
|
8
|
+
parentId: stored.parent_id,
|
|
9
|
+
message: {
|
|
10
|
+
id: stored.id,
|
|
11
|
+
...stored.content
|
|
12
|
+
}
|
|
13
|
+
}),
|
|
14
|
+
getId: (message) => message.id
|
|
15
|
+
};
|
|
16
|
+
function isRecord(value) {
|
|
17
|
+
return value !== null && typeof value === "object";
|
|
18
|
+
}
|
|
19
|
+
function isPart(value) {
|
|
20
|
+
return isRecord(value) && typeof value.type === "string";
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The AI SDK's own tool part rules, kept here so the entry loads without the
|
|
24
|
+
* `ai` runtime: a static tool part is `tool-<name>`, a dynamic one is
|
|
25
|
+
* `dynamic-tool` with its name in `toolName`.
|
|
26
|
+
*/
|
|
27
|
+
function toolCallOf(part) {
|
|
28
|
+
if (typeof part.toolCallId !== "string") return void 0;
|
|
29
|
+
const isStatic = part.type.startsWith("tool-");
|
|
30
|
+
if (!isStatic && part.type !== "dynamic-tool") return void 0;
|
|
31
|
+
const toolName = isStatic ? part.type.slice(5) : typeof part.toolName === "string" ? part.toolName : void 0;
|
|
32
|
+
if (!toolName) return void 0;
|
|
33
|
+
return createRunTelemetryToolCall({
|
|
34
|
+
toolName,
|
|
35
|
+
toolCallId: part.toolCallId,
|
|
36
|
+
args: part.input ?? part.args,
|
|
37
|
+
result: part.output ?? part.result,
|
|
38
|
+
toolSource: isStatic ? "frontend" : "mcp"
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function attachSamplingCalls(toolCalls, metadata) {
|
|
42
|
+
const samplingCalls = isRecord(metadata?.samplingCalls) ? metadata.samplingCalls : void 0;
|
|
43
|
+
if (!samplingCalls) return;
|
|
44
|
+
for (const toolCall of toolCalls) {
|
|
45
|
+
const calls = samplingCalls[toolCall.tool_call_id];
|
|
46
|
+
if (Array.isArray(calls) && calls.length > 0) toolCall.sampling_calls = calls;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function stepUsages(metadata) {
|
|
50
|
+
const steps = metadata?.steps;
|
|
51
|
+
if (!Array.isArray(steps)) return [];
|
|
52
|
+
return steps.map((step) => isRecord(step) && isRecord(step.usage) ? step.usage : void 0);
|
|
53
|
+
}
|
|
54
|
+
function sumUsage(usages) {
|
|
55
|
+
const total = {};
|
|
56
|
+
for (const usage of usages) {
|
|
57
|
+
if (usage.inputTokens != null) total.inputTokens = (total.inputTokens ?? 0) + usage.inputTokens;
|
|
58
|
+
if (usage.outputTokens != null) total.outputTokens = (total.outputTokens ?? 0) + usage.outputTokens;
|
|
59
|
+
if (usage.reasoningTokens != null) total.reasoningTokens = (total.reasoningTokens ?? 0) + usage.reasoningTokens;
|
|
60
|
+
if (usage.cachedInputTokens != null) total.cachedInputTokens = (total.cachedInputTokens ?? 0) + usage.cachedInputTokens;
|
|
61
|
+
}
|
|
62
|
+
return total;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The usage a message reports: `metadata.usage` when the integration copied
|
|
66
|
+
* the run total there, else the sum over `metadata.steps[].usage`.
|
|
67
|
+
*/
|
|
68
|
+
function messageUsage(metadata) {
|
|
69
|
+
const total = isRecord(metadata?.usage) ? normalizeRunTelemetryUsage(metadata.usage) : void 0;
|
|
70
|
+
if (total) return total;
|
|
71
|
+
const perStep = stepUsages(metadata).flatMap((usage) => {
|
|
72
|
+
const normalized = usage ? normalizeRunTelemetryUsage(usage) : void 0;
|
|
73
|
+
return normalized ? [normalized] : [];
|
|
74
|
+
});
|
|
75
|
+
return perStep.length > 0 ? sumUsage(perStep) : void 0;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Reads the run report fields out of the assistant messages of one run. A run
|
|
79
|
+
* the AI SDK streamed as one message is one element; a run the cloud stored as
|
|
80
|
+
* several assistant rows is aggregated, step by step, in order. Returns null
|
|
81
|
+
* when no assistant message is present. Status reads completed when the run
|
|
82
|
+
* produced text or tool calls, as a live finish with reason `tool-calls` does;
|
|
83
|
+
* an integration that observed the finish event overrides it.
|
|
84
|
+
*/
|
|
85
|
+
function extractAISDKRunTelemetry(messages) {
|
|
86
|
+
const textParts = [];
|
|
87
|
+
const toolCalls = [];
|
|
88
|
+
const steps = [];
|
|
89
|
+
const usages = [];
|
|
90
|
+
let assistant;
|
|
91
|
+
for (const message of messages) {
|
|
92
|
+
if (message.role !== "assistant") continue;
|
|
93
|
+
assistant = message;
|
|
94
|
+
const metadata = isRecord(message.metadata) ? message.metadata : void 0;
|
|
95
|
+
const usagePerStep = stepUsages(metadata);
|
|
96
|
+
const messageToolCalls = [];
|
|
97
|
+
let step;
|
|
98
|
+
let stepIndex = -1;
|
|
99
|
+
for (const part of message.parts) {
|
|
100
|
+
if (!isPart(part)) continue;
|
|
101
|
+
if (part.type === "step-start") {
|
|
102
|
+
stepIndex += 1;
|
|
103
|
+
const usage = usagePerStep[stepIndex];
|
|
104
|
+
step = usage ? { usage } : {};
|
|
105
|
+
steps.push(step);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (part.type === "text" && typeof part.text === "string" && part.text) {
|
|
109
|
+
textParts.push(part.text);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const toolCall = toolCallOf(part);
|
|
113
|
+
if (!toolCall) continue;
|
|
114
|
+
toolCalls.push(toolCall);
|
|
115
|
+
messageToolCalls.push(toolCall);
|
|
116
|
+
if (step) {
|
|
117
|
+
step.toolCalls = [...step.toolCalls ?? [], toolCall];
|
|
118
|
+
step.finishReason = "tool-calls";
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
attachSamplingCalls(messageToolCalls, metadata);
|
|
122
|
+
const usage = messageUsage(metadata);
|
|
123
|
+
if (usage) usages.push(usage);
|
|
124
|
+
}
|
|
125
|
+
if (!assistant) return null;
|
|
126
|
+
const metadata = isRecord(assistant.metadata) ? assistant.metadata : void 0;
|
|
127
|
+
const usage = usages.length > 0 ? sumUsage(usages) : void 0;
|
|
128
|
+
const modelId = extractRunTelemetryModelId(metadata);
|
|
129
|
+
const completed = textParts.length > 0 || toolCalls.length > 0;
|
|
130
|
+
return {
|
|
131
|
+
...assistant.id !== void 0 ? { assistantMessageId: assistant.id } : void 0,
|
|
132
|
+
status: completed ? "completed" : "incomplete",
|
|
133
|
+
...toolCalls.length > 0 ? { toolCalls } : void 0,
|
|
134
|
+
...steps.length > 0 ? {
|
|
135
|
+
steps,
|
|
136
|
+
totalSteps: steps.length
|
|
137
|
+
} : void 0,
|
|
138
|
+
...textParts.length > 0 ? { outputText: truncateRunTelemetryText(textParts.join("")) } : void 0,
|
|
139
|
+
...usage ? { usage } : void 0,
|
|
140
|
+
...modelId ? { modelId } : void 0,
|
|
141
|
+
...metadata ? { metadata } : void 0
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { aiSDKV6FormatAdapter, extractAISDKRunTelemetry };
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/ai-sdk/index.ts"],"sourcesContent":["import type { UIMessage } from \"ai\";\nimport type { MessageFormatAdapter } from \"../FormattedCloudPersistence\";\nimport type { SamplingCallData } from \"../instrumentMcpSampling\";\nimport {\n type AssistantCloudRunReportToolCall,\n createRunTelemetryToolCall,\n extractRunTelemetryModelId,\n normalizeRunTelemetryUsage,\n type RunMessageTelemetry,\n type RunReportStepInit,\n type RunTelemetryUsage,\n type RunTelemetryUsageInit,\n truncateRunTelemetryText,\n} from \"../runTelemetry\";\n\nexport type AISDKStorageFormat = Omit<UIMessage, \"id\">;\n\n/** The stored form of an AI SDK message: the message without its id. */\nexport const aiSDKV6FormatAdapter: MessageFormatAdapter<\n UIMessage,\n AISDKStorageFormat\n> = {\n format: \"ai-sdk/v6\",\n encode: ({ message: { id: _id, ...message } }) => message,\n decode: (stored) => ({\n parentId: stored.parent_id,\n message: { id: stored.id, ...stored.content } as UIMessage,\n }),\n getId: (message) => message.id,\n};\n\n/**\n * A message as an AI SDK integration holds it, or as the cloud stored it under\n * the ai-sdk/v6 format, which drops the id. Parts are typed by their `type`\n * alone, so this shape and the telemetry read from it need nothing from `ai`.\n */\nexport type AISDKMessageLike = {\n id?: string | undefined;\n role: string;\n parts: readonly { type: string; [key: string]: unknown }[];\n metadata?: unknown;\n};\n\ntype Part = Record<string, unknown> & { type: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\";\n}\n\nfunction isPart(value: unknown): value is Part {\n return isRecord(value) && typeof value.type === \"string\";\n}\n\n/**\n * The AI SDK's own tool part rules, kept here so the entry loads without the\n * `ai` runtime: a static tool part is `tool-<name>`, a dynamic one is\n * `dynamic-tool` with its name in `toolName`.\n */\nfunction toolCallOf(part: Part): AssistantCloudRunReportToolCall | undefined {\n if (typeof part.toolCallId !== \"string\") return undefined;\n const isStatic = part.type.startsWith(\"tool-\");\n if (!isStatic && part.type !== \"dynamic-tool\") return undefined;\n const toolName = isStatic\n ? part.type.slice(\"tool-\".length)\n : typeof part.toolName === \"string\"\n ? part.toolName\n : undefined;\n if (!toolName) return undefined;\n return createRunTelemetryToolCall({\n toolName,\n toolCallId: part.toolCallId,\n args: part.input ?? part.args,\n result: part.output ?? part.result,\n toolSource: isStatic ? \"frontend\" : \"mcp\",\n });\n}\n\nfunction attachSamplingCalls(\n toolCalls: readonly AssistantCloudRunReportToolCall[],\n metadata: Record<string, unknown> | undefined,\n): void {\n const samplingCalls = isRecord(metadata?.samplingCalls)\n ? (metadata.samplingCalls as Record<string, SamplingCallData[]>)\n : undefined;\n if (!samplingCalls) return;\n for (const toolCall of toolCalls) {\n const calls = samplingCalls[toolCall.tool_call_id];\n if (Array.isArray(calls) && calls.length > 0) {\n toolCall.sampling_calls = calls;\n }\n }\n}\n\nfunction stepUsages(\n metadata: Record<string, unknown> | undefined,\n): (RunTelemetryUsageInit | undefined)[] {\n const steps = metadata?.steps;\n if (!Array.isArray(steps)) return [];\n return steps.map((step) =>\n isRecord(step) && isRecord(step.usage)\n ? (step.usage as RunTelemetryUsageInit)\n : undefined,\n );\n}\n\nfunction sumUsage(usages: readonly RunTelemetryUsage[]): RunTelemetryUsage {\n const total: RunTelemetryUsage = {};\n for (const usage of usages) {\n if (usage.inputTokens != null) {\n total.inputTokens = (total.inputTokens ?? 0) + usage.inputTokens;\n }\n if (usage.outputTokens != null) {\n total.outputTokens = (total.outputTokens ?? 0) + usage.outputTokens;\n }\n if (usage.reasoningTokens != null) {\n total.reasoningTokens =\n (total.reasoningTokens ?? 0) + usage.reasoningTokens;\n }\n if (usage.cachedInputTokens != null) {\n total.cachedInputTokens =\n (total.cachedInputTokens ?? 0) + usage.cachedInputTokens;\n }\n }\n return total;\n}\n\n/**\n * The usage a message reports: `metadata.usage` when the integration copied\n * the run total there, else the sum over `metadata.steps[].usage`.\n */\nfunction messageUsage(\n metadata: Record<string, unknown> | undefined,\n): RunTelemetryUsage | undefined {\n const total = isRecord(metadata?.usage)\n ? normalizeRunTelemetryUsage(metadata.usage as RunTelemetryUsageInit)\n : undefined;\n if (total) return total;\n const perStep = stepUsages(metadata).flatMap((usage) => {\n const normalized = usage ? normalizeRunTelemetryUsage(usage) : undefined;\n return normalized ? [normalized] : [];\n });\n return perStep.length > 0 ? sumUsage(perStep) : undefined;\n}\n\n/**\n * Reads the run report fields out of the assistant messages of one run. A run\n * the AI SDK streamed as one message is one element; a run the cloud stored as\n * several assistant rows is aggregated, step by step, in order. Returns null\n * when no assistant message is present. Status reads completed when the run\n * produced text or tool calls, as a live finish with reason `tool-calls` does;\n * an integration that observed the finish event overrides it.\n */\nexport function extractAISDKRunTelemetry(\n messages: readonly AISDKMessageLike[],\n): RunMessageTelemetry | null {\n const textParts: string[] = [];\n const toolCalls: AssistantCloudRunReportToolCall[] = [];\n const steps: RunReportStepInit[] = [];\n const usages: RunTelemetryUsage[] = [];\n let assistant: AISDKMessageLike | undefined;\n\n for (const message of messages) {\n if (message.role !== \"assistant\") continue;\n assistant = message;\n const metadata = isRecord(message.metadata) ? message.metadata : undefined;\n const usagePerStep = stepUsages(metadata);\n const messageToolCalls: AssistantCloudRunReportToolCall[] = [];\n let step: RunReportStepInit | undefined;\n let stepIndex = -1;\n\n for (const part of message.parts) {\n if (!isPart(part)) continue;\n if (part.type === \"step-start\") {\n stepIndex += 1;\n const usage = usagePerStep[stepIndex];\n step = usage ? { usage } : {};\n steps.push(step);\n continue;\n }\n if (part.type === \"text\" && typeof part.text === \"string\" && part.text) {\n textParts.push(part.text);\n continue;\n }\n const toolCall = toolCallOf(part);\n if (!toolCall) continue;\n toolCalls.push(toolCall);\n messageToolCalls.push(toolCall);\n if (step) {\n step.toolCalls = [...(step.toolCalls ?? []), toolCall];\n step.finishReason = \"tool-calls\";\n }\n }\n\n attachSamplingCalls(messageToolCalls, metadata);\n const usage = messageUsage(metadata);\n if (usage) usages.push(usage);\n }\n\n if (!assistant) return null;\n\n const metadata = isRecord(assistant.metadata)\n ? assistant.metadata\n : undefined;\n\n const usage = usages.length > 0 ? sumUsage(usages) : undefined;\n const modelId = extractRunTelemetryModelId(metadata);\n const completed = textParts.length > 0 || toolCalls.length > 0;\n return {\n ...(assistant.id !== undefined\n ? { assistantMessageId: assistant.id }\n : undefined),\n status: completed ? \"completed\" : \"incomplete\",\n ...(toolCalls.length > 0 ? { toolCalls } : undefined),\n ...(steps.length > 0 ? { steps, totalSteps: steps.length } : undefined),\n ...(textParts.length > 0\n ? { outputText: truncateRunTelemetryText(textParts.join(\"\")) }\n : undefined),\n ...(usage ? { usage } : undefined),\n ...(modelId ? { modelId } : undefined),\n ...(metadata ? { metadata } : undefined),\n };\n}\n"],"mappings":"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"}
|
package/dist/cloudResponse.d.ts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { ReadonlyJSONObject } from "assistant-stream/utils";
|
|
2
2
|
//#region src/cloudResponse.d.ts
|
|
3
|
-
declare class CloudResponseError extends Error {
|
|
3
|
+
export declare class CloudResponseError extends Error {
|
|
4
4
|
constructor(message: string);
|
|
5
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 readCloudNumber: (value: unknown, field: string) => number;
|
|
10
|
-
declare const readCloudNullableNumber: (value: unknown, field: string) => number | null;
|
|
11
|
-
declare const readCloudEnum: <const T extends readonly string[]>(value: unknown, field: string, allowed: T) => T[number];
|
|
12
|
-
declare const readCloudNullableString: (value: unknown, field: string) => string | null;
|
|
13
|
-
declare const readCloudBoolean: (value: unknown, field: string) => boolean;
|
|
14
|
-
declare const readCloudInteger: (value: unknown, field: string) => number;
|
|
15
|
-
declare const readCloudTimestamp: (value: unknown, field: string) => Date;
|
|
16
|
-
declare const readCloudJSONObject: (value: unknown, field: string) => ReadonlyJSONObject;
|
|
6
|
+
export declare const readCloudRecord: (value: unknown, field: string) => Record<string, unknown>;
|
|
7
|
+
export declare const readCloudArray: (value: unknown, field: string) => unknown[];
|
|
8
|
+
export declare const readCloudString: (value: unknown, field: string) => string;
|
|
9
|
+
export declare const readCloudNumber: (value: unknown, field: string) => number;
|
|
10
|
+
export declare const readCloudNullableNumber: (value: unknown, field: string) => number | null;
|
|
11
|
+
export declare const readCloudEnum: <const T extends readonly string[]>(value: unknown, field: string, allowed: T) => T[number];
|
|
12
|
+
export declare const readCloudNullableString: (value: unknown, field: string) => string | null;
|
|
13
|
+
export declare const readCloudBoolean: (value: unknown, field: string) => boolean;
|
|
14
|
+
export declare const readCloudInteger: (value: unknown, field: string) => number;
|
|
15
|
+
export declare const readCloudTimestamp: (value: unknown, field: string) => Date;
|
|
16
|
+
export declare const readCloudJSONObject: (value: unknown, field: string) => ReadonlyJSONObject;
|
|
17
17
|
//#endregion
|
|
18
|
-
export { CloudResponseError, readCloudArray, readCloudBoolean, readCloudEnum, readCloudInteger, readCloudJSONObject, readCloudNullableNumber, readCloudNullableString, readCloudNumber, readCloudRecord, readCloudString, readCloudTimestamp };
|
|
19
18
|
//# sourceMappingURL=cloudResponse.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudResponse.d.ts","names":[],"sources":["../src/cloudResponse.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"cloudResponse.d.ts","names":[],"sources":["../src/cloudResponse.ts"],"mappings":";;qBAEa,2BAA2B;EAC1B,YAAA;;qBAWD,kBACX,gBACA,kBACC;qBAOU,iBAAkB,gBAAgB;qBAKlC,kBAAmB,gBAAgB;qBAKnC,kBAAmB,gBAAgB;qBAOnC,0BACX,gBACA;qBAMW,sBAAuB,6BAClC,gBACA,eACA,SAAS,MACR;qBAWU,0BACX,gBACA;qBAMW,mBAAoB,gBAAgB;qBAOpC,mBAAoB,gBAAgB;qBAKpC,qBAAsB,gBAAgB,kBAAgB;qBActD,sBACX,gBACA,kBACC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AssistantCloud } from "./AssistantCloud.js";
|
|
2
2
|
//#region src/generateThreadTitle.d.ts
|
|
3
|
-
declare function generateThreadTitle(cloud: AssistantCloud, options: {
|
|
3
|
+
export declare function generateThreadTitle(cloud: AssistantCloud, options: {
|
|
4
4
|
threadId: string;
|
|
5
5
|
messages: readonly {
|
|
6
6
|
role: string;
|
|
@@ -11,5 +11,4 @@ declare function generateThreadTitle(cloud: AssistantCloud, options: {
|
|
|
11
11
|
}[];
|
|
12
12
|
}): Promise<string | null>;
|
|
13
13
|
//#endregion
|
|
14
|
-
export { generateThreadTitle };
|
|
15
14
|
//# sourceMappingURL=generateThreadTitle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateThreadTitle.d.ts","names":[],"sources":["../src/generateThreadTitle.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"generateThreadTitle.d.ts","names":[],"sources":["../src/generateThreadTitle.ts"],"mappings":";;wBAEsB,oBACpB,OAAO,gBACP;EACE;EACA;IACE;IACA;MAAoB;MAAc;;;IAGrC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateThreadTitle.js","names":[],"sources":["../src/generateThreadTitle.ts"],"sourcesContent":["import type { AssistantCloud } from \"./AssistantCloud\";\n\nexport async function generateThreadTitle(\n cloud: AssistantCloud,\n options: {\n threadId: string;\n messages: readonly {\n role: string;\n content: readonly { type: \"text\"; text: string }[];\n }[];\n },\n): Promise<string | null> {\n const stream = await cloud.runs.stream({\n thread_id: options.threadId,\n assistant_id: \"system/thread_title\",\n messages: options.messages,\n });\n\n let title = \"\";\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value: chunk } = await reader.read();\n if (done) break;\n if (chunk.type === \"text-delta\") {\n title += chunk.textDelta;\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n if (title) {\n await cloud.threads.update(options.threadId, { title });\n }\n\n return title || null;\n}\n"],"mappings":";AAEA,eAAsB,oBACpB,OACA,SAOwB;CACxB,MAAM,SAAS,MAAM,MAAM,KAAK,OAAO;EACrC,WAAW,QAAQ;EACnB,cAAc;EACd,UAAU,QAAQ;CACpB,CAAC;CAED,IAAI,QAAQ;CACZ,MAAM,SAAS,OAAO,UAAU;CAChC,IAAI;EACF,OAAO,MAAM;GACX,MAAM,EAAE,MAAM,OAAO,UAAU,MAAM,OAAO,KAAK;GACjD,IAAI,MAAM;GACV,IAAI,MAAM,SAAS,cACjB,SAAS,MAAM;EAEnB;CACF,UAAU;EACR,OAAO,YAAY;CACrB;CAEA,IAAI,OACF,MAAM,MAAM,QAAQ,OAAO,QAAQ,UAAU,EAAE,MAAM,CAAC;CAGxD,OAAO,SAAS;AAClB"}
|
|
1
|
+
{"version":3,"file":"generateThreadTitle.js","names":[],"sources":["../src/generateThreadTitle.ts"],"sourcesContent":["import type { AssistantCloud } from \"./AssistantCloud\";\n\nexport async function generateThreadTitle(\n cloud: AssistantCloud,\n options: {\n threadId: string;\n messages: readonly {\n role: string;\n content: readonly { type: \"text\"; text: string }[];\n }[];\n },\n): Promise<string | null> {\n const stream = await cloud.runs.stream({\n thread_id: options.threadId,\n assistant_id: \"system/thread_title\",\n messages: options.messages,\n });\n\n let title = \"\";\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value: chunk } = await reader.read();\n if (done) break;\n if (chunk.type === \"text-delta\") {\n title += chunk.textDelta;\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n title = title.trim();\n if (title) {\n await cloud.threads.update(options.threadId, { title });\n }\n\n return title || null;\n}\n"],"mappings":";AAEA,eAAsB,oBACpB,OACA,SAOwB;CACxB,MAAM,SAAS,MAAM,MAAM,KAAK,OAAO;EACrC,WAAW,QAAQ;EACnB,cAAc;EACd,UAAU,QAAQ;CACpB,CAAC;CAED,IAAI,QAAQ;CACZ,MAAM,SAAS,OAAO,UAAU;CAChC,IAAI;EACF,OAAO,MAAM;GACX,MAAM,EAAE,MAAM,OAAO,UAAU,MAAM,OAAO,KAAK;GACjD,IAAI,MAAM;GACV,IAAI,MAAM,SAAS,cACjB,SAAS,MAAM;EAEnB;CACF,UAAU;EACR,OAAO,YAAY;CACrB;CAEA,QAAQ,MAAM,KAAK;CACnB,IAAI,OACF,MAAM,MAAM,QAAQ,OAAO,QAAQ,UAAU,EAAE,MAAM,CAAC;CAGxD,OAAO,SAAS;AAClB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { readAnonymousRefreshToken } from "./AssistantCloudAuthStrategy.js";
|
|
2
2
|
import { McpSamplingHandler, SamplingCallData, createSamplingCollector, wrapSamplingHandler } from "./instrumentMcpSampling.js";
|
|
3
|
-
import { AssistantCloudRunReportToolCall, RunReportInit, RunReportOutcome, RunReportStepInit, RunTelemetryToolCallInit, RunTelemetryUsage, RunTelemetryUsageInit, createRunReport, createRunTelemetryToolCall, deriveRunOutcome, describeRunError, extractRunTelemetryModelId, normalizeRunTelemetryUsage, truncateRunTelemetryText } from "./runTelemetry.js";
|
|
3
|
+
import { AssistantCloudRunReportToolCall, RunMessageTelemetry, RunReportInit, RunReportOutcome, RunReportStepInit, RunTelemetryToolCallInit, RunTelemetryUsage, RunTelemetryUsageInit, createRunReport, createRunTelemetryToolCall, deriveRunOutcome, describeRunError, extractRunTelemetryModelId, normalizeRunTelemetryUsage, truncateRunTelemetryText } from "./runTelemetry.js";
|
|
4
4
|
import { AssistantCloudRunReport } from "./AssistantCloudRuns.js";
|
|
5
|
-
import { AssistantCloudTelemetryConfig, CloudAPIError } from "./AssistantCloudAPI.js";
|
|
5
|
+
import { AssistantCloudTelemetryConfig, CloudAPIError, SdkIdentity } from "./AssistantCloudAPI.js";
|
|
6
6
|
import { AssistantCloudThreadMessageFeedbackBody, AssistantCloudThreadMessageFeedbackResponse, CloudMessage } from "./AssistantCloudThreadMessages.js";
|
|
7
7
|
import { GeneratePresignedDownloadUrlResponse } from "./AssistantCloudFiles.js";
|
|
8
8
|
import { AssistantCloudEvent, AssistantCloudEventKind, AssistantCloudEvents } from "./AssistantCloudEvents.js";
|
|
9
9
|
import { AssistantCloudScoreBody, AssistantCloudScoreResponse, AssistantCloudScores } from "./AssistantCloudScores.js";
|
|
10
10
|
import { AssistantCloud } from "./AssistantCloud.js";
|
|
11
|
+
import { CloudEngagementReporter, EngagementEventIds, EngagementIdResolver } from "./CloudEngagementReporter.js";
|
|
11
12
|
import { CloudMessagePersistence } from "./CloudMessagePersistence.js";
|
|
13
|
+
import { CloudRunReportInit, CloudRunReporter } from "./CloudRunReporter.js";
|
|
12
14
|
import { MessageFormatAdapter, createFormattedPersistence } from "./FormattedCloudPersistence.js";
|
|
13
15
|
import { CloudResponseError } from "./cloudResponse.js";
|
|
14
16
|
import { generateThreadTitle } from "./generateThreadTitle.js";
|
|
15
|
-
export { AssistantCloud, type AssistantCloudEvent, type AssistantCloudEventKind, AssistantCloudEvents, type AssistantCloudRunReport, type AssistantCloudRunReportToolCall, type AssistantCloudScoreBody, type AssistantCloudScoreResponse, AssistantCloudScores, type AssistantCloudTelemetryConfig, type AssistantCloudThreadMessageFeedbackBody, type AssistantCloudThreadMessageFeedbackResponse, CloudAPIError, type CloudMessage, CloudMessagePersistence, CloudResponseError, type GeneratePresignedDownloadUrlResponse, type McpSamplingHandler, type MessageFormatAdapter, type RunReportInit, type RunReportOutcome, type RunReportStepInit, type RunTelemetryToolCallInit, type RunTelemetryUsage, type RunTelemetryUsageInit, type SamplingCallData, createFormattedPersistence, createRunReport, createRunTelemetryToolCall, createSamplingCollector, deriveRunOutcome, describeRunError, extractRunTelemetryModelId, generateThreadTitle, normalizeRunTelemetryUsage, readAnonymousRefreshToken, truncateRunTelemetryText, wrapSamplingHandler };
|
|
17
|
+
export { AssistantCloud, type AssistantCloudEvent, type AssistantCloudEventKind, AssistantCloudEvents, type AssistantCloudRunReport, type AssistantCloudRunReportToolCall, type AssistantCloudScoreBody, type AssistantCloudScoreResponse, AssistantCloudScores, type AssistantCloudTelemetryConfig, type AssistantCloudThreadMessageFeedbackBody, type AssistantCloudThreadMessageFeedbackResponse, CloudAPIError, CloudEngagementReporter, type CloudMessage, CloudMessagePersistence, CloudResponseError, type CloudRunReportInit, CloudRunReporter, type EngagementEventIds, type EngagementIdResolver, type GeneratePresignedDownloadUrlResponse, type McpSamplingHandler, type MessageFormatAdapter, type RunMessageTelemetry, type RunReportInit, type RunReportOutcome, type RunReportStepInit, type RunTelemetryToolCallInit, type RunTelemetryUsage, type RunTelemetryUsageInit, type SamplingCallData, type SdkIdentity, createFormattedPersistence, createRunReport, createRunTelemetryToolCall, createSamplingCollector, deriveRunOutcome, describeRunError, extractRunTelemetryModelId, generateThreadTitle, normalizeRunTelemetryUsage, readAnonymousRefreshToken, truncateRunTelemetryText, wrapSamplingHandler };
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,11 @@ import { CloudAPIError } from "./AssistantCloudAPI.js";
|
|
|
4
4
|
import { AssistantCloudEvents } from "./AssistantCloudEvents.js";
|
|
5
5
|
import { AssistantCloudScores } from "./AssistantCloudScores.js";
|
|
6
6
|
import { AssistantCloud } from "./AssistantCloud.js";
|
|
7
|
+
import { CloudEngagementReporter } from "./CloudEngagementReporter.js";
|
|
7
8
|
import { CloudMessagePersistence } from "./CloudMessagePersistence.js";
|
|
9
|
+
import { createRunReport, createRunTelemetryToolCall, deriveRunOutcome, describeRunError, extractRunTelemetryModelId, normalizeRunTelemetryUsage, truncateRunTelemetryText } from "./runTelemetry.js";
|
|
10
|
+
import { CloudRunReporter } from "./CloudRunReporter.js";
|
|
8
11
|
import { createFormattedPersistence } from "./FormattedCloudPersistence.js";
|
|
9
12
|
import { generateThreadTitle } from "./generateThreadTitle.js";
|
|
10
|
-
import { createRunReport, createRunTelemetryToolCall, deriveRunOutcome, describeRunError, extractRunTelemetryModelId, normalizeRunTelemetryUsage, truncateRunTelemetryText } from "./runTelemetry.js";
|
|
11
13
|
import { createSamplingCollector, wrapSamplingHandler } from "./instrumentMcpSampling.js";
|
|
12
|
-
export { AssistantCloud, AssistantCloudEvents, AssistantCloudScores, CloudAPIError, CloudMessagePersistence, CloudResponseError, createFormattedPersistence, createRunReport, createRunTelemetryToolCall, createSamplingCollector, deriveRunOutcome, describeRunError, extractRunTelemetryModelId, generateThreadTitle, normalizeRunTelemetryUsage, readAnonymousRefreshToken, truncateRunTelemetryText, wrapSamplingHandler };
|
|
14
|
+
export { AssistantCloud, AssistantCloudEvents, AssistantCloudScores, CloudAPIError, CloudEngagementReporter, CloudMessagePersistence, CloudResponseError, CloudRunReporter, createFormattedPersistence, createRunReport, createRunTelemetryToolCall, createSamplingCollector, deriveRunOutcome, describeRunError, extractRunTelemetryModelId, generateThreadTitle, normalizeRunTelemetryUsage, readAnonymousRefreshToken, truncateRunTelemetryText, wrapSamplingHandler };
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (sampling/createMessage requests) made during tool execution.
|
|
7
7
|
* The captured data can be reported as child generation spans.
|
|
8
8
|
*/
|
|
9
|
-
type SamplingCallData = {
|
|
9
|
+
export type SamplingCallData = {
|
|
10
10
|
model_id?: string;
|
|
11
11
|
input_tokens?: number;
|
|
12
12
|
output_tokens?: number;
|
|
@@ -14,8 +14,8 @@ type SamplingCallData = {
|
|
|
14
14
|
cached_input_tokens?: number;
|
|
15
15
|
duration_ms?: number;
|
|
16
16
|
};
|
|
17
|
-
type McpSamplingHandler = (request: McpSamplingRequest) => Promise<McpSamplingResponse>;
|
|
18
|
-
type McpSamplingRequest = {
|
|
17
|
+
export type McpSamplingHandler = (request: McpSamplingRequest) => Promise<McpSamplingResponse>;
|
|
18
|
+
export type McpSamplingRequest = {
|
|
19
19
|
method: "sampling/createMessage";
|
|
20
20
|
params: {
|
|
21
21
|
messages: unknown[];
|
|
@@ -28,7 +28,7 @@ type McpSamplingRequest = {
|
|
|
28
28
|
[key: string]: unknown;
|
|
29
29
|
};
|
|
30
30
|
};
|
|
31
|
-
type McpSamplingResponse = {
|
|
31
|
+
export type McpSamplingResponse = {
|
|
32
32
|
model?: string;
|
|
33
33
|
content: unknown;
|
|
34
34
|
usage?: {
|
|
@@ -59,7 +59,7 @@ type McpSamplingResponse = {
|
|
|
59
59
|
* // After tool execution, `samplingCalls` contains metrics for all nested LLM calls
|
|
60
60
|
* ```
|
|
61
61
|
*/
|
|
62
|
-
declare function wrapSamplingHandler(handler: McpSamplingHandler, onSamplingCall: (data: SamplingCallData) => void): McpSamplingHandler;
|
|
62
|
+
export declare function wrapSamplingHandler(handler: McpSamplingHandler, onSamplingCall: (data: SamplingCallData) => void): McpSamplingHandler;
|
|
63
63
|
/**
|
|
64
64
|
* Creates a collector that accumulates sampling call data during tool execution.
|
|
65
65
|
* Use with `wrapSamplingHandler` to capture all sampling calls for a tool invocation.
|
|
@@ -72,11 +72,10 @@ declare function wrapSamplingHandler(handler: McpSamplingHandler, onSamplingCall
|
|
|
72
72
|
* const calls = collector.getCalls(); // SamplingCallData[]
|
|
73
73
|
* ```
|
|
74
74
|
*/
|
|
75
|
-
declare function createSamplingCollector(): {
|
|
75
|
+
export declare function createSamplingCollector(): {
|
|
76
76
|
collect: (data: SamplingCallData) => number;
|
|
77
77
|
getCalls: () => SamplingCallData[];
|
|
78
78
|
reset: () => void;
|
|
79
79
|
};
|
|
80
80
|
//#endregion
|
|
81
|
-
export { McpSamplingHandler, McpSamplingRequest, McpSamplingResponse, SamplingCallData, createSamplingCollector, wrapSamplingHandler };
|
|
82
81
|
//# sourceMappingURL=instrumentMcpSampling.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentMcpSampling.d.ts","names":[],"sources":["../src/instrumentMcpSampling.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"instrumentMcpSampling.d.ts","names":[],"sources":["../src/instrumentMcpSampling.ts"],"mappings":";;;;;;;;YAQY;EACV;EACA;EACA;EACA;EACA;EACA;;YAGU,sBACV,SAAS,uBACN,QAAQ;YAED;EACV;EACA;IACE;IACA;MAAqB;QAAU;;;IAC/B;KACC;;;YAIO;EACV;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;;GAED;;;;;;;;;;;;;;;;;;;;wBA8Ba,oBACd,SAAS,oBACT,iBAAiB,MAAM,4BACtB;;;;;;;;;;;;;wBAkDa;EAGI,UAAA,MAAA;kBAAA"}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
//#region src/instrumentMcpSampling.ts
|
|
2
|
+
const reportSamplingError = (error) => {
|
|
3
|
+
try {
|
|
4
|
+
console.error("[assistant-cloud] onSamplingCall callback threw an error", error);
|
|
5
|
+
} catch {}
|
|
6
|
+
};
|
|
2
7
|
/**
|
|
3
8
|
* Wraps an MCP sampling handler to intercept and measure sampling calls.
|
|
4
9
|
*
|
|
@@ -27,14 +32,19 @@ function wrapSamplingHandler(handler, onSamplingCall) {
|
|
|
27
32
|
const outputTokens = response.usage?.outputTokens ?? response.usage?.completionTokens;
|
|
28
33
|
const reasoningTokens = response.usage?.reasoningTokens;
|
|
29
34
|
const cachedInputTokens = response.usage?.cachedInputTokens;
|
|
30
|
-
|
|
35
|
+
const data = {
|
|
31
36
|
...modelId ? { model_id: modelId } : void 0,
|
|
32
37
|
...inputTokens != null ? { input_tokens: inputTokens } : void 0,
|
|
33
38
|
...outputTokens != null ? { output_tokens: outputTokens } : void 0,
|
|
34
39
|
...reasoningTokens != null ? { reasoning_tokens: reasoningTokens } : void 0,
|
|
35
40
|
...cachedInputTokens != null ? { cached_input_tokens: cachedInputTokens } : void 0,
|
|
36
41
|
duration_ms: durationMs
|
|
37
|
-
}
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
Promise.resolve(onSamplingCall(data)).catch(reportSamplingError);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
reportSamplingError(error);
|
|
47
|
+
}
|
|
38
48
|
return response;
|
|
39
49
|
};
|
|
40
50
|
}
|