kernl 0.1.3 → 0.2.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.
Files changed (58) hide show
  1. package/.turbo/turbo-build.log +5 -4
  2. package/CHANGELOG.md +18 -0
  3. package/dist/agent.d.ts +20 -3
  4. package/dist/agent.d.ts.map +1 -1
  5. package/dist/agent.js +60 -41
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/kernl.d.ts +27 -1
  10. package/dist/kernl.d.ts.map +1 -1
  11. package/dist/kernl.js +36 -2
  12. package/dist/mcp/__tests__/integration.test.js +16 -0
  13. package/dist/thread/__tests__/fixtures/mock-model.d.ts +7 -0
  14. package/dist/thread/__tests__/fixtures/mock-model.d.ts.map +1 -0
  15. package/dist/thread/__tests__/fixtures/mock-model.js +59 -0
  16. package/dist/thread/__tests__/integration.test.d.ts +2 -0
  17. package/dist/thread/__tests__/integration.test.d.ts.map +1 -0
  18. package/dist/thread/__tests__/integration.test.js +247 -0
  19. package/dist/thread/__tests__/stream.test.d.ts +2 -0
  20. package/dist/thread/__tests__/stream.test.d.ts.map +1 -0
  21. package/dist/thread/__tests__/stream.test.js +244 -0
  22. package/dist/thread/__tests__/thread.test.js +612 -763
  23. package/dist/thread/thread.d.ts +30 -25
  24. package/dist/thread/thread.d.ts.map +1 -1
  25. package/dist/thread/thread.js +114 -314
  26. package/dist/thread/utils.d.ts +16 -1
  27. package/dist/thread/utils.d.ts.map +1 -1
  28. package/dist/thread/utils.js +30 -0
  29. package/dist/tool/index.d.ts +1 -1
  30. package/dist/tool/index.d.ts.map +1 -1
  31. package/dist/tool/index.js +1 -1
  32. package/dist/tool/tool.d.ts.map +1 -1
  33. package/dist/tool/tool.js +6 -2
  34. package/dist/tool/toolkit.d.ts +13 -3
  35. package/dist/tool/toolkit.d.ts.map +1 -1
  36. package/dist/tool/toolkit.js +11 -3
  37. package/dist/tool/types.d.ts +8 -0
  38. package/dist/tool/types.d.ts.map +1 -1
  39. package/dist/types/agent.d.ts +5 -5
  40. package/dist/types/agent.d.ts.map +1 -1
  41. package/dist/types/thread.d.ts +10 -16
  42. package/dist/types/thread.d.ts.map +1 -1
  43. package/package.json +6 -4
  44. package/src/agent.ts +97 -86
  45. package/src/index.ts +1 -1
  46. package/src/kernl.ts +51 -2
  47. package/src/mcp/__tests__/integration.test.ts +17 -0
  48. package/src/thread/__tests__/fixtures/mock-model.ts +71 -0
  49. package/src/thread/__tests__/integration.test.ts +349 -0
  50. package/src/thread/__tests__/thread.test.ts +625 -775
  51. package/src/thread/thread.ts +134 -381
  52. package/src/thread/utils.ts +36 -1
  53. package/src/tool/index.ts +1 -1
  54. package/src/tool/tool.ts +6 -2
  55. package/src/tool/toolkit.ts +19 -3
  56. package/src/tool/types.ts +10 -0
  57. package/src/types/agent.ts +9 -6
  58. package/src/types/thread.ts +25 -17
@@ -1,4 +1,5 @@
1
-
2
- > kernl@0.1.3 build /Users/andjones/Documents/projects/kernl/packages/kernl
3
- > tsc && tsc-alias
4
-
1
+
2
+ 
3
+ > kernl@0.1.4 build /Users/andjones/Documents/projects/kernl/packages/kernl
4
+ > tsc && tsc-alias
5
+
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @kernl/core
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 91b1285: Add agent.run() and agent.stream() convenience methods for thread execution. Kernl now mediates all thread lifecycle with spawn/schedule methods.
8
+ - fffa89e: Refactor thread execution to support streaming and fix tool schema serialization. Adds new `stream()` method for async iteration over thread events, fixes tool parameter schemas to use JSON Schema instead of raw Zod schemas.
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [fffa89e]
13
+ - @kernl-sdk/protocol@0.2.0
14
+
15
+ ## 0.1.4
16
+
17
+ ### Patch Changes
18
+
19
+ - Add description field to Toolkit base class and implementations
20
+
3
21
  ## 0.1.3
4
22
 
5
23
  ### Patch Changes
package/dist/agent.d.ts CHANGED
@@ -2,17 +2,20 @@ import { LanguageModel, LanguageModelRequestSettings } from "@kernl-sdk/protocol
2
2
  import type { Context, UnknownContext } from "./context";
3
3
  import { InputGuardrail, OutputGuardrail } from "./guardrail";
4
4
  import { AgentHooks } from "./lifecycle";
5
- import { Toolkit } from "./tool/toolkit";
5
+ import { BaseToolkit } from "./tool/toolkit";
6
6
  import { Tool } from "./tool";
7
7
  import type { AgentConfig, AgentResponseType } from "./types/agent";
8
- import { TextResponse } from "./types/thread";
8
+ import type { TextResponse, ThreadOptions, ThreadExecuteResult, ThreadStreamEvent } from "./types/thread";
9
+ import type { Kernl } from "./kernl";
10
+ import type { ResolvedAgentResponse } from "./guardrail";
9
11
  export declare class Agent<TContext = UnknownContext, TResponse extends AgentResponseType = TextResponse> extends AgentHooks<TContext, TResponse> implements AgentConfig<TContext, TResponse> {
12
+ private kernl?;
10
13
  id: string;
11
14
  name: string;
12
15
  instructions: (context: Context<TContext>) => Promise<string> | string;
13
16
  model: LanguageModel;
14
17
  modelSettings: LanguageModelRequestSettings;
15
- toolkits: Toolkit<TContext>[];
18
+ toolkits: BaseToolkit<TContext>[];
16
19
  guardrails: {
17
20
  input: InputGuardrail[];
18
21
  output: OutputGuardrail<AgentResponseType>[];
@@ -20,6 +23,20 @@ export declare class Agent<TContext = UnknownContext, TResponse extends AgentRes
20
23
  responseType: TResponse;
21
24
  resetToolChoice: boolean;
22
25
  constructor(config: AgentConfig<TContext, TResponse>);
26
+ /**
27
+ * Bind this agent to a kernl instance. Called by kernl.register().
28
+ */
29
+ bind(kernl: Kernl): void;
30
+ /**
31
+ * Blocking execution - spawns or resumes thread and waits for completion
32
+ */
33
+ run(instructions: string, options?: ThreadOptions<TContext>): Promise<ThreadExecuteResult<ResolvedAgentResponse<TResponse>>>;
34
+ /**
35
+ * Streaming execution - spawns or resumes thread and returns async iterator
36
+ *
37
+ * NOTE: streaming probably won't make sense in scheduling contexts so spawnStream etc. won't make sense
38
+ */
39
+ stream(instructions: string, options?: ThreadOptions<TContext>): AsyncIterable<ThreadStreamEvent>;
23
40
  /**
24
41
  * Get a specific tool by ID from all toolkits.
25
42
  *
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAElF,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAK9B,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,qBAAa,KAAK,CACd,QAAQ,GAAG,cAAc,EACzB,SAAS,SAAS,iBAAiB,GAAG,YAAY,CAEpD,SAAQ,UAAU,CAAC,QAAQ,EAAE,SAAS,CACtC,YAAW,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC;IAE3C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAEvE,KAAK,EAAE,aAAa,CAAC;IACrB,aAAa,EAAE,4BAA4B,CAAC;IAC5C,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IAa9B,UAAU,EAAE;QACV,KAAK,EAAE,cAAc,EAAE,CAAC;QACxB,MAAM,EAAE,eAAe,CAAC,iBAAiB,CAAC,EAAE,CAAC;KAC9C,CAAC;IACF,YAAY,EAAE,SAAS,CAAuB;IAC9C,eAAe,EAAE,OAAO,CAAC;gBAsBb,MAAM,EAAE,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC;IAsDpD;;;;;OAKG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,SAAS;IAQ5C;;;;;;;;;;OAUG;IACG,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;CAwDnE"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,4BAA4B,EAE7B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAK9B,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,qBAAa,KAAK,CACd,QAAQ,GAAG,cAAc,EACzB,SAAS,SAAS,iBAAiB,GAAG,YAAY,CAEpD,SAAQ,UAAU,CAAC,QAAQ,EAAE,SAAS,CACtC,YAAW,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC;IAE3C,OAAO,CAAC,KAAK,CAAC,CAAQ;IAEtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAEvE,KAAK,EAAE,aAAa,CAAC;IACrB,aAAa,EAAE,4BAA4B,CAAC;IAC5C,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;IAClC,UAAU,EAAE;QACV,KAAK,EAAE,cAAc,EAAE,CAAC;QACxB,MAAM,EAAE,eAAe,CAAC,iBAAiB,CAAC,EAAE,CAAC;KAC9C,CAAC;IACF,YAAY,EAAE,SAAS,CAAuB;IAC9C,eAAe,EAAE,OAAO,CAAC;gBAgBb,MAAM,EAAE,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC;IA0CpD;;OAEG;IACH,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAIxB;;OAEG;IACG,GAAG,CACP,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,GAChC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAC;IAqBjE;;;;OAIG;IACI,MAAM,CACX,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,GAChC,aAAa,CAAC,iBAAiB,CAAC;IAsBnC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,SAAS;IAQ5C;;;;;;;;;;OAUG;IACG,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;CAoBnE"}
package/dist/agent.js CHANGED
@@ -1,13 +1,19 @@
1
+ import { message, } from "@kernl-sdk/protocol";
1
2
  import { AgentHooks } from "./lifecycle";
2
- // import { DEFAULT_LANGUAGE_MODEL } from "./providers/default";
3
+ import { Thread } from "./thread";
3
4
  import { MisconfiguredError } from "./lib/error";
4
5
  export class Agent extends AgentHooks {
6
+ kernl;
5
7
  id;
6
8
  name;
7
9
  instructions;
8
10
  model;
9
11
  modelSettings;
10
12
  toolkits;
13
+ guardrails;
14
+ responseType = "text";
15
+ resetToolChoice;
16
+ // toolUseBehavior: ToolUseBehavior; (TODO)
11
17
  // --- (TODO) ---
12
18
  // handoffDescription: string; // ??
13
19
  // handoffs: (Agent<any, TResponse> | Handoff<any, TResponse>)[];
@@ -15,30 +21,10 @@ export class Agent extends AgentHooks {
15
21
  // /* Process/thread-group–wide signal state shared by all threads in the group: shared pending signals, job control
16
22
  // (stops/cont, group exit), rlimits, etc. */
17
23
  // signal: *struct signal_struct;
18
- // /* Table of signal handlers (sa_handler, sa_mask, flags) shared by threads (CLONE_SIGHAND). RCU-protected so readers can access it locklessly. */
24
+ //
25
+ // /* Table of signal handlers (sa_handler, sa_mask, flags) shared by threads
26
+ // (CLONE_SIGHAND). RCU-protected so readers can access it locklessly. */
19
27
  // sighand: *struct sighand_struct __rcu;
20
- guardrails;
21
- responseType = "text";
22
- resetToolChoice;
23
- // toolUseBehavior: ToolUseBehavior; (TODO)
24
- // /**
25
- // * Create an Agent with handoffs and automatically infer the union type for TResponse from the handoff agents' response types.
26
- // */
27
- // static create<
28
- // TResponse extends AgentResponseType = TextResponse,
29
- // Handoffs extends readonly (Agent<any, any> | Handoff<any, any>)[] = [],
30
- // >(
31
- // config: AgentConfigWithHandoffs<TResponse, Handoffs>,
32
- // ): Agent<UnknownContext, TResponse | HandoffsOutputUnion<Handoffs>> {
33
- // return new Agent<UnknownContext, TResponse | HandoffsOutputUnion<Handoffs>>(
34
- // {
35
- // ...config,
36
- // handoffs: config.handoffs as any,
37
- // responseType: config.responseType,
38
- // handoffresponseTypeWarningEnabled: false,
39
- // },
40
- // );
41
- // }
42
28
  constructor(config) {
43
29
  super();
44
30
  if (config.id.trim() === "") {
@@ -50,7 +36,7 @@ export class Agent extends AgentHooks {
50
36
  typeof config.instructions === "function"
51
37
  ? config.instructions
52
38
  : () => config.instructions;
53
- this.model = config.model; // TODO: Add default model
39
+ this.model = config.model; // (TODO): include optional default setting for convenience like env.DEFAULT_LLM = "gpt-5"
54
40
  this.modelSettings = config.modelSettings ?? {};
55
41
  this.toolkits = config.toolkits ?? [];
56
42
  for (const toolkit of this.toolkits) {
@@ -65,29 +51,62 @@ export class Agent extends AgentHooks {
65
51
  // this.handoffDescription = config.handoffDescription ?? "";
66
52
  // this.handoffs = config.handoffs ?? [];
67
53
  // --- Runtime warning for handoff response type compatibility ---
68
- // if (
69
- // config.handoffresponseTypeWarningEnabled === undefined ||
70
- // config.handoffresponseTypeWarningEnabled
71
- // ) {
72
- // if (this.handoffs && this.responseType) {
73
- // const responseTypes = new Set<string>([
74
- // JSON.stringify(this.responseType),
75
- // ]);
76
- // for (const h of this.handoffs) {
77
- // if ("responseType" in h && h.responseType) {
78
- // responseTypes.add(JSON.stringify(h.responseType));
79
- // } else if ("agent" in h && h.agent.responseType) {
80
- // responseTypes.add(JSON.stringify(h.agent.responseType));
81
- // }
82
- // }
54
+ // if (config.handoffresponseTypeWarningEnabled) {
55
+ // ...
83
56
  // if (responseTypes.size > 1) {
84
57
  // logger.warn(
85
- // `[Agent] Warning: Handoff agents have different response types: ${Array.from(responseTypes).join(", ")}. You can make it type-safe by using Agent.create({ ... }) method instead.`,
58
+ // `[Agent] Warning: Handoff agents have different response types: ${Array.from(responseTypes).join(", ")}.
59
+ // You can make it type-safe by using Agent.create({ ... }) method instead.`,
86
60
  // );
87
61
  // }
88
62
  // }
89
63
  // }
90
64
  }
65
+ /**
66
+ * Bind this agent to a kernl instance. Called by kernl.register().
67
+ */
68
+ bind(kernl) {
69
+ this.kernl = kernl;
70
+ }
71
+ /**
72
+ * Blocking execution - spawns or resumes thread and waits for completion
73
+ */
74
+ async run(instructions, options) {
75
+ if (!this.kernl) {
76
+ throw new MisconfiguredError(`Agent ${this.id} not bound to kernl. Call kernl.register(agent) first.`);
77
+ }
78
+ const m = message({ role: "user", text: instructions });
79
+ const tid = options?.threadId;
80
+ // NOTE: may end up moving this to the kernl
81
+ let thread = tid ? this.kernl.threads.get(tid) : null;
82
+ if (!thread) {
83
+ thread = new Thread(this.kernl, this, [m], options);
84
+ return this.kernl.spawn(thread);
85
+ }
86
+ thread.append(m);
87
+ return this.kernl.schedule(thread);
88
+ }
89
+ /**
90
+ * Streaming execution - spawns or resumes thread and returns async iterator
91
+ *
92
+ * NOTE: streaming probably won't make sense in scheduling contexts so spawnStream etc. won't make sense
93
+ */
94
+ async *stream(instructions, options) {
95
+ if (!this.kernl) {
96
+ throw new MisconfiguredError(`Agent ${this.id} not bound to kernl. Call kernl.register(agent) first.`);
97
+ }
98
+ const m = message({ role: "user", text: instructions });
99
+ const tid = options?.threadId;
100
+ // NOTE: may end up moving this to the kernl
101
+ let thread = tid ? this.kernl.threads.get(tid) : null;
102
+ if (!thread) {
103
+ thread = new Thread(this.kernl, this, [m], options);
104
+ yield* this.kernl.spawnStream(thread);
105
+ return;
106
+ }
107
+ thread.append(m);
108
+ yield* this.kernl.scheduleStream(thread);
109
+ }
91
110
  /**
92
111
  * Get a specific tool by ID from all toolkits.
93
112
  *
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { Kernl } from "./kernl";
2
2
  export { Agent } from "./agent";
3
3
  export type { Context } from "./context";
4
- export { tool, FunctionToolkit, MCPToolkit } from "./tool";
4
+ export { tool, Toolkit, FunctionToolkit, MCPToolkit } from "./tool";
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { Kernl } from "./kernl";
2
2
  export { Agent } from "./agent";
3
- export { tool, FunctionToolkit, MCPToolkit } from "./tool";
3
+ export { tool, Toolkit, FunctionToolkit, MCPToolkit } from "./tool";
package/dist/kernl.d.ts CHANGED
@@ -1,18 +1,44 @@
1
1
  import { Agent } from "./agent";
2
2
  import { UnknownContext } from "./context";
3
3
  import { KernlHooks } from "./lifecycle";
4
+ import type { Thread } from "./thread";
4
5
  import type { AgentResponseType } from "./types/agent";
6
+ import type { ThreadExecuteResult, ThreadStreamEvent } from "./types/thread";
7
+ import type { ResolvedAgentResponse } from "./guardrail";
5
8
  /**
6
- * Central coordinator for the entire application.
9
+ * The kernl - manages agent processes, scheduling, and task lifecycle
7
10
  *
8
11
  * Orchestrates agent execution, including guardrails, tool calls, session persistence, and
9
12
  * tracing.
10
13
  */
11
14
  export declare class Kernl extends KernlHooks<UnknownContext, AgentResponseType> {
12
15
  private agents;
16
+ threads: Map<string, Thread<any, any>>;
13
17
  /**
14
18
  * Registers a new agent with the kernl instance.
15
19
  */
16
20
  register(agent: Agent): void;
21
+ /**
22
+ * Spawn a new thread - blocking execution
23
+ */
24
+ spawn<TContext, TResponse extends AgentResponseType>(thread: Thread<TContext, TResponse>): Promise<ThreadExecuteResult<ResolvedAgentResponse<TResponse>>>;
25
+ /**
26
+ * Schedule an existing thread - blocking execution
27
+ *
28
+ * NOTE: just blocks for now
29
+ */
30
+ schedule<TContext, TResponse extends AgentResponseType>(thread: Thread<TContext, TResponse>): Promise<ThreadExecuteResult<ResolvedAgentResponse<TResponse>>>;
31
+ /**
32
+ * (TMP) - probably won't make sense with assync scheduling contexts
33
+ *
34
+ * Spawn a new thread - streaming execution
35
+ */
36
+ spawnStream<TContext, TResponse extends AgentResponseType>(thread: Thread<TContext, TResponse>): AsyncIterable<ThreadStreamEvent>;
37
+ /**
38
+ * (TMP) - probably won't make sense with assync scheduling contexts
39
+ *
40
+ * Schedule an existing thread - streaming execution
41
+ */
42
+ scheduleStream<TContext, TResponse extends AgentResponseType>(thread: Thread<TContext, TResponse>): AsyncIterable<ThreadStreamEvent>;
17
43
  }
18
44
  //# sourceMappingURL=kernl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kernl.d.ts","sourceRoot":"","sources":["../src/kernl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD;;;;;GAKG;AACH,qBAAa,KAAM,SAAQ,UAAU,CAAC,cAAc,EAAE,iBAAiB,CAAC;IACtE,OAAO,CAAC,MAAM,CAAiC;IAE/C;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAG7B"}
1
+ {"version":3,"file":"kernl.d.ts","sourceRoot":"","sources":["../src/kernl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD;;;;;GAKG;AACH,qBAAa,KAAM,SAAQ,UAAU,CAAC,cAAc,EAAE,iBAAiB,CAAC;IACtE,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAa;IAEnD;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAK5B;;OAEG;IACG,KAAK,CAAC,QAAQ,EAAE,SAAS,SAAS,iBAAiB,EACvD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,GAClC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAC;IAKjE;;;;OAIG;IACG,QAAQ,CAAC,QAAQ,EAAE,SAAS,SAAS,iBAAiB,EAC1D,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,GAClC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAC;IAIjE;;;;OAIG;IACI,WAAW,CAAC,QAAQ,EAAE,SAAS,SAAS,iBAAiB,EAC9D,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,GAClC,aAAa,CAAC,iBAAiB,CAAC;IAKnC;;;;OAIG;IACI,cAAc,CAAC,QAAQ,EAAE,SAAS,SAAS,iBAAiB,EACjE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,GAClC,aAAa,CAAC,iBAAiB,CAAC;CAGpC"}
package/dist/kernl.js CHANGED
@@ -1,16 +1,50 @@
1
1
  import { KernlHooks } from "./lifecycle";
2
2
  /**
3
- * Central coordinator for the entire application.
3
+ * The kernl - manages agent processes, scheduling, and task lifecycle
4
4
  *
5
5
  * Orchestrates agent execution, including guardrails, tool calls, session persistence, and
6
6
  * tracing.
7
7
  */
8
8
  export class Kernl extends KernlHooks {
9
9
  agents = new Map();
10
+ threads = new Map();
10
11
  /**
11
12
  * Registers a new agent with the kernl instance.
12
13
  */
13
14
  register(agent) {
14
- // TODO: Implement agent registration
15
+ this.agents.set(agent.id, agent);
16
+ agent.bind(this);
17
+ }
18
+ /**
19
+ * Spawn a new thread - blocking execution
20
+ */
21
+ async spawn(thread) {
22
+ this.threads.set(thread.id, thread);
23
+ return await thread.execute();
24
+ }
25
+ /**
26
+ * Schedule an existing thread - blocking execution
27
+ *
28
+ * NOTE: just blocks for now
29
+ */
30
+ async schedule(thread) {
31
+ return await thread.execute();
32
+ }
33
+ /**
34
+ * (TMP) - probably won't make sense with assync scheduling contexts
35
+ *
36
+ * Spawn a new thread - streaming execution
37
+ */
38
+ async *spawnStream(thread) {
39
+ this.threads.set(thread.id, thread);
40
+ yield* thread.stream();
41
+ }
42
+ /**
43
+ * (TMP) - probably won't make sense with assync scheduling contexts
44
+ *
45
+ * Schedule an existing thread - streaming execution
46
+ */
47
+ async *scheduleStream(thread) {
48
+ yield* thread.stream();
15
49
  }
16
50
  }
@@ -8,7 +8,15 @@ import { Context } from "../../context";
8
8
  import { tool } from "../../tool";
9
9
  import { z } from "zod";
10
10
  import { createMCPToolStaticFilter } from "../utils";
11
+ import { createMockModel } from "../../thread/__tests__/fixtures/mock-model";
11
12
  const TEST_SERVER = path.join(__dirname, "fixtures", "server.ts");
13
+ // Mock model for tests that only need toolkit functionality
14
+ const mockModel = createMockModel(async () => ({
15
+ content: [],
16
+ finishReason: "stop",
17
+ usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
18
+ warnings: [],
19
+ }));
12
20
  describe("MCP Integration Tests", () => {
13
21
  describe("MCPToolkit Integration", () => {
14
22
  let server;
@@ -128,6 +136,7 @@ describe("MCP Integration Tests", () => {
128
136
  id: "test-agent",
129
137
  name: "Test Agent",
130
138
  instructions: "Test",
139
+ model: mockModel,
131
140
  toolkits: [toolkit],
132
141
  });
133
142
  const context = new Context({});
@@ -158,6 +167,7 @@ describe("MCP Integration Tests", () => {
158
167
  id: "test-agent",
159
168
  name: "Test Agent",
160
169
  instructions: "Test",
170
+ model: mockModel,
161
171
  toolkits: [toolkit],
162
172
  });
163
173
  const context = new Context({});
@@ -189,6 +199,7 @@ describe("MCP Integration Tests", () => {
189
199
  id: "test-agent",
190
200
  name: "Test Agent",
191
201
  instructions: "Test",
202
+ model: mockModel,
192
203
  toolkits: [toolkit],
193
204
  });
194
205
  const context = new Context({ userId: "test-user" });
@@ -216,6 +227,7 @@ describe("MCP Integration Tests", () => {
216
227
  id: "test-agent",
217
228
  name: "Test Agent",
218
229
  instructions: "Test",
230
+ model: mockModel,
219
231
  toolkits: [mcpToolkit],
220
232
  });
221
233
  const context = new Context({});
@@ -239,6 +251,7 @@ describe("MCP Integration Tests", () => {
239
251
  id: "test-agent",
240
252
  name: "Test Agent",
241
253
  instructions: "Test",
254
+ model: mockModel,
242
255
  toolkits: [mcpToolkit],
243
256
  });
244
257
  // Populate toolkit cache
@@ -264,6 +277,7 @@ describe("MCP Integration Tests", () => {
264
277
  id: "test-agent",
265
278
  name: "Test Agent",
266
279
  instructions: "Test",
280
+ model: mockModel,
267
281
  toolkits: [mcpToolkit],
268
282
  });
269
283
  const context = new Context({});
@@ -308,6 +322,7 @@ describe("MCP Integration Tests", () => {
308
322
  id: "test-agent",
309
323
  name: "Test Agent",
310
324
  instructions: "Test",
325
+ model: mockModel,
311
326
  toolkits: [mcpToolkit, functionToolkit],
312
327
  });
313
328
  const context = new Context({});
@@ -349,6 +364,7 @@ describe("MCP Integration Tests", () => {
349
364
  id: "test-agent",
350
365
  name: "Test Agent",
351
366
  instructions: "Test",
367
+ model: mockModel,
352
368
  toolkits: [mcpToolkit, functionToolkit],
353
369
  });
354
370
  const context = new Context({});
@@ -0,0 +1,7 @@
1
+ import type { LanguageModel, LanguageModelRequest, LanguageModelResponse } from "@kernl-sdk/protocol";
2
+ /**
3
+ * Creates a mock LanguageModel that automatically implements streaming
4
+ * based on the generate() implementation.
5
+ */
6
+ export declare function createMockModel(generateFn: (req: LanguageModelRequest) => Promise<LanguageModelResponse>): LanguageModel;
7
+ //# sourceMappingURL=mock-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-model.d.ts","sourceRoot":"","sources":["../../../../src/thread/__tests__/fixtures/mock-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EAGtB,MAAM,qBAAqB,CAAC;AA+C7B;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,CAAC,GAAG,EAAE,oBAAoB,KAAK,OAAO,CAAC,qBAAqB,CAAC,GACxE,aAAa,CAWf"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Helper to convert LanguageModelResponse content to stream events.
3
+ * Yields both delta events (for streaming UX) and complete items (for history).
4
+ */
5
+ async function* streamFromResponse(response) {
6
+ for (const item of response.content) {
7
+ if (item.kind === "message") {
8
+ // Stream message with text deltas
9
+ for (const contentItem of item.content) {
10
+ if (contentItem.kind === "text") {
11
+ // Yield text-start
12
+ yield {
13
+ kind: "text-start",
14
+ id: item.id,
15
+ };
16
+ // Yield text-delta
17
+ yield {
18
+ kind: "text-delta",
19
+ id: item.id,
20
+ text: contentItem.text,
21
+ };
22
+ // Yield text-end
23
+ yield {
24
+ kind: "text-end",
25
+ id: item.id,
26
+ };
27
+ }
28
+ }
29
+ // Yield complete message
30
+ yield item;
31
+ }
32
+ else {
33
+ // For tool-call, reasoning, tool-result - just yield as-is
34
+ yield item;
35
+ }
36
+ }
37
+ // Yield finish event
38
+ yield {
39
+ kind: "finish",
40
+ finishReason: response.finishReason,
41
+ usage: response.usage,
42
+ };
43
+ }
44
+ /**
45
+ * Creates a mock LanguageModel that automatically implements streaming
46
+ * based on the generate() implementation.
47
+ */
48
+ export function createMockModel(generateFn) {
49
+ return {
50
+ spec: "1.0",
51
+ provider: "test",
52
+ modelId: "test-model",
53
+ generate: generateFn,
54
+ stream: async function* (req) {
55
+ const response = await generateFn(req);
56
+ yield* streamFromResponse(response);
57
+ },
58
+ };
59
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../../../src/thread/__tests__/integration.test.ts"],"names":[],"mappings":""}