@kognitivedev/vercel-ai-provider 0.1.7 → 0.1.9

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.
@@ -36,6 +36,110 @@ describe("wrapStream logging", () => {
36
36
  );
37
37
  });
38
38
 
39
+ it("should capture tool-call chunks and include them in logged conversation", async () => {
40
+ const mockModel = new MockLanguageModelV3({
41
+ doStream: async () => ({
42
+ stream: convertArrayToReadableStream([
43
+ { type: "text-start" as const, id: "t1" },
44
+ { type: "text-delta" as const, id: "t1", delta: "Let me check" },
45
+ { type: "text-end" as const, id: "t1" },
46
+ {
47
+ type: "tool-call" as const,
48
+ toolCallId: "call-1",
49
+ toolName: "get_weather",
50
+ input: '{"city":"London"}',
51
+ },
52
+ {
53
+ type: "tool-result" as const,
54
+ toolCallId: "call-1",
55
+ toolName: "get_weather",
56
+ result: { temperature: 15, unit: "celsius" },
57
+ },
58
+ {
59
+ type: "finish" as const,
60
+ finishReason: {
61
+ unified: "tool-calls" as const,
62
+ raw: undefined,
63
+ },
64
+ usage: {
65
+ inputTokens: { total: 20, noCache: undefined, cacheRead: undefined, cacheWrite: undefined },
66
+ outputTokens: { total: 15, text: undefined, reasoning: undefined },
67
+ },
68
+ },
69
+ ] satisfies import("@ai-sdk/provider").LanguageModelV3StreamPart[]),
70
+ }),
71
+ });
72
+
73
+ const mockProvider = () => mockModel;
74
+
75
+ const cl = createCognitiveLayer({
76
+ provider: mockProvider,
77
+ clConfig: {
78
+ apiKey: "test-api-key",
79
+ appId: "test-app",
80
+ projectId: "test-project",
81
+ processDelayMs: 0,
82
+ logLevel: "none",
83
+ },
84
+ });
85
+
86
+ const model = cl("mock-model", {
87
+ userId: "user-1",
88
+ projectId: "project-1",
89
+ sessionId: "session-1",
90
+ });
91
+
92
+ const result = streamText({
93
+ model,
94
+ messages: [{ role: "user", content: "What's the weather in London?" }],
95
+ });
96
+
97
+ // Fully consume the stream
98
+ await result.text;
99
+
100
+ // Wait for async logConversation to complete
101
+ await new Promise((r) => setTimeout(r, 100));
102
+
103
+ // Find the log call
104
+ const logCall = fetchCalls.find((c) => c.url.includes("/api/cognitive/log"));
105
+ expect(logCall).toBeDefined();
106
+
107
+ const messages = logCall!.body.messages;
108
+
109
+ // Assistant message should contain text + tool-call parts
110
+ const assistantMsg = messages.find((m: any) => m.role === "assistant");
111
+ expect(assistantMsg).toBeDefined();
112
+ expect(assistantMsg.content).toEqual([
113
+ { type: "text", text: "Let me check" },
114
+ {
115
+ type: "tool-call",
116
+ toolCallId: "call-1",
117
+ toolName: "get_weather",
118
+ input: '{"city":"London"}',
119
+ },
120
+ ]);
121
+
122
+ // Tool results should be in a separate tool message
123
+ const toolMsg = messages.find((m: any) => m.role === "tool");
124
+ expect(toolMsg).toBeDefined();
125
+ expect(toolMsg.content).toEqual([
126
+ {
127
+ type: "tool-result",
128
+ toolCallId: "call-1",
129
+ toolName: "get_weather",
130
+ result: { temperature: 15, unit: "celsius" },
131
+ },
132
+ ]);
133
+
134
+ // Spans should include the tool call with populated previews
135
+ const spans = logCall!.body.spans;
136
+ const toolSpan = spans?.find((s: any) => s.spanType === "tool");
137
+ expect(toolSpan).toBeDefined();
138
+ expect(toolSpan.toolName).toBe("get_weather");
139
+ expect(toolSpan.inputPreview).toContain("London");
140
+ expect(toolSpan.outputPreview).toContain("15");
141
+ });
142
+
39
143
  it("should include assistant message in logged conversation after streaming", async () => {
40
144
  const mockModel = new MockLanguageModelV3({
41
145
  doStream: async () => ({