@objectstack/service-ai 4.0.1 → 4.0.2

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.
Files changed (39) hide show
  1. package/.turbo/turbo-build.log +11 -11
  2. package/CHANGELOG.md +9 -0
  3. package/dist/index.cjs +1120 -66
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +316 -78
  6. package/dist/index.d.ts +316 -78
  7. package/dist/index.js +1105 -63
  8. package/dist/index.js.map +1 -1
  9. package/package.json +26 -4
  10. package/src/__tests__/ai-service.test.ts +248 -27
  11. package/src/__tests__/auth-and-toolcalling.test.ts +30 -28
  12. package/src/__tests__/chatbot-features.test.ts +229 -82
  13. package/src/__tests__/metadata-tools.test.ts +964 -0
  14. package/src/__tests__/objectql-conversation-service.test.ts +34 -16
  15. package/src/__tests__/vercel-stream-encoder.test.ts +263 -0
  16. package/src/adapters/index.ts +2 -0
  17. package/src/adapters/memory-adapter.ts +17 -9
  18. package/src/adapters/vercel-adapter.ts +148 -0
  19. package/src/agent-runtime.ts +27 -3
  20. package/src/agents/index.ts +1 -0
  21. package/src/agents/metadata-assistant-agent.ts +87 -0
  22. package/src/ai-service.ts +68 -36
  23. package/src/conversation/in-memory-conversation-service.ts +2 -2
  24. package/src/conversation/objectql-conversation-service.ts +67 -18
  25. package/src/index.ts +21 -2
  26. package/src/plugin.ts +166 -9
  27. package/src/routes/agent-routes.ts +26 -3
  28. package/src/routes/ai-routes.ts +156 -13
  29. package/src/stream/index.ts +3 -0
  30. package/src/stream/vercel-stream-encoder.ts +129 -0
  31. package/src/tools/add-field.tool.ts +70 -0
  32. package/src/tools/create-object.tool.ts +66 -0
  33. package/src/tools/delete-field.tool.ts +38 -0
  34. package/src/tools/describe-metadata-object.tool.ts +32 -0
  35. package/src/tools/index.ts +12 -1
  36. package/src/tools/list-metadata-objects.tool.ts +34 -0
  37. package/src/tools/metadata-tools.ts +430 -0
  38. package/src/tools/modify-field.tool.ts +44 -0
  39. package/src/tools/tool-registry.ts +32 -9
@@ -0,0 +1,44 @@
1
+ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
+
3
+ import { defineTool } from '@objectstack/spec/ai';
4
+
5
+ /**
6
+ * modify_field — AI Tool Metadata
7
+ *
8
+ * Modifies an existing field definition (label, type, required, default value, etc.)
9
+ * on a data object. Does not support renaming the field.
10
+ */
11
+ export const modifyFieldTool = defineTool({
12
+ name: 'modify_field',
13
+ label: 'Modify Field',
14
+ description:
15
+ 'Modifies an existing field definition (label, type, required, default value, etc.) on a data object. ' +
16
+ 'Use this when the user wants to change or reconfigure an existing column or attribute (not rename it).',
17
+ category: 'data',
18
+ builtIn: true,
19
+ parameters: {
20
+ type: 'object',
21
+ properties: {
22
+ objectName: {
23
+ type: 'string',
24
+ description: 'Target object machine name (snake_case)',
25
+ },
26
+ fieldName: {
27
+ type: 'string',
28
+ description: 'Existing field machine name to modify (snake_case)',
29
+ },
30
+ changes: {
31
+ type: 'object',
32
+ description: 'Field properties to update (partial patch)',
33
+ properties: {
34
+ label: { type: 'string', description: 'New display label' },
35
+ type: { type: 'string', description: 'New field type' },
36
+ required: { type: 'boolean', description: 'Update required constraint' },
37
+ defaultValue: { description: 'New default value' },
38
+ },
39
+ },
40
+ },
41
+ required: ['objectName', 'fieldName', 'changes'],
42
+ additionalProperties: false,
43
+ },
44
+ });
@@ -1,6 +1,6 @@
1
1
  // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
2
 
3
- import type { AIToolDefinition, AIToolCall, AIToolResult } from '@objectstack/spec/contracts';
3
+ import type { AIToolDefinition, ToolCallPart, ToolResultPart } from '@objectstack/spec/contracts';
4
4
 
5
5
  /**
6
6
  * Handler function for a registered tool.
@@ -9,6 +9,14 @@ import type { AIToolDefinition, AIToolCall, AIToolResult } from '@objectstack/sp
9
9
  */
10
10
  export type ToolHandler = (args: Record<string, unknown>) => Promise<string> | string;
11
11
 
12
+ /**
13
+ * Extended ToolResultPart that carries an `isError` flag for internal
14
+ * error-tracking in the tool-call loop.
15
+ */
16
+ export interface ToolExecutionResult extends ToolResultPart {
17
+ isError?: boolean;
18
+ }
19
+
12
20
  /**
13
21
  * ToolRegistry — Central registry for AI-callable tools.
14
22
  *
@@ -72,30 +80,45 @@ export class ToolRegistry {
72
80
  /**
73
81
  * Execute a tool call and return the result.
74
82
  */
75
- async execute(toolCall: AIToolCall): Promise<AIToolResult> {
76
- const handler = this.handlers.get(toolCall.name);
83
+ async execute(toolCall: ToolCallPart): Promise<ToolExecutionResult> {
84
+ const handler = this.handlers.get(toolCall.toolName);
77
85
  if (!handler) {
78
86
  return {
79
- toolCallId: toolCall.id,
80
- content: `Tool "${toolCall.name}" is not registered`,
87
+ type: 'tool-result',
88
+ toolCallId: toolCall.toolCallId,
89
+ toolName: toolCall.toolName,
90
+ output: { type: 'text', value: `Tool "${toolCall.toolName}" is not registered` },
81
91
  isError: true,
82
92
  };
83
93
  }
84
94
 
85
95
  try {
86
- const args: Record<string, unknown> = JSON.parse(toolCall.arguments);
96
+ const args = typeof toolCall.input === 'string'
97
+ ? JSON.parse(toolCall.input)
98
+ : (toolCall.input as Record<string, unknown>) ?? {};
87
99
  const content = await handler(args);
88
- return { toolCallId: toolCall.id, content };
100
+ return {
101
+ type: 'tool-result',
102
+ toolCallId: toolCall.toolCallId,
103
+ toolName: toolCall.toolName,
104
+ output: { type: 'text', value: content },
105
+ };
89
106
  } catch (err) {
90
107
  const message = err instanceof Error ? err.message : String(err);
91
- return { toolCallId: toolCall.id, content: message, isError: true };
108
+ return {
109
+ type: 'tool-result',
110
+ toolCallId: toolCall.toolCallId,
111
+ toolName: toolCall.toolName,
112
+ output: { type: 'text', value: message },
113
+ isError: true,
114
+ };
92
115
  }
93
116
  }
94
117
 
95
118
  /**
96
119
  * Execute multiple tool calls in parallel.
97
120
  */
98
- async executeAll(toolCalls: AIToolCall[]): Promise<AIToolResult[]> {
121
+ async executeAll(toolCalls: ToolCallPart[]): Promise<ToolExecutionResult[]> {
99
122
  return Promise.all(toolCalls.map(tc => this.execute(tc)));
100
123
  }
101
124