@looopy-ai/core 2.1.19 → 2.1.21

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.
@@ -1,5 +1,5 @@
1
1
  import { type Observable } from 'rxjs';
2
- import type { IterationConfig, IterationContext } from '../types/core';
2
+ import { type IterationConfig, type IterationContext } from '../types/core';
3
3
  import type { ContextAnyEvent } from '../types/event';
4
4
  import type { LLMMessage } from '../types/message';
5
5
  export declare const runIteration: <AuthContext>(context: IterationContext<AuthContext>, config: IterationConfig<AuthContext>, history: LLMMessage[]) => Observable<ContextAnyEvent>;
@@ -1,7 +1,6 @@
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';
3
+ import { isToolPlugin, } from '../types/core';
5
4
  import { getSystemPrompts } from '../utils/prompt';
6
5
  import { runToolCall } from './tools';
7
6
  export const runIteration = (context, config, history) => {
@@ -37,35 +36,7 @@ export const runIteration = (context, config, history) => {
37
36
  stream: true,
38
37
  sessionId: context.taskId,
39
38
  })
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) => ({
39
+ .pipe(finishLLMCallSpan, map((event) => ({
69
40
  contextId: context.contextId,
70
41
  taskId: context.taskId,
71
42
  path: undefined,
@@ -89,8 +60,8 @@ const prepareMessages = async (systemPrompts, history) => {
89
60
  content: sp.content,
90
61
  })));
91
62
  };
92
- const prepareTools = async (toolProviders) => {
93
- const toolPromises = toolProviders.map((p) => p.listTools?.());
63
+ const prepareTools = async (plugins) => {
64
+ const toolPromises = plugins.filter(isToolPlugin).map((p) => p.listTools());
94
65
  const toolArrays = await Promise.all(toolPromises);
95
66
  return toolArrays.filter(Boolean).flat();
96
67
  };
@@ -88,7 +88,7 @@ export class LiteLLMProvider {
88
88
  id: tc.id,
89
89
  type: 'function',
90
90
  function: {
91
- name: tc.function?.name,
91
+ name: fixToolFunctionName(tc.function?.name),
92
92
  arguments: (typeof tc.function?.arguments === 'string'
93
93
  ? JSON.parse(tc.function?.arguments)
94
94
  : tc.function?.arguments) || {},
@@ -111,7 +111,7 @@ export class LiteLLMProvider {
111
111
  const toolCalls$ = contentComplete$.pipe(filter((event) => event.finishReason === 'tool_calls'), mergeMap((event) => event.toolCalls?.map((tc) => ({
112
112
  kind: 'tool-call',
113
113
  toolCallId: tc.id,
114
- toolName: tc.function.name,
114
+ toolName: fixToolFunctionName(tc.function.name),
115
115
  arguments: tc.function.arguments,
116
116
  timestamp: event.timestamp,
117
117
  })) || []));
@@ -191,7 +191,7 @@ export class LiteLLMProvider {
191
191
  id: tc.id,
192
192
  type: tc.type,
193
193
  function: {
194
- name: tc.function.name,
194
+ name: fixToolFunctionName(tc.function.name),
195
195
  arguments: typeof tc.function.arguments === 'string'
196
196
  ? tc.function.arguments
197
197
  : JSON.stringify(tc.function.arguments),
@@ -216,7 +216,7 @@ export class LiteLLMProvider {
216
216
  litellmRequest.tools = request.tools.map((tool) => ({
217
217
  type: 'function',
218
218
  function: {
219
- name: getValidToolName(tool.id),
219
+ name: fixToolFunctionName(tool.id),
220
220
  description: tool.description,
221
221
  parameters: tool.parameters,
222
222
  },
@@ -378,7 +378,7 @@ export const LiteLLM = {
378
378
  });
379
379
  },
380
380
  };
381
- const getValidToolName = (toolId) => {
381
+ const fixToolFunctionName = (toolId) => {
382
382
  const match = toolId.match(/^[a-zA-Z0-9_-]+/);
383
383
  return match ? match[0] : 'invalid_tool_name';
384
384
  };
@@ -1,6 +1,6 @@
1
1
  import { Observable } from 'rxjs';
2
2
  import z from 'zod';
3
- import type { AnyEvent, ExecutionContext, Plugin } from '../types';
3
+ import type { AnyEvent, ExecutionContext, ToolPlugin } from '../types';
4
4
  import type { ToolCall, ToolDefinition } from '../types/tools';
5
5
  export type HeaderFactory<AuthContext> = (context: ExecutionContext<AuthContext>, card: AgentCard) => Promise<Record<string, string | undefined>>;
6
6
  export declare const cardSchema: z.ZodObject<{
@@ -18,7 +18,7 @@ export declare const cardSchema: z.ZodObject<{
18
18
  }, z.core.$loose>>;
19
19
  }, z.core.$strip>;
20
20
  export type AgentCard = z.infer<typeof cardSchema>;
21
- export declare class AgentToolProvider<AuthContext> implements Plugin<AuthContext> {
21
+ export declare class AgentToolProvider<AuthContext> implements ToolPlugin<AuthContext> {
22
22
  readonly card: AgentCard;
23
23
  readonly getHeaders?: HeaderFactory<AuthContext> | undefined;
24
24
  static fromUrl: <AuthContext_1>(cardUrl: string, getHeaders?: HeaderFactory<AuthContext_1>) => Promise<AgentToolProvider<AuthContext_1>>;
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import type { ExecutionContext } from '../types/context';
3
- import type { Plugin } from '../types/core';
3
+ import type { ToolPlugin } from '../types/core';
4
4
  import type { ToolResult } from '../types/tools';
5
5
  type InternalToolResult = Omit<ToolResult, 'toolCallId' | 'toolName'>;
6
6
  export type ToolHandler<TParams, AuthContext> = (params: TParams, context: ExecutionContext<AuthContext>) => Promise<InternalToolResult> | InternalToolResult;
@@ -12,5 +12,5 @@ export interface LocalToolDefinition<TSchema extends z.ZodObject, AuthContext> {
12
12
  handler: ToolHandler<z.infer<TSchema>, AuthContext>;
13
13
  }
14
14
  export declare function tool<TSchema extends z.ZodObject, AuthContext>(definition: LocalToolDefinition<TSchema, AuthContext>): LocalToolDefinition<TSchema, AuthContext>;
15
- export declare function localTools<AuthContext>(tools: LocalToolDefinition<z.ZodObject, AuthContext>[]): Plugin<AuthContext>;
15
+ export declare function localTools<AuthContext>(tools: LocalToolDefinition<z.ZodObject, AuthContext>[]): ToolPlugin<AuthContext>;
16
16
  export {};
@@ -1,4 +1,4 @@
1
- import type { Plugin } from '..';
1
+ import type { ToolPlugin } from '..';
2
2
  import type { ExecutionContext } from '../types/context';
3
3
  import type { ToolCall, ToolDefinition } from '../types/tools';
4
4
  export interface MCPProviderConfig<AuthContext> {
@@ -8,7 +8,7 @@ export interface MCPProviderConfig<AuthContext> {
8
8
  getHeaders: (authContext?: AuthContext) => Record<string, string>;
9
9
  }
10
10
  export declare const mcp: <AuthContext>(config: MCPProviderConfig<AuthContext>) => McpToolProvider<AuthContext>;
11
- export declare class McpToolProvider<AuthContext> implements Plugin<AuthContext> {
11
+ export declare class McpToolProvider<AuthContext> implements ToolPlugin<AuthContext> {
12
12
  name: string;
13
13
  readonly id: string;
14
14
  private readonly client;
@@ -27,16 +27,16 @@ export type IterationConfig<AuthContext> = {
27
27
  llmProvider: LLMProvider | ((context: LoopContext<AuthContext>, systemPromptMetadata: Record<string, unknown> | undefined) => LLMProvider);
28
28
  iterationNumber: number;
29
29
  };
30
- export type Plugin<AuthContext> = BasePlugin & Partial<SystemPromptPlugin<AuthContext>> & Partial<ToolPlugin<AuthContext>>;
30
+ export type Plugin<AuthContext> = SystemPromptPlugin<AuthContext> | ToolPlugin<AuthContext>;
31
31
  type BasePlugin = {
32
32
  readonly name: string;
33
33
  readonly version?: string;
34
34
  };
35
- export type SystemPromptPlugin<AuthContext> = {
35
+ export type SystemPromptPlugin<AuthContext> = BasePlugin & {
36
36
  generateSystemPrompts: (context: IterationContext<AuthContext>) => SystemPrompt[] | Promise<SystemPrompt[]>;
37
37
  };
38
38
  export declare const isSystemPromptPlugin: <AuthContext>(plugin: Plugin<AuthContext>) => plugin is BasePlugin & SystemPromptPlugin<AuthContext>;
39
- export type ToolPlugin<AuthContext> = {
39
+ export type ToolPlugin<AuthContext> = BasePlugin & {
40
40
  listTools: () => Promise<ToolDefinition[]>;
41
41
  getTool: (toolId: string) => Promise<ToolDefinition | undefined>;
42
42
  executeTool: (toolCall: ToolCall, context: IterationContext<AuthContext>) => Observable<ContextAnyEvent | AnyEvent>;
@@ -1,4 +1,4 @@
1
- import type { IterationContext, Plugin, SystemPrompt } from '../types/core';
1
+ import { type IterationContext, type Plugin, type SystemPrompt } from '../types/core';
2
2
  export type SystemPrompts = {
3
3
  before: readonly SystemPrompt[];
4
4
  after: readonly SystemPrompt[];
@@ -1,8 +1,9 @@
1
+ import { isSystemPromptPlugin, } from '../types/core';
1
2
  export const getSystemPrompts = async (plugins, loopContext) => {
2
3
  if (!plugins?.length) {
3
4
  return { before: [], after: [] };
4
5
  }
5
- const prompts = await Promise.all(plugins.map((p) => p.generateSystemPrompts?.(loopContext)));
6
+ const prompts = await Promise.all(plugins.filter(isSystemPromptPlugin).map((p) => p.generateSystemPrompts?.(loopContext)));
6
7
  const flattened = prompts.flat().filter((p) => p !== undefined);
7
8
  const before = Object.freeze(flattened
8
9
  .filter((p) => p.position === 'before')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@looopy-ai/core",
3
- "version": "2.1.19",
3
+ "version": "2.1.21",
4
4
  "description": "RxJS-based AI agent framework",
5
5
  "repository": {
6
6
  "url": "https://github.com/looopy-ai/lib"