@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.
@@ -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() {
@@ -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: getValidToolName(tool.id),
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 getValidToolName = (toolId) => {
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@looopy-ai/core",
3
- "version": "2.1.18",
3
+ "version": "2.1.20",
4
4
  "description": "RxJS-based AI agent framework",
5
5
  "repository": {
6
6
  "url": "https://github.com/looopy-ai/lib"