kernl 0.1.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.
Files changed (257) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/CHANGELOG.md +53 -0
  3. package/LICENSE +201 -0
  4. package/dist/agent.d.ts +43 -0
  5. package/dist/agent.d.ts.map +1 -0
  6. package/dist/agent.js +130 -0
  7. package/dist/context.d.ts +70 -0
  8. package/dist/context.d.ts.map +1 -0
  9. package/dist/context.js +111 -0
  10. package/dist/env.d.ts +45 -0
  11. package/dist/env.d.ts.map +1 -0
  12. package/dist/env.js +31 -0
  13. package/dist/error.d.ts +1 -0
  14. package/dist/error.d.ts.map +1 -0
  15. package/dist/error.js +1 -0
  16. package/dist/guardrail.d.ts +178 -0
  17. package/dist/guardrail.d.ts.map +1 -0
  18. package/dist/guardrail.js +34 -0
  19. package/dist/index.d.ts +4 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +2 -0
  22. package/dist/kernel.d.ts +7 -0
  23. package/dist/kernel.d.ts.map +1 -0
  24. package/dist/kernel.js +7 -0
  25. package/dist/kernl.d.ts +18 -0
  26. package/dist/kernl.d.ts.map +1 -0
  27. package/dist/kernl.js +16 -0
  28. package/dist/lib/env.d.ts +43 -0
  29. package/dist/lib/env.d.ts.map +1 -0
  30. package/dist/lib/env.js +29 -0
  31. package/dist/lib/error.d.ts +88 -0
  32. package/dist/lib/error.d.ts.map +1 -0
  33. package/dist/lib/error.js +117 -0
  34. package/dist/lib/logger.d.ts +36 -0
  35. package/dist/lib/logger.d.ts.map +1 -0
  36. package/dist/lib/logger.js +43 -0
  37. package/dist/lib/serde/__tests__/codec.test.d.ts +2 -0
  38. package/dist/lib/serde/__tests__/codec.test.d.ts.map +1 -0
  39. package/dist/lib/serde/__tests__/codec.test.js +75 -0
  40. package/dist/lib/serde/codec.d.ts +12 -0
  41. package/dist/lib/serde/codec.d.ts.map +1 -0
  42. package/dist/lib/serde/codec.js +54 -0
  43. package/dist/lib/serde/json.d.ts +8 -0
  44. package/dist/lib/serde/json.d.ts.map +1 -0
  45. package/dist/lib/serde/json.js +13 -0
  46. package/dist/lib/serde/thread.d.ts +1 -0
  47. package/dist/lib/serde/thread.d.ts.map +1 -0
  48. package/dist/lib/serde/thread.js +172 -0
  49. package/dist/lib/serde/tool.d.ts +36 -0
  50. package/dist/lib/serde/tool.d.ts.map +1 -0
  51. package/dist/lib/serde/tool.js +1 -0
  52. package/dist/lib/utils.d.ts +19 -0
  53. package/dist/lib/utils.d.ts.map +1 -0
  54. package/dist/lib/utils.js +41 -0
  55. package/dist/lifecycle.d.ts +133 -0
  56. package/dist/lifecycle.d.ts.map +1 -0
  57. package/dist/lifecycle.js +29 -0
  58. package/dist/logger.d.ts +36 -0
  59. package/dist/logger.d.ts.map +1 -0
  60. package/dist/logger.js +43 -0
  61. package/dist/mcp/__tests__/base.test.d.ts +2 -0
  62. package/dist/mcp/__tests__/base.test.d.ts.map +1 -0
  63. package/dist/mcp/__tests__/base.test.js +268 -0
  64. package/dist/mcp/__tests__/fixtures/echo-server.d.ts +3 -0
  65. package/dist/mcp/__tests__/fixtures/echo-server.d.ts.map +1 -0
  66. package/dist/mcp/__tests__/fixtures/echo-server.js +92 -0
  67. package/dist/mcp/__tests__/fixtures/math-server.d.ts +3 -0
  68. package/dist/mcp/__tests__/fixtures/math-server.d.ts.map +1 -0
  69. package/dist/mcp/__tests__/fixtures/math-server.js +98 -0
  70. package/dist/mcp/__tests__/fixtures/server.d.ts +3 -0
  71. package/dist/mcp/__tests__/fixtures/server.d.ts.map +1 -0
  72. package/dist/mcp/__tests__/fixtures/server.js +162 -0
  73. package/dist/mcp/__tests__/fixtures/test-server.d.ts +3 -0
  74. package/dist/mcp/__tests__/fixtures/test-server.d.ts.map +1 -0
  75. package/dist/mcp/__tests__/fixtures/test-server.js +163 -0
  76. package/dist/mcp/__tests__/fixtures/utils.d.ts +17 -0
  77. package/dist/mcp/__tests__/fixtures/utils.d.ts.map +1 -0
  78. package/dist/mcp/__tests__/fixtures/utils.js +42 -0
  79. package/dist/mcp/__tests__/integration.test.d.ts +2 -0
  80. package/dist/mcp/__tests__/integration.test.d.ts.map +1 -0
  81. package/dist/mcp/__tests__/integration.test.js +360 -0
  82. package/dist/mcp/__tests__/stdio.test.d.ts +2 -0
  83. package/dist/mcp/__tests__/stdio.test.d.ts.map +1 -0
  84. package/dist/mcp/__tests__/stdio.test.js +180 -0
  85. package/dist/mcp/__tests__/test-utils.d.ts +17 -0
  86. package/dist/mcp/__tests__/test-utils.d.ts.map +1 -0
  87. package/dist/mcp/__tests__/test-utils.js +42 -0
  88. package/dist/mcp/__tests__/utils.test.d.ts +2 -0
  89. package/dist/mcp/__tests__/utils.test.d.ts.map +1 -0
  90. package/dist/mcp/__tests__/utils.test.js +300 -0
  91. package/dist/mcp/base.d.ts +88 -0
  92. package/dist/mcp/base.d.ts.map +1 -0
  93. package/dist/mcp/base.js +68 -0
  94. package/dist/mcp/http.d.ts +34 -0
  95. package/dist/mcp/http.d.ts.map +1 -0
  96. package/dist/mcp/http.js +100 -0
  97. package/dist/mcp/node.d.ts +60 -0
  98. package/dist/mcp/node.d.ts.map +1 -0
  99. package/dist/mcp/node.js +297 -0
  100. package/dist/mcp/sse.d.ts +34 -0
  101. package/dist/mcp/sse.d.ts.map +1 -0
  102. package/dist/mcp/sse.js +97 -0
  103. package/dist/mcp/stdio.d.ts +32 -0
  104. package/dist/mcp/stdio.d.ts.map +1 -0
  105. package/dist/mcp/stdio.js +96 -0
  106. package/dist/mcp/types.d.ts +172 -0
  107. package/dist/mcp/types.d.ts.map +1 -0
  108. package/dist/mcp/types.js +16 -0
  109. package/dist/mcp/utils.d.ts +23 -0
  110. package/dist/mcp/utils.d.ts.map +1 -0
  111. package/dist/mcp/utils.js +44 -0
  112. package/dist/model.d.ts +175 -0
  113. package/dist/model.d.ts.map +1 -0
  114. package/dist/model.js +1 -0
  115. package/dist/providers/ai.d.ts +1 -0
  116. package/dist/providers/ai.d.ts.map +1 -0
  117. package/dist/providers/ai.js +1 -0
  118. package/dist/providers/default.d.ts +16 -0
  119. package/dist/providers/default.d.ts.map +1 -0
  120. package/dist/providers/default.js +17 -0
  121. package/dist/providers/registry.d.ts +1 -0
  122. package/dist/providers/registry.d.ts.map +1 -0
  123. package/dist/providers/registry.js +1 -0
  124. package/dist/sched/scheduler.d.ts +20 -0
  125. package/dist/sched/scheduler.d.ts.map +1 -0
  126. package/dist/sched/scheduler.js +1 -0
  127. package/dist/sched/task.d.ts +92 -0
  128. package/dist/sched/task.d.ts.map +1 -0
  129. package/dist/sched/task.js +102 -0
  130. package/dist/serde/__tests__/codec.test.d.ts +2 -0
  131. package/dist/serde/__tests__/codec.test.d.ts.map +1 -0
  132. package/dist/serde/__tests__/codec.test.js +75 -0
  133. package/dist/serde/codec.d.ts +12 -0
  134. package/dist/serde/codec.d.ts.map +1 -0
  135. package/dist/serde/codec.js +54 -0
  136. package/dist/serde/json.d.ts +8 -0
  137. package/dist/serde/json.d.ts.map +1 -0
  138. package/dist/serde/json.js +13 -0
  139. package/dist/serde/thread.d.ts +687 -0
  140. package/dist/serde/thread.d.ts.map +1 -0
  141. package/dist/serde/thread.js +158 -0
  142. package/dist/serde/tool.d.ts +36 -0
  143. package/dist/serde/tool.d.ts.map +1 -0
  144. package/dist/serde/tool.js +1 -0
  145. package/dist/session.d.ts +1 -0
  146. package/dist/session.d.ts.map +1 -0
  147. package/dist/session.js +1 -0
  148. package/dist/task.d.ts +87 -0
  149. package/dist/task.d.ts.map +1 -0
  150. package/dist/task.js +97 -0
  151. package/dist/thread/__tests__/mock.d.ts +28 -0
  152. package/dist/thread/__tests__/mock.d.ts.map +1 -0
  153. package/dist/thread/__tests__/mock.js +74 -0
  154. package/dist/thread/__tests__/thread.test.d.ts +2 -0
  155. package/dist/thread/__tests__/thread.test.d.ts.map +1 -0
  156. package/dist/thread/__tests__/thread.test.js +1412 -0
  157. package/dist/thread/index.d.ts +2 -0
  158. package/dist/thread/index.d.ts.map +1 -0
  159. package/dist/thread/index.js +1 -0
  160. package/dist/thread/thread.d.ts +66 -0
  161. package/dist/thread/thread.d.ts.map +1 -0
  162. package/dist/thread/thread.js +472 -0
  163. package/dist/thread/utils.d.ts +19 -0
  164. package/dist/thread/utils.d.ts.map +1 -0
  165. package/dist/thread/utils.js +50 -0
  166. package/dist/tool/__tests__/fixtures.d.ts +45 -0
  167. package/dist/tool/__tests__/fixtures.d.ts.map +1 -0
  168. package/dist/tool/__tests__/fixtures.js +97 -0
  169. package/dist/tool/__tests__/tool.test.d.ts +2 -0
  170. package/dist/tool/__tests__/tool.test.d.ts.map +1 -0
  171. package/dist/tool/__tests__/tool.test.js +172 -0
  172. package/dist/tool/__tests__/toolkit.test.d.ts +2 -0
  173. package/dist/tool/__tests__/toolkit.test.d.ts.map +1 -0
  174. package/dist/tool/__tests__/toolkit.test.js +134 -0
  175. package/dist/tool/index.d.ts +4 -0
  176. package/dist/tool/index.d.ts.map +1 -0
  177. package/dist/tool/index.js +2 -0
  178. package/dist/tool/mcp.d.ts +75 -0
  179. package/dist/tool/mcp.d.ts.map +1 -0
  180. package/dist/tool/mcp.js +111 -0
  181. package/dist/tool/tool.d.ts +95 -0
  182. package/dist/tool/tool.d.ts.map +1 -0
  183. package/dist/tool/tool.js +176 -0
  184. package/dist/tool/toolkit.d.ts +121 -0
  185. package/dist/tool/toolkit.d.ts.map +1 -0
  186. package/dist/tool/toolkit.js +180 -0
  187. package/dist/tool/types.d.ts +187 -0
  188. package/dist/tool/types.d.ts.map +1 -0
  189. package/dist/tool/types.js +1 -0
  190. package/dist/tools.d.ts +362 -0
  191. package/dist/tools.d.ts.map +1 -0
  192. package/dist/tools.js +220 -0
  193. package/dist/trace/processor.d.ts +1 -0
  194. package/dist/trace/processor.d.ts.map +1 -0
  195. package/dist/trace/processor.js +1 -0
  196. package/dist/trace/traces.d.ts +1 -0
  197. package/dist/trace/traces.d.ts.map +1 -0
  198. package/dist/trace/traces.js +73 -0
  199. package/dist/trace/utils.d.ts +22 -0
  200. package/dist/trace/utils.d.ts.map +1 -0
  201. package/dist/trace/utils.js +30 -0
  202. package/dist/types/agent.d.ts +91 -0
  203. package/dist/types/agent.d.ts.map +1 -0
  204. package/dist/types/agent.js +1 -0
  205. package/dist/types/proto.d.ts +1551 -0
  206. package/dist/types/proto.d.ts.map +1 -0
  207. package/dist/types/proto.js +531 -0
  208. package/dist/types/thread.d.ts +71 -0
  209. package/dist/types/thread.d.ts.map +1 -0
  210. package/dist/types/thread.js +5 -0
  211. package/dist/usage.d.ts +43 -0
  212. package/dist/usage.d.ts.map +1 -0
  213. package/dist/usage.js +61 -0
  214. package/package.json +52 -0
  215. package/src/agent.ts +203 -0
  216. package/src/context.ts +265 -0
  217. package/src/guardrail.ts +277 -0
  218. package/src/index.ts +3 -0
  219. package/src/kernl.ts +22 -0
  220. package/src/lib/env.ts +36 -0
  221. package/src/lib/error.ts +158 -0
  222. package/src/lib/logger.ts +78 -0
  223. package/src/lib/serde/json.ts +18 -0
  224. package/src/lib/serde/thread.ts +188 -0
  225. package/src/lifecycle.ts +181 -0
  226. package/src/mcp/__tests__/base.test.ts +344 -0
  227. package/src/mcp/__tests__/fixtures/server.ts +179 -0
  228. package/src/mcp/__tests__/fixtures/utils.ts +58 -0
  229. package/src/mcp/__tests__/integration.test.ts +447 -0
  230. package/src/mcp/__tests__/stdio.test.ts +236 -0
  231. package/src/mcp/__tests__/utils.test.ts +360 -0
  232. package/src/mcp/base.ts +162 -0
  233. package/src/mcp/http.ts +147 -0
  234. package/src/mcp/sse.ts +137 -0
  235. package/src/mcp/stdio.ts +136 -0
  236. package/src/mcp/types.ts +202 -0
  237. package/src/mcp/utils.ts +62 -0
  238. package/src/task.ts +119 -0
  239. package/src/thread/__tests__/mock.ts +95 -0
  240. package/src/thread/__tests__/thread.test.ts +1574 -0
  241. package/src/thread/index.ts +1 -0
  242. package/src/thread/thread.ts +611 -0
  243. package/src/thread/utils.ts +67 -0
  244. package/src/tool/__tests__/fixtures.ts +106 -0
  245. package/src/tool/__tests__/tool.test.ts +235 -0
  246. package/src/tool/__tests__/toolkit.test.ts +174 -0
  247. package/src/tool/index.ts +10 -0
  248. package/src/tool/tool.ts +264 -0
  249. package/src/tool/toolkit.ts +234 -0
  250. package/src/tool/types.ts +243 -0
  251. package/src/trace/processor.ts +0 -0
  252. package/src/trace/traces.ts +86 -0
  253. package/src/trace/utils.ts +38 -0
  254. package/src/types/agent.ts +145 -0
  255. package/src/types/thread.ts +86 -0
  256. package/tsconfig.json +13 -0
  257. package/vitest.config.ts +14 -0
package/dist/usage.js ADDED
@@ -0,0 +1,61 @@
1
+ import { UsageData } from "./types/thread";
2
+ /**
3
+ * Tracks token usage and request counts for an agent run.
4
+ */
5
+ export class Usage {
6
+ /**
7
+ * The number of requests made to the LLM API.
8
+ */
9
+ requests;
10
+ /**
11
+ * The number of input tokens used across all requests.
12
+ */
13
+ inputTokens;
14
+ /**
15
+ * The number of output tokens used across all requests.
16
+ */
17
+ outputTokens;
18
+ /**
19
+ * The total number of tokens sent and received, across all requests.
20
+ */
21
+ totalTokens;
22
+ /**
23
+ * Details about the input tokens used across all requests.
24
+ */
25
+ inputTokensDetails = [];
26
+ /**
27
+ * Details about the output tokens used across all requests.
28
+ */
29
+ outputTokensDetails = [];
30
+ constructor(input) {
31
+ if (typeof input === "undefined") {
32
+ this.requests = 0;
33
+ this.inputTokens = 0;
34
+ this.outputTokens = 0;
35
+ this.totalTokens = 0;
36
+ this.inputTokensDetails = [];
37
+ this.outputTokensDetails = [];
38
+ }
39
+ else {
40
+ this.requests = input?.requests ?? 1;
41
+ this.inputTokens = input?.inputTokens ?? input?.input_tokens ?? 0;
42
+ this.outputTokens = input?.outputTokens ?? input?.output_tokens ?? 0;
43
+ this.totalTokens = input?.totalTokens ?? input?.total_tokens ?? 0;
44
+ }
45
+ }
46
+ add(newUsage) {
47
+ this.requests += newUsage.requests;
48
+ this.inputTokens += newUsage.inputTokens;
49
+ this.outputTokens += newUsage.outputTokens;
50
+ this.totalTokens += newUsage.totalTokens;
51
+ if (newUsage.inputTokensDetails) {
52
+ // The type does not allow undefined, but it could happen runtime
53
+ this.inputTokensDetails.push(...newUsage.inputTokensDetails);
54
+ }
55
+ if (newUsage.outputTokensDetails) {
56
+ // The type does not allow undefined, but it could happen runtime
57
+ this.outputTokensDetails.push(...newUsage.outputTokensDetails);
58
+ }
59
+ }
60
+ }
61
+ export { UsageData };
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "kernl",
3
+ "version": "0.1.1",
4
+ "description": "A modern AI agent framework with MCP integration",
5
+ "keywords": [
6
+ "kernl",
7
+ "ai",
8
+ "agent",
9
+ "framework",
10
+ "mcp"
11
+ ],
12
+ "author": "dremnik",
13
+ "license": "MIT",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/dremnik/kernl.git",
17
+ "directory": "packages/kernl"
18
+ },
19
+ "homepage": "https://github.com/dremnik/kernl#readme",
20
+ "bugs": {
21
+ "url": "https://github.com/dremnik/kernl/issues"
22
+ },
23
+ "type": "module",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js"
28
+ }
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.20.2",
32
+ "pino": "^9.6.0",
33
+ "zod": "^4.1.12",
34
+ "@kernl/protocol": "0.1.1",
35
+ "@kernl/shared": "^0.1.1"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^24.10.0",
39
+ "tsc-alias": "^1.8.10",
40
+ "typescript": "5.9.2",
41
+ "vitest": "^4.0.8"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc && tsc-alias",
45
+ "dev": "tsc --watch",
46
+ "lint": "eslint src/",
47
+ "check-types": "tsc --noEmit",
48
+ "test": "vitest",
49
+ "test:watch": "vitest --watch",
50
+ "test:run": "vitest run"
51
+ }
52
+ }
package/src/agent.ts ADDED
@@ -0,0 +1,203 @@
1
+ import { LanguageModel, LanguageModelRequestSettings } from "@kernl/protocol";
2
+
3
+ import type { Context, UnknownContext } from "./context";
4
+ import { InputGuardrail, OutputGuardrail } from "./guardrail";
5
+ import { AgentHooks } from "./lifecycle";
6
+ import { Toolkit } from "./tool/toolkit";
7
+ import { Tool } from "./tool";
8
+ // import { DEFAULT_LANGUAGE_MODEL } from "@/providers/default";
9
+
10
+ import { MisconfiguredError } from "./lib/error";
11
+
12
+ import type { AgentConfig, AgentResponseType } from "./types/agent";
13
+ import { TextResponse } from "./types/thread";
14
+
15
+ export class Agent<
16
+ TContext = UnknownContext,
17
+ TResponse extends AgentResponseType = TextResponse,
18
+ >
19
+ extends AgentHooks<TContext, TResponse>
20
+ implements AgentConfig<TContext, TResponse>
21
+ {
22
+ id: string;
23
+ name: string;
24
+ instructions: (context: Context<TContext>) => Promise<string> | string;
25
+
26
+ model: LanguageModel;
27
+ modelSettings: LanguageModelRequestSettings;
28
+ toolkits: Toolkit<TContext>[];
29
+
30
+ // --- (TODO) ---
31
+ // handoffDescription: string; // ??
32
+ // handoffs: (Agent<any, TResponse> | Handoff<any, TResponse>)[];
33
+ // ----------
34
+
35
+ // /* Process/thread-group–wide signal state shared by all threads in the group: shared pending signals, job control
36
+ // (stops/cont, group exit), rlimits, etc. */
37
+ // signal: *struct signal_struct;
38
+ // /* Table of signal handlers (sa_handler, sa_mask, flags) shared by threads (CLONE_SIGHAND). RCU-protected so readers can access it locklessly. */
39
+ // sighand: *struct sighand_struct __rcu;
40
+
41
+ guardrails: {
42
+ input: InputGuardrail[];
43
+ output: OutputGuardrail<AgentResponseType>[];
44
+ };
45
+ responseType: TResponse = "text" as TResponse;
46
+ resetToolChoice: boolean;
47
+ // toolUseBehavior: ToolUseBehavior; (TODO)
48
+
49
+ // /**
50
+ // * Create an Agent with handoffs and automatically infer the union type for TResponse from the handoff agents' response types.
51
+ // */
52
+ // static create<
53
+ // TResponse extends AgentResponseType = TextResponse,
54
+ // Handoffs extends readonly (Agent<any, any> | Handoff<any, any>)[] = [],
55
+ // >(
56
+ // config: AgentConfigWithHandoffs<TResponse, Handoffs>,
57
+ // ): Agent<UnknownContext, TResponse | HandoffsOutputUnion<Handoffs>> {
58
+ // return new Agent<UnknownContext, TResponse | HandoffsOutputUnion<Handoffs>>(
59
+ // {
60
+ // ...config,
61
+ // handoffs: config.handoffs as any,
62
+ // responseType: config.responseType,
63
+ // handoffresponseTypeWarningEnabled: false,
64
+ // },
65
+ // );
66
+ // }
67
+
68
+ constructor(config: AgentConfig<TContext, TResponse>) {
69
+ super();
70
+ if (config.id.trim() === "") {
71
+ throw new MisconfiguredError("Agent must have an id.");
72
+ }
73
+ this.id = config.id;
74
+ this.name = config.name;
75
+ this.instructions =
76
+ typeof config.instructions === "function"
77
+ ? config.instructions
78
+ : () => config.instructions as string;
79
+ this.model = config.model as LanguageModel; // TODO: Add default model
80
+ this.modelSettings = config.modelSettings ?? {};
81
+
82
+ this.toolkits = config.toolkits ?? [];
83
+ for (const toolkit of this.toolkits) {
84
+ toolkit.bind(this);
85
+ }
86
+
87
+ this.guardrails = config.guardrails ?? { input: [], output: [] };
88
+ if (config.responseType) {
89
+ this.responseType = config.responseType;
90
+ }
91
+ this.resetToolChoice = config.resetToolChoice ?? true;
92
+ // this.toolUseBehavior = config.toolUseBehavior ?? "run_llm_again";
93
+
94
+ // this.handoffDescription = config.handoffDescription ?? "";
95
+ // this.handoffs = config.handoffs ?? [];
96
+
97
+ // --- Runtime warning for handoff response type compatibility ---
98
+ // if (
99
+ // config.handoffresponseTypeWarningEnabled === undefined ||
100
+ // config.handoffresponseTypeWarningEnabled
101
+ // ) {
102
+ // if (this.handoffs && this.responseType) {
103
+ // const responseTypes = new Set<string>([
104
+ // JSON.stringify(this.responseType),
105
+ // ]);
106
+ // for (const h of this.handoffs) {
107
+ // if ("responseType" in h && h.responseType) {
108
+ // responseTypes.add(JSON.stringify(h.responseType));
109
+ // } else if ("agent" in h && h.agent.responseType) {
110
+ // responseTypes.add(JSON.stringify(h.agent.responseType));
111
+ // }
112
+ // }
113
+ // if (responseTypes.size > 1) {
114
+ // logger.warn(
115
+ // `[Agent] Warning: Handoff agents have different response types: ${Array.from(responseTypes).join(", ")}. You can make it type-safe by using Agent.create({ ... }) method instead.`,
116
+ // );
117
+ // }
118
+ // }
119
+ // }
120
+ }
121
+
122
+ /**
123
+ * Get a specific tool by ID from all toolkits.
124
+ *
125
+ * @param id The tool ID to look up
126
+ * @returns The tool if found, undefined otherwise
127
+ */
128
+ tool(id: string): Tool<TContext> | undefined {
129
+ for (const toolkit of this.toolkits) {
130
+ const tool = toolkit.get(id);
131
+ if (tool) return tool;
132
+ }
133
+ return undefined;
134
+ }
135
+
136
+ /**
137
+ * Get all tools available from all toolkits for the given context.
138
+ * Checks for duplicate tool IDs across toolkits and throws an error if found.
139
+ *
140
+ * (TODO): Consider returning toolkits alongside tools so we can serialize them
141
+ * together and give agents more options for dealing with tool groups.
142
+ *
143
+ * @param context The context to use for filtering tools
144
+ * @returns Array of all available tools
145
+ * @throws {MisconfiguredError} If duplicate tool IDs are found across toolkits
146
+ */
147
+ async tools(context: Context<TContext>): Promise<Tool<TContext>[]> {
148
+ const allTools: Tool<TContext>[] = [];
149
+ const toolIds = new Set<string>();
150
+
151
+ for (const toolkit of this.toolkits) {
152
+ const tools = await toolkit.list(context);
153
+
154
+ const duplicates = tools.map((t) => t.id).filter((id) => toolIds.has(id));
155
+ if (duplicates.length > 0) {
156
+ throw new MisconfiguredError(
157
+ `Duplicate tool IDs found across toolkits: ${duplicates.join(", ")}`,
158
+ );
159
+ }
160
+
161
+ tools.forEach((t) => toolIds.add(t.id));
162
+ allTools.push(...tools);
163
+ }
164
+
165
+ return allTools;
166
+ }
167
+
168
+ // async run<TContext>(
169
+ // input: string,
170
+ // options: SharedRunOptions<TContext>,
171
+ // ): Promise<RunResult<TContext>> {
172
+ // // TODO
173
+ // // ...
174
+ // }
175
+
176
+ // async stream<TContext>(
177
+ // input: string,
178
+ // options: StreamOptions<TContext>,
179
+ // ): Promise<StreamedRunResult<TContext>> {
180
+ // // TODO
181
+ // // ...
182
+ // }
183
+ //
184
+
185
+ // ----------------------
186
+ // Events
187
+ // ----------------------
188
+
189
+ // on(event: any, handler: Function): void {
190
+ // // TODO
191
+ // // ...
192
+ // }
193
+
194
+ // once(event: any, handler: Function): void {
195
+ // // TODO
196
+ // // ...
197
+ // }
198
+
199
+ // off(event: any, handler: Function): void {
200
+ // // TODO
201
+ // // ...
202
+ // }
203
+ }
package/src/context.ts ADDED
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Status of a tool call approval.
3
+ */
4
+ export type ApprovalStatus = "approved" | "rejected" | "pending";
5
+
6
+ /**
7
+ * A propagation mechanism which carries execution-scoped values across API boundaries and between logically associated
8
+ * execution units.
9
+ */
10
+ export class Context<TContext = UnknownContext> {
11
+ /**
12
+ * The inner context object.
13
+ */
14
+ context: TContext;
15
+
16
+ // ----------------------
17
+ // TEMPORARY: Tool approval tracking until actions system is refined
18
+ // ----------------------
19
+
20
+ /**
21
+ * Map of tool call IDs to their approval status.
22
+ * (TEMPORARY) Used until the actions system is refined.
23
+ */
24
+ approvals: Map<string, ApprovalStatus>;
25
+
26
+ /**
27
+ * Approve a tool call by its call ID.
28
+ * (TEMPORARY) Used until the actions system is refined.
29
+ */
30
+ approve(callId: string): void {
31
+ this.approvals.set(callId, "approved");
32
+ }
33
+
34
+ /**
35
+ * Reject a tool call by its call ID.
36
+ * (TEMPORARY) Used until the actions system is refined.
37
+ */
38
+ reject(callId: string): void {
39
+ this.approvals.set(callId, "rejected");
40
+ }
41
+
42
+ // ----------------------
43
+ // End temporary approval tracking
44
+ // ----------------------
45
+
46
+ // /**
47
+ // * Serialization format in which to render the context to the agent
48
+ // */
49
+ // private format: "md" | "yaml" | "json" | "html" | "xml";
50
+
51
+ // /**
52
+ // * The usage of the agent run so far. For streamed responses, the usage will be stale until the
53
+ // * last chunk of the stream is processed.
54
+ // */
55
+ // usage: Usage;
56
+
57
+ // /**
58
+ // * A map of tool names to whether they have been approved.
59
+ // */
60
+ // #approvals: Map<string, ApprovalRecord>;
61
+
62
+ constructor(context: TContext = {} as TContext) {
63
+ this.context = context;
64
+ this.approvals = new Map();
65
+ // this.format = format; // (TODO): configure()
66
+ // this.usage = new Usage();
67
+ // this.#approvals = new Map();
68
+ }
69
+
70
+ /**
71
+ * Renders the context as a prompt using the default format selected. Kernel would inject this info automatically, but exposed in case of control
72
+ */
73
+ render(self: Context<TContext>): string {
74
+ throw new Error("UNIMPLEMENTED");
75
+ // switch (self.format) {
76
+ // case "yaml":
77
+ // return self.yaml();
78
+ // // case "json":
79
+ // // return self.json();
80
+ // // case "xml":
81
+ // // return self.xml();
82
+ // case "md":
83
+ // default:
84
+ // return self.md();
85
+ // }
86
+ }
87
+
88
+ /**
89
+ * Render the context object as a markdown string:
90
+ *
91
+ * <context>
92
+ * <user>
93
+ * <name>John</name>
94
+ * <email>john@gmail.com</email>
95
+ * </user>
96
+ * <org>
97
+ * <id>org_235234523</id>
98
+ * <name>Acme Corp.<name>
99
+ * </org>
100
+ * </context>
101
+ *
102
+ */
103
+ md(): string {
104
+ throw new Error("UNIMPLEMENTED");
105
+ }
106
+
107
+ /**
108
+ * Render the context object as a yaml string:
109
+ *
110
+ * context:
111
+ * user:
112
+ * name: John
113
+ * email: john@gmail.com
114
+ * org:
115
+ * id: org_235234523
116
+ * name: Acme Corp.
117
+ */
118
+ yaml(): string {
119
+ throw new Error("UNIMPLEMENTED");
120
+ }
121
+
122
+ toJSON(): {
123
+ context: any;
124
+ // usage: Usage;
125
+ // approvals: Record<string, ApprovalRecord>;
126
+ } {
127
+ return {
128
+ context: this.context,
129
+ // usage: this.usage,
130
+ // approvals: Object.fromEntries(this.#approvals.entries()),
131
+ };
132
+ }
133
+
134
+ // /**
135
+ // * Rebuild the approvals map from a serialized state.
136
+ // * @internal
137
+ // *
138
+ // * @param approvals - The approvals map to rebuild.
139
+ // */
140
+ // _rebuildApprovals(approvals: Record<string, ApprovalRecord>) {
141
+ // this.#approvals = new Map(Object.entries(approvals));
142
+ // }
143
+
144
+ // /**
145
+ // * Check if a tool call has been approved.
146
+ // *
147
+ // * @param approval - Details about the tool call being evaluated.
148
+ // * @returns `true` if the tool call has been approved, `false` if blocked and `undefined` if not yet approved or rejected.
149
+ // */
150
+ // isToolApproved(approval: { toolName: string; callId: string }) {
151
+ // const { toolName, callId } = approval;
152
+ // const approvalEntry = this.#approvals.get(toolName);
153
+ // if (approvalEntry?.approved === true && approvalEntry.rejected === true) {
154
+ // logger.warn(
155
+ // "Tool is permanently approved and rejected at the same time. Approval takes precedence",
156
+ // );
157
+ // return true;
158
+ // }
159
+
160
+ // if (approvalEntry?.approved === true) {
161
+ // return true;
162
+ // }
163
+
164
+ // if (approvalEntry?.rejected === true) {
165
+ // return false;
166
+ // }
167
+
168
+ // const individualCallApproval = Array.isArray(approvalEntry?.approved)
169
+ // ? approvalEntry.approved.includes(callId)
170
+ // : false;
171
+ // const individualCallRejection = Array.isArray(approvalEntry?.rejected)
172
+ // ? approvalEntry.rejected.includes(callId)
173
+ // : false;
174
+
175
+ // if (individualCallApproval && individualCallRejection) {
176
+ // logger.warn(
177
+ // `Tool call ${callId} is both approved and rejected at the same time. Approval takes precedence`,
178
+ // );
179
+ // return true;
180
+ // }
181
+
182
+ // if (individualCallApproval) {
183
+ // return true;
184
+ // }
185
+
186
+ // if (individualCallRejection) {
187
+ // return false;
188
+ // }
189
+
190
+ // return undefined;
191
+ // }
192
+
193
+ // /**
194
+ // * Approve a tool call.
195
+ // *
196
+ // * @param approvalItem - The tool approval item to approve.
197
+ // * @param options - Additional approval behavior options.
198
+ // */
199
+ // approveTool(
200
+ // approvalItem: RunToolApprovalItem,
201
+ // { alwaysApprove = false }: { alwaysApprove?: boolean } = {},
202
+ // ) {
203
+ // const toolName = approvalItem.rawItem.name;
204
+ // if (alwaysApprove) {
205
+ // this.#approvals.set(toolName, {
206
+ // approved: true,
207
+ // rejected: [],
208
+ // });
209
+ // return;
210
+ // }
211
+
212
+ // const approvalEntry = this.#approvals.get(toolName) ?? {
213
+ // approved: [],
214
+ // rejected: [],
215
+ // };
216
+ // if (Array.isArray(approvalEntry.approved)) {
217
+ // // function tool has call_id, hosted tool call has id
218
+ // const callId =
219
+ // "callId" in approvalItem.rawItem
220
+ // ? approvalItem.rawItem.callId // function tools
221
+ // : approvalItem.rawItem.id!; // hosted tools
222
+ // approvalEntry.approved.push(callId);
223
+ // }
224
+ // this.#approvals.set(toolName, approvalEntry);
225
+ // }
226
+
227
+ // /**
228
+ // * Reject a tool call.
229
+ // *
230
+ // * @param approvalItem - The tool approval item to reject.
231
+ // */
232
+ // rejectTool(
233
+ // approvalItem: RunToolApprovalItem,
234
+ // { alwaysReject = false }: { alwaysReject?: boolean } = {},
235
+ // ) {
236
+ // const toolName = approvalItem.rawItem.name;
237
+ // if (alwaysReject) {
238
+ // this.#approvals.set(toolName, {
239
+ // approved: false,
240
+ // rejected: true,
241
+ // });
242
+ // return;
243
+ // }
244
+
245
+ // const approvalEntry = this.#approvals.get(toolName) ?? {
246
+ // approved: [] as string[],
247
+ // rejected: [] as string[],
248
+ // };
249
+
250
+ // if (Array.isArray(approvalEntry.rejected)) {
251
+ // // function tool has call_id, hosted tool call has id
252
+ // const callId =
253
+ // "callId" in approvalItem.rawItem
254
+ // ? approvalItem.rawItem.callId // function tools
255
+ // : approvalItem.rawItem.id!; // hosted tools
256
+ // approvalEntry.rejected.push(callId);
257
+ // }
258
+ // this.#approvals.set(toolName, approvalEntry);
259
+ // }
260
+ }
261
+
262
+ /**
263
+ * Context that is being passed around as part of the session is unknown
264
+ */
265
+ export type UnknownContext = unknown;