@looopy-ai/core 2.1.18 → 2.1.20
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/core/agent.js
CHANGED
|
@@ -227,7 +227,7 @@ export class Agent {
|
|
|
227
227
|
observer.next(event);
|
|
228
228
|
},
|
|
229
229
|
error: (error) => {
|
|
230
|
-
logger.error({ error }, 'Turn execution failed');
|
|
230
|
+
logger.error({ error: serializeError(error) }, 'Turn execution failed');
|
|
231
231
|
failAgentTurnSpan(turnSpan, error);
|
|
232
232
|
observer.error(error);
|
|
233
233
|
},
|
|
@@ -247,7 +247,7 @@ export class Agent {
|
|
|
247
247
|
observer.complete();
|
|
248
248
|
}
|
|
249
249
|
catch (error) {
|
|
250
|
-
logger.error({ error }, 'Failed to save turn results');
|
|
250
|
+
logger.error({ error: serializeError(error) }, 'Failed to save turn results');
|
|
251
251
|
failAgentTurnSpan(turnSpan, error);
|
|
252
252
|
observer.error(error);
|
|
253
253
|
}
|
|
@@ -255,7 +255,7 @@ export class Agent {
|
|
|
255
255
|
});
|
|
256
256
|
}
|
|
257
257
|
catch (error) {
|
|
258
|
-
logger.error({ error }, 'Failed to prepare turn');
|
|
258
|
+
logger.error({ error: serializeError(error) }, 'Failed to prepare turn');
|
|
259
259
|
failAgentTurnSpan(turnSpan, error);
|
|
260
260
|
observer.error(error);
|
|
261
261
|
}
|
|
@@ -294,7 +294,7 @@ export class Agent {
|
|
|
294
294
|
this.config.logger.info('Agent shutdown complete');
|
|
295
295
|
}
|
|
296
296
|
catch (error) {
|
|
297
|
-
this.config.logger.error({ error }, 'Failed to shutdown agent');
|
|
297
|
+
this.config.logger.error({ error: serializeError(error) }, 'Failed to shutdown agent');
|
|
298
298
|
throw error;
|
|
299
299
|
}
|
|
300
300
|
finally {
|
|
@@ -317,7 +317,7 @@ export class Agent {
|
|
|
317
317
|
this.logger.info('Agent data cleared');
|
|
318
318
|
}
|
|
319
319
|
catch (error) {
|
|
320
|
-
this.logger.error({ error }, 'Failed to clear agent');
|
|
320
|
+
this.logger.error({ error: serializeError(error) }, 'Failed to clear agent');
|
|
321
321
|
throw error;
|
|
322
322
|
}
|
|
323
323
|
}
|
|
@@ -337,7 +337,7 @@ export class Agent {
|
|
|
337
337
|
return;
|
|
338
338
|
}
|
|
339
339
|
void this.persistState().catch((error) => {
|
|
340
|
-
this.logger.error({ error }, 'Failed to persist agent state');
|
|
340
|
+
this.logger.error({ error: serializeError(error) }, 'Failed to persist agent state');
|
|
341
341
|
});
|
|
342
342
|
}
|
|
343
343
|
async loadPersistedState() {
|
package/dist/core/iteration.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { concat, defer, filter, map, mergeMap, shareReplay } from 'rxjs';
|
|
2
2
|
import { startLLMCallSpan, startLoopIterationSpan } from '../observability/spans';
|
|
3
|
-
import { toolErrorEvent } from '../tools/tool-result-events';
|
|
4
|
-
import { safeValidateToolCall } from '../types/tools';
|
|
5
3
|
import { getSystemPrompts } from '../utils/prompt';
|
|
6
4
|
import { runToolCall } from './tools';
|
|
7
5
|
export const runIteration = (context, config, history) => {
|
|
@@ -37,35 +35,7 @@ export const runIteration = (context, config, history) => {
|
|
|
37
35
|
stream: true,
|
|
38
36
|
sessionId: context.taskId,
|
|
39
37
|
})
|
|
40
|
-
.pipe(finishLLMCallSpan, map((event) => {
|
|
41
|
-
if (event.kind === 'tool-call') {
|
|
42
|
-
const validation = safeValidateToolCall({
|
|
43
|
-
id: event.toolCallId,
|
|
44
|
-
type: 'function',
|
|
45
|
-
function: {
|
|
46
|
-
name: event.toolName,
|
|
47
|
-
arguments: event.arguments,
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
if (!validation.success) {
|
|
51
|
-
const errorMessage = `Invalid tool call format: ${(validation.errors || []).map((e) => `${e.path.join('.')}: ${e.message}`).join(', ')}`;
|
|
52
|
-
context.logger.error({
|
|
53
|
-
toolCallId: event.toolCallId,
|
|
54
|
-
toolName: event.toolName,
|
|
55
|
-
errors: validation.errors,
|
|
56
|
-
}, 'Invalid tool call from LLM - tool name must match ^[a-zA-Z0-9_-]+$');
|
|
57
|
-
return toolErrorEvent({
|
|
58
|
-
id: event.toolCallId,
|
|
59
|
-
type: 'function',
|
|
60
|
-
function: {
|
|
61
|
-
name: event.toolName,
|
|
62
|
-
arguments: event.arguments,
|
|
63
|
-
},
|
|
64
|
-
}, errorMessage);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return event;
|
|
68
|
-
}), map((event) => ({
|
|
38
|
+
.pipe(finishLLMCallSpan, map((event) => ({
|
|
69
39
|
contextId: context.contextId,
|
|
70
40
|
taskId: context.taskId,
|
|
71
41
|
path: undefined,
|
|
@@ -28,13 +28,19 @@ export const startLLMCallSpan = (context, systemPrompts, messages, tools) => {
|
|
|
28
28
|
if (isChildTaskEvent(event))
|
|
29
29
|
return;
|
|
30
30
|
switch (event.kind) {
|
|
31
|
-
case 'content-complete':
|
|
31
|
+
case 'content-complete': {
|
|
32
32
|
if (event.content) {
|
|
33
33
|
span.setAttribute(SpanAttributes.GEN_AI_COMPLETION, event.content);
|
|
34
34
|
}
|
|
35
35
|
span.setAttribute(SpanAttributes.LLM_FINISH_REASON, event.finishReason || 'unknown');
|
|
36
|
+
const toolCalls = event.toolCalls?.map((t) => t.function);
|
|
37
|
+
if (toolCalls?.length) {
|
|
38
|
+
context.logger.debug({ toolCalls }, 'Tools calls');
|
|
39
|
+
span.setAttribute('llm.tool_calls', JSON.stringify(toolCalls.map((t) => t.name)));
|
|
40
|
+
}
|
|
36
41
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
37
42
|
break;
|
|
43
|
+
}
|
|
38
44
|
case 'llm-usage':
|
|
39
45
|
span.setAttribute(SpanAttributes.GEN_AI_RESPONSE_MODEL, event.model);
|
|
40
46
|
span.setAttribute(SpanAttributes.GEN_AI_USAGE_PROMPT_TOKENS, event.prompt_tokens || 0);
|
|
@@ -4,6 +4,7 @@ import { merge, Observable } from 'rxjs';
|
|
|
4
4
|
import { concatWith, filter, map, mergeMap, shareReplay, tap } from 'rxjs/operators';
|
|
5
5
|
import { getLogger } from '../core/logger';
|
|
6
6
|
import { generateEventId } from '../events/utils';
|
|
7
|
+
import { serializeError } from '../utils';
|
|
7
8
|
import { aggregateChoice, aggregateLLMUsage, choices, getContent, splitInlineXml, usage, } from './chat-completions';
|
|
8
9
|
const singleString = (input) => {
|
|
9
10
|
if (!input)
|
|
@@ -87,7 +88,7 @@ export class LiteLLMProvider {
|
|
|
87
88
|
id: tc.id,
|
|
88
89
|
type: 'function',
|
|
89
90
|
function: {
|
|
90
|
-
name: tc.function?.name,
|
|
91
|
+
name: fixToolFunctionName(tc.function?.name),
|
|
91
92
|
arguments: (typeof tc.function?.arguments === 'string'
|
|
92
93
|
? JSON.parse(tc.function?.arguments)
|
|
93
94
|
: tc.function?.arguments) || {},
|
|
@@ -110,7 +111,7 @@ export class LiteLLMProvider {
|
|
|
110
111
|
const toolCalls$ = contentComplete$.pipe(filter((event) => event.finishReason === 'tool_calls'), mergeMap((event) => event.toolCalls?.map((tc) => ({
|
|
111
112
|
kind: 'tool-call',
|
|
112
113
|
toolCallId: tc.id,
|
|
113
|
-
toolName: tc.function.name,
|
|
114
|
+
toolName: fixToolFunctionName(tc.function.name),
|
|
114
115
|
arguments: tc.function.arguments,
|
|
115
116
|
timestamp: event.timestamp,
|
|
116
117
|
})) || []));
|
|
@@ -127,7 +128,7 @@ export class LiteLLMProvider {
|
|
|
127
128
|
this.debugLogInitialized = true;
|
|
128
129
|
}
|
|
129
130
|
catch (error) {
|
|
130
|
-
this.logger.warn({ error }, 'Failed to initialize debug log file');
|
|
131
|
+
this.logger.warn({ error: serializeError(error) }, 'Failed to initialize debug log file');
|
|
131
132
|
return;
|
|
132
133
|
}
|
|
133
134
|
}
|
|
@@ -140,7 +141,7 @@ export class LiteLLMProvider {
|
|
|
140
141
|
appendFileSync(this.config.debugLogPath, `${logEntry}\n`);
|
|
141
142
|
}
|
|
142
143
|
catch (error) {
|
|
143
|
-
this.logger.warn({ error }, 'Failed to write debug log');
|
|
144
|
+
this.logger.warn({ error: serializeError(error) }, 'Failed to write debug log');
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
debugLog(eventType) {
|
|
@@ -190,7 +191,7 @@ export class LiteLLMProvider {
|
|
|
190
191
|
id: tc.id,
|
|
191
192
|
type: tc.type,
|
|
192
193
|
function: {
|
|
193
|
-
name: tc.function.name,
|
|
194
|
+
name: fixToolFunctionName(tc.function.name),
|
|
194
195
|
arguments: typeof tc.function.arguments === 'string'
|
|
195
196
|
? tc.function.arguments
|
|
196
197
|
: JSON.stringify(tc.function.arguments),
|
|
@@ -215,7 +216,7 @@ export class LiteLLMProvider {
|
|
|
215
216
|
litellmRequest.tools = request.tools.map((tool) => ({
|
|
216
217
|
type: 'function',
|
|
217
218
|
function: {
|
|
218
|
-
name:
|
|
219
|
+
name: fixToolFunctionName(tool.id),
|
|
219
220
|
description: tool.description,
|
|
220
221
|
parameters: tool.parameters,
|
|
221
222
|
},
|
|
@@ -377,7 +378,7 @@ export const LiteLLM = {
|
|
|
377
378
|
});
|
|
378
379
|
},
|
|
379
380
|
};
|
|
380
|
-
const
|
|
381
|
+
const fixToolFunctionName = (toolId) => {
|
|
381
382
|
const match = toolId.match(/^[a-zA-Z0-9_-]+/);
|
|
382
383
|
return match ? match[0] : 'invalid_tool_name';
|
|
383
384
|
};
|