graphlit-client 1.0.20250610009 → 1.0.20250611001
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 +427 -553
- package/dist/client.d.ts +2 -37
- package/dist/client.js +11 -10
- package/dist/streaming/providers.d.ts +1 -1
- package/dist/streaming/ui-event-adapter.d.ts +1 -1
- package/dist/types/internal.d.ts +42 -0
- package/dist/types/internal.js +5 -0
- package/package.json +1 -1
- package/dist/stream-helpers.d.ts +0 -106
- package/dist/stream-helpers.js +0 -237
package/dist/client.d.ts
CHANGED
@@ -1,41 +1,7 @@
|
|
1
|
-
import { ApolloClient, NormalizedCacheObject } from "@apollo/client
|
1
|
+
import { ApolloClient, NormalizedCacheObject } from "@apollo/client";
|
2
2
|
import * as Types from "./generated/graphql-types.js";
|
3
3
|
import { AgentOptions, AgentResult, StreamAgentOptions, ToolHandler } from "./types/agent.js";
|
4
4
|
import { AgentStreamEvent } from "./types/ui-events.js";
|
5
|
-
export type StreamEvent = {
|
6
|
-
type: "start";
|
7
|
-
conversationId: string;
|
8
|
-
} | {
|
9
|
-
type: "token";
|
10
|
-
token: string;
|
11
|
-
} | {
|
12
|
-
type: "message";
|
13
|
-
message: string;
|
14
|
-
} | {
|
15
|
-
type: "tool_call_start";
|
16
|
-
toolCall: {
|
17
|
-
id: string;
|
18
|
-
name: string;
|
19
|
-
};
|
20
|
-
} | {
|
21
|
-
type: "tool_call_delta";
|
22
|
-
toolCallId: string;
|
23
|
-
argumentDelta: string;
|
24
|
-
} | {
|
25
|
-
type: "tool_call_complete";
|
26
|
-
toolCall: {
|
27
|
-
id: string;
|
28
|
-
name: string;
|
29
|
-
arguments: string;
|
30
|
-
};
|
31
|
-
} | {
|
32
|
-
type: "complete";
|
33
|
-
messageId?: string;
|
34
|
-
conversationId?: string;
|
35
|
-
} | {
|
36
|
-
type: "error";
|
37
|
-
error: string;
|
38
|
-
};
|
39
5
|
export type { AgentOptions, AgentResult, StreamAgentOptions, ToolCallResult, UsageInfo, AgentError, } from "./types/agent.js";
|
40
6
|
export type { AgentStreamEvent } from "./types/ui-events.js";
|
41
7
|
declare class Graphlit {
|
@@ -376,7 +342,7 @@ declare class Graphlit {
|
|
376
342
|
* @param options - Stream agent options
|
377
343
|
* @throws Error if streaming is not supported
|
378
344
|
*/
|
379
|
-
streamAgent(prompt: string, onEvent: (event:
|
345
|
+
streamAgent(prompt: string, onEvent: (event: AgentStreamEvent) => void, conversationId?: string, specification?: Types.EntityReferenceInput, tools?: Types.ToolDefinitionInput[], toolHandlers?: Record<string, ToolHandler>, options?: StreamAgentOptions, mimeType?: string, data?: string, // base64 encoded
|
380
346
|
correlationId?: string): Promise<void>;
|
381
347
|
/**
|
382
348
|
* Execute the streaming agent workflow with tool calling loop
|
@@ -417,4 +383,3 @@ declare class Graphlit {
|
|
417
383
|
}
|
418
384
|
export { Graphlit };
|
419
385
|
export * as Types from "./generated/graphql-types.js";
|
420
|
-
export { StreamEventAggregator, AggregatedEvent, formatSSEEvent, createSSEStream, wrapToolHandlers, enhanceToolCalls, ConversationMetrics, ToolResultEmitter, ServerMapping, } from "./stream-helpers.js";
|
package/dist/client.js
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
import * as jwt from "jsonwebtoken";
|
2
|
-
import { ApolloClient, InMemoryCache, createHttpLink, ApolloLink, ApolloError, } from "@apollo/client
|
2
|
+
import { ApolloClient, InMemoryCache, createHttpLink, ApolloLink, ApolloError, } from "@apollo/client";
|
3
3
|
import * as Types from "./generated/graphql-types.js";
|
4
4
|
import * as Documents from "./generated/graphql-documents.js";
|
5
5
|
import * as dotenv from "dotenv";
|
6
|
-
import { getServiceType
|
6
|
+
import { getServiceType } from "./model-mapping.js";
|
7
7
|
import { UIEventAdapter } from "./streaming/ui-event-adapter.js";
|
8
8
|
import { formatMessagesForOpenAI, formatMessagesForAnthropic, formatMessagesForGoogle, } from "./streaming/llm-formatters.js";
|
9
9
|
import { streamWithOpenAI, streamWithAnthropic, streamWithGoogle, } from "./streaming/providers.js";
|
@@ -1724,7 +1724,8 @@ class Graphlit {
|
|
1724
1724
|
// Check for common truncation patterns
|
1725
1725
|
const lastChars = toolCall.arguments.slice(-20);
|
1726
1726
|
let isTruncated = false;
|
1727
|
-
if (!toolCall.arguments.includes(
|
1727
|
+
if (!toolCall.arguments.includes("}") ||
|
1728
|
+
!lastChars.includes("}")) {
|
1728
1729
|
console.error(`Possible truncation detected - arguments don't end with '}': ...${lastChars}`);
|
1729
1730
|
isTruncated = true;
|
1730
1731
|
}
|
@@ -1737,7 +1738,8 @@ class Graphlit {
|
|
1737
1738
|
const missingBraces = openBraces - closeBraces;
|
1738
1739
|
if (missingBraces > 0) {
|
1739
1740
|
// Check if we're mid-value (ends with number or boolean)
|
1740
|
-
if (fixedJson.match(/:\s*\d+$/) ||
|
1741
|
+
if (fixedJson.match(/:\s*\d+$/) ||
|
1742
|
+
fixedJson.match(/:\s*(true|false)$/)) {
|
1741
1743
|
// Complete the current property and close
|
1742
1744
|
fixedJson += ', "content": ""'; // Add empty content field
|
1743
1745
|
}
|
@@ -1747,7 +1749,8 @@ class Graphlit {
|
|
1747
1749
|
fixedJson += ', "content": ""';
|
1748
1750
|
}
|
1749
1751
|
// Add missing closing quote if the string ends with an unfinished string
|
1750
|
-
else if (fixedJson.endsWith('"') === false &&
|
1752
|
+
else if (fixedJson.endsWith('"') === false &&
|
1753
|
+
fixedJson.includes('"')) {
|
1751
1754
|
const lastQuoteIndex = fixedJson.lastIndexOf('"');
|
1752
1755
|
const afterLastQuote = fixedJson.slice(lastQuoteIndex + 1);
|
1753
1756
|
if (!afterLastQuote.includes('"')) {
|
@@ -1755,7 +1758,7 @@ class Graphlit {
|
|
1755
1758
|
}
|
1756
1759
|
}
|
1757
1760
|
// Add missing closing braces
|
1758
|
-
fixedJson +=
|
1761
|
+
fixedJson += "}".repeat(missingBraces);
|
1759
1762
|
console.log(`Attempting to fix truncated JSON by adding ${missingBraces} closing brace(s):`);
|
1760
1763
|
console.log(fixedJson);
|
1761
1764
|
try {
|
@@ -1771,7 +1774,7 @@ class Graphlit {
|
|
1771
1774
|
// If we couldn't parse or fix the JSON, log details and continue
|
1772
1775
|
if (!args) {
|
1773
1776
|
// Log position mentioned in error if available
|
1774
|
-
const errorMsg = parseError instanceof Error ? parseError.message :
|
1777
|
+
const errorMsg = parseError instanceof Error ? parseError.message : "";
|
1775
1778
|
const posMatch = errorMsg.match(/position (\d+)/);
|
1776
1779
|
if (posMatch) {
|
1777
1780
|
const pos = parseInt(posMatch[1]);
|
@@ -1781,7 +1784,7 @@ class Graphlit {
|
|
1781
1784
|
// Update UI with error - use StreamEvent error type
|
1782
1785
|
uiAdapter.handleEvent({
|
1783
1786
|
type: "error",
|
1784
|
-
error: `Tool ${toolCall.name} failed: Invalid JSON arguments: ${parseError instanceof Error ? parseError.message :
|
1787
|
+
error: `Tool ${toolCall.name} failed: Invalid JSON arguments: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
|
1785
1788
|
});
|
1786
1789
|
continue;
|
1787
1790
|
}
|
@@ -2113,5 +2116,3 @@ class Graphlit {
|
|
2113
2116
|
}
|
2114
2117
|
export { Graphlit };
|
2115
2118
|
export * as Types from "./generated/graphql-types.js";
|
2116
|
-
// Export streaming helpers
|
2117
|
-
export { StreamEventAggregator, formatSSEEvent, createSSEStream, wrapToolHandlers, enhanceToolCalls, ConversationMetrics, } from "./stream-helpers.js";
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { ConversationToolCall, Specification, ToolDefinitionInput } from "../generated/graphql-types.js";
|
2
|
-
import { StreamEvent } from "../client.js";
|
3
2
|
import { OpenAIMessage, AnthropicMessage, GoogleMessage } from "./llm-formatters.js";
|
3
|
+
import { StreamEvent } from "../types/internal.js";
|
4
4
|
/**
|
5
5
|
* Stream with OpenAI SDK
|
6
6
|
*/
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { AgentStreamEvent } from "../types/ui-events.js";
|
2
|
-
import { StreamEvent } from "../
|
2
|
+
import { StreamEvent } from "../types/internal.js";
|
3
3
|
import { ChunkingStrategy } from "./chunk-buffer.js";
|
4
4
|
/**
|
5
5
|
* Adapter that transforms low-level streaming events into high-level UI events
|
@@ -0,0 +1,42 @@
|
|
1
|
+
/**
|
2
|
+
* Internal types used by the streaming implementation
|
3
|
+
* These are not exported to consumers of the library
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* Low-level streaming events used internally by providers
|
7
|
+
* These get transformed into AgentStreamEvent by UIEventAdapter
|
8
|
+
*/
|
9
|
+
export type StreamEvent = {
|
10
|
+
type: "start";
|
11
|
+
conversationId: string;
|
12
|
+
} | {
|
13
|
+
type: "token";
|
14
|
+
token: string;
|
15
|
+
} | {
|
16
|
+
type: "message";
|
17
|
+
message: string;
|
18
|
+
} | {
|
19
|
+
type: "tool_call_start";
|
20
|
+
toolCall: {
|
21
|
+
id: string;
|
22
|
+
name: string;
|
23
|
+
};
|
24
|
+
} | {
|
25
|
+
type: "tool_call_delta";
|
26
|
+
toolCallId: string;
|
27
|
+
argumentDelta: string;
|
28
|
+
} | {
|
29
|
+
type: "tool_call_complete";
|
30
|
+
toolCall: {
|
31
|
+
id: string;
|
32
|
+
name: string;
|
33
|
+
arguments: string;
|
34
|
+
};
|
35
|
+
} | {
|
36
|
+
type: "complete";
|
37
|
+
messageId?: string;
|
38
|
+
conversationId?: string;
|
39
|
+
} | {
|
40
|
+
type: "error";
|
41
|
+
error: string;
|
42
|
+
};
|
package/package.json
CHANGED
package/dist/stream-helpers.d.ts
DELETED
@@ -1,106 +0,0 @@
|
|
1
|
-
import { StreamEvent } from "./client.js";
|
2
|
-
import { ConversationRoleTypes } from "./generated/graphql-types.js";
|
3
|
-
export declare class StreamEventAggregator {
|
4
|
-
private conversationId;
|
5
|
-
private messageBuffer;
|
6
|
-
private toolCallsBuffer;
|
7
|
-
private isFirstAssistantMessage;
|
8
|
-
private hasReceivedToolCalls;
|
9
|
-
private tokenBuffer;
|
10
|
-
/**
|
11
|
-
* Process a stream event and return any complete messages ready for the UI
|
12
|
-
*/
|
13
|
-
processEvent(event: StreamEvent): AggregatedEvent | null;
|
14
|
-
/**
|
15
|
-
* Reset the aggregator for a new conversation
|
16
|
-
*/
|
17
|
-
reset(): void;
|
18
|
-
/**
|
19
|
-
* Get current state (useful for debugging)
|
20
|
-
*/
|
21
|
-
getState(): {
|
22
|
-
conversationId: string;
|
23
|
-
messageBuffer: string;
|
24
|
-
toolCallsCount: number;
|
25
|
-
hasReceivedToolCalls: boolean;
|
26
|
-
isFirstAssistantMessage: boolean;
|
27
|
-
tokenCount: number;
|
28
|
-
};
|
29
|
-
}
|
30
|
-
/**
|
31
|
-
* Aggregated event types that are ready for UI consumption
|
32
|
-
*/
|
33
|
-
export type AggregatedEvent = {
|
34
|
-
type: "conversationStarted";
|
35
|
-
conversationId: string;
|
36
|
-
} | {
|
37
|
-
type: "token";
|
38
|
-
token: string;
|
39
|
-
accumulated: string;
|
40
|
-
} | {
|
41
|
-
type: "assistantMessage";
|
42
|
-
message: {
|
43
|
-
message?: string | null;
|
44
|
-
role?: ConversationRoleTypes | null;
|
45
|
-
toolCalls?: any[];
|
46
|
-
};
|
47
|
-
isFinal: boolean;
|
48
|
-
conversationId?: string;
|
49
|
-
} | {
|
50
|
-
type: "streamComplete";
|
51
|
-
conversationId?: string;
|
52
|
-
} | {
|
53
|
-
type: "error";
|
54
|
-
error: string;
|
55
|
-
};
|
56
|
-
/**
|
57
|
-
* Helper to create an SSE response with proper formatting
|
58
|
-
*/
|
59
|
-
export declare function formatSSEEvent(data: any, eventName?: string): string;
|
60
|
-
/**
|
61
|
-
* Helper to create a TransformStream for SSE with built-in ping support
|
62
|
-
*/
|
63
|
-
export declare function createSSEStream(options?: {
|
64
|
-
pingInterval?: number;
|
65
|
-
}): {
|
66
|
-
readable: ReadableStream<any>;
|
67
|
-
sendEvent: (data: any, eventName?: string) => Promise<void>;
|
68
|
-
close: () => Promise<void>;
|
69
|
-
writer: WritableStreamDefaultWriter<any>;
|
70
|
-
};
|
71
|
-
/**
|
72
|
-
* Helper to wrap tool handlers with result emission
|
73
|
-
*/
|
74
|
-
export interface ToolResultEmitter {
|
75
|
-
(toolCallId: string, result: any, status: "complete" | "error" | "blocked", duration: number): void;
|
76
|
-
}
|
77
|
-
export declare function wrapToolHandlers(handlers: Record<string, (args: any) => Promise<any>>, emitResult: ToolResultEmitter): Record<string, (args: any) => Promise<any>>;
|
78
|
-
/**
|
79
|
-
* Helper to enhance tool calls with server information
|
80
|
-
*/
|
81
|
-
export interface ServerMapping {
|
82
|
-
toolName: string;
|
83
|
-
serverName: string;
|
84
|
-
serverId: string;
|
85
|
-
}
|
86
|
-
export declare function enhanceToolCalls(toolCalls: any[], serverMappings: ServerMapping[]): any[];
|
87
|
-
/**
|
88
|
-
* Helper to track conversation metrics
|
89
|
-
*/
|
90
|
-
export declare class ConversationMetrics {
|
91
|
-
private startTime;
|
92
|
-
private tokenCount;
|
93
|
-
private toolCallCount;
|
94
|
-
private errorCount;
|
95
|
-
recordToken(): void;
|
96
|
-
recordToolCall(): void;
|
97
|
-
recordError(): void;
|
98
|
-
getMetrics(): {
|
99
|
-
duration: number;
|
100
|
-
tokenCount: number;
|
101
|
-
toolCallCount: number;
|
102
|
-
errorCount: number;
|
103
|
-
tokensPerSecond: number;
|
104
|
-
};
|
105
|
-
reset(): void;
|
106
|
-
}
|
package/dist/stream-helpers.js
DELETED
@@ -1,237 +0,0 @@
|
|
1
|
-
import { ConversationRoleTypes, } from "./generated/graphql-types.js";
|
2
|
-
export class StreamEventAggregator {
|
3
|
-
conversationId = "";
|
4
|
-
messageBuffer = "";
|
5
|
-
toolCallsBuffer = new Map();
|
6
|
-
isFirstAssistantMessage = true;
|
7
|
-
hasReceivedToolCalls = false;
|
8
|
-
tokenBuffer = [];
|
9
|
-
/**
|
10
|
-
* Process a stream event and return any complete messages ready for the UI
|
11
|
-
*/
|
12
|
-
processEvent(event) {
|
13
|
-
switch (event.type) {
|
14
|
-
case "start":
|
15
|
-
this.conversationId = event.conversationId;
|
16
|
-
return {
|
17
|
-
type: "conversationStarted",
|
18
|
-
conversationId: event.conversationId,
|
19
|
-
};
|
20
|
-
case "token":
|
21
|
-
this.messageBuffer += event.token;
|
22
|
-
this.tokenBuffer.push(event.token);
|
23
|
-
return {
|
24
|
-
type: "token",
|
25
|
-
token: event.token,
|
26
|
-
accumulated: this.messageBuffer,
|
27
|
-
};
|
28
|
-
case "message":
|
29
|
-
// SDK provides accumulated message - we can use this instead of our buffer
|
30
|
-
this.messageBuffer = event.message;
|
31
|
-
return null; // Don't emit, wait for complete event
|
32
|
-
case "tool_call_start":
|
33
|
-
this.hasReceivedToolCalls = true;
|
34
|
-
this.toolCallsBuffer.set(event.toolCall.id, {
|
35
|
-
id: event.toolCall.id,
|
36
|
-
name: event.toolCall.name,
|
37
|
-
argumentsBuffer: "",
|
38
|
-
isComplete: false,
|
39
|
-
startTime: Date.now(),
|
40
|
-
});
|
41
|
-
return null; // Buffer until complete
|
42
|
-
case "tool_call_delta":
|
43
|
-
const toolCall = this.toolCallsBuffer.get(event.toolCallId);
|
44
|
-
if (toolCall) {
|
45
|
-
toolCall.argumentsBuffer += event.argumentDelta;
|
46
|
-
}
|
47
|
-
return null; // Buffer until complete
|
48
|
-
case "tool_call_complete":
|
49
|
-
const completeToolCall = this.toolCallsBuffer.get(event.toolCall.id);
|
50
|
-
if (completeToolCall) {
|
51
|
-
completeToolCall.argumentsBuffer = event.toolCall.arguments;
|
52
|
-
completeToolCall.isComplete = true;
|
53
|
-
}
|
54
|
-
// Check if all tool calls are complete
|
55
|
-
const allComplete = Array.from(this.toolCallsBuffer.values()).every((tc) => tc.isComplete);
|
56
|
-
if (allComplete &&
|
57
|
-
this.hasReceivedToolCalls &&
|
58
|
-
this.isFirstAssistantMessage) {
|
59
|
-
// Emit complete assistant message with all tool calls
|
60
|
-
const toolCalls = Array.from(this.toolCallsBuffer.values()).map((tc) => ({
|
61
|
-
id: tc.id,
|
62
|
-
name: tc.name,
|
63
|
-
arguments: tc.argumentsBuffer,
|
64
|
-
status: "pending",
|
65
|
-
}));
|
66
|
-
this.isFirstAssistantMessage = false;
|
67
|
-
return {
|
68
|
-
type: "assistantMessage",
|
69
|
-
message: {
|
70
|
-
message: this.messageBuffer,
|
71
|
-
role: ConversationRoleTypes.Assistant,
|
72
|
-
toolCalls,
|
73
|
-
},
|
74
|
-
isFinal: false,
|
75
|
-
};
|
76
|
-
}
|
77
|
-
return null;
|
78
|
-
case "complete":
|
79
|
-
// If we haven't sent a message yet (no tool calls), send it now
|
80
|
-
if (this.isFirstAssistantMessage && !this.hasReceivedToolCalls) {
|
81
|
-
return {
|
82
|
-
type: "assistantMessage",
|
83
|
-
message: {
|
84
|
-
message: this.messageBuffer,
|
85
|
-
role: ConversationRoleTypes.Assistant,
|
86
|
-
},
|
87
|
-
isFinal: true,
|
88
|
-
conversationId: event.conversationId,
|
89
|
-
};
|
90
|
-
}
|
91
|
-
return { type: "streamComplete", conversationId: event.conversationId };
|
92
|
-
case "error":
|
93
|
-
return { type: "error", error: event.error };
|
94
|
-
default:
|
95
|
-
return null;
|
96
|
-
}
|
97
|
-
}
|
98
|
-
/**
|
99
|
-
* Reset the aggregator for a new conversation
|
100
|
-
*/
|
101
|
-
reset() {
|
102
|
-
this.conversationId = "";
|
103
|
-
this.messageBuffer = "";
|
104
|
-
this.toolCallsBuffer.clear();
|
105
|
-
this.isFirstAssistantMessage = true;
|
106
|
-
this.hasReceivedToolCalls = false;
|
107
|
-
this.tokenBuffer = [];
|
108
|
-
}
|
109
|
-
/**
|
110
|
-
* Get current state (useful for debugging)
|
111
|
-
*/
|
112
|
-
getState() {
|
113
|
-
return {
|
114
|
-
conversationId: this.conversationId,
|
115
|
-
messageBuffer: this.messageBuffer,
|
116
|
-
toolCallsCount: this.toolCallsBuffer.size,
|
117
|
-
hasReceivedToolCalls: this.hasReceivedToolCalls,
|
118
|
-
isFirstAssistantMessage: this.isFirstAssistantMessage,
|
119
|
-
tokenCount: this.tokenBuffer.length,
|
120
|
-
};
|
121
|
-
}
|
122
|
-
}
|
123
|
-
/**
|
124
|
-
* Helper to create an SSE response with proper formatting
|
125
|
-
*/
|
126
|
-
export function formatSSEEvent(data, eventName = "message") {
|
127
|
-
if (typeof data === "string") {
|
128
|
-
return `event: ${eventName}\ndata: ${data}\n\n`;
|
129
|
-
}
|
130
|
-
return `event: ${eventName}\ndata: ${JSON.stringify(data)}\n\n`;
|
131
|
-
}
|
132
|
-
/**
|
133
|
-
* Helper to create a TransformStream for SSE with built-in ping support
|
134
|
-
*/
|
135
|
-
export function createSSEStream(options) {
|
136
|
-
const encoder = new TextEncoder();
|
137
|
-
const { readable, writable } = new TransformStream();
|
138
|
-
const writer = writable.getWriter();
|
139
|
-
let pingInterval = null;
|
140
|
-
if (options?.pingInterval) {
|
141
|
-
pingInterval = globalThis.setInterval(() => {
|
142
|
-
writer.write(encoder.encode(":\n\n")).catch(() => {
|
143
|
-
// Ignore errors on ping
|
144
|
-
});
|
145
|
-
}, options.pingInterval);
|
146
|
-
}
|
147
|
-
const sendEvent = (data, eventName = "message") => {
|
148
|
-
const formatted = formatSSEEvent(data, eventName);
|
149
|
-
return writer.write(encoder.encode(formatted));
|
150
|
-
};
|
151
|
-
const close = async () => {
|
152
|
-
if (pingInterval) {
|
153
|
-
globalThis.clearInterval(pingInterval);
|
154
|
-
}
|
155
|
-
await writer.close();
|
156
|
-
};
|
157
|
-
return {
|
158
|
-
readable,
|
159
|
-
sendEvent,
|
160
|
-
close,
|
161
|
-
writer,
|
162
|
-
};
|
163
|
-
}
|
164
|
-
export function wrapToolHandlers(handlers, emitResult) {
|
165
|
-
const wrapped = {};
|
166
|
-
Object.entries(handlers).forEach(([name, handler]) => {
|
167
|
-
wrapped[name] = async (args) => {
|
168
|
-
const toolCallId = `tool_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
169
|
-
const startTime = Date.now();
|
170
|
-
try {
|
171
|
-
const result = await handler(args);
|
172
|
-
const duration = Date.now() - startTime;
|
173
|
-
// Emit success result
|
174
|
-
emitResult(toolCallId, { status: "success", result }, "complete", duration);
|
175
|
-
return result;
|
176
|
-
}
|
177
|
-
catch (error) {
|
178
|
-
const duration = Date.now() - startTime;
|
179
|
-
// Emit error result
|
180
|
-
emitResult(toolCallId, {
|
181
|
-
status: "error",
|
182
|
-
error: error instanceof Error ? error.message : String(error),
|
183
|
-
}, "error", duration);
|
184
|
-
throw error;
|
185
|
-
}
|
186
|
-
};
|
187
|
-
});
|
188
|
-
return wrapped;
|
189
|
-
}
|
190
|
-
export function enhanceToolCalls(toolCalls, serverMappings) {
|
191
|
-
const mappingDict = serverMappings.reduce((acc, mapping) => {
|
192
|
-
acc[mapping.toolName] = {
|
193
|
-
serverName: mapping.serverName,
|
194
|
-
serverId: mapping.serverId,
|
195
|
-
};
|
196
|
-
return acc;
|
197
|
-
}, {});
|
198
|
-
return toolCalls.map((toolCall) => ({
|
199
|
-
...toolCall,
|
200
|
-
serverName: mappingDict[toolCall.name]?.serverName,
|
201
|
-
serverId: mappingDict[toolCall.name]?.serverId,
|
202
|
-
}));
|
203
|
-
}
|
204
|
-
/**
|
205
|
-
* Helper to track conversation metrics
|
206
|
-
*/
|
207
|
-
export class ConversationMetrics {
|
208
|
-
startTime = Date.now();
|
209
|
-
tokenCount = 0;
|
210
|
-
toolCallCount = 0;
|
211
|
-
errorCount = 0;
|
212
|
-
recordToken() {
|
213
|
-
this.tokenCount++;
|
214
|
-
}
|
215
|
-
recordToolCall() {
|
216
|
-
this.toolCallCount++;
|
217
|
-
}
|
218
|
-
recordError() {
|
219
|
-
this.errorCount++;
|
220
|
-
}
|
221
|
-
getMetrics() {
|
222
|
-
const duration = Date.now() - this.startTime;
|
223
|
-
return {
|
224
|
-
duration,
|
225
|
-
tokenCount: this.tokenCount,
|
226
|
-
toolCallCount: this.toolCallCount,
|
227
|
-
errorCount: this.errorCount,
|
228
|
-
tokensPerSecond: this.tokenCount / (duration / 1000),
|
229
|
-
};
|
230
|
-
}
|
231
|
-
reset() {
|
232
|
-
this.startTime = Date.now();
|
233
|
-
this.tokenCount = 0;
|
234
|
-
this.toolCallCount = 0;
|
235
|
-
this.errorCount = 0;
|
236
|
-
}
|
237
|
-
}
|