@adminforth/agent 1.23.0 → 1.24.1

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/apiBasedTools.ts CHANGED
@@ -65,10 +65,11 @@ type ToolHttpResponse = IAdminForthHttpResponse & {
65
65
  type ToolOverrideCallParams = Pick<ApiBasedToolCallParams, 'httpExtra' | 'inputs' | 'userTimeZone'>;
66
66
 
67
67
  type ToolOverrideContext = {
68
- output: unknown;
68
+ output?: unknown;
69
69
  adminUser?: AdminUser;
70
70
  httpExtra?: Partial<HttpExtra>;
71
71
  inputs?: Record<string, unknown>;
72
+ resourceLabel?: string;
72
73
  userTimeZone?: string;
73
74
  invokeTool: (toolName: string, params?: ToolOverrideCallParams) => Promise<unknown>;
74
75
  };
@@ -98,6 +99,42 @@ type DateTimeColumnType = AdminForthDataTypes.DATETIME | AdminForthDataTypes.TIM
98
99
 
99
100
  const DEFAULT_USER_TIME_ZONE = 'UTC';
100
101
 
102
+ function getInputString(inputs: Record<string, unknown> | undefined, key: string) {
103
+ const value = inputs?.[key];
104
+
105
+ return typeof value === 'string' && value ? value : undefined;
106
+ }
107
+
108
+ function getInputArrayLength(inputs: Record<string, unknown> | undefined, key: string) {
109
+ const value = inputs?.[key];
110
+
111
+ return Array.isArray(value) ? value.length : undefined;
112
+ }
113
+
114
+ function resourceLabel(adminforth: IAdminForth, inputs: Record<string, unknown> | undefined) {
115
+ const resourceId = getInputString(inputs, 'resourceId');
116
+ const resource = adminforth.config.resources.find((res) => res.resourceId === resourceId);
117
+
118
+ return resource?.label ?? resourceId ?? 'resource';
119
+ }
120
+
121
+ function getDataPrefix(inputs: Record<string, unknown> | undefined) {
122
+ const offset = typeof inputs?.offset === 'number' ? inputs.offset : undefined;
123
+ const limit = typeof inputs?.limit === 'number' ? inputs.limit : undefined;
124
+
125
+ if (offset !== undefined && limit !== undefined) {
126
+ return `${offset}-${offset + limit} `;
127
+ }
128
+
129
+ return limit === undefined ? '' : `${limit} `;
130
+ }
131
+
132
+ function actionText(inputs: Record<string, unknown> | undefined) {
133
+ const actionId = getInputString(inputs, 'actionId');
134
+
135
+ return actionId ? ` action ${actionId}` : ' action';
136
+ }
137
+
101
138
  const TOOL_OVERRIDES: Record<string, ToolOverride> = {
102
139
  get_resource: {
103
140
  wipe_frontend_specific_data: [
@@ -106,11 +143,12 @@ const TOOL_OVERRIDES: Record<string, ToolOverride> = {
106
143
  'resource.options.actions[].customComponent',
107
144
  'resource.options.pageInjections',
108
145
  ],
109
- format_tool: async ({ }) => {
110
- return "get resource Apartments"
111
- }
146
+ format_tool: ({ resourceLabel }) => `Get ${resourceLabel} resource`,
112
147
  },
113
148
  get_resource_data: {
149
+ format_tool: ({ inputs, resourceLabel }) => (
150
+ `Get ${getDataPrefix(inputs)}${resourceLabel}`
151
+ ),
114
152
  post_process_response: async ({ output, inputs, invokeTool, userTimeZone }) => {
115
153
  if (hasToolError(output)) {
116
154
  return output;
@@ -132,9 +170,37 @@ const TOOL_OVERRIDES: Record<string, ToolOverride> = {
132
170
 
133
171
  return response;
134
172
  },
135
- format_tool: async ({ }) => {
136
- return "get 1-20 Apartment filtered listed=yes"
137
- }
173
+ },
174
+ aggregate: {
175
+ format_tool: ({ resourceLabel }) => `Aggregate ${resourceLabel}`,
176
+ },
177
+ start_custom_action: {
178
+ format_tool: ({ inputs, resourceLabel }) => `Run ${resourceLabel}${actionText(inputs)}`,
179
+ },
180
+ start_custom_bulk_action: {
181
+ format_tool: ({ inputs, resourceLabel }) => {
182
+ const recordCount = getInputArrayLength(inputs, 'recordIds');
183
+ const recordsText = recordCount === undefined ? '' : ` for ${recordCount} records`;
184
+
185
+ return `Run ${resourceLabel}${actionText(inputs)}${recordsText}`;
186
+ },
187
+ },
188
+ start_bulk_action: {
189
+ format_tool: ({ inputs, resourceLabel }) => {
190
+ const recordCount = getInputArrayLength(inputs, 'recordIds');
191
+ const recordsText = recordCount === undefined ? '' : ` for ${recordCount} records`;
192
+
193
+ return `Run ${resourceLabel}${actionText(inputs)}${recordsText}`;
194
+ },
195
+ },
196
+ create_record: {
197
+ format_tool: ({ resourceLabel }) => `Create ${resourceLabel}`,
198
+ },
199
+ update_record: {
200
+ format_tool: ({ resourceLabel }) => `Update ${resourceLabel}`,
201
+ },
202
+ delete_record: {
203
+ format_tool: ({ resourceLabel }) => `Delete ${resourceLabel}`,
138
204
  },
139
205
  };
140
206
 
@@ -401,7 +467,31 @@ function endpointPathToToolName(path: string) {
401
467
  .replace(/^_+|_+$/g, '');
402
468
  }
403
469
 
404
- function normalizeCookies(cookies?: Partial<HttpExtra>['cookies']): CookieItem[] {
470
+ export async function formatApiBasedToolCall(params: {
471
+ adminforth: IAdminForth;
472
+ adminUser?: AdminUser;
473
+ httpExtra?: Partial<HttpExtra>;
474
+ inputs?: Record<string, unknown>;
475
+ toolName: string;
476
+ userTimeZone?: string;
477
+ }) {
478
+ const formatTool = TOOL_OVERRIDES[params.toolName]?.format_tool;
479
+
480
+ return await formatTool?.({
481
+ adminUser: params.adminUser,
482
+ httpExtra: params.httpExtra,
483
+ inputs: params.inputs,
484
+ resourceLabel: resourceLabel(params.adminforth, params.inputs),
485
+ userTimeZone: params.userTimeZone,
486
+ invokeTool: async () => {
487
+ throw new Error('Tool info formatting cannot invoke tools');
488
+ },
489
+ });
490
+ }
491
+
492
+ function normalizeCookies(
493
+ cookies?: Partial<HttpExtra>['cookies'] | Record<string, string>,
494
+ ): CookieItem[] {
405
495
  if (!cookies) {
406
496
  return [];
407
497
  }
package/build.log CHANGED
@@ -38,5 +38,5 @@ custom/skills/fetch_data/SKILL.md
38
38
  custom/skills/mutate_data/
39
39
  custom/skills/mutate_data/SKILL.md
40
40
 
41
- sent 199,973 bytes received 562 bytes 401,070.00 bytes/sec
42
- total size is 197,669 speedup is 0.99
41
+ sent 200,052 bytes received 562 bytes 401,228.00 bytes/sec
42
+ total size is 197,748 speedup is 0.99
@@ -541,6 +541,9 @@ export const useAgentStore = defineStore('agent', () => {
541
541
  const res = await callAdminForthApi({
542
542
  method: 'POST',
543
543
  path: '/agent/get-sessions',
544
+ body: {
545
+ limit: 100,
546
+ },
544
547
  });
545
548
  if (res.error) {
546
549
  console.error('Error fetching sessions list:', res.error);
@@ -7,7 +7,7 @@
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
8
8
  },
9
9
  "keywords": [],
10
- "author": "",
10
+ "author": "DevForth (https://devforth.io)",
11
11
  "license": "ISC",
12
12
  "packageManager": "pnpm@10.33.0",
13
13
  "dependencies": {
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { ToolMessage } from "@langchain/core/messages";
11
11
  import { createMiddleware } from "langchain";
12
12
  import { logger } from "adminforth";
13
+ import { formatApiBasedToolCall, } from "../../apiBasedTools.js";
13
14
  import { createToolCallTracker, } from "../toolCallEvents.js";
14
15
  import { ALWAYS_AVAILABLE_API_TOOL_NAMES } from "../tools/index.js";
15
16
  import { createApiTool } from "../tools/apiTool.js";
@@ -40,7 +41,7 @@ function getEnabledApiToolNames(messages) {
40
41
  }
41
42
  return enabledToolNames;
42
43
  }
43
- export function createApiBasedToolsMiddleware(apiBasedTools) {
44
+ export function createApiBasedToolsMiddleware(apiBasedTools, adminforth) {
44
45
  const alwaysAvailableApiToolNames = new Set(ALWAYS_AVAILABLE_API_TOOL_NAMES);
45
46
  const dynamicTools = Object.fromEntries(Object.entries(apiBasedTools).map(([toolName, apiBasedTool]) => [
46
47
  toolName,
@@ -62,12 +63,30 @@ export function createApiBasedToolsMiddleware(apiBasedTools) {
62
63
  var _a, _b, _c, _d;
63
64
  const startedAt = Date.now();
64
65
  const toolInput = JSON.stringify((_a = request.toolCall.args) !== null && _a !== void 0 ? _a : {});
65
- const { emitToolCallEvent } = request.runtime.context;
66
+ const { adminUser, emitToolCallEvent, userTimeZone } = request.runtime.context;
67
+ const toolArgs = ((_b = request.toolCall.args) !== null && _b !== void 0 ? _b : {});
68
+ let toolInfo;
69
+ if (request.toolCall.name === "fetch_skill") {
70
+ toolInfo = `Load ${toolArgs.skillName.split("_").join(" ")} skill`;
71
+ }
72
+ else if (request.toolCall.name === "fetch_tool_schema") {
73
+ toolInfo = `Load ${toolArgs.toolName.split("_").join(" ")} tool `;
74
+ }
75
+ else {
76
+ toolInfo = yield formatApiBasedToolCall({
77
+ adminforth,
78
+ adminUser,
79
+ inputs: toolArgs,
80
+ toolName: request.toolCall.name,
81
+ userTimeZone,
82
+ });
83
+ }
66
84
  const toolCallTracker = createToolCallTracker({
67
85
  emit: emitToolCallEvent,
68
86
  toolCallId: request.toolCall.id,
69
87
  toolName: request.toolCall.name,
70
- input: ((_b = request.toolCall.args) !== null && _b !== void 0 ? _b : {}),
88
+ toolInfo,
89
+ input: toolArgs,
71
90
  startedAt,
72
91
  });
73
92
  toolCallTracker.start();
@@ -66,15 +66,31 @@ function finalizeSequenceDebug(sequence) {
66
66
  resultType: (_a = sequence.resultType) !== null && _a !== void 0 ? _a : "final_text",
67
67
  };
68
68
  }
69
+ function getDebugModelName(model) {
70
+ return typeof model.getName === "function" ? model.getName() : undefined;
71
+ }
72
+ function supportsOpenAiResponseDebug(model) {
73
+ return (getDebugModelName(model) === "ChatOpenAI" &&
74
+ typeof model.model === "string" &&
75
+ typeof model.invocationParams === "function");
76
+ }
69
77
  function stringifyPromptForDebug(params) {
70
- var _a;
78
+ var _a, _b, _c, _d;
71
79
  const { model, systemMessage, messages, tools, toolChoice, modelSettings } = params;
80
+ if (!supportsOpenAiResponseDebug(model)) {
81
+ return YAML.stringify(Object.assign(Object.assign(Object.assign({ model: {
82
+ name: (_a = getDebugModelName(model)) !== null && _a !== void 0 ? _a : null,
83
+ provider: (_c = (_b = model._defaultConfig) === null || _b === void 0 ? void 0 : _b.modelProvider) !== null && _c !== void 0 ? _c : null,
84
+ configuredModel: typeof model.model === "string" ? model.model : null,
85
+ }, systemMessage,
86
+ messages }, (tools.length > 0 ? { tools } : {})), (toolChoice !== undefined ? { toolChoice } : {})), (modelSettings ? { modelSettings } : {})));
87
+ }
72
88
  return YAML.stringify(Object.assign({ input: convertMessagesToResponsesInput({
73
89
  messages: [
74
90
  ...(systemMessage.text === "" ? [] : [systemMessage]),
75
91
  ...messages,
76
92
  ],
77
- zdrEnabled: (_a = model.zdrEnabled) !== null && _a !== void 0 ? _a : false,
93
+ zdrEnabled: (_d = model.zdrEnabled) !== null && _d !== void 0 ? _d : false,
78
94
  model: model.model,
79
95
  }) }, model.invocationParams(Object.assign(Object.assign(Object.assign({}, (modelSettings !== null && modelSettings !== void 0 ? modelSettings : {})), (tools.length > 0 ? { tools } : {})), (toolChoice !== undefined ? { tool_choice: toolChoice } : {})))));
80
96
  }
@@ -8,10 +8,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { createAgent, summarizationMiddleware } from "langchain";
11
- import { logger } from "adminforth";
11
+ import { MODEL_PROVIDER_CONFIG, getChatModelByClassName, } from "langchain/chat_models/universal";
12
+ import { logger, } from "adminforth";
12
13
  import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
13
14
  import { z } from "zod";
14
- import { ChatOpenAI } from "@langchain/openai";
15
15
  import { createAgentTools } from "./tools/index.js";
16
16
  import { createApiBasedToolsMiddleware } from "./middleware/apiBasedTools.js";
17
17
  import { createSequenceDebugMiddleware, } from "./middleware/sequenceDebug.js";
@@ -23,6 +23,149 @@ export const contextSchema = z.object({
23
23
  turnId: z.string(),
24
24
  emitToolCallEvent: z.custom(),
25
25
  });
26
+ function isRecord(value) {
27
+ return typeof value === "object" && value !== null;
28
+ }
29
+ function normalizeProvider(value) {
30
+ if (typeof value !== "string") {
31
+ return undefined;
32
+ }
33
+ const normalized = value.toLowerCase().replace(/[_\s]+/g, "-");
34
+ if (["openai", "open-ai"].includes(normalized)) {
35
+ return "openai";
36
+ }
37
+ if (["anthropic", "claude"].includes(normalized)) {
38
+ return "anthropic";
39
+ }
40
+ if ([
41
+ "google",
42
+ "gemini",
43
+ "google-genai",
44
+ "google-gemini",
45
+ "google-generative-ai",
46
+ "google-generativeai",
47
+ ].includes(normalized)) {
48
+ return "google-genai";
49
+ }
50
+ return undefined;
51
+ }
52
+ function detectProviderFromConstructorName(constructorName) {
53
+ const normalized = constructorName === null || constructorName === void 0 ? void 0 : constructorName.toLowerCase();
54
+ if (!normalized) {
55
+ return undefined;
56
+ }
57
+ if (normalized.includes("openai")) {
58
+ return "openai";
59
+ }
60
+ if (normalized.includes("anthropic") || normalized.includes("claude")) {
61
+ return "anthropic";
62
+ }
63
+ if (normalized.includes("gemini") || normalized.includes("google")) {
64
+ return "google-genai";
65
+ }
66
+ return undefined;
67
+ }
68
+ function detectProviderFromModelName(model) {
69
+ const normalized = model === null || model === void 0 ? void 0 : model.toLowerCase();
70
+ if (!normalized) {
71
+ return undefined;
72
+ }
73
+ if (normalized.startsWith("claude")) {
74
+ return "anthropic";
75
+ }
76
+ if (normalized.startsWith("gemini")) {
77
+ return "google-genai";
78
+ }
79
+ if (/^(gpt|o[1-9]|chatgpt)/.test(normalized)) {
80
+ return "openai";
81
+ }
82
+ return undefined;
83
+ }
84
+ function detectAgentModelProvider(adapter) {
85
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
86
+ const options = (_a = adapter.options) !== null && _a !== void 0 ? _a : {};
87
+ return ((_j = (_h = (_g = (_f = (_e = (_c = (_b = normalizeProvider(options.modelProvider)) !== null && _b !== void 0 ? _b : normalizeProvider(options.provider)) !== null && _c !== void 0 ? _c : detectProviderFromConstructorName((_d = adapter.constructor) === null || _d === void 0 ? void 0 : _d.name)) !== null && _e !== void 0 ? _e : (options.openAiApiKey || options.openAIApiKey
88
+ ? "openai"
89
+ : undefined)) !== null && _f !== void 0 ? _f : (options.anthropicApiKey ? "anthropic" : undefined)) !== null && _g !== void 0 ? _g : (options.geminiApiKey ||
90
+ options.googleApiKey ||
91
+ options.googleGenAiApiKey ||
92
+ options.googleGenerativeAiApiKey
93
+ ? "google-genai"
94
+ : undefined)) !== null && _h !== void 0 ? _h : detectProviderFromModelName(options.model)) !== null && _j !== void 0 ? _j : (() => {
95
+ throw new Error("Could not infer completion adapter provider. Set options.modelProvider to openai, anthropic, or google-genai.");
96
+ })());
97
+ }
98
+ function getProviderApiKey(provider, options) {
99
+ var _a, _b, _c, _d, _e, _f, _g;
100
+ switch (provider) {
101
+ case "openai":
102
+ return (_b = (_a = options === null || options === void 0 ? void 0 : options.openAiApiKey) !== null && _a !== void 0 ? _a : options === null || options === void 0 ? void 0 : options.openAIApiKey) !== null && _b !== void 0 ? _b : options === null || options === void 0 ? void 0 : options.apiKey;
103
+ case "anthropic":
104
+ return (_c = options === null || options === void 0 ? void 0 : options.anthropicApiKey) !== null && _c !== void 0 ? _c : options === null || options === void 0 ? void 0 : options.apiKey;
105
+ case "google-genai":
106
+ return ((_g = (_f = (_e = (_d = options === null || options === void 0 ? void 0 : options.geminiApiKey) !== null && _d !== void 0 ? _d : options === null || options === void 0 ? void 0 : options.googleApiKey) !== null && _e !== void 0 ? _e : options === null || options === void 0 ? void 0 : options.googleGenAiApiKey) !== null && _f !== void 0 ? _f : options === null || options === void 0 ? void 0 : options.googleGenerativeAiApiKey) !== null && _g !== void 0 ? _g : options === null || options === void 0 ? void 0 : options.apiKey);
107
+ }
108
+ }
109
+ function getProviderModel(provider, options) {
110
+ if (options === null || options === void 0 ? void 0 : options.model) {
111
+ return options.model;
112
+ }
113
+ if (provider === "openai") {
114
+ return "gpt-5-nano";
115
+ }
116
+ if (provider === "google-genai") {
117
+ return "gemini-3-flash-preview";
118
+ }
119
+ throw new Error(`CompletionAdapter for provider ${provider} must expose options.model`);
120
+ }
121
+ function buildChatModelConfig(params) {
122
+ var _a, _b;
123
+ const { provider, options, maxTokens } = params;
124
+ const apiKey = getProviderApiKey(provider, options);
125
+ if (!apiKey) {
126
+ const optionName = provider === "openai"
127
+ ? "options.openAiApiKey"
128
+ : provider === "anthropic"
129
+ ? "options.anthropicApiKey"
130
+ : "options.geminiApiKey";
131
+ throw new Error(`CompletionAdapter must expose ${optionName} for ${provider} agent mode`);
132
+ }
133
+ const model = getProviderModel(provider, options);
134
+ const baseURL = (_a = options === null || options === void 0 ? void 0 : options.baseURL) !== null && _a !== void 0 ? _a : options === null || options === void 0 ? void 0 : options.baseUrl;
135
+ const extraRequestBodyParameters = Object.assign({}, ((_b = options === null || options === void 0 ? void 0 : options.extraRequestBodyParameters) !== null && _b !== void 0 ? _b : {}));
136
+ if (provider === "openai" && isRecord(extraRequestBodyParameters.reasoning)) {
137
+ extraRequestBodyParameters.reasoning = Object.assign(Object.assign({}, extraRequestBodyParameters.reasoning), { summary: "auto" });
138
+ }
139
+ const config = Object.assign({ model,
140
+ apiKey,
141
+ maxTokens, streaming: true }, extraRequestBodyParameters);
142
+ if (typeof (options === null || options === void 0 ? void 0 : options.timeoutMs) === "number") {
143
+ config.timeout = options.timeoutMs;
144
+ }
145
+ if (baseURL) {
146
+ config.baseURL = baseURL;
147
+ config.baseUrl = baseURL;
148
+ config.configuration = {
149
+ baseURL,
150
+ };
151
+ }
152
+ if (provider === "openai") {
153
+ config.openAIApiKey = apiKey;
154
+ config.useResponsesApi = true;
155
+ config.outputVersion = "v1";
156
+ config.promptCacheKey = `adminforth-agent:${model}:system-v1:tools-v1`;
157
+ config.promptCacheRetention = "in_memory";
158
+ }
159
+ if (provider === "anthropic") {
160
+ config.anthropicApiKey = apiKey;
161
+ }
162
+ if (provider === "google-genai") {
163
+ config.geminiApiKey = apiKey;
164
+ config.googleApiKey = apiKey;
165
+ config.maxOutputTokens = maxTokens;
166
+ }
167
+ return { model, config };
168
+ }
26
169
  function getFiniteNumber(value) {
27
170
  return typeof value === "number" && Number.isFinite(value)
28
171
  ? value
@@ -102,38 +245,35 @@ function createAgentLlmMetricsLogger() {
102
245
  return new AgentLlmMetricsLogger();
103
246
  }
104
247
  export function createAgentChatModel(params) {
105
- var _a, _b, _c, _d;
106
- const adapter = params.adapter;
107
- const options = (_a = adapter.options) !== null && _a !== void 0 ? _a : {};
108
- if (!options.openAiApiKey) {
109
- throw new Error("CompletionAdapter must expose options.openAiApiKey for ChatOpenAI");
110
- }
111
- const model = (_b = options.model) !== null && _b !== void 0 ? _b : "gpt-5-nano";
112
- const baseURL = (_c = options.baseURL) !== null && _c !== void 0 ? _c : options.baseUrl;
113
- const reasoning = (_d = options.extraRequestBodyParameters) === null || _d === void 0 ? void 0 : _d.reasoning;
114
- const reasoningConfig = reasoning
115
- ? Object.assign(Object.assign({}, reasoning), { summary: "auto" }) : undefined;
116
- // @ts-ignore
117
- return new ChatOpenAI(Object.assign(Object.assign(Object.assign({ apiKey: options.openAiApiKey, model, maxTokens: params.maxTokens, useResponsesApi: true, outputVersion: "v1", streaming: true, promptCacheKey: `adminforth-agent:${model}:system-v1:tools-v1`, promptCacheRetention: "in_memory" }, (reasoningConfig ? { reasoning: reasoningConfig } : {})), (typeof options.timeoutMs === "number"
118
- ? { timeout: options.timeoutMs }
119
- : {})), (baseURL
120
- ? {
121
- configuration: {
122
- baseURL,
123
- },
124
- }
125
- : {})));
248
+ return __awaiter(this, void 0, void 0, function* () {
249
+ var _a;
250
+ const adapter = params.adapter;
251
+ const options = (_a = adapter.options) !== null && _a !== void 0 ? _a : {};
252
+ const provider = detectAgentModelProvider(adapter);
253
+ const { config } = buildChatModelConfig({
254
+ provider,
255
+ options,
256
+ maxTokens: params.maxTokens,
257
+ });
258
+ const className = MODEL_PROVIDER_CONFIG[provider].className;
259
+ const ChatModelClass = yield getChatModelByClassName(className, provider);
260
+ return {
261
+ model: new ChatModelClass(config),
262
+ provider,
263
+ };
264
+ });
126
265
  }
127
266
  export function callAgent(params) {
128
267
  return __awaiter(this, void 0, void 0, function* () {
129
- const { name, model, summaryModel, checkpointer, messages, adminUser, apiBasedTools, customComponentsDir, sessionId, turnId, userTimeZone, emitToolCallEvent, sequenceDebugSink, } = params;
268
+ const { name, model, summaryModel, modelProvider, checkpointer, messages, adminUser, adminforth, apiBasedTools, customComponentsDir, sessionId, turnId, userTimeZone, emitToolCallEvent, sequenceDebugSink, } = params;
130
269
  const tools = yield createAgentTools(customComponentsDir, apiBasedTools);
131
- const apiBasedToolsMiddleware = createApiBasedToolsMiddleware(apiBasedTools);
132
- const openAiResponsesContinuationMiddleware = createOpenAiResponsesContinuationMiddleware();
270
+ const apiBasedToolsMiddleware = createApiBasedToolsMiddleware(apiBasedTools, adminforth);
133
271
  const sequenceDebugMiddleware = createSequenceDebugMiddleware(sequenceDebugSink);
134
272
  const middleware = [
135
273
  apiBasedToolsMiddleware,
136
- openAiResponsesContinuationMiddleware,
274
+ ...(modelProvider === "openai"
275
+ ? [createOpenAiResponsesContinuationMiddleware()]
276
+ : []),
137
277
  sequenceDebugMiddleware,
138
278
  summarizationMiddleware({
139
279
  model: summaryModel,
@@ -39,6 +39,7 @@ export function createToolCallTracker(params) {
39
39
  params.emit({
40
40
  toolCallId,
41
41
  toolName: params.toolName,
42
+ toolInfo: params.toolInfo,
42
43
  phase: "start",
43
44
  input: YAML.stringify((_a = params.input) !== null && _a !== void 0 ? _a : {}),
44
45
  });
@@ -17,6 +17,32 @@ import YAML from 'yaml';
17
17
  dayjs.extend(utc);
18
18
  dayjs.extend(timezone);
19
19
  const DEFAULT_USER_TIME_ZONE = 'UTC';
20
+ function getInputString(inputs, key) {
21
+ const value = inputs === null || inputs === void 0 ? void 0 : inputs[key];
22
+ return typeof value === 'string' && value ? value : undefined;
23
+ }
24
+ function getInputArrayLength(inputs, key) {
25
+ const value = inputs === null || inputs === void 0 ? void 0 : inputs[key];
26
+ return Array.isArray(value) ? value.length : undefined;
27
+ }
28
+ function resourceLabel(adminforth, inputs) {
29
+ var _a, _b;
30
+ const resourceId = getInputString(inputs, 'resourceId');
31
+ const resource = adminforth.config.resources.find((res) => res.resourceId === resourceId);
32
+ return (_b = (_a = resource === null || resource === void 0 ? void 0 : resource.label) !== null && _a !== void 0 ? _a : resourceId) !== null && _b !== void 0 ? _b : 'resource';
33
+ }
34
+ function getDataPrefix(inputs) {
35
+ const offset = typeof (inputs === null || inputs === void 0 ? void 0 : inputs.offset) === 'number' ? inputs.offset : undefined;
36
+ const limit = typeof (inputs === null || inputs === void 0 ? void 0 : inputs.limit) === 'number' ? inputs.limit : undefined;
37
+ if (offset !== undefined && limit !== undefined) {
38
+ return `${offset}-${offset + limit} `;
39
+ }
40
+ return limit === undefined ? '' : `${limit} `;
41
+ }
42
+ function actionText(inputs) {
43
+ const actionId = getInputString(inputs, 'actionId');
44
+ return actionId ? ` action ${actionId}` : ' action';
45
+ }
20
46
  const TOOL_OVERRIDES = {
21
47
  get_resource: {
22
48
  wipe_frontend_specific_data: [
@@ -25,11 +51,10 @@ const TOOL_OVERRIDES = {
25
51
  'resource.options.actions[].customComponent',
26
52
  'resource.options.pageInjections',
27
53
  ],
28
- format_tool: (_a) => __awaiter(void 0, [_a], void 0, function* ({}) {
29
- return "get resource Apartments";
30
- })
54
+ format_tool: ({ resourceLabel }) => `Get ${resourceLabel} resource`,
31
55
  },
32
56
  get_resource_data: {
57
+ format_tool: ({ inputs, resourceLabel }) => (`Get ${getDataPrefix(inputs)}${resourceLabel}`),
33
58
  post_process_response: (_a) => __awaiter(void 0, [_a], void 0, function* ({ output, inputs, invokeTool, userTimeZone }) {
34
59
  if (hasToolError(output)) {
35
60
  return output;
@@ -47,9 +72,35 @@ const TOOL_OVERRIDES = {
47
72
  formatDateTimeColumns(response.data, dateTimeColumnNames, localizedTimeZone);
48
73
  return response;
49
74
  }),
50
- format_tool: (_a) => __awaiter(void 0, [_a], void 0, function* ({}) {
51
- return "get 1-20 Apartment filtered listed=yes";
52
- })
75
+ },
76
+ aggregate: {
77
+ format_tool: ({ resourceLabel }) => `Aggregate ${resourceLabel}`,
78
+ },
79
+ start_custom_action: {
80
+ format_tool: ({ inputs, resourceLabel }) => `Run ${resourceLabel}${actionText(inputs)}`,
81
+ },
82
+ start_custom_bulk_action: {
83
+ format_tool: ({ inputs, resourceLabel }) => {
84
+ const recordCount = getInputArrayLength(inputs, 'recordIds');
85
+ const recordsText = recordCount === undefined ? '' : ` for ${recordCount} records`;
86
+ return `Run ${resourceLabel}${actionText(inputs)}${recordsText}`;
87
+ },
88
+ },
89
+ start_bulk_action: {
90
+ format_tool: ({ inputs, resourceLabel }) => {
91
+ const recordCount = getInputArrayLength(inputs, 'recordIds');
92
+ const recordsText = recordCount === undefined ? '' : ` for ${recordCount} records`;
93
+ return `Run ${resourceLabel}${actionText(inputs)}${recordsText}`;
94
+ },
95
+ },
96
+ create_record: {
97
+ format_tool: ({ resourceLabel }) => `Create ${resourceLabel}`,
98
+ },
99
+ update_record: {
100
+ format_tool: ({ resourceLabel }) => `Update ${resourceLabel}`,
101
+ },
102
+ delete_record: {
103
+ format_tool: ({ resourceLabel }) => `Delete ${resourceLabel}`,
53
104
  },
54
105
  };
55
106
  function sanitizeForYaml(value) {
@@ -235,6 +286,22 @@ function endpointPathToToolName(path) {
235
286
  .replace(/[^a-zA-Z0-9_]+/g, '_')
236
287
  .replace(/^_+|_+$/g, '');
237
288
  }
289
+ export function formatApiBasedToolCall(params) {
290
+ return __awaiter(this, void 0, void 0, function* () {
291
+ var _a;
292
+ const formatTool = (_a = TOOL_OVERRIDES[params.toolName]) === null || _a === void 0 ? void 0 : _a.format_tool;
293
+ return yield (formatTool === null || formatTool === void 0 ? void 0 : formatTool({
294
+ adminUser: params.adminUser,
295
+ httpExtra: params.httpExtra,
296
+ inputs: params.inputs,
297
+ resourceLabel: resourceLabel(params.adminforth, params.inputs),
298
+ userTimeZone: params.userTimeZone,
299
+ invokeTool: () => __awaiter(this, void 0, void 0, function* () {
300
+ throw new Error('Tool info formatting cannot invoke tools');
301
+ }),
302
+ }));
303
+ });
304
+ }
238
305
  function normalizeCookies(cookies) {
239
306
  if (!cookies) {
240
307
  return [];
@@ -541,6 +541,9 @@ export const useAgentStore = defineStore('agent', () => {
541
541
  const res = await callAdminForthApi({
542
542
  method: 'POST',
543
543
  path: '/agent/get-sessions',
544
+ body: {
545
+ limit: 100,
546
+ },
544
547
  });
545
548
  if (res.error) {
546
549
  console.error('Error fetching sessions list:', res.error);
@@ -7,7 +7,7 @@
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
8
8
  },
9
9
  "keywords": [],
10
- "author": "",
10
+ "author": "DevForth (https://devforth.io)",
11
11
  "license": "ISC",
12
12
  "packageManager": "pnpm@10.33.0",
13
13
  "dependencies": {