confused-ai-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/FEATURES.md +169 -0
  2. package/package.json +119 -0
  3. package/src/agent.ts +187 -0
  4. package/src/agentic/index.ts +87 -0
  5. package/src/agentic/runner.ts +386 -0
  6. package/src/agentic/types.ts +91 -0
  7. package/src/artifacts/artifact.ts +417 -0
  8. package/src/artifacts/index.ts +42 -0
  9. package/src/artifacts/media.ts +304 -0
  10. package/src/cli/index.ts +122 -0
  11. package/src/core/base-agent.ts +151 -0
  12. package/src/core/context-builder.ts +106 -0
  13. package/src/core/index.ts +8 -0
  14. package/src/core/schemas.ts +17 -0
  15. package/src/core/types.ts +158 -0
  16. package/src/create-agent.ts +309 -0
  17. package/src/debug-logger.ts +188 -0
  18. package/src/dx/agent.ts +88 -0
  19. package/src/dx/define-agent.ts +183 -0
  20. package/src/dx/dev-logger.ts +57 -0
  21. package/src/dx/index.ts +11 -0
  22. package/src/errors.ts +175 -0
  23. package/src/execution/engine.ts +522 -0
  24. package/src/execution/graph-builder.ts +362 -0
  25. package/src/execution/index.ts +8 -0
  26. package/src/execution/types.ts +257 -0
  27. package/src/execution/worker-pool.ts +308 -0
  28. package/src/extensions/index.ts +123 -0
  29. package/src/guardrails/allowlist.ts +155 -0
  30. package/src/guardrails/index.ts +17 -0
  31. package/src/guardrails/types.ts +159 -0
  32. package/src/guardrails/validator.ts +265 -0
  33. package/src/index.ts +74 -0
  34. package/src/knowledge/index.ts +5 -0
  35. package/src/knowledge/types.ts +52 -0
  36. package/src/learning/in-memory-store.ts +72 -0
  37. package/src/learning/index.ts +6 -0
  38. package/src/learning/types.ts +42 -0
  39. package/src/llm/cache.ts +300 -0
  40. package/src/llm/index.ts +22 -0
  41. package/src/llm/model-resolver.ts +81 -0
  42. package/src/llm/openai-provider.ts +313 -0
  43. package/src/llm/openrouter-provider.ts +29 -0
  44. package/src/llm/types.ts +131 -0
  45. package/src/memory/in-memory-store.ts +255 -0
  46. package/src/memory/index.ts +7 -0
  47. package/src/memory/types.ts +193 -0
  48. package/src/memory/vector-store.ts +251 -0
  49. package/src/observability/console-logger.ts +123 -0
  50. package/src/observability/index.ts +12 -0
  51. package/src/observability/metrics.ts +85 -0
  52. package/src/observability/otlp-exporter.ts +417 -0
  53. package/src/observability/tracer.ts +105 -0
  54. package/src/observability/types.ts +341 -0
  55. package/src/orchestration/agent-adapter.ts +33 -0
  56. package/src/orchestration/index.ts +34 -0
  57. package/src/orchestration/load-balancer.ts +151 -0
  58. package/src/orchestration/mcp-types.ts +59 -0
  59. package/src/orchestration/message-bus.ts +192 -0
  60. package/src/orchestration/orchestrator.ts +349 -0
  61. package/src/orchestration/pipeline.ts +66 -0
  62. package/src/orchestration/supervisor.ts +107 -0
  63. package/src/orchestration/swarm.ts +1099 -0
  64. package/src/orchestration/toolkit.ts +47 -0
  65. package/src/orchestration/types.ts +339 -0
  66. package/src/planner/classical-planner.ts +383 -0
  67. package/src/planner/index.ts +8 -0
  68. package/src/planner/llm-planner.ts +353 -0
  69. package/src/planner/types.ts +227 -0
  70. package/src/planner/validator.ts +297 -0
  71. package/src/production/circuit-breaker.ts +290 -0
  72. package/src/production/graceful-shutdown.ts +251 -0
  73. package/src/production/health.ts +333 -0
  74. package/src/production/index.ts +57 -0
  75. package/src/production/latency-eval.ts +62 -0
  76. package/src/production/rate-limiter.ts +287 -0
  77. package/src/production/resumable-stream.ts +289 -0
  78. package/src/production/types.ts +81 -0
  79. package/src/sdk/index.ts +374 -0
  80. package/src/session/db-driver.ts +50 -0
  81. package/src/session/in-memory-store.ts +235 -0
  82. package/src/session/index.ts +12 -0
  83. package/src/session/sql-store.ts +315 -0
  84. package/src/session/sqlite-store.ts +61 -0
  85. package/src/session/types.ts +153 -0
  86. package/src/tools/base-tool.ts +223 -0
  87. package/src/tools/browser-tool.ts +123 -0
  88. package/src/tools/calculator-tool.ts +265 -0
  89. package/src/tools/file-tools.ts +394 -0
  90. package/src/tools/github-tool.ts +432 -0
  91. package/src/tools/hackernews-tool.ts +187 -0
  92. package/src/tools/http-tool.ts +118 -0
  93. package/src/tools/index.ts +99 -0
  94. package/src/tools/jira-tool.ts +373 -0
  95. package/src/tools/notion-tool.ts +322 -0
  96. package/src/tools/openai-tool.ts +236 -0
  97. package/src/tools/registry.ts +131 -0
  98. package/src/tools/serpapi-tool.ts +234 -0
  99. package/src/tools/shell-tool.ts +118 -0
  100. package/src/tools/slack-tool.ts +327 -0
  101. package/src/tools/telegram-tool.ts +127 -0
  102. package/src/tools/types.ts +229 -0
  103. package/src/tools/websearch-tool.ts +335 -0
  104. package/src/tools/wikipedia-tool.ts +177 -0
  105. package/src/tools/yfinance-tool.ts +33 -0
  106. package/src/voice/index.ts +17 -0
  107. package/src/voice/voice-provider.ts +228 -0
  108. package/tests/artifact.test.ts +241 -0
  109. package/tests/circuit-breaker.test.ts +171 -0
  110. package/tests/health.test.ts +192 -0
  111. package/tests/llm-cache.test.ts +186 -0
  112. package/tests/rate-limiter.test.ts +161 -0
  113. package/tsconfig.json +29 -0
  114. package/vitest.config.ts +47 -0
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Guardrails types and interfaces
3
+ *
4
+ * Provides output validation, allowlists, and safety controls for agent outputs.
5
+ */
6
+
7
+ import type { z } from 'zod';
8
+
9
+ /**
10
+ * Guardrail check result
11
+ */
12
+ export interface GuardrailResult {
13
+ readonly passed: boolean;
14
+ readonly rule: string;
15
+ readonly message?: string;
16
+ readonly details?: unknown;
17
+ }
18
+
19
+ /**
20
+ * Guardrail violation
21
+ */
22
+ export interface GuardrailViolation {
23
+ readonly rule: string;
24
+ readonly message: string;
25
+ readonly severity: 'error' | 'warning';
26
+ readonly details?: unknown;
27
+ }
28
+
29
+ /**
30
+ * Guardrail check context
31
+ */
32
+ export interface GuardrailContext {
33
+ readonly agentId: string;
34
+ readonly sessionId?: string;
35
+ readonly toolName?: string;
36
+ readonly toolArgs?: Record<string, unknown>;
37
+ readonly output?: unknown;
38
+ readonly metadata?: Record<string, unknown>;
39
+ }
40
+
41
+ /**
42
+ * Guardrail rule interface
43
+ */
44
+ export interface GuardrailRule {
45
+ readonly name: string;
46
+ readonly description: string;
47
+ readonly severity: 'error' | 'warning';
48
+ check(context: GuardrailContext): GuardrailResult | Promise<GuardrailResult>;
49
+ }
50
+
51
+ /**
52
+ * Output validation rule using Zod schema
53
+ */
54
+ export interface SchemaValidationRule<T = unknown> {
55
+ readonly name: string;
56
+ readonly schema: z.ZodType<T>;
57
+ readonly description?: string;
58
+ }
59
+
60
+ /**
61
+ * Allowlist configuration
62
+ */
63
+ export interface AllowlistConfig {
64
+ readonly allowedTools?: string[];
65
+ readonly allowedHosts?: string[];
66
+ readonly allowedPaths?: string[];
67
+ readonly allowedOutputs?: string[];
68
+ readonly blockedPatterns?: RegExp[];
69
+ }
70
+
71
+ /**
72
+ * Guardrail configuration
73
+ */
74
+ export interface GuardrailsConfig {
75
+ readonly enabled?: boolean;
76
+ readonly rules?: GuardrailRule[];
77
+ readonly schemaValidations?: SchemaValidationRule[];
78
+ readonly allowlist?: AllowlistConfig;
79
+ readonly onViolation?: (violation: GuardrailViolation, context: GuardrailContext) => void | Promise<void>;
80
+ }
81
+
82
+ /**
83
+ * Guardrail engine interface
84
+ */
85
+ export interface GuardrailEngine {
86
+ /**
87
+ * Check if a tool call is allowed
88
+ */
89
+ checkToolCall(toolName: string, args: Record<string, unknown>, context: GuardrailContext): Promise<GuardrailResult[]>;
90
+
91
+ /**
92
+ * Validate output against schemas
93
+ */
94
+ validateOutput(output: unknown, context: GuardrailContext): Promise<GuardrailResult[]>;
95
+
96
+ /**
97
+ * Run all guardrail checks
98
+ */
99
+ checkAll(context: GuardrailContext): Promise<GuardrailResult[]>;
100
+
101
+ /**
102
+ * Get all violations from results
103
+ */
104
+ getViolations(results: GuardrailResult[]): GuardrailViolation[];
105
+ }
106
+
107
+ /**
108
+ * Human-in-the-loop hook types
109
+ */
110
+ export interface HumanInTheLoopHooks {
111
+ /**
112
+ * Called before executing a tool - can pause for approval
113
+ * Return true to allow, false to block, or throw to abort
114
+ */
115
+ beforeToolCall?: (
116
+ toolName: string,
117
+ args: Record<string, unknown>,
118
+ context: GuardrailContext
119
+ ) => Promise<boolean> | boolean;
120
+
121
+ /**
122
+ * Called before finishing the run - can pause for review
123
+ * Return true to allow finish, false to continue, or throw to abort
124
+ */
125
+ beforeFinish?: (
126
+ output: unknown,
127
+ context: GuardrailContext
128
+ ) => Promise<boolean> | boolean;
129
+
130
+ /**
131
+ * Called on guardrail violation
132
+ */
133
+ onViolation?: (violation: GuardrailViolation, context: GuardrailContext) => void | Promise<void>;
134
+ }
135
+
136
+ /**
137
+ * Approval request for human-in-the-loop
138
+ */
139
+ export interface ApprovalRequest {
140
+ readonly id: string;
141
+ readonly type: 'tool_call' | 'finish';
142
+ readonly context: GuardrailContext;
143
+ readonly data: {
144
+ toolName?: string;
145
+ args?: Record<string, unknown>;
146
+ output?: unknown;
147
+ };
148
+ readonly requestedAt: Date;
149
+ readonly timeoutMs?: number;
150
+ }
151
+
152
+ /**
153
+ * Approval response
154
+ */
155
+ export interface ApprovalResponse {
156
+ readonly approved: boolean;
157
+ readonly reason?: string;
158
+ readonly modifiedArgs?: Record<string, unknown>;
159
+ }
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Guardrail validator implementation
3
+ */
4
+
5
+ import {
6
+ GuardrailEngine,
7
+ GuardrailRule,
8
+ GuardrailResult,
9
+ GuardrailViolation,
10
+ GuardrailContext,
11
+ GuardrailsConfig,
12
+ SchemaValidationRule,
13
+ } from './types.js';
14
+
15
+ /**
16
+ * Default guardrail engine implementation
17
+ */
18
+ export class GuardrailValidator implements GuardrailEngine {
19
+ private rules: GuardrailRule[];
20
+ private schemaValidations: SchemaValidationRule[];
21
+ private onViolation?: (violation: GuardrailViolation, context: GuardrailContext) => void | Promise<void>;
22
+
23
+ constructor(config: GuardrailsConfig = {}) {
24
+ this.rules = config.rules ?? [];
25
+ this.schemaValidations = config.schemaValidations ?? [];
26
+ this.onViolation = config.onViolation;
27
+ }
28
+
29
+ /**
30
+ * Add a rule to the validator
31
+ */
32
+ addRule(rule: GuardrailRule): void {
33
+ this.rules.push(rule);
34
+ }
35
+
36
+ /**
37
+ * Add a schema validation
38
+ */
39
+ addSchemaValidation<T>(validation: SchemaValidationRule<T>): void {
40
+ this.schemaValidations.push(validation);
41
+ }
42
+
43
+ /**
44
+ * Check if a tool call is allowed
45
+ */
46
+ async checkToolCall(
47
+ toolName: string,
48
+ args: Record<string, unknown>,
49
+ context: GuardrailContext
50
+ ): Promise<GuardrailResult[]> {
51
+ const ctx: GuardrailContext = {
52
+ ...context,
53
+ toolName,
54
+ toolArgs: args,
55
+ };
56
+
57
+ const results: GuardrailResult[] = [];
58
+ for (const rule of this.rules) {
59
+ try {
60
+ const result = await rule.check(ctx);
61
+ results.push(result);
62
+ if (!result.passed && this.onViolation) {
63
+ await this.onViolation(
64
+ {
65
+ rule: rule.name,
66
+ message: result.message ?? 'Guardrail check failed',
67
+ severity: rule.severity,
68
+ details: result.details,
69
+ },
70
+ ctx
71
+ );
72
+ }
73
+ } catch (error) {
74
+ results.push({
75
+ passed: false,
76
+ rule: rule.name,
77
+ message: error instanceof Error ? error.message : String(error),
78
+ });
79
+ }
80
+ }
81
+
82
+ return results;
83
+ }
84
+
85
+ /**
86
+ * Validate output against schemas
87
+ */
88
+ async validateOutput(output: unknown, context: GuardrailContext): Promise<GuardrailResult[]> {
89
+ const results: GuardrailResult[] = [];
90
+
91
+ for (const validation of this.schemaValidations) {
92
+ try {
93
+ validation.schema.parse(output);
94
+ results.push({
95
+ passed: true,
96
+ rule: validation.name,
97
+ });
98
+ } catch (error) {
99
+ const message = error instanceof Error ? error.message : String(error);
100
+ results.push({
101
+ passed: false,
102
+ rule: validation.name,
103
+ message: `Schema validation failed: ${message}`,
104
+ details: error,
105
+ });
106
+
107
+ if (this.onViolation) {
108
+ await this.onViolation(
109
+ {
110
+ rule: validation.name,
111
+ message,
112
+ severity: 'error',
113
+ details: error,
114
+ },
115
+ { ...context, output }
116
+ );
117
+ }
118
+ }
119
+ }
120
+
121
+ return results;
122
+ }
123
+
124
+ /**
125
+ * Run all guardrail checks
126
+ */
127
+ async checkAll(context: GuardrailContext): Promise<GuardrailResult[]> {
128
+ const results: GuardrailResult[] = [];
129
+
130
+ // Check tool call if present
131
+ if (context.toolName) {
132
+ const toolResults = await this.checkToolCall(
133
+ context.toolName,
134
+ context.toolArgs ?? {},
135
+ context
136
+ );
137
+ results.push(...toolResults);
138
+ }
139
+
140
+ // Validate output if present
141
+ if (context.output !== undefined) {
142
+ const outputResults = await this.validateOutput(context.output, context);
143
+ results.push(...outputResults);
144
+ }
145
+
146
+ // Run general rules
147
+ for (const rule of this.rules) {
148
+ try {
149
+ const result = await rule.check(context);
150
+ results.push(result);
151
+ if (!result.passed && this.onViolation) {
152
+ await this.onViolation(
153
+ {
154
+ rule: rule.name,
155
+ message: result.message ?? 'Guardrail check failed',
156
+ severity: rule.severity,
157
+ details: result.details,
158
+ },
159
+ context
160
+ );
161
+ }
162
+ } catch (error) {
163
+ results.push({
164
+ passed: false,
165
+ rule: rule.name,
166
+ message: error instanceof Error ? error.message : String(error),
167
+ });
168
+ }
169
+ }
170
+
171
+ return results;
172
+ }
173
+
174
+ /**
175
+ * Get all violations from results
176
+ */
177
+ getViolations(results: GuardrailResult[]): GuardrailViolation[] {
178
+ return results
179
+ .filter(r => !r.passed)
180
+ .map(r => ({
181
+ rule: r.rule,
182
+ message: r.message ?? 'Guardrail check failed',
183
+ severity: 'error',
184
+ details: r.details,
185
+ }));
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Create a regex-based content guardrail rule
191
+ */
192
+ export function createContentRule(
193
+ name: string,
194
+ description: string,
195
+ pattern: RegExp,
196
+ severity: 'error' | 'warning' = 'error'
197
+ ): GuardrailRule {
198
+ return {
199
+ name,
200
+ description,
201
+ severity,
202
+ check(context: GuardrailContext): GuardrailResult {
203
+ const raw = context.output;
204
+ const content =
205
+ typeof raw === 'string' ? raw : raw === undefined || raw === null ? '' : JSON.stringify(raw);
206
+
207
+ const matches = pattern.test(content);
208
+ return {
209
+ passed: !matches,
210
+ rule: name,
211
+ message: matches ? `Content matched forbidden pattern: ${pattern}` : undefined,
212
+ };
213
+ },
214
+ };
215
+ }
216
+
217
+ /**
218
+ * Create a tool allowlist rule
219
+ */
220
+ export function createToolAllowlistRule(allowedTools: string[]): GuardrailRule {
221
+ return {
222
+ name: 'tool_allowlist',
223
+ description: `Only allow tools: ${allowedTools.join(', ')}`,
224
+ severity: 'error',
225
+ check(context: GuardrailContext): GuardrailResult {
226
+ if (!context.toolName) {
227
+ return { passed: true, rule: 'tool_allowlist' };
228
+ }
229
+
230
+ const allowed = allowedTools.includes(context.toolName);
231
+ return {
232
+ passed: allowed,
233
+ rule: 'tool_allowlist',
234
+ message: allowed ? undefined : `Tool '${context.toolName}' is not in the allowlist`,
235
+ };
236
+ },
237
+ };
238
+ }
239
+
240
+ /**
241
+ * Create a maximum length rule
242
+ */
243
+ export function createMaxLengthRule(
244
+ name: string,
245
+ maxLength: number,
246
+ severity: 'error' | 'warning' = 'error'
247
+ ): GuardrailRule {
248
+ return {
249
+ name,
250
+ description: `Maximum length: ${maxLength}`,
251
+ severity,
252
+ check(context: GuardrailContext): GuardrailResult {
253
+ const raw = context.output;
254
+ const content =
255
+ typeof raw === 'string' ? raw : raw === undefined || raw === null ? '' : JSON.stringify(raw);
256
+
257
+ const withinLimit = content.length <= maxLength;
258
+ return {
259
+ passed: withinLimit,
260
+ rule: name,
261
+ message: withinLimit ? undefined : `Output exceeds maximum length of ${maxLength}`,
262
+ };
263
+ },
264
+ };
265
+ }
package/src/index.ts ADDED
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Agent Framework - A production-grade TypeScript agent framework
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+
7
+ // Core exports
8
+ export * from './core/index.js';
9
+
10
+ // Memory exports
11
+ export * from './memory/index.js';
12
+
13
+ // Tools exports
14
+ export * from './tools/index.js';
15
+
16
+ // Planner exports
17
+ export * from './planner/index.js';
18
+
19
+ // Execution exports
20
+ export * from './execution/index.js';
21
+
22
+ // Orchestration exports
23
+ export * from './orchestration/index.js';
24
+
25
+ // Observability exports
26
+ export * from './observability/index.js';
27
+
28
+ // LLM provider abstraction (optional peer: openai for OpenAIProvider)
29
+ export * from './llm/index.js';
30
+
31
+ // Agentic loop (ReAct-style)
32
+ export * from './agentic/index.js';
33
+
34
+ // SDK exports
35
+ export * from './sdk/index.js';
36
+
37
+ // Session exports
38
+ export * from './session/index.js';
39
+
40
+ // Guardrails exports
41
+ export * from './guardrails/index.js';
42
+
43
+ // Learning: user profiles, memories across sessions, learning modes (always / agentic)
44
+ export * from './learning/index.js';
45
+
46
+ // Knowledge: RAG, hybrid search, reranking, persistent session/state
47
+ export * from './knowledge/index.js';
48
+
49
+ // Production: runtime, control plane, evals (accuracy, performance, latency)
50
+ export * from './production/index.js';
51
+
52
+ // Structured errors for production (ErrorCode, AgentError, LLMError, ToolExecutionError, etc.)
53
+ export * from './errors.js';
54
+
55
+ // Extensions: plug any DB, tools, cross-tool middleware; wrap agents for Orchestrator/Pipeline
56
+ export * from './extensions/index.js';
57
+
58
+ // One-line production agent (auto LLM, memory, tools, session, guardrails)
59
+ export {
60
+ createAgent,
61
+ type CreateAgentOptions,
62
+ type CreateAgentResult,
63
+ type AgentRunOptions,
64
+ } from './create-agent.js';
65
+
66
+ // Agno-style Agent class: clean process, run anytime (model, db, learning, tools)
67
+ export { Agent, type AgentOptions } from './agent.js';
68
+
69
+ // Best DX: minimal agent(), fluent defineAgent(), dev logging
70
+ export { agent, defineAgent, createDevLogger, createDevToolMiddleware } from './dx/index.js';
71
+ export type { AgentMinimalOptions, DefineAgentOptions } from './dx/index.js';
72
+
73
+ // Version
74
+ export const VERSION = '1.0.0';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Knowledge module: RAG, hybrid search, reranking, persistent storage.
3
+ */
4
+
5
+ export * from './types.js';
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Knowledge: agentic RAG, hybrid search, reranking, persistent session/state.
3
+ */
4
+
5
+ import type { EntityId } from '../core/types.js';
6
+
7
+ /** Single retrieved chunk for RAG */
8
+ export interface RAGChunk {
9
+ readonly id: EntityId;
10
+ readonly content: string;
11
+ readonly score: number;
12
+ readonly metadata?: Record<string, unknown>;
13
+ readonly source?: string;
14
+ }
15
+
16
+ /** RAG query options */
17
+ export interface RAGQueryOptions {
18
+ readonly limit?: number;
19
+ readonly threshold?: number;
20
+ readonly filter?: Record<string, unknown>;
21
+ readonly rerank?: boolean;
22
+ readonly hybrid?: boolean;
23
+ }
24
+
25
+ /** RAG query result */
26
+ export interface RAGQueryResult {
27
+ readonly chunks: RAGChunk[];
28
+ readonly query: string;
29
+ readonly totalRetrieved?: number;
30
+ }
31
+
32
+ /** RAG engine: retrieve (and optionally generate). Plug 20+ vector stores, hybrid search, reranking. */
33
+ export interface RAGEngine {
34
+ /** Retrieve relevant chunks for a query (vector + optional keyword + rerank) */
35
+ retrieve(query: string, options?: RAGQueryOptions): Promise<RAGQueryResult>;
36
+
37
+ /** Optional: generate answer from query + retrieved context (agentic RAG) */
38
+ generate?(query: string, options?: RAGQueryOptions & { maxTokens?: number }): Promise<{ answer: string; chunks: RAGChunk[] }>;
39
+
40
+ /** Ingest documents/chunks for later retrieval */
41
+ ingest?(chunks: Array<{ content: string; metadata?: Record<string, unknown> }>): Promise<void>;
42
+ }
43
+
44
+ /** Hybrid search: combine vector similarity + keyword (e.g. BM25). */
45
+ export interface HybridSearchProvider {
46
+ search(query: string, limit: number, filter?: Record<string, unknown>): Promise<RAGChunk[]>;
47
+ }
48
+
49
+ /** Reranker: score and reorder retrieved chunks. */
50
+ export interface RerankerProvider {
51
+ rerank(query: string, chunks: RAGChunk[], topK?: number): Promise<RAGChunk[]>;
52
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * In-memory user profile store (default; plug SQLite/Postgres for production).
3
+ */
4
+
5
+ import type { EntityId } from '../core/types.js';
6
+ import type { UserProfile, UserProfileQuery } from './types.js';
7
+
8
+ export class InMemoryUserProfileStore {
9
+ private profiles = new Map<string, UserProfile>();
10
+
11
+ private key(userId: string, agentId?: EntityId): string {
12
+ return agentId ? `${userId}:${agentId}` : userId;
13
+ }
14
+
15
+ async get(userId: string, agentId?: EntityId): Promise<UserProfile | null> {
16
+ return this.profiles.get(this.key(userId, agentId)) ?? null;
17
+ }
18
+
19
+ async set(profile: Omit<UserProfile, 'id' | 'createdAt' | 'updatedAt'>): Promise<UserProfile> {
20
+ const now = new Date();
21
+ const id = `profile-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
22
+ const entry: UserProfile = {
23
+ ...profile,
24
+ id,
25
+ createdAt: now,
26
+ updatedAt: now,
27
+ };
28
+ this.profiles.set(this.key(profile.userId, profile.agentId), entry);
29
+ return entry;
30
+ }
31
+
32
+ async update(
33
+ userId: string,
34
+ updates: Partial<Omit<UserProfile, 'id' | 'userId' | 'createdAt'>>,
35
+ agentId?: EntityId
36
+ ): Promise<UserProfile> {
37
+ const existing = await this.get(userId, agentId);
38
+ if (!existing) {
39
+ const now = new Date();
40
+ const entry: UserProfile = {
41
+ id: `profile-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
42
+ userId,
43
+ agentId,
44
+ metadata: (updates.metadata as Record<string, unknown>) ?? {},
45
+ createdAt: now,
46
+ updatedAt: now,
47
+ ...updates,
48
+ };
49
+ this.profiles.set(this.key(userId, agentId), entry);
50
+ return entry;
51
+ }
52
+ const updated: UserProfile = {
53
+ ...existing,
54
+ ...updates,
55
+ updatedAt: new Date(),
56
+ };
57
+ this.profiles.set(this.key(userId, agentId), updated);
58
+ return updated;
59
+ }
60
+
61
+ async list(query?: UserProfileQuery): Promise<UserProfile[]> {
62
+ let list = Array.from(this.profiles.values());
63
+ if (query?.userId) list = list.filter(p => p.userId === query.userId);
64
+ if (query?.agentId) list = list.filter(p => p.agentId === query.agentId);
65
+ if (query?.limit) list = list.slice(0, query.limit);
66
+ return list;
67
+ }
68
+
69
+ async delete(userId: string, agentId?: EntityId): Promise<boolean> {
70
+ return this.profiles.delete(this.key(userId, agentId));
71
+ }
72
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Learning module: user profiles, memories across sessions, learning modes.
3
+ */
4
+
5
+ export * from './types.js';
6
+ export { InMemoryUserProfileStore } from './in-memory-store.js';
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Learning: user profiles, memories that accumulate, knowledge that transfers.
3
+ * Supports always-on or agentic learning modes.
4
+ */
5
+
6
+ import type { EntityId } from '../core/types.js';
7
+
8
+ /** Learning mode: always persist/learn vs. only when agent explicitly stores */
9
+ export enum LearningMode {
10
+ /** Always: persist session, accumulate memories, update profiles automatically */
11
+ ALWAYS = 'always',
12
+ /** Agentic: agent decides when to store/update (e.g. via tools) */
13
+ AGENTIC = 'agentic',
14
+ }
15
+
16
+ /** User profile that persists across sessions */
17
+ export interface UserProfile {
18
+ readonly id: EntityId;
19
+ readonly userId: string;
20
+ readonly agentId?: EntityId;
21
+ readonly displayName?: string;
22
+ readonly preferences?: Record<string, unknown>;
23
+ readonly metadata: Record<string, unknown>;
24
+ readonly createdAt: Date;
25
+ readonly updatedAt: Date;
26
+ }
27
+
28
+ /** Query for user profiles */
29
+ export interface UserProfileQuery {
30
+ readonly userId?: string;
31
+ readonly agentId?: EntityId;
32
+ readonly limit?: number;
33
+ }
34
+
35
+ /** Store for user profiles (plug any DB) */
36
+ export interface UserProfileStore {
37
+ get(userId: string, agentId?: EntityId): Promise<UserProfile | null>;
38
+ set(profile: Omit<UserProfile, 'id' | 'createdAt' | 'updatedAt'>): Promise<UserProfile>;
39
+ update(userId: string, updates: Partial<Omit<UserProfile, 'id' | 'userId' | 'createdAt'>>, agentId?: EntityId): Promise<UserProfile>;
40
+ list(query?: UserProfileQuery): Promise<UserProfile[]>;
41
+ delete(userId: string, agentId?: EntityId): Promise<boolean>;
42
+ }