kernl 0.8.3 → 0.9.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 (87) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +21 -0
  3. package/dist/agent/base.d.ts +73 -0
  4. package/dist/agent/base.d.ts.map +1 -0
  5. package/dist/agent/base.js +137 -0
  6. package/dist/agent/index.d.ts +2 -0
  7. package/dist/agent/index.d.ts.map +1 -1
  8. package/dist/agent/index.js +2 -1
  9. package/dist/agent/types.d.ts +4 -0
  10. package/dist/agent/types.d.ts.map +1 -1
  11. package/dist/agent.d.ts +10 -90
  12. package/dist/agent.d.ts.map +1 -1
  13. package/dist/agent.js +5 -171
  14. package/dist/api/resources/agents/agents.d.ts +11 -7
  15. package/dist/api/resources/agents/agents.d.ts.map +1 -1
  16. package/dist/api/resources/agents/agents.js +14 -8
  17. package/dist/kernl/__tests__/memory-config.test.d.ts +2 -0
  18. package/dist/kernl/__tests__/memory-config.test.d.ts.map +1 -0
  19. package/dist/kernl/__tests__/memory-config.test.js +157 -0
  20. package/dist/kernl/kernl.d.ts +11 -2
  21. package/dist/kernl/kernl.d.ts.map +1 -1
  22. package/dist/kernl/kernl.js +62 -28
  23. package/dist/kernl/types.d.ts +6 -5
  24. package/dist/kernl/types.d.ts.map +1 -1
  25. package/dist/lib/env.d.ts +2 -2
  26. package/dist/mcp/__tests__/utils.test.js +4 -2
  27. package/dist/mcp/utils.d.ts +1 -1
  28. package/dist/mcp/utils.js +1 -1
  29. package/dist/memory/__tests__/encoder.test.js +46 -0
  30. package/dist/memory/codecs/domain.js +1 -2
  31. package/dist/memory/encoder.d.ts +7 -7
  32. package/dist/memory/encoder.d.ts.map +1 -1
  33. package/dist/memory/encoder.js +15 -7
  34. package/dist/memory/memory.js +1 -1
  35. package/dist/memory/types.d.ts +6 -2
  36. package/dist/memory/types.d.ts.map +1 -1
  37. package/dist/realtime/agent.d.ts +17 -0
  38. package/dist/realtime/agent.d.ts.map +1 -0
  39. package/dist/realtime/agent.js +17 -0
  40. package/dist/realtime/channel.d.ts +30 -0
  41. package/dist/realtime/channel.d.ts.map +1 -0
  42. package/dist/realtime/channel.js +1 -0
  43. package/dist/realtime/index.d.ts +5 -0
  44. package/dist/realtime/index.d.ts.map +1 -0
  45. package/dist/realtime/index.js +4 -0
  46. package/dist/realtime/session.d.ts +98 -0
  47. package/dist/realtime/session.d.ts.map +1 -0
  48. package/dist/realtime/session.js +203 -0
  49. package/dist/realtime/types.d.ts +58 -0
  50. package/dist/realtime/types.d.ts.map +1 -0
  51. package/dist/realtime/types.js +1 -0
  52. package/dist/storage/in-memory.d.ts.map +1 -1
  53. package/dist/storage/in-memory.js +5 -1
  54. package/dist/tool/__tests__/toolkit.test.js +2 -2
  55. package/dist/tool/tool.d.ts +2 -1
  56. package/dist/tool/tool.d.ts.map +1 -1
  57. package/dist/tool/toolkit.d.ts +4 -4
  58. package/dist/tool/toolkit.d.ts.map +1 -1
  59. package/dist/tool/toolkit.js +2 -1
  60. package/dist/tool/types.d.ts +4 -4
  61. package/dist/tool/types.d.ts.map +1 -1
  62. package/package.json +4 -4
  63. package/src/agent/base.ts +220 -0
  64. package/src/agent/index.ts +2 -0
  65. package/src/agent/types.ts +5 -0
  66. package/src/agent.ts +12 -231
  67. package/src/api/resources/agents/agents.ts +19 -13
  68. package/src/kernl/__tests__/memory-config.test.ts +203 -0
  69. package/src/kernl/kernl.ts +81 -39
  70. package/src/kernl/types.ts +6 -5
  71. package/src/mcp/__tests__/utils.test.ts +4 -2
  72. package/src/mcp/utils.ts +1 -1
  73. package/src/memory/__tests__/encoder.test.ts +63 -0
  74. package/src/memory/codecs/domain.ts +1 -1
  75. package/src/memory/encoder.ts +18 -10
  76. package/src/memory/memory.ts +1 -1
  77. package/src/memory/types.ts +6 -2
  78. package/src/realtime/agent.ts +24 -0
  79. package/src/realtime/channel.ts +32 -0
  80. package/src/realtime/index.ts +4 -0
  81. package/src/realtime/session.ts +259 -0
  82. package/src/realtime/types.ts +73 -0
  83. package/src/storage/in-memory.ts +9 -1
  84. package/src/tool/__tests__/toolkit.test.ts +2 -2
  85. package/src/tool/tool.ts +2 -1
  86. package/src/tool/toolkit.ts +6 -5
  87. package/src/tool/types.ts +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../../src/api/resources/agents/agents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;GAMG;AACH,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC;IAEzD;;;;;OAKG;IACH,GAAG,CACD,QAAQ,GAAG,cAAc,EACzB,OAAO,SAAS,eAAe,GAAG,UAAU,EAC5C,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,SAAS;IAKnD;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB;;;;;OAKG;IACH,IAAI,IAAI,KAAK,CAAC,cAAc,EAAE,eAAe,CAAC,EAAE;IAOhD;;OAEG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;CAGhC"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../../src/api/resources/agents/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;IAE7D;;;;;;;OAOG;IACH,GAAG,CACD,QAAQ,GAAG,cAAc,EACzB,OAAO,SAAS,eAAe,GAAG,UAAU,EAC5C,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,SAAS;IAQnD;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB;;OAEG;IACH,IAAI,IAAI,KAAK,CAAC,cAAc,EAAE,eAAe,CAAC,EAAE;IAMhD;;OAEG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;CAGhC"}
@@ -4,6 +4,10 @@
4
4
  * Thin facade over the in-process agent registry, returning live Agent instances.
5
5
  *
6
6
  * Note: agents are code, not persisted data; this is process-local.
7
+ *
8
+ * Currently only exposes LLM agents (kind: "llm"). RealtimeAgents are stored
9
+ * in the internal registry but not returned by these methods. If public access
10
+ * to realtime agents is needed, add a separate `kernl.realtimeAgents` resource.
7
11
  */
8
12
  export class RAgents {
9
13
  registry;
@@ -13,27 +17,29 @@ export class RAgents {
13
17
  /**
14
18
  * Get a live Agent instance by id.
15
19
  *
20
+ * Only returns LLM agents. Returns undefined for realtime agents.
21
+ *
16
22
  * Callers are expected to know the concrete TContext/TOutput types
17
23
  * for their own agents and can specify them via generics.
18
24
  */
19
25
  get(id) {
20
26
  const agent = this.registry.get(id);
21
- return agent;
27
+ if (agent?.kind === "llm") {
28
+ return agent;
29
+ }
30
+ return undefined;
22
31
  }
23
32
  /**
24
- * Check if an agent with the given id is registered.
33
+ * Check if an LLM agent with the given id is registered.
25
34
  */
26
35
  has(id) {
27
- return this.registry.has(id);
36
+ return this.registry.get(id)?.kind === "llm";
28
37
  }
29
38
  /**
30
- * List all registered agents as live instances.
31
- *
32
- * Since this is a heterogeneous collection, we expose the widest safe
33
- * type parameters here.
39
+ * List all registered LLM agents as live instances.
34
40
  */
35
41
  list() {
36
- return Array.from(this.registry.values());
42
+ return Array.from(this.registry.values()).filter((a) => a.kind === "llm");
37
43
  }
38
44
  /**
39
45
  * Unregister an agent at runtime.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=memory-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-config.test.d.ts","sourceRoot":"","sources":["../../../src/kernl/__tests__/memory-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,157 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { Kernl } from "../kernl.js";
3
+ import { Agent } from "../../agent.js";
4
+ import { logger } from "../../lib/logger.js";
5
+ function createMockLanguageModel() {
6
+ return {
7
+ spec: "1.0",
8
+ provider: "test",
9
+ modelId: "test-model",
10
+ };
11
+ }
12
+ function createMockEmbeddingModel() {
13
+ return {
14
+ provider: "test",
15
+ modelId: "test-embedder",
16
+ embed: vi.fn(async ({ values }) => ({
17
+ embeddings: values.map((v) => [v.length, 0, 0]),
18
+ })),
19
+ };
20
+ }
21
+ function createMockVectorIndex() {
22
+ return {
23
+ id: "mock",
24
+ capabilities: () => ({
25
+ namespacing: false,
26
+ filtering: { basic: true },
27
+ hybrid: false,
28
+ }),
29
+ createIndex: vi.fn(),
30
+ deleteIndex: vi.fn(),
31
+ upsert: vi.fn(),
32
+ query: vi.fn(),
33
+ delete: vi.fn(),
34
+ };
35
+ }
36
+ describe("Kernl memory config warnings", () => {
37
+ let warnSpy;
38
+ beforeEach(() => {
39
+ warnSpy = vi.spyOn(logger, "warn").mockImplementation(() => { });
40
+ });
41
+ afterEach(() => {
42
+ warnSpy.mockRestore();
43
+ });
44
+ it("warns when agent enables memory but no embedding configured", () => {
45
+ const kernl = new Kernl({
46
+ storage: {
47
+ vector: createMockVectorIndex(),
48
+ },
49
+ // no memory.embedding
50
+ });
51
+ const agent = new Agent({
52
+ id: "test-agent",
53
+ name: "Test Agent",
54
+ instructions: "test",
55
+ model: createMockLanguageModel(),
56
+ memory: { enabled: true },
57
+ });
58
+ kernl.register(agent);
59
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("Embeddings are not configured"));
60
+ });
61
+ it("warns when agent enables memory but no vector storage configured", () => {
62
+ const kernl = new Kernl({
63
+ memory: {
64
+ embedding: createMockEmbeddingModel(),
65
+ },
66
+ // no storage.vector
67
+ });
68
+ const agent = new Agent({
69
+ id: "test-agent",
70
+ name: "Test Agent",
71
+ instructions: "test",
72
+ model: createMockLanguageModel(),
73
+ memory: { enabled: true },
74
+ });
75
+ kernl.register(agent);
76
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("No vector storage configured"));
77
+ });
78
+ it("warns for both missing embedding and vector storage", () => {
79
+ const kernl = new Kernl({});
80
+ const agent = new Agent({
81
+ id: "test-agent",
82
+ name: "Test Agent",
83
+ instructions: "test",
84
+ model: createMockLanguageModel(),
85
+ memory: { enabled: true },
86
+ });
87
+ kernl.register(agent);
88
+ expect(warnSpy).toHaveBeenCalledTimes(2);
89
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("Embeddings are not configured"));
90
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("No vector storage configured"));
91
+ });
92
+ it("warns only once across multiple agents", () => {
93
+ const kernl = new Kernl({});
94
+ const agent1 = new Agent({
95
+ id: "agent-1",
96
+ name: "Agent 1",
97
+ instructions: "test",
98
+ model: createMockLanguageModel(),
99
+ memory: { enabled: true },
100
+ });
101
+ const agent2 = new Agent({
102
+ id: "agent-2",
103
+ name: "Agent 2",
104
+ instructions: "test",
105
+ model: createMockLanguageModel(),
106
+ memory: { enabled: true },
107
+ });
108
+ kernl.register(agent1);
109
+ kernl.register(agent2);
110
+ // Should only warn twice total (once for embedding, once for vector)
111
+ // not four times (twice per agent)
112
+ expect(warnSpy).toHaveBeenCalledTimes(2);
113
+ });
114
+ it("does not warn when memory config is complete", () => {
115
+ const kernl = new Kernl({
116
+ storage: {
117
+ vector: createMockVectorIndex(),
118
+ },
119
+ memory: {
120
+ embedding: createMockEmbeddingModel(),
121
+ },
122
+ });
123
+ const agent = new Agent({
124
+ id: "test-agent",
125
+ name: "Test Agent",
126
+ instructions: "test",
127
+ model: createMockLanguageModel(),
128
+ memory: { enabled: true },
129
+ });
130
+ kernl.register(agent);
131
+ expect(warnSpy).not.toHaveBeenCalled();
132
+ });
133
+ it("does not warn when agent does not enable memory", () => {
134
+ const kernl = new Kernl({});
135
+ const agent = new Agent({
136
+ id: "test-agent",
137
+ name: "Test Agent",
138
+ instructions: "test",
139
+ model: createMockLanguageModel(),
140
+ memory: { enabled: false },
141
+ });
142
+ kernl.register(agent);
143
+ expect(warnSpy).not.toHaveBeenCalled();
144
+ });
145
+ it("does not warn when agent has no memory config", () => {
146
+ const kernl = new Kernl({});
147
+ const agent = new Agent({
148
+ id: "test-agent",
149
+ name: "Test Agent",
150
+ instructions: "test",
151
+ model: createMockLanguageModel(),
152
+ // no memory config at all
153
+ });
154
+ kernl.register(agent);
155
+ expect(warnSpy).not.toHaveBeenCalled();
156
+ });
157
+ });
@@ -1,4 +1,4 @@
1
- import { Agent } from "../agent.js";
1
+ import { BaseAgent } from "../agent/base.js";
2
2
  import { UnknownContext } from "../context.js";
3
3
  import { KernlHooks } from "../lifecycle.js";
4
4
  import type { Thread } from "../thread/index.js";
@@ -21,6 +21,9 @@ export declare class Kernl extends KernlHooks<UnknownContext, AgentOutputType> {
21
21
  private readonly _models;
22
22
  readonly storage: KernlStorage;
23
23
  athreads: Map<string, Thread<any, any>>;
24
+ private readonly _memopts;
25
+ private readonly _storopts;
26
+ private warnings;
24
27
  readonly threads: RThreads;
25
28
  readonly agents: RAgents;
26
29
  readonly memories: Memory;
@@ -28,7 +31,7 @@ export declare class Kernl extends KernlHooks<UnknownContext, AgentOutputType> {
28
31
  /**
29
32
  * Registers a new agent with the kernl instance.
30
33
  */
31
- register(agent: Agent): void;
34
+ register(agent: BaseAgent): void;
32
35
  /**
33
36
  * Spawn a new thread - blocking execution
34
37
  */
@@ -51,5 +54,11 @@ export declare class Kernl extends KernlHooks<UnknownContext, AgentOutputType> {
51
54
  * Schedule an existing thread - streaming execution
52
55
  */
53
56
  scheduleStream<TContext, TOutput extends AgentOutputType>(thread: Thread<TContext, TOutput>): AsyncIterable<ThreadStreamEvent>;
57
+ /**
58
+ * @internal
59
+ *
60
+ * Initialize the memory system based on the storage + memory configuration.
61
+ */
62
+ private initializeMemory;
54
63
  }
55
64
  //# sourceMappingURL=kernl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kernl.d.ts","sourceRoot":"","sources":["../../src/kernl/kernl.ts"],"names":[],"mappings":"AAGA,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;AACvC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EACL,MAAM,EAIP,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;;GAKG;AACH,qBAAa,KAAM,SAAQ,UAAU,CAAC,cAAc,EAAE,eAAe,CAAC;IACpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IAEjE,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAa;IAGpD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,GAAE,YAAiB;IAoCtC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAa5B;;OAEG;IACG,KAAK,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EACnD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAS/D;;;;OAIG;IACG,QAAQ,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EACtD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAS/D;;;;OAIG;IACI,WAAW,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EAC1D,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,aAAa,CAAC,iBAAiB,CAAC;IASnC;;;;OAIG;IACI,cAAc,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EAC7D,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,aAAa,CAAC,iBAAiB,CAAC;CAQpC"}
1
+ {"version":3,"file":"kernl.d.ts","sourceRoot":"","sources":["../../src/kernl/kernl.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EACL,MAAM,EAIP,MAAM,UAAU,CAAC;AAIlB,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAiC,MAAM,SAAS,CAAC;AAE3E;;;;;GAKG;AACH,qBAAa,KAAM,SAAQ,UAAU,CAAC,cAAc,EAAE,eAAe,CAAC;IACpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IAEjE,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAa;IAEpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;IAEvD,OAAO,CAAC,QAAQ,CAGd;IAGF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,GAAE,YAAiB;IAatC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAgChC;;OAEG;IACG,KAAK,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EACnD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAS/D;;;;OAIG;IACG,QAAQ,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EACtD,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAS/D;;;;OAIG;IACI,WAAW,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EAC1D,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,aAAa,CAAC,iBAAiB,CAAC;IASnC;;;;OAIG;IACI,cAAc,CAAC,QAAQ,EAAE,OAAO,SAAS,eAAe,EAC7D,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAChC,aAAa,CAAC,iBAAiB,CAAC;IAWnC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;CA6BzB"}
@@ -4,6 +4,7 @@ import { InMemoryStorage } from "../storage/index.js";
4
4
  import { RThreads } from "../api/resources/threads/index.js";
5
5
  import { RAgents } from "../api/resources/agents/index.js";
6
6
  import { Memory, MemoryByteEncoder, MemoryIndexHandle, buildMemoryIndexSchema, } from "../memory/index.js";
7
+ import { logger } from "../lib/logger.js";
7
8
  /**
8
9
  * The kernl - manages agent processes, scheduling, and task lifecycle.
9
10
  *
@@ -15,38 +16,25 @@ export class Kernl extends KernlHooks {
15
16
  _models = new Map();
16
17
  storage;
17
18
  athreads = new Map(); /* active threads */
19
+ _memopts;
20
+ _storopts;
21
+ warnings = {
22
+ embedding: false, // "Embeddings are not configured. If you want memories to auto-embed text content..."
23
+ vector: false, // "No vector storage configured. The memories.search() function will not be..."
24
+ }; /* tracks warnings that have been logged */
18
25
  // --- public API ---
19
26
  threads;
20
27
  agents;
21
28
  memories;
22
29
  constructor(options = {}) {
23
30
  super();
31
+ this._memopts = options.memory;
32
+ this._storopts = options.storage;
24
33
  this.storage = options.storage?.db ?? new InMemoryStorage();
25
34
  this.storage.bind({ agents: this._agents, models: this._models });
26
35
  this.threads = new RThreads(this.storage.threads);
27
36
  this.agents = new RAgents(this._agents);
28
- // initialize memory
29
- const embeddingModel = options.memory?.embeddingModel ?? "openai/text-embedding-3-small";
30
- const embedder = typeof embeddingModel === "string"
31
- ? resolveEmbeddingModel(embeddingModel)
32
- : embeddingModel;
33
- const encoder = new MemoryByteEncoder(embedder);
34
- const vector = options.storage?.vector;
35
- const indexId = options.memory?.indexId ?? "memories_sindex";
36
- const dimensions = options.memory?.dimensions ?? 1536;
37
- const providerOptions = options.memory?.indexProviderOptions ?? { schema: "kernl" };
38
- this.memories = new Memory({
39
- store: this.storage.memories,
40
- search: vector !== undefined
41
- ? new MemoryIndexHandle({
42
- index: vector,
43
- indexId,
44
- schema: buildMemoryIndexSchema({ dimensions }),
45
- providerOptions,
46
- })
47
- : undefined,
48
- encoder,
49
- });
37
+ this.memories = this.initializeMemory();
50
38
  }
51
39
  /**
52
40
  * Registers a new agent with the kernl instance.
@@ -54,12 +42,25 @@ export class Kernl extends KernlHooks {
54
42
  register(agent) {
55
43
  this._agents.set(agent.id, agent);
56
44
  agent.bind(this);
57
- // (TODO): implement exhaustive model registry in protocol/ package
58
- //
59
- // auto-populate model registry for storage hydration
60
- const key = `${agent.model.provider}/${agent.model.modelId}`;
61
- if (!this._models.has(key)) {
62
- this._models.set(key, agent.model);
45
+ // memory config warnings (log once)
46
+ if (agent.memory.enabled) {
47
+ if (!this._memopts?.embedding && !this.warnings.embedding) {
48
+ logger.warn("Embeddings are not configured. If you want memories to auto-embed text content, " +
49
+ "pass an embedding model into the memory config in new Kernl()");
50
+ this.warnings.embedding = true;
51
+ }
52
+ if (!this._storopts?.vector && !this.warnings.vector) {
53
+ logger.warn("No vector storage configured. The memories.search() function will not be " +
54
+ "available. To enable memory search, pass storage.vector in new Kernl()");
55
+ this.warnings.vector = true;
56
+ }
57
+ }
58
+ // auto-populate model registry for storage hydration (llm agents only - for now)
59
+ if (agent.kind === "llm") {
60
+ const key = `${agent.model.provider}/${agent.model.modelId}`;
61
+ if (!this._models.has(key)) {
62
+ this._models.set(key, agent.model);
63
+ }
63
64
  }
64
65
  }
65
66
  /**
@@ -116,4 +117,37 @@ export class Kernl extends KernlHooks {
116
117
  this.athreads.delete(thread.tid);
117
118
  }
118
119
  }
120
+ // --- private utils ---
121
+ /**
122
+ * @internal
123
+ *
124
+ * Initialize the memory system based on the storage + memory configuration.
125
+ */
126
+ initializeMemory() {
127
+ const embeddingModel = this._memopts?.embedding;
128
+ const embedder = embeddingModel
129
+ ? typeof embeddingModel === "string"
130
+ ? resolveEmbeddingModel(embeddingModel)
131
+ : embeddingModel
132
+ : undefined;
133
+ const encoder = new MemoryByteEncoder(embedder);
134
+ const vector = this._storopts?.vector;
135
+ const indexId = this._memopts?.indexId ?? "memories_sindex";
136
+ const dimensions = this._memopts?.dimensions ?? 1536;
137
+ const providerOptions = this._memopts?.indexProviderOptions ?? {
138
+ schema: "kernl",
139
+ };
140
+ return new Memory({
141
+ store: this.storage.memories,
142
+ search: vector
143
+ ? new MemoryIndexHandle({
144
+ index: vector,
145
+ indexId,
146
+ schema: buildMemoryIndexSchema({ dimensions }),
147
+ providerOptions,
148
+ })
149
+ : undefined,
150
+ encoder,
151
+ });
152
+ }
119
153
  }
@@ -1,6 +1,6 @@
1
1
  import { LanguageModel, EmbeddingModel } from "@kernl-sdk/protocol";
2
2
  import { SearchIndex } from "@kernl-sdk/retrieval";
3
- import { Agent } from "../agent.js";
3
+ import { BaseAgent } from "../agent/base.js";
4
4
  import { KernlStorage } from "../storage/index.js";
5
5
  /**
6
6
  * Storage configuration for Kernl.
@@ -27,9 +27,10 @@ export interface MemoryOptions {
27
27
  * - A string like "openai/text-embedding-3-small" (resolved via provider registry)
28
28
  * - An EmbeddingModel instance
29
29
  *
30
- * @default "openai/text-embedding-3-small"
30
+ * If not provided, memories will not auto-embed text content and
31
+ * semantic search will not be available.
31
32
  */
32
- embeddingModel?: string | EmbeddingModel<string>;
33
+ embedding?: string | EmbeddingModel<string>;
33
34
  /**
34
35
  * Logical index ID used by the search backend.
35
36
  * - For pgvector: becomes the table name (with schema from indexProviderOptions)
@@ -71,10 +72,10 @@ export interface KernlOptions {
71
72
  /**
72
73
  * Agent registry interface.
73
74
  *
74
- * Satisfied by Map<string, Agent>.
75
+ * Satisfied by Map<string, BaseAgent>.
75
76
  */
76
77
  export interface AgentRegistry {
77
- get(id: string): Agent<any> | undefined;
78
+ get(id: string): BaseAgent<any> | undefined;
78
79
  }
79
80
  /**
80
81
  * Model registry interface.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/kernl/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,EAAE,CAAC,EAAE,YAAY,CAAC;IAElB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CAKtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAEjD;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/C;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,aAAa,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB;;OAEG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;CACzC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAC;CAC7C"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/kernl/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,EAAE,CAAC,EAAE,YAAY,CAAC;IAElB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CAKtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAE5C;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/C;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,aAAa,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB;;OAEG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;CAC7C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAC;CAC7C"}
package/dist/lib/env.d.ts CHANGED
@@ -7,11 +7,11 @@ import { z } from "zod";
7
7
  */
8
8
  declare const envSchema: z.ZodObject<{
9
9
  LOG_LEVEL: z.ZodDefault<z.ZodEnum<{
10
+ error: "error";
10
11
  trace: "trace";
11
12
  debug: "debug";
12
13
  info: "info";
13
14
  warn: "warn";
14
- error: "error";
15
15
  fatal: "fatal";
16
16
  }>>;
17
17
  KERNL_LOG_MODEL_DATA: z.ZodPipe<z.ZodOptional<z.ZodEnum<{
@@ -31,7 +31,7 @@ declare const envSchema: z.ZodObject<{
31
31
  * console.log(env.LOG_LEVEL);
32
32
  */
33
33
  export declare const env: {
34
- LOG_LEVEL: "trace" | "debug" | "info" | "warn" | "error" | "fatal";
34
+ LOG_LEVEL: "error" | "trace" | "debug" | "info" | "warn" | "fatal";
35
35
  KERNL_LOG_MODEL_DATA: boolean;
36
36
  KERNL_LOG_TOOL_DATA: boolean;
37
37
  };
@@ -52,7 +52,7 @@ describe("mcpToFunctionTool", () => {
52
52
  expect(functionTool.description).toBe("Performs calculations");
53
53
  expect(functionTool.parameters).toBeDefined();
54
54
  });
55
- it("should handle tools without inputSchema (undefined parameters)", () => {
55
+ it("should handle tools without inputSchema (empty object parameters)", () => {
56
56
  const server = createMockServer();
57
57
  // In practice, MCP SDK tools require inputSchema, but our function handles
58
58
  // the case where it might not be present. We use 'as any' to test this edge case.
@@ -62,7 +62,9 @@ describe("mcpToFunctionTool", () => {
62
62
  };
63
63
  const functionTool = mcpToFunctionTool(server, mcpTool);
64
64
  expect(functionTool.id).toBe("no_params");
65
- expect(functionTool.parameters).toBeUndefined();
65
+ // When no inputSchema, we use an empty z.object({}) to match AI SDK behavior
66
+ expect(functionTool.parameters).toBeDefined();
67
+ expect(functionTool.parameters?.def.type).toBe("object");
66
68
  });
67
69
  it("should invoke server.callTool with correct params", async () => {
68
70
  const server = createMockServer();
@@ -5,7 +5,7 @@ import type { MCPTool, MCPToolFilter } from "./types.js";
5
5
  /**
6
6
  * Converts an MCP tool definition into a function tool usable by the SDK.
7
7
  */
8
- export declare function mcpToFunctionTool(server: MCPServer, mcpTool: MCPTool): import("../tool/index.js").FunctionTool<unknown, z.ZodObject<{}, z.core.$strip>, {
8
+ export declare function mcpToFunctionTool(server: MCPServer, mcpTool: MCPTool): import("../tool/tool.js").FunctionTool<unknown, z.ZodObject<{}, z.core.$strip>, {
9
9
  type: string;
10
10
  text: string;
11
11
  } | {
package/dist/mcp/utils.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { tool } from "../tool/index.js";
2
+ import { tool } from "../tool/tool.js";
3
3
  /**
4
4
  * Converts an MCP tool definition into a function tool usable by the SDK.
5
5
  */
@@ -117,5 +117,51 @@ describe("MemoryByteEncoder", () => {
117
117
  const vec = await encoder.embed("search query");
118
118
  expect(vec).toEqual([12, 0, 0]); // "search query".length = 12
119
119
  });
120
+ it("returns null when no embedder configured", async () => {
121
+ const encoder = new MemoryByteEncoder(); // no embedder
122
+ const vec = await encoder.embed("search query");
123
+ expect(vec).toBeNull();
124
+ });
125
+ it("throws when embedder returns empty embedding", async () => {
126
+ const embedder = {
127
+ provider: "test",
128
+ modelId: "test-embedder",
129
+ embed: vi.fn(async () => ({
130
+ embeddings: [[]], // empty embedding
131
+ })),
132
+ };
133
+ const encoder = new MemoryByteEncoder(embedder);
134
+ await expect(encoder.embed("test")).rejects.toThrow("Embedder returned empty embedding");
135
+ });
136
+ it("throws when embedder returns undefined embedding", async () => {
137
+ const embedder = {
138
+ provider: "test",
139
+ modelId: "test-embedder",
140
+ embed: vi.fn(async () => ({
141
+ embeddings: [], // no embeddings at all
142
+ })),
143
+ };
144
+ const encoder = new MemoryByteEncoder(embedder);
145
+ await expect(encoder.embed("test")).rejects.toThrow("Embedder returned empty embedding");
146
+ });
147
+ });
148
+ describe("without embedder", () => {
149
+ it("returns undefined tvec when encoding with no embedder", async () => {
150
+ const encoder = new MemoryByteEncoder(); // no embedder
151
+ const byte = { text: "Hello world" };
152
+ const result = await encoder.encode(byte);
153
+ expect(result.text).toBe("Hello world");
154
+ expect(result.tvec).toBeUndefined();
155
+ });
156
+ it("still produces objtext projection without embedder", async () => {
157
+ const encoder = new MemoryByteEncoder(); // no embedder
158
+ const byte = {
159
+ object: { preference: "coffee", shots: 2 },
160
+ };
161
+ const result = await encoder.encode(byte);
162
+ expect(result.text).toContain("preference: coffee");
163
+ expect(result.objtext).toContain("preference: coffee");
164
+ expect(result.tvec).toBeUndefined();
165
+ });
120
166
  });
121
167
  });
@@ -95,8 +95,7 @@ export const PATCH_CODEC = {
95
95
  patch.timestamp = update.timestamp;
96
96
  if (update.updatedAt !== undefined)
97
97
  patch.updatedAt = update.updatedAt;
98
- if (update.metadata !== undefined)
99
- patch.metadata = update.metadata;
98
+ // metadata is stored in primary DB only, not indexed
100
99
  return patch;
101
100
  },
102
101
  decode(_patch) {
@@ -24,19 +24,17 @@ export declare const ObjectTextCodec: {
24
24
  * Encoder that converts MemoryByte to IndexableByte.
25
25
  *
26
26
  * Extracts canonical text from content and computes embeddings.
27
+ * If no embedder is provided, skips embedding and tvec will be undefined.
27
28
  */
28
29
  export declare class MemoryByteEncoder implements MemoryByteCodec {
29
- private readonly embedder;
30
- constructor(embedder: EmbeddingModel<string>);
30
+ private readonly embedder?;
31
+ constructor(embedder?: EmbeddingModel<string>);
31
32
  /**
32
33
  * Encode a MemoryByte to IndexableByte.
33
34
  *
34
35
  * - Produces `objtext` string projection for FTS indexing
35
36
  * - Combines text + objtext for embedding input
36
37
  * - Returns text (fallback to objtext if no text provided)
37
- *
38
- * Note: metadata is NOT set here - it comes from record.metadata
39
- * via the domain codec, not from MemoryByte.object.
40
38
  */
41
39
  encode(byte: MemoryByte): Promise<IndexableByte>;
42
40
  /**
@@ -45,8 +43,10 @@ export declare class MemoryByteEncoder implements MemoryByteCodec {
45
43
  decode(_indexable: IndexableByte): Promise<MemoryByte>;
46
44
  /**
47
45
  * Embed a text string.
48
- * Exposed for query embedding.
46
+ *
47
+ * @returns Embedding vector, or null if no embedder configured.
48
+ * @throws If embedder returns empty embedding.
49
49
  */
50
- embed(text: string): Promise<number[]>;
50
+ embed(text: string): Promise<number[] | null>;
51
51
  }
52
52
  //# sourceMappingURL=encoder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../src/memory/encoder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtE,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAQ1E;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe;IAC1B;;;;OAIG;gBACS,UAAU,GAAG,MAAM;CAOhC,CAAC;AAEF;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,eAAe;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;gBAEtC,QAAQ,EAAE,cAAc,CAAC,MAAM,CAAC;IAI5C;;;;;;;;;OASG;IACG,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAwBtD;;OAEG;IACG,MAAM,CAAC,UAAU,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC;IAI5D;;;OAGG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAI7C"}
1
+ {"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../src/memory/encoder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtE,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAQ1E;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe;IAC1B;;;;OAIG;gBACS,UAAU,GAAG,MAAM;CAOhC,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,eAAe;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAyB;gBAEvC,QAAQ,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC;IAI7C;;;;;;OAMG;IACG,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAyBtD;;OAEG;IACG,MAAM,CAAC,UAAU,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC;IAI5D;;;;;OAKG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;CAWpD"}