@sentrial/sdk 0.4.2 → 0.4.4
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/dist/index.cjs +391 -291
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.js +391 -291
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -437,8 +437,18 @@ function wrapOpenAI(client, options = {}) {
|
|
|
437
437
|
const completionTokens = response.usage?.completion_tokens ?? 0;
|
|
438
438
|
const totalTokens = response.usage?.total_tokens ?? 0;
|
|
439
439
|
let outputContent = "";
|
|
440
|
-
|
|
441
|
-
|
|
440
|
+
const toolCalls = [];
|
|
441
|
+
const msg = response.choices?.[0]?.message;
|
|
442
|
+
if (msg?.content) {
|
|
443
|
+
outputContent = msg.content;
|
|
444
|
+
}
|
|
445
|
+
if (msg?.tool_calls) {
|
|
446
|
+
for (const tc of msg.tool_calls) {
|
|
447
|
+
toolCalls.push({
|
|
448
|
+
name: tc.function?.name ?? "unknown",
|
|
449
|
+
arguments: tc.function?.arguments ?? "{}"
|
|
450
|
+
});
|
|
451
|
+
}
|
|
442
452
|
}
|
|
443
453
|
const cost = calculateOpenAICost({ model, inputTokens: promptTokens, outputTokens: completionTokens });
|
|
444
454
|
trackLLMCall({
|
|
@@ -446,6 +456,7 @@ function wrapOpenAI(client, options = {}) {
|
|
|
446
456
|
model,
|
|
447
457
|
messages,
|
|
448
458
|
output: outputContent,
|
|
459
|
+
toolCalls,
|
|
449
460
|
promptTokens,
|
|
450
461
|
completionTokens,
|
|
451
462
|
totalTokens,
|
|
@@ -500,10 +511,16 @@ function wrapAnthropic(client, options = {}) {
|
|
|
500
511
|
const completionTokens = response.usage?.output_tokens ?? 0;
|
|
501
512
|
const totalTokens = promptTokens + completionTokens;
|
|
502
513
|
let outputContent = "";
|
|
514
|
+
const toolCalls = [];
|
|
503
515
|
if (response.content) {
|
|
504
516
|
for (const block of response.content) {
|
|
505
517
|
if (block.type === "text") {
|
|
506
518
|
outputContent += block.text;
|
|
519
|
+
} else if (block.type === "tool_use") {
|
|
520
|
+
toolCalls.push({
|
|
521
|
+
name: block.name ?? "unknown",
|
|
522
|
+
arguments: JSON.stringify(block.input ?? {})
|
|
523
|
+
});
|
|
507
524
|
}
|
|
508
525
|
}
|
|
509
526
|
}
|
|
@@ -514,6 +531,7 @@ function wrapAnthropic(client, options = {}) {
|
|
|
514
531
|
model,
|
|
515
532
|
messages: fullMessages,
|
|
516
533
|
output: outputContent,
|
|
534
|
+
toolCalls,
|
|
517
535
|
promptTokens,
|
|
518
536
|
completionTokens,
|
|
519
537
|
totalTokens,
|
|
@@ -627,6 +645,7 @@ function wrapLLM(client, provider) {
|
|
|
627
645
|
function wrapOpenAIStream(stream, ctx) {
|
|
628
646
|
let fullContent = "";
|
|
629
647
|
let usage = null;
|
|
648
|
+
const toolCallMap = /* @__PURE__ */ new Map();
|
|
630
649
|
let tracked = false;
|
|
631
650
|
const originalIterator = stream[Symbol.asyncIterator]?.bind(stream);
|
|
632
651
|
if (!originalIterator) return stream;
|
|
@@ -643,6 +662,7 @@ function wrapOpenAIStream(stream, ctx) {
|
|
|
643
662
|
model: ctx.model,
|
|
644
663
|
messages: ctx.messages,
|
|
645
664
|
output: fullContent,
|
|
665
|
+
toolCalls: Array.from(toolCallMap.values()),
|
|
646
666
|
promptTokens,
|
|
647
667
|
completionTokens,
|
|
648
668
|
totalTokens,
|
|
@@ -661,8 +681,17 @@ function wrapOpenAIStream(stream, ctx) {
|
|
|
661
681
|
const result = await iter.next();
|
|
662
682
|
if (!result.done) {
|
|
663
683
|
const chunk = result.value;
|
|
664
|
-
const delta = chunk.choices?.[0]?.delta
|
|
665
|
-
if (delta) fullContent += delta;
|
|
684
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
685
|
+
if (delta?.content) fullContent += delta.content;
|
|
686
|
+
if (delta?.tool_calls) {
|
|
687
|
+
for (const tc of delta.tool_calls) {
|
|
688
|
+
const idx = tc.index ?? 0;
|
|
689
|
+
const existing = toolCallMap.get(idx) ?? { name: "", arguments: "" };
|
|
690
|
+
if (tc.function?.name) existing.name = tc.function.name;
|
|
691
|
+
if (tc.function?.arguments) existing.arguments += tc.function.arguments;
|
|
692
|
+
toolCallMap.set(idx, existing);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
666
695
|
if (chunk.usage) usage = chunk.usage;
|
|
667
696
|
} else {
|
|
668
697
|
trackResult();
|
|
@@ -687,6 +716,8 @@ function wrapAnthropicStream(stream, ctx) {
|
|
|
687
716
|
let fullContent = "";
|
|
688
717
|
let inputTokens = 0;
|
|
689
718
|
let outputTokens = 0;
|
|
719
|
+
const toolCallsById = /* @__PURE__ */ new Map();
|
|
720
|
+
let currentBlockIdx = -1;
|
|
690
721
|
let tracked = false;
|
|
691
722
|
const originalIterator = stream[Symbol.asyncIterator]?.bind(stream);
|
|
692
723
|
if (!originalIterator) return stream;
|
|
@@ -702,6 +733,7 @@ function wrapAnthropicStream(stream, ctx) {
|
|
|
702
733
|
model: ctx.model,
|
|
703
734
|
messages: fullMessages,
|
|
704
735
|
output: fullContent,
|
|
736
|
+
toolCalls: Array.from(toolCallsById.values()),
|
|
705
737
|
promptTokens: inputTokens,
|
|
706
738
|
completionTokens: outputTokens,
|
|
707
739
|
totalTokens,
|
|
@@ -720,8 +752,26 @@ function wrapAnthropicStream(stream, ctx) {
|
|
|
720
752
|
const result = await iter.next();
|
|
721
753
|
if (!result.done) {
|
|
722
754
|
const event = result.value;
|
|
723
|
-
if (event.type === "
|
|
724
|
-
|
|
755
|
+
if (event.type === "content_block_start") {
|
|
756
|
+
currentBlockIdx = event.index ?? currentBlockIdx + 1;
|
|
757
|
+
if (event.content_block?.type === "tool_use") {
|
|
758
|
+
toolCallsById.set(currentBlockIdx, {
|
|
759
|
+
name: event.content_block.name ?? "unknown",
|
|
760
|
+
arguments: ""
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
if (event.type === "content_block_delta") {
|
|
765
|
+
if (event.delta?.text) {
|
|
766
|
+
fullContent += event.delta.text;
|
|
767
|
+
}
|
|
768
|
+
if (event.delta?.type === "input_json_delta" && event.delta?.partial_json) {
|
|
769
|
+
const idx = event.index ?? currentBlockIdx;
|
|
770
|
+
const existing = toolCallsById.get(idx);
|
|
771
|
+
if (existing) {
|
|
772
|
+
existing.arguments += event.delta.partial_json;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
725
775
|
}
|
|
726
776
|
if (event.type === "message_start" && event.message?.usage) {
|
|
727
777
|
inputTokens = event.message.usage.input_tokens ?? 0;
|
|
@@ -755,6 +805,18 @@ function trackLLMCall(params) {
|
|
|
755
805
|
if (!sessionId && !params.trackWithoutSession) {
|
|
756
806
|
return;
|
|
757
807
|
}
|
|
808
|
+
const toolOutput = {
|
|
809
|
+
content: params.output,
|
|
810
|
+
tokens: {
|
|
811
|
+
prompt: params.promptTokens,
|
|
812
|
+
completion: params.completionTokens,
|
|
813
|
+
total: params.totalTokens
|
|
814
|
+
},
|
|
815
|
+
cost_usd: params.cost
|
|
816
|
+
};
|
|
817
|
+
if (params.toolCalls && params.toolCalls.length > 0) {
|
|
818
|
+
toolOutput.tool_calls = params.toolCalls;
|
|
819
|
+
}
|
|
758
820
|
if (sessionId) {
|
|
759
821
|
client.trackToolCall({
|
|
760
822
|
sessionId,
|
|
@@ -764,15 +826,7 @@ function trackLLMCall(params) {
|
|
|
764
826
|
model: params.model,
|
|
765
827
|
provider: params.provider
|
|
766
828
|
},
|
|
767
|
-
toolOutput
|
|
768
|
-
content: params.output,
|
|
769
|
-
tokens: {
|
|
770
|
-
prompt: params.promptTokens,
|
|
771
|
-
completion: params.completionTokens,
|
|
772
|
-
total: params.totalTokens
|
|
773
|
-
},
|
|
774
|
-
cost_usd: params.cost
|
|
775
|
-
},
|
|
829
|
+
toolOutput,
|
|
776
830
|
reasoning: `LLM call to ${params.provider} ${params.model}`,
|
|
777
831
|
estimatedCost: params.cost,
|
|
778
832
|
tokenCount: params.totalTokens,
|
|
@@ -801,15 +855,7 @@ function trackLLMCall(params) {
|
|
|
801
855
|
model: params.model,
|
|
802
856
|
provider: params.provider
|
|
803
857
|
},
|
|
804
|
-
toolOutput
|
|
805
|
-
content: params.output,
|
|
806
|
-
tokens: {
|
|
807
|
-
prompt: params.promptTokens,
|
|
808
|
-
completion: params.completionTokens,
|
|
809
|
-
total: params.totalTokens
|
|
810
|
-
},
|
|
811
|
-
cost_usd: params.cost
|
|
812
|
-
},
|
|
858
|
+
toolOutput,
|
|
813
859
|
estimatedCost: params.cost,
|
|
814
860
|
tokenCount: params.totalTokens,
|
|
815
861
|
metadata: {
|
|
@@ -1592,6 +1638,7 @@ function getClient() {
|
|
|
1592
1638
|
}
|
|
1593
1639
|
function configure(config) {
|
|
1594
1640
|
defaultClient = new SentrialClient(config);
|
|
1641
|
+
setDefaultClient(defaultClient);
|
|
1595
1642
|
}
|
|
1596
1643
|
function begin(params) {
|
|
1597
1644
|
return getClient().begin(params);
|
|
@@ -1610,6 +1657,10 @@ var sentrial = {
|
|
|
1610
1657
|
};
|
|
1611
1658
|
|
|
1612
1659
|
// src/vercel.ts
|
|
1660
|
+
function resolveStringOrFn(value, fallback) {
|
|
1661
|
+
if (typeof value === "function") return value() ?? fallback;
|
|
1662
|
+
return value ?? fallback;
|
|
1663
|
+
}
|
|
1613
1664
|
var _defaultClient2 = null;
|
|
1614
1665
|
var _globalConfig = {};
|
|
1615
1666
|
function configureVercel(config) {
|
|
@@ -1618,6 +1669,7 @@ function configureVercel(config) {
|
|
|
1618
1669
|
apiUrl: config.apiUrl,
|
|
1619
1670
|
failSilently: config.failSilently ?? true
|
|
1620
1671
|
});
|
|
1672
|
+
setDefaultClient(_defaultClient2);
|
|
1621
1673
|
_globalConfig = {
|
|
1622
1674
|
defaultAgent: config.defaultAgent,
|
|
1623
1675
|
userId: config.userId,
|
|
@@ -1632,7 +1684,8 @@ function getClient2() {
|
|
|
1632
1684
|
}
|
|
1633
1685
|
function extractModelInfo(model) {
|
|
1634
1686
|
const modelId = model.modelId || model.id || "unknown";
|
|
1635
|
-
const
|
|
1687
|
+
const rawProvider = model.provider || "";
|
|
1688
|
+
const provider = rawProvider.split(".")[0] || guessProvider(modelId);
|
|
1636
1689
|
return { modelId, provider };
|
|
1637
1690
|
}
|
|
1638
1691
|
function guessProvider(modelId) {
|
|
@@ -1666,17 +1719,38 @@ function calculateCostForCall(provider, modelId, promptTokens, completionTokens)
|
|
|
1666
1719
|
return 0;
|
|
1667
1720
|
}
|
|
1668
1721
|
}
|
|
1722
|
+
function extractContentText(content) {
|
|
1723
|
+
if (typeof content === "string") return content;
|
|
1724
|
+
if (Array.isArray(content)) {
|
|
1725
|
+
const textParts = content.filter((part) => part && part.type === "text" && typeof part.text === "string").map((part) => part.text);
|
|
1726
|
+
if (textParts.length > 0) return textParts.join("\n");
|
|
1727
|
+
}
|
|
1728
|
+
return JSON.stringify(content);
|
|
1729
|
+
}
|
|
1669
1730
|
function extractInput(params) {
|
|
1670
1731
|
if (params.prompt) return params.prompt;
|
|
1671
1732
|
if (params.messages && params.messages.length > 0) {
|
|
1672
1733
|
const lastUserMessage = [...params.messages].reverse().find((m) => m.role === "user");
|
|
1673
1734
|
if (lastUserMessage) {
|
|
1674
|
-
return
|
|
1735
|
+
return extractContentText(lastUserMessage.content);
|
|
1736
|
+
}
|
|
1737
|
+
const lastNonSystem = [...params.messages].reverse().find((m) => m.role !== "system");
|
|
1738
|
+
if (lastNonSystem) {
|
|
1739
|
+
return extractContentText(lastNonSystem.content);
|
|
1675
1740
|
}
|
|
1676
|
-
return
|
|
1741
|
+
return "";
|
|
1677
1742
|
}
|
|
1678
1743
|
return "";
|
|
1679
1744
|
}
|
|
1745
|
+
function normalizeUsage(usage) {
|
|
1746
|
+
if (!usage) return void 0;
|
|
1747
|
+
const u = usage;
|
|
1748
|
+
const promptTokens = (u.inputTokens ?? u.promptTokens ?? 0) || 0;
|
|
1749
|
+
const completionTokens = (u.outputTokens ?? u.completionTokens ?? 0) || 0;
|
|
1750
|
+
const totalTokens = (u.totalTokens ?? promptTokens + completionTokens) || 0;
|
|
1751
|
+
if (promptTokens === 0 && completionTokens === 0 && totalTokens === 0) return void 0;
|
|
1752
|
+
return { promptTokens, completionTokens, totalTokens };
|
|
1753
|
+
}
|
|
1680
1754
|
function wrapTools(tools, sessionId, client) {
|
|
1681
1755
|
if (!tools) return void 0;
|
|
1682
1756
|
const wrappedTools = {};
|
|
@@ -1729,34 +1803,37 @@ function wrapToolsAsync(tools, sessionPromise, client) {
|
|
|
1729
1803
|
...tool,
|
|
1730
1804
|
execute: async (...args) => {
|
|
1731
1805
|
const startTime = Date.now();
|
|
1732
|
-
const sid = await sessionPromise;
|
|
1733
1806
|
try {
|
|
1734
1807
|
const result = await originalExecute(...args);
|
|
1735
1808
|
const durationMs = Date.now() - startTime;
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1809
|
+
sessionPromise.then((sid) => {
|
|
1810
|
+
if (sid) {
|
|
1811
|
+
client.trackToolCall({
|
|
1812
|
+
sessionId: sid,
|
|
1813
|
+
toolName,
|
|
1814
|
+
toolInput: args[0],
|
|
1815
|
+
toolOutput: result,
|
|
1816
|
+
reasoning: `Tool executed in ${durationMs}ms`
|
|
1817
|
+
}).catch(() => {
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1746
1821
|
return result;
|
|
1747
1822
|
} catch (error) {
|
|
1748
1823
|
const durationMs = Date.now() - startTime;
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1824
|
+
sessionPromise.then((sid) => {
|
|
1825
|
+
if (sid) {
|
|
1826
|
+
client.trackToolCall({
|
|
1827
|
+
sessionId: sid,
|
|
1828
|
+
toolName,
|
|
1829
|
+
toolInput: args[0],
|
|
1830
|
+
toolOutput: {},
|
|
1831
|
+
toolError: { message: error instanceof Error ? error.message : "Unknown error" },
|
|
1832
|
+
reasoning: `Tool failed after ${durationMs}ms`
|
|
1833
|
+
}).catch(() => {
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
});
|
|
1760
1837
|
throw error;
|
|
1761
1838
|
}
|
|
1762
1839
|
}
|
|
@@ -1775,8 +1852,8 @@ function wrapGenerateText(originalFn, client, config) {
|
|
|
1775
1852
|
const sessionId = await client.createSession({
|
|
1776
1853
|
name: `generateText: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
|
|
1777
1854
|
agentName: config.defaultAgent ?? "vercel-ai-sdk",
|
|
1778
|
-
userId: config.userId
|
|
1779
|
-
convoId: config.convoId,
|
|
1855
|
+
userId: resolveStringOrFn(config.userId, "anonymous"),
|
|
1856
|
+
convoId: resolveStringOrFn(config.convoId),
|
|
1780
1857
|
metadata: {
|
|
1781
1858
|
model: modelId,
|
|
1782
1859
|
provider,
|
|
@@ -1796,44 +1873,50 @@ function wrapGenerateText(originalFn, client, config) {
|
|
|
1796
1873
|
const result = await originalFn(wrappedParams);
|
|
1797
1874
|
const durationMs = Date.now() - startTime;
|
|
1798
1875
|
const resolvedModelId = result.response?.modelId || modelId;
|
|
1799
|
-
const
|
|
1800
|
-
const
|
|
1801
|
-
const
|
|
1876
|
+
const usage = normalizeUsage(result.usage);
|
|
1877
|
+
const promptTokens = usage?.promptTokens ?? 0;
|
|
1878
|
+
const completionTokens = usage?.completionTokens ?? 0;
|
|
1879
|
+
const totalTokens = usage?.totalTokens ?? 0;
|
|
1802
1880
|
const cost = calculateCostForCall(provider, resolvedModelId, promptTokens, completionTokens);
|
|
1803
1881
|
const steps = result.steps;
|
|
1804
1882
|
if (steps && steps.length >= 1) {
|
|
1805
|
-
const stepPromises = steps.map(
|
|
1806
|
-
|
|
1883
|
+
const stepPromises = steps.map((step) => {
|
|
1884
|
+
const su = normalizeUsage(step.usage);
|
|
1885
|
+
return client.trackToolCall({
|
|
1807
1886
|
sessionId,
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1887
|
+
toolName: `llm:${provider}:${resolvedModelId}`,
|
|
1888
|
+
toolInput: { finishReason: step.finishReason },
|
|
1889
|
+
toolOutput: {
|
|
1890
|
+
text: step.text?.slice(0, 500),
|
|
1891
|
+
tokens: {
|
|
1892
|
+
prompt: su?.promptTokens ?? 0,
|
|
1893
|
+
completion: su?.completionTokens ?? 0
|
|
1894
|
+
}
|
|
1895
|
+
},
|
|
1896
|
+
estimatedCost: calculateCostForCall(provider, resolvedModelId, su?.promptTokens ?? 0, su?.completionTokens ?? 0),
|
|
1897
|
+
tokenCount: su?.totalTokens,
|
|
1898
|
+
metadata: {
|
|
1818
1899
|
tool_calls: step.toolCalls?.map((tc) => tc.toolName)
|
|
1819
1900
|
}
|
|
1820
1901
|
}).catch(() => {
|
|
1821
|
-
})
|
|
1822
|
-
);
|
|
1902
|
+
});
|
|
1903
|
+
});
|
|
1823
1904
|
await Promise.all(stepPromises);
|
|
1824
1905
|
} else {
|
|
1825
|
-
await client.
|
|
1906
|
+
await client.trackToolCall({
|
|
1826
1907
|
sessionId,
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1908
|
+
toolName: `llm:${provider}:${resolvedModelId}`,
|
|
1909
|
+
toolInput: { finishReason: result.finishReason },
|
|
1910
|
+
toolOutput: {
|
|
1911
|
+
text: result.text?.slice(0, 500),
|
|
1912
|
+
tokens: { prompt: promptTokens, completion: completionTokens }
|
|
1913
|
+
},
|
|
1914
|
+
estimatedCost: cost,
|
|
1915
|
+
tokenCount: totalTokens,
|
|
1916
|
+
metadata: {
|
|
1835
1917
|
tool_calls: result.toolCalls?.map((tc) => tc.toolName)
|
|
1836
1918
|
}
|
|
1919
|
+
}).catch(() => {
|
|
1837
1920
|
});
|
|
1838
1921
|
}
|
|
1839
1922
|
await client.completeSession({
|
|
@@ -1870,13 +1953,18 @@ function wrapStreamText(originalFn, client, config) {
|
|
|
1870
1953
|
const { modelId, provider } = extractModelInfo(params.model);
|
|
1871
1954
|
const input = extractInput(params);
|
|
1872
1955
|
let sessionId = null;
|
|
1873
|
-
|
|
1956
|
+
let sessionCompleted = false;
|
|
1957
|
+
let resolveSessionReady;
|
|
1958
|
+
const sessionReady = new Promise((resolve) => {
|
|
1959
|
+
resolveSessionReady = resolve;
|
|
1960
|
+
});
|
|
1961
|
+
(async () => {
|
|
1874
1962
|
try {
|
|
1875
1963
|
const id = await client.createSession({
|
|
1876
1964
|
name: `streamText: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
|
|
1877
1965
|
agentName: config.defaultAgent ?? "vercel-ai-sdk",
|
|
1878
|
-
userId: config.userId
|
|
1879
|
-
convoId: config.convoId,
|
|
1966
|
+
userId: resolveStringOrFn(config.userId, "anonymous"),
|
|
1967
|
+
convoId: resolveStringOrFn(config.convoId),
|
|
1880
1968
|
metadata: {
|
|
1881
1969
|
model: modelId,
|
|
1882
1970
|
provider,
|
|
@@ -1888,143 +1976,122 @@ function wrapStreamText(originalFn, client, config) {
|
|
|
1888
1976
|
client.setInput(id, input).catch(() => {
|
|
1889
1977
|
});
|
|
1890
1978
|
}
|
|
1891
|
-
return id;
|
|
1892
1979
|
} catch {
|
|
1893
|
-
|
|
1980
|
+
sessionId = null;
|
|
1894
1981
|
}
|
|
1982
|
+
resolveSessionReady();
|
|
1895
1983
|
})();
|
|
1984
|
+
const userOnStepFinish = params.onStepFinish;
|
|
1985
|
+
const userOnFinish = params.onFinish;
|
|
1986
|
+
const userOnError = params.onError;
|
|
1896
1987
|
const wrappedParams = {
|
|
1897
1988
|
...params,
|
|
1898
|
-
tools: params.tools ? wrapToolsAsync(params.tools,
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
sessionId: sid,
|
|
1919
|
-
success: false,
|
|
1920
|
-
failureReason: error.message || "Unknown error",
|
|
1921
|
-
durationMs
|
|
1922
|
-
}).catch(() => {
|
|
1923
|
-
});
|
|
1924
|
-
return;
|
|
1925
|
-
}
|
|
1926
|
-
let resolvedModelId = modelId;
|
|
1927
|
-
try {
|
|
1928
|
-
const resp = result.response ? await result.response : void 0;
|
|
1929
|
-
if (resp?.modelId) resolvedModelId = resp.modelId;
|
|
1930
|
-
} catch {
|
|
1931
|
-
}
|
|
1932
|
-
let usage;
|
|
1933
|
-
try {
|
|
1934
|
-
usage = result.usage ? await result.usage : void 0;
|
|
1935
|
-
} catch {
|
|
1936
|
-
}
|
|
1937
|
-
let steps;
|
|
1938
|
-
try {
|
|
1939
|
-
steps = result.steps ? await result.steps : void 0;
|
|
1940
|
-
} catch {
|
|
1941
|
-
}
|
|
1942
|
-
if (steps && steps.length >= 1) {
|
|
1943
|
-
let totalPrompt = 0, totalCompletion = 0;
|
|
1944
|
-
const stepPromises = steps.map((step, i) => {
|
|
1945
|
-
const sp = step.usage?.promptTokens ?? 0;
|
|
1946
|
-
const sc = step.usage?.completionTokens ?? 0;
|
|
1947
|
-
totalPrompt += sp;
|
|
1948
|
-
totalCompletion += sc;
|
|
1949
|
-
return client.trackEvent({
|
|
1950
|
-
sessionId: sid,
|
|
1951
|
-
eventType: "llm_call",
|
|
1952
|
-
eventData: {
|
|
1953
|
-
model: resolvedModelId,
|
|
1954
|
-
provider,
|
|
1955
|
-
step: i + 1,
|
|
1956
|
-
total_steps: steps.length,
|
|
1957
|
-
prompt_tokens: sp,
|
|
1958
|
-
completion_tokens: sc,
|
|
1959
|
-
total_tokens: step.usage?.totalTokens ?? 0,
|
|
1960
|
-
finish_reason: step.finishReason,
|
|
1989
|
+
tools: params.tools ? wrapToolsAsync(params.tools, sessionReady.then(() => sessionId), client) : void 0,
|
|
1990
|
+
onStepFinish: async (step) => {
|
|
1991
|
+
await sessionReady;
|
|
1992
|
+
if (sessionId) {
|
|
1993
|
+
const su = normalizeUsage(step.usage);
|
|
1994
|
+
const resolvedStepModel = step.response?.modelId ?? modelId;
|
|
1995
|
+
client.trackToolCall({
|
|
1996
|
+
sessionId,
|
|
1997
|
+
toolName: `llm:${provider}:${resolvedStepModel}`,
|
|
1998
|
+
toolInput: { finishReason: step.finishReason },
|
|
1999
|
+
toolOutput: {
|
|
2000
|
+
text: step.text?.slice(0, 500),
|
|
2001
|
+
tokens: {
|
|
2002
|
+
prompt: su?.promptTokens ?? 0,
|
|
2003
|
+
completion: su?.completionTokens ?? 0
|
|
2004
|
+
}
|
|
2005
|
+
},
|
|
2006
|
+
estimatedCost: calculateCostForCall(provider, resolvedStepModel, su?.promptTokens ?? 0, su?.completionTokens ?? 0),
|
|
2007
|
+
tokenCount: su?.totalTokens,
|
|
2008
|
+
metadata: {
|
|
1961
2009
|
tool_calls: step.toolCalls?.map((tc) => tc.toolName)
|
|
1962
2010
|
}
|
|
1963
2011
|
}).catch(() => {
|
|
1964
2012
|
});
|
|
1965
|
-
}
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
2013
|
+
}
|
|
2014
|
+
if (userOnStepFinish) {
|
|
2015
|
+
try {
|
|
2016
|
+
userOnStepFinish(step);
|
|
2017
|
+
} catch {
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
},
|
|
2021
|
+
onFinish: async (event) => {
|
|
2022
|
+
await sessionReady;
|
|
2023
|
+
if (sessionId && !sessionCompleted) {
|
|
2024
|
+
sessionCompleted = true;
|
|
2025
|
+
const durationMs = Date.now() - startTime;
|
|
2026
|
+
const usage = normalizeUsage(event.totalUsage ?? event.usage);
|
|
2027
|
+
const resolvedModelId = event.response?.modelId ?? modelId;
|
|
2028
|
+
const text = event.text ?? "";
|
|
2029
|
+
const promptTokens = usage?.promptTokens ?? 0;
|
|
2030
|
+
const completionTokens = usage?.completionTokens ?? 0;
|
|
2031
|
+
const totalTokens = usage?.totalTokens ?? promptTokens + completionTokens;
|
|
2032
|
+
const cost = calculateCostForCall(provider, resolvedModelId, promptTokens, completionTokens);
|
|
2033
|
+
await client.completeSession({
|
|
2034
|
+
sessionId,
|
|
2035
|
+
success: true,
|
|
2036
|
+
output: text,
|
|
2037
|
+
durationMs,
|
|
2038
|
+
estimatedCost: cost,
|
|
2039
|
+
promptTokens,
|
|
2040
|
+
completionTokens,
|
|
2041
|
+
totalTokens
|
|
2042
|
+
}).catch(() => {
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
if (userOnFinish) {
|
|
2046
|
+
try {
|
|
2047
|
+
userOnFinish(event);
|
|
2048
|
+
} catch {
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
},
|
|
2052
|
+
onError: async (event) => {
|
|
2053
|
+
await sessionReady;
|
|
2054
|
+
if (sessionId && !sessionCompleted) {
|
|
2055
|
+
sessionCompleted = true;
|
|
2056
|
+
const durationMs = Date.now() - startTime;
|
|
2057
|
+
const msg = event.error?.message ?? "Unknown error";
|
|
2058
|
+
await client.trackError({
|
|
2059
|
+
sessionId,
|
|
2060
|
+
errorType: event.error?.name ?? "Error",
|
|
2061
|
+
errorMessage: msg
|
|
2062
|
+
}).catch(() => {
|
|
2063
|
+
});
|
|
2064
|
+
await client.completeSession({
|
|
2065
|
+
sessionId,
|
|
2066
|
+
success: false,
|
|
2067
|
+
failureReason: msg,
|
|
2068
|
+
durationMs
|
|
2069
|
+
}).catch(() => {
|
|
2070
|
+
});
|
|
2071
|
+
}
|
|
2072
|
+
if (userOnError) {
|
|
2073
|
+
try {
|
|
2074
|
+
userOnError(event);
|
|
2075
|
+
} catch {
|
|
1996
2076
|
}
|
|
1997
|
-
}).catch(() => {
|
|
1998
|
-
});
|
|
1999
|
-
await client.completeSession({
|
|
2000
|
-
sessionId: sid,
|
|
2001
|
-
success: true,
|
|
2002
|
-
output: text,
|
|
2003
|
-
durationMs,
|
|
2004
|
-
estimatedCost: cost,
|
|
2005
|
-
promptTokens,
|
|
2006
|
-
completionTokens,
|
|
2007
|
-
totalTokens
|
|
2008
|
-
}).catch(() => {
|
|
2009
|
-
});
|
|
2010
|
-
}
|
|
2011
|
-
}
|
|
2012
|
-
result.textStream = (async function* () {
|
|
2013
|
-
try {
|
|
2014
|
-
for await (const chunk of originalTextStream) {
|
|
2015
|
-
fullText += chunk;
|
|
2016
|
-
yield chunk;
|
|
2017
2077
|
}
|
|
2018
|
-
await trackCompletion(fullText);
|
|
2019
|
-
} catch (error) {
|
|
2020
|
-
await trackCompletion(
|
|
2021
|
-
fullText,
|
|
2022
|
-
error instanceof Error ? error : new Error(String(error))
|
|
2023
|
-
);
|
|
2024
|
-
throw error;
|
|
2025
2078
|
}
|
|
2026
|
-
}
|
|
2027
|
-
|
|
2079
|
+
};
|
|
2080
|
+
try {
|
|
2081
|
+
return originalFn(wrappedParams);
|
|
2082
|
+
} catch (error) {
|
|
2083
|
+
sessionReady.then(() => {
|
|
2084
|
+
if (sessionId) {
|
|
2085
|
+
const durationMs = Date.now() - startTime;
|
|
2086
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
2087
|
+
client.trackError({ sessionId, errorType: error instanceof Error ? error.name : "Error", errorMessage: msg }).catch(() => {
|
|
2088
|
+
});
|
|
2089
|
+
client.completeSession({ sessionId, success: false, failureReason: msg, durationMs }).catch(() => {
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
});
|
|
2093
|
+
throw error;
|
|
2094
|
+
}
|
|
2028
2095
|
};
|
|
2029
2096
|
}
|
|
2030
2097
|
function wrapGenerateObject(originalFn, client, config) {
|
|
@@ -2035,8 +2102,8 @@ function wrapGenerateObject(originalFn, client, config) {
|
|
|
2035
2102
|
const sessionId = await client.createSession({
|
|
2036
2103
|
name: `generateObject: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
|
|
2037
2104
|
agentName: config.defaultAgent ?? "vercel-ai-sdk",
|
|
2038
|
-
userId: config.userId
|
|
2039
|
-
convoId: config.convoId,
|
|
2105
|
+
userId: resolveStringOrFn(config.userId, "anonymous"),
|
|
2106
|
+
convoId: resolveStringOrFn(config.convoId),
|
|
2040
2107
|
metadata: {
|
|
2041
2108
|
model: modelId,
|
|
2042
2109
|
provider,
|
|
@@ -2051,20 +2118,21 @@ function wrapGenerateObject(originalFn, client, config) {
|
|
|
2051
2118
|
const result = await originalFn(params);
|
|
2052
2119
|
const durationMs = Date.now() - startTime;
|
|
2053
2120
|
const resolvedModelId = result.response?.modelId || modelId;
|
|
2054
|
-
const
|
|
2055
|
-
const
|
|
2056
|
-
const
|
|
2121
|
+
const usage = normalizeUsage(result.usage);
|
|
2122
|
+
const promptTokens = usage?.promptTokens ?? 0;
|
|
2123
|
+
const completionTokens = usage?.completionTokens ?? 0;
|
|
2124
|
+
const totalTokens = usage?.totalTokens ?? 0;
|
|
2057
2125
|
const cost = calculateCostForCall(provider, resolvedModelId, promptTokens, completionTokens);
|
|
2058
|
-
await client.
|
|
2126
|
+
await client.trackToolCall({
|
|
2059
2127
|
sessionId,
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2128
|
+
toolName: `llm:${provider}:${resolvedModelId}`,
|
|
2129
|
+
toolInput: { function: "generateObject" },
|
|
2130
|
+
toolOutput: {
|
|
2131
|
+
object: result.object,
|
|
2132
|
+
tokens: { prompt: promptTokens, completion: completionTokens }
|
|
2133
|
+
},
|
|
2134
|
+
estimatedCost: cost,
|
|
2135
|
+
tokenCount: totalTokens
|
|
2068
2136
|
}).catch(() => {
|
|
2069
2137
|
});
|
|
2070
2138
|
await client.completeSession({
|
|
@@ -2100,99 +2168,131 @@ function wrapStreamObject(originalFn, client, config) {
|
|
|
2100
2168
|
const startTime = Date.now();
|
|
2101
2169
|
const { modelId, provider } = extractModelInfo(params.model);
|
|
2102
2170
|
const input = extractInput(params);
|
|
2103
|
-
|
|
2171
|
+
let sessionId = null;
|
|
2172
|
+
let resolveSessionReady;
|
|
2173
|
+
const sessionReady = new Promise((resolve) => {
|
|
2174
|
+
resolveSessionReady = resolve;
|
|
2175
|
+
});
|
|
2176
|
+
(async () => {
|
|
2104
2177
|
try {
|
|
2105
2178
|
const id = await client.createSession({
|
|
2106
2179
|
name: `streamObject: ${input.slice(0, 50)}${input.length > 50 ? "..." : ""}`,
|
|
2107
2180
|
agentName: config.defaultAgent ?? "vercel-ai-sdk",
|
|
2108
|
-
userId: config.userId
|
|
2109
|
-
convoId: config.convoId,
|
|
2181
|
+
userId: resolveStringOrFn(config.userId, "anonymous"),
|
|
2182
|
+
convoId: resolveStringOrFn(config.convoId),
|
|
2110
2183
|
metadata: {
|
|
2111
2184
|
model: modelId,
|
|
2112
2185
|
provider,
|
|
2113
2186
|
function: "streamObject"
|
|
2114
2187
|
}
|
|
2115
2188
|
});
|
|
2189
|
+
sessionId = id;
|
|
2116
2190
|
if (id) {
|
|
2117
2191
|
client.setInput(id, input).catch(() => {
|
|
2118
2192
|
});
|
|
2119
2193
|
}
|
|
2120
|
-
return id;
|
|
2121
2194
|
} catch {
|
|
2122
|
-
|
|
2195
|
+
sessionId = null;
|
|
2123
2196
|
}
|
|
2197
|
+
resolveSessionReady();
|
|
2124
2198
|
})();
|
|
2125
|
-
const
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2199
|
+
const userOnFinish = params.onFinish;
|
|
2200
|
+
const userOnError = params.onError;
|
|
2201
|
+
const wrappedParams = {
|
|
2202
|
+
...params,
|
|
2203
|
+
onFinish: async (event) => {
|
|
2204
|
+
await sessionReady;
|
|
2205
|
+
if (sessionId) {
|
|
2206
|
+
const durationMs = Date.now() - startTime;
|
|
2207
|
+
const usage = normalizeUsage(event.usage);
|
|
2208
|
+
const resolvedModelId = event.response?.modelId ?? modelId;
|
|
2209
|
+
const promptTokens = usage?.promptTokens ?? 0;
|
|
2210
|
+
const completionTokens = usage?.completionTokens ?? 0;
|
|
2211
|
+
const totalTokens = usage?.totalTokens ?? 0;
|
|
2212
|
+
const cost = calculateCostForCall(provider, resolvedModelId, promptTokens, completionTokens);
|
|
2213
|
+
if (event.error) {
|
|
2214
|
+
const errMsg = event.error instanceof Error ? event.error.message : String(event.error);
|
|
2215
|
+
await client.trackError({
|
|
2216
|
+
sessionId,
|
|
2217
|
+
errorType: "SchemaValidationError",
|
|
2218
|
+
errorMessage: errMsg
|
|
2219
|
+
}).catch(() => {
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
await client.trackToolCall({
|
|
2223
|
+
sessionId,
|
|
2224
|
+
toolName: `llm:${provider}:${resolvedModelId}`,
|
|
2225
|
+
toolInput: { function: "streamObject" },
|
|
2226
|
+
toolOutput: {
|
|
2227
|
+
object: event.object,
|
|
2228
|
+
tokens: { prompt: promptTokens, completion: completionTokens }
|
|
2229
|
+
},
|
|
2230
|
+
estimatedCost: cost,
|
|
2231
|
+
tokenCount: totalTokens
|
|
2232
|
+
}).catch(() => {
|
|
2233
|
+
});
|
|
2234
|
+
await client.completeSession({
|
|
2235
|
+
sessionId,
|
|
2236
|
+
success: !event.error,
|
|
2237
|
+
output: event.object != null ? JSON.stringify(event.object) : void 0,
|
|
2238
|
+
failureReason: event.error ? String(event.error) : void 0,
|
|
2239
|
+
durationMs,
|
|
2240
|
+
estimatedCost: cost,
|
|
2241
|
+
promptTokens,
|
|
2242
|
+
completionTokens,
|
|
2243
|
+
totalTokens
|
|
2244
|
+
}).catch(() => {
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
if (userOnFinish) {
|
|
2248
|
+
try {
|
|
2249
|
+
userOnFinish(event);
|
|
2250
|
+
} catch {
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
},
|
|
2254
|
+
onError: async (event) => {
|
|
2255
|
+
await sessionReady;
|
|
2256
|
+
if (sessionId) {
|
|
2257
|
+
const durationMs = Date.now() - startTime;
|
|
2258
|
+
const msg = event.error?.message ?? "Unknown error";
|
|
2259
|
+
await client.trackError({
|
|
2260
|
+
sessionId,
|
|
2261
|
+
errorType: event.error?.name ?? "Error",
|
|
2262
|
+
errorMessage: msg
|
|
2263
|
+
}).catch(() => {
|
|
2264
|
+
});
|
|
2265
|
+
await client.completeSession({
|
|
2266
|
+
sessionId,
|
|
2267
|
+
success: false,
|
|
2268
|
+
failureReason: msg,
|
|
2269
|
+
durationMs
|
|
2270
|
+
}).catch(() => {
|
|
2271
|
+
});
|
|
2272
|
+
}
|
|
2273
|
+
if (userOnError) {
|
|
2274
|
+
try {
|
|
2275
|
+
userOnError(event);
|
|
2276
|
+
} catch {
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2150
2279
|
}
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
sessionId
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
total_tokens: totalTokens
|
|
2280
|
+
};
|
|
2281
|
+
try {
|
|
2282
|
+
return originalFn(wrappedParams);
|
|
2283
|
+
} catch (error) {
|
|
2284
|
+
sessionReady.then(() => {
|
|
2285
|
+
if (sessionId) {
|
|
2286
|
+
const durationMs = Date.now() - startTime;
|
|
2287
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
2288
|
+
client.trackError({ sessionId, errorType: error instanceof Error ? error.name : "Error", errorMessage: msg }).catch(() => {
|
|
2289
|
+
});
|
|
2290
|
+
client.completeSession({ sessionId, success: false, failureReason: msg, durationMs }).catch(() => {
|
|
2291
|
+
});
|
|
2164
2292
|
}
|
|
2165
|
-
}).catch(() => {
|
|
2166
|
-
});
|
|
2167
|
-
await client.completeSession({
|
|
2168
|
-
sessionId: sid,
|
|
2169
|
-
success: true,
|
|
2170
|
-
output: JSON.stringify(obj),
|
|
2171
|
-
durationMs,
|
|
2172
|
-
estimatedCost: cost,
|
|
2173
|
-
promptTokens,
|
|
2174
|
-
completionTokens,
|
|
2175
|
-
totalTokens
|
|
2176
|
-
}).catch(() => {
|
|
2177
|
-
});
|
|
2178
|
-
}
|
|
2179
|
-
if (result.object) {
|
|
2180
|
-
const originalObjectPromise = result.object;
|
|
2181
|
-
result.object = originalObjectPromise.then(async (obj) => {
|
|
2182
|
-
await completeStreamObject(obj);
|
|
2183
|
-
return obj;
|
|
2184
|
-
}).catch(async (error) => {
|
|
2185
|
-
await completeStreamObject(void 0, error instanceof Error ? error : new Error(String(error)));
|
|
2186
|
-
throw error;
|
|
2187
|
-
});
|
|
2188
|
-
} else if (result.usage) {
|
|
2189
|
-
result.usage.then(async () => {
|
|
2190
|
-
await completeStreamObject(void 0);
|
|
2191
|
-
}).catch(async (error) => {
|
|
2192
|
-
await completeStreamObject(void 0, error instanceof Error ? error : new Error(String(error)));
|
|
2193
2293
|
});
|
|
2294
|
+
throw error;
|
|
2194
2295
|
}
|
|
2195
|
-
return result;
|
|
2196
2296
|
};
|
|
2197
2297
|
}
|
|
2198
2298
|
function wrapAISDK(ai, options) {
|