@adminforth/agent 1.0.0 → 1.1.0

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,7 +1,11 @@
1
1
  import { ToolMessage } from "@langchain/core/messages";
2
2
  import { createMiddleware } from "langchain";
3
3
  import { logger } from "adminforth";
4
- import type { ApiBasedTool } from "../../apiBasedTools.js";
4
+ import { type ApiBasedTool } from "../../apiBasedTools.js";
5
+ import {
6
+ createToolCallTracker,
7
+ type ToolCallEventSink,
8
+ } from "../toolCallEvents.js";
5
9
  import { ALWAYS_AVAILABLE_API_TOOL_NAMES } from "../tools/index.js";
6
10
  import { createApiTool } from "../tools/apiTool.js";
7
11
 
@@ -67,30 +71,46 @@ export function createApiBasedToolsMiddleware(
67
71
  async wrapToolCall(request, handler) {
68
72
  const startedAt = Date.now();
69
73
  const toolInput = JSON.stringify(request.toolCall.args ?? {});
74
+ const { emitToolCallEvent } = request.runtime.context as {
75
+ emitToolCallEvent: ToolCallEventSink;
76
+ };
77
+ const toolCallTracker = createToolCallTracker({
78
+ emit: emitToolCallEvent,
79
+ toolCallId: request.toolCall.id,
80
+ toolName: request.toolCall.name,
81
+ input: (request.toolCall.args ?? {}) as Record<string, unknown>,
82
+ startedAt,
83
+ });
84
+ toolCallTracker.start();
70
85
  logger.info(
71
86
  `Invoking tool "${request.toolCall.name}" with input: ${toolInput}`,
72
87
  );
73
88
 
74
89
  try {
75
- if (request.tool) {
76
- return await handler(request);
77
- }
90
+ let result;
78
91
 
79
- const enabledApiToolNames = getEnabledApiToolNames(request.state.messages);
92
+ if (request.tool) {
93
+ result = await handler(request);
94
+ } else {
95
+ const enabledApiToolNames = getEnabledApiToolNames(request.state.messages);
80
96
 
81
- if (enabledApiToolNames.has(request.toolCall.name)) {
82
- return await handler({
83
- ...request,
84
- tool: dynamicTools[request.toolCall.name],
85
- });
97
+ if (enabledApiToolNames.has(request.toolCall.name)) {
98
+ result = await handler({
99
+ ...request,
100
+ tool: dynamicTools[request.toolCall.name],
101
+ });
102
+ } else {
103
+ result = new ToolMessage({
104
+ content: `Tool "${request.toolCall.name}" is not loaded. Call fetch_tool_schema first.`,
105
+ tool_call_id: request.toolCall.id ?? "",
106
+ name: request.toolCall.name,
107
+ status: "error",
108
+ });
109
+ }
86
110
  }
87
111
 
88
- return new ToolMessage({
89
- content: `Tool "${request.toolCall.name}" is not loaded. Call fetch_tool_schema first.`,
90
- tool_call_id: request.toolCall.id ?? "",
91
- name: request.toolCall.name,
92
- status: "error",
93
- });
112
+ toolCallTracker.finishSuccess(result);
113
+ return result;
94
114
  } catch (error) {
95
115
  const errorDetails =
96
116
  error instanceof Error ? error.stack ?? error.message : String(error);
@@ -98,6 +118,7 @@ export function createApiBasedToolsMiddleware(
98
118
  logger.error(
99
119
  `Tool "${request.toolCall.name}" failed after ${Date.now() - startedAt}ms with input: ${toolInput}\n${errorDetails}`,
100
120
  );
121
+ toolCallTracker.finishError(error);
101
122
  throw error;
102
123
  } finally {
103
124
  logger.info(
@@ -1,3 +1,7 @@
1
+ import { randomUUID } from "crypto";
2
+ import YAML from "yaml";
3
+ import { serializeUnknownError } from "../apiBasedTools.js";
4
+
1
5
  export type ToolCallEvent =
2
6
  | {
3
7
  toolCallId: string;
@@ -15,3 +19,45 @@ export type ToolCallEvent =
15
19
  };
16
20
 
17
21
  export type ToolCallEventSink = (event: ToolCallEvent) => void;
22
+
23
+ export function createToolCallTracker(params: {
24
+ emit: ToolCallEventSink;
25
+ toolCallId?: string;
26
+ toolName: string;
27
+ input?: Record<string, unknown>;
28
+ startedAt?: number;
29
+ }) {
30
+ const toolCallId = params.toolCallId ?? randomUUID();
31
+ const startedAt = params.startedAt ?? Date.now();
32
+
33
+ return {
34
+ start() {
35
+ params.emit({
36
+ toolCallId,
37
+ toolName: params.toolName,
38
+ phase: "start",
39
+ input: YAML.stringify(params.input ?? {}),
40
+ });
41
+ },
42
+ finishSuccess(output: unknown) {
43
+ params.emit({
44
+ toolCallId,
45
+ toolName: params.toolName,
46
+ phase: "end",
47
+ durationMs: Date.now() - startedAt,
48
+ output: YAML.stringify(output).trimEnd(),
49
+ error: null,
50
+ });
51
+ },
52
+ finishError(error: unknown) {
53
+ params.emit({
54
+ toolCallId,
55
+ toolName: params.toolName,
56
+ phase: "end",
57
+ durationMs: Date.now() - startedAt,
58
+ output: null,
59
+ error: YAML.stringify(serializeUnknownError(error)).trimEnd(),
60
+ });
61
+ },
62
+ };
63
+ }
@@ -1,8 +1,5 @@
1
1
  import { tool } from "langchain";
2
- import { randomUUID } from "crypto";
3
- import YAML from "yaml";
4
2
  import type { ApiBasedTool } from "../../apiBasedTools.js";
5
- import { serializeUnknownError } from "../../apiBasedTools.js";
6
3
 
7
4
  const emptyToolSchema = {
8
5
  type: "object",
@@ -52,43 +49,11 @@ export function createApiTool(toolName: string, apiBasedTool: ApiBasedTool) {
52
49
  return tool(
53
50
  async (input, runtime) => {
54
51
  const normalizedInput = (input ?? {}) as Record<string, unknown>;
55
- const toolCallId = randomUUID();
56
- const startedAt = Date.now();
57
- runtime.context.emitToolCallEvent({
58
- toolCallId,
59
- toolName,
60
- phase: "start",
61
- input: YAML.stringify(normalizedInput),
52
+ return apiBasedTool.call({
53
+ adminUser: runtime.context.adminUser,
54
+ inputs: normalizedInput,
55
+ userTimeZone: runtime.context.userTimeZone,
62
56
  });
63
-
64
- try {
65
- const output = await apiBasedTool.call({
66
- adminUser: runtime.context.adminUser,
67
- inputs: normalizedInput,
68
- userTimeZone: runtime.context.userTimeZone,
69
- });
70
-
71
- runtime.context.emitToolCallEvent({
72
- toolCallId,
73
- toolName,
74
- phase: "end",
75
- durationMs: Date.now() - startedAt,
76
- output,
77
- error: null,
78
- });
79
-
80
- return output;
81
- } catch (error) {
82
- runtime.context.emitToolCallEvent({
83
- toolCallId,
84
- toolName,
85
- phase: "end",
86
- durationMs: Date.now() - startedAt,
87
- output: null,
88
- error: YAML.stringify(serializeUnknownError(error)),
89
- });
90
- throw error;
91
- }
92
57
  },
93
58
  {
94
59
  name: toolName,
package/build.log CHANGED
@@ -26,5 +26,5 @@ custom/skills/fetch_data/SKILL.md
26
26
  custom/skills/mutate_data/
27
27
  custom/skills/mutate_data/SKILL.md
28
28
 
29
- sent 136,251 bytes received 367 bytes 273,236.00 bytes/sec
29
+ sent 136,273 bytes received 367 bytes 273,280.00 bytes/sec
30
30
  total size is 134,767 speedup is 0.99
@@ -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 { createToolCallTracker, } from "../toolCallEvents.js";
13
14
  import { ALWAYS_AVAILABLE_API_TOOL_NAMES } from "../tools/index.js";
14
15
  import { createApiTool } from "../tools/apiTool.js";
15
16
  function getEnabledApiToolNames(messages) {
@@ -58,28 +59,45 @@ export function createApiBasedToolsMiddleware(apiBasedTools) {
58
59
  },
59
60
  wrapToolCall(request, handler) {
60
61
  return __awaiter(this, void 0, void 0, function* () {
61
- var _a, _b, _c;
62
+ var _a, _b, _c, _d;
62
63
  const startedAt = Date.now();
63
64
  const toolInput = JSON.stringify((_a = request.toolCall.args) !== null && _a !== void 0 ? _a : {});
65
+ const { emitToolCallEvent } = request.runtime.context;
66
+ const toolCallTracker = createToolCallTracker({
67
+ emit: emitToolCallEvent,
68
+ toolCallId: request.toolCall.id,
69
+ toolName: request.toolCall.name,
70
+ input: ((_b = request.toolCall.args) !== null && _b !== void 0 ? _b : {}),
71
+ startedAt,
72
+ });
73
+ toolCallTracker.start();
64
74
  logger.info(`Invoking tool "${request.toolCall.name}" with input: ${toolInput}`);
65
75
  try {
76
+ let result;
66
77
  if (request.tool) {
67
- return yield handler(request);
78
+ result = yield handler(request);
68
79
  }
69
- const enabledApiToolNames = getEnabledApiToolNames(request.state.messages);
70
- if (enabledApiToolNames.has(request.toolCall.name)) {
71
- return yield handler(Object.assign(Object.assign({}, request), { tool: dynamicTools[request.toolCall.name] }));
80
+ else {
81
+ const enabledApiToolNames = getEnabledApiToolNames(request.state.messages);
82
+ if (enabledApiToolNames.has(request.toolCall.name)) {
83
+ result = yield handler(Object.assign(Object.assign({}, request), { tool: dynamicTools[request.toolCall.name] }));
84
+ }
85
+ else {
86
+ result = new ToolMessage({
87
+ content: `Tool "${request.toolCall.name}" is not loaded. Call fetch_tool_schema first.`,
88
+ tool_call_id: (_c = request.toolCall.id) !== null && _c !== void 0 ? _c : "",
89
+ name: request.toolCall.name,
90
+ status: "error",
91
+ });
92
+ }
72
93
  }
73
- return new ToolMessage({
74
- content: `Tool "${request.toolCall.name}" is not loaded. Call fetch_tool_schema first.`,
75
- tool_call_id: (_b = request.toolCall.id) !== null && _b !== void 0 ? _b : "",
76
- name: request.toolCall.name,
77
- status: "error",
78
- });
94
+ toolCallTracker.finishSuccess(result);
95
+ return result;
79
96
  }
80
97
  catch (error) {
81
- const errorDetails = error instanceof Error ? (_c = error.stack) !== null && _c !== void 0 ? _c : error.message : String(error);
98
+ const errorDetails = error instanceof Error ? (_d = error.stack) !== null && _d !== void 0 ? _d : error.message : String(error);
82
99
  logger.error(`Tool "${request.toolCall.name}" failed after ${Date.now() - startedAt}ms with input: ${toolInput}\n${errorDetails}`);
100
+ toolCallTracker.finishError(error);
83
101
  throw error;
84
102
  }
85
103
  finally {
@@ -1 +1,39 @@
1
- export {};
1
+ import { randomUUID } from "crypto";
2
+ import YAML from "yaml";
3
+ import { serializeUnknownError } from "../apiBasedTools.js";
4
+ export function createToolCallTracker(params) {
5
+ var _a, _b;
6
+ const toolCallId = (_a = params.toolCallId) !== null && _a !== void 0 ? _a : randomUUID();
7
+ const startedAt = (_b = params.startedAt) !== null && _b !== void 0 ? _b : Date.now();
8
+ return {
9
+ start() {
10
+ var _a;
11
+ params.emit({
12
+ toolCallId,
13
+ toolName: params.toolName,
14
+ phase: "start",
15
+ input: YAML.stringify((_a = params.input) !== null && _a !== void 0 ? _a : {}),
16
+ });
17
+ },
18
+ finishSuccess(output) {
19
+ params.emit({
20
+ toolCallId,
21
+ toolName: params.toolName,
22
+ phase: "end",
23
+ durationMs: Date.now() - startedAt,
24
+ output: YAML.stringify(output).trimEnd(),
25
+ error: null,
26
+ });
27
+ },
28
+ finishError(error) {
29
+ params.emit({
30
+ toolCallId,
31
+ toolName: params.toolName,
32
+ phase: "end",
33
+ durationMs: Date.now() - startedAt,
34
+ output: null,
35
+ error: YAML.stringify(serializeUnknownError(error)).trimEnd(),
36
+ });
37
+ },
38
+ };
39
+ }
@@ -8,9 +8,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { tool } from "langchain";
11
- import { randomUUID } from "crypto";
12
- import YAML from "yaml";
13
- import { serializeUnknownError } from "../../apiBasedTools.js";
14
11
  const emptyToolSchema = {
15
12
  type: "object",
16
13
  properties: {},
@@ -50,41 +47,11 @@ export function createApiTool(toolName, apiBasedTool) {
50
47
  var _a;
51
48
  return tool((input, runtime) => __awaiter(this, void 0, void 0, function* () {
52
49
  const normalizedInput = (input !== null && input !== void 0 ? input : {});
53
- const toolCallId = randomUUID();
54
- const startedAt = Date.now();
55
- runtime.context.emitToolCallEvent({
56
- toolCallId,
57
- toolName,
58
- phase: "start",
59
- input: YAML.stringify(normalizedInput),
50
+ return apiBasedTool.call({
51
+ adminUser: runtime.context.adminUser,
52
+ inputs: normalizedInput,
53
+ userTimeZone: runtime.context.userTimeZone,
60
54
  });
61
- try {
62
- const output = yield apiBasedTool.call({
63
- adminUser: runtime.context.adminUser,
64
- inputs: normalizedInput,
65
- userTimeZone: runtime.context.userTimeZone,
66
- });
67
- runtime.context.emitToolCallEvent({
68
- toolCallId,
69
- toolName,
70
- phase: "end",
71
- durationMs: Date.now() - startedAt,
72
- output,
73
- error: null,
74
- });
75
- return output;
76
- }
77
- catch (error) {
78
- runtime.context.emitToolCallEvent({
79
- toolCallId,
80
- toolName,
81
- phase: "end",
82
- durationMs: Date.now() - startedAt,
83
- output: null,
84
- error: YAML.stringify(serializeUnknownError(error)),
85
- });
86
- throw error;
87
- }
88
55
  }), {
89
56
  name: toolName,
90
57
  description: (_a = apiBasedTool.description) !== null && _a !== void 0 ? _a : `${toolName} tool`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/agent",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",