@dot-ai/core 0.5.2 → 0.8.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.
- package/dist/boot-cache.d.ts +40 -0
- package/dist/boot-cache.d.ts.map +1 -0
- package/dist/boot-cache.js +72 -0
- package/dist/boot-cache.js.map +1 -0
- package/dist/capabilities.d.ts +35 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +17 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/config.d.ts +7 -23
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +131 -108
- package/dist/config.js.map +1 -1
- package/dist/extension-api.d.ts +65 -0
- package/dist/extension-api.d.ts.map +1 -0
- package/dist/extension-api.js +2 -0
- package/dist/extension-api.js.map +1 -0
- package/dist/extension-loader.d.ts +19 -0
- package/dist/extension-loader.d.ts.map +1 -0
- package/dist/extension-loader.js +113 -0
- package/dist/extension-loader.js.map +1 -0
- package/dist/extension-runner.d.ts +62 -0
- package/dist/extension-runner.d.ts.map +1 -0
- package/dist/extension-runner.js +260 -0
- package/dist/extension-runner.js.map +1 -0
- package/dist/extension-types.d.ts +312 -0
- package/dist/extension-types.d.ts.map +1 -0
- package/dist/extension-types.js +89 -0
- package/dist/extension-types.js.map +1 -0
- package/dist/format.d.ts +13 -1
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +131 -15
- package/dist/format.js.map +1 -1
- package/dist/format.spec.d.ts +2 -0
- package/dist/format.spec.d.ts.map +1 -0
- package/dist/format.spec.js +140 -0
- package/dist/format.spec.js.map +1 -0
- package/dist/index.d.ts +21 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -14
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/package-manager.d.ts +30 -0
- package/dist/package-manager.d.ts.map +1 -0
- package/dist/package-manager.js +91 -0
- package/dist/package-manager.js.map +1 -0
- package/dist/runtime.d.ts +119 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +441 -0
- package/dist/runtime.js.map +1 -0
- package/dist/types.d.ts +29 -10
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -1
- package/src/__tests__/capabilities.test.ts +72 -0
- package/src/__tests__/config.test.ts +22 -120
- package/src/__tests__/extension-loader.test.ts +84 -0
- package/src/__tests__/extension-runner.test.ts +228 -0
- package/src/__tests__/fixtures/extensions/ctx-aware.js +26 -0
- package/src/__tests__/fixtures/extensions/security-gate.js +20 -0
- package/src/__tests__/fixtures/extensions/session-analytics.js +28 -0
- package/src/__tests__/fixtures/extensions/smart-context.js +10 -0
- package/src/__tests__/format.test.ts +207 -2
- package/src/__tests__/runtime.test.ts +141 -0
- package/src/boot-cache.ts +104 -0
- package/src/capabilities.ts +49 -0
- package/src/config.ts +131 -133
- package/src/extension-api.ts +99 -0
- package/src/extension-loader.ts +127 -0
- package/src/extension-runner.ts +297 -0
- package/src/extension-types.ts +416 -0
- package/src/format.spec.ts +175 -0
- package/src/format.test.ts +218 -0
- package/src/format.ts +140 -16
- package/src/index.ts +68 -30
- package/src/logger.ts +1 -1
- package/src/package-manager.ts +119 -0
- package/src/runtime.ts +562 -0
- package/src/types.ts +36 -14
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/.ai/memory/2026-03-04.md +0 -2
- package/.ai/tasks.json +0 -7
- package/dist/__tests__/config.test.d.ts +0 -2
- package/dist/__tests__/config.test.d.ts.map +0 -1
- package/dist/__tests__/config.test.js +0 -128
- package/dist/__tests__/config.test.js.map +0 -1
- package/dist/__tests__/e2e.test.d.ts +0 -2
- package/dist/__tests__/e2e.test.d.ts.map +0 -1
- package/dist/__tests__/e2e.test.js +0 -211
- package/dist/__tests__/e2e.test.js.map +0 -1
- package/dist/__tests__/engine.test.d.ts +0 -2
- package/dist/__tests__/engine.test.d.ts.map +0 -1
- package/dist/__tests__/engine.test.js +0 -271
- package/dist/__tests__/engine.test.js.map +0 -1
- package/dist/__tests__/format.test.d.ts +0 -2
- package/dist/__tests__/format.test.d.ts.map +0 -1
- package/dist/__tests__/format.test.js +0 -200
- package/dist/__tests__/format.test.js.map +0 -1
- package/dist/__tests__/labels.test.d.ts +0 -2
- package/dist/__tests__/labels.test.d.ts.map +0 -1
- package/dist/__tests__/labels.test.js +0 -82
- package/dist/__tests__/labels.test.js.map +0 -1
- package/dist/__tests__/loader.test.d.ts +0 -2
- package/dist/__tests__/loader.test.d.ts.map +0 -1
- package/dist/__tests__/loader.test.js +0 -161
- package/dist/__tests__/loader.test.js.map +0 -1
- package/dist/__tests__/logger.test.d.ts +0 -2
- package/dist/__tests__/logger.test.d.ts.map +0 -1
- package/dist/__tests__/logger.test.js +0 -95
- package/dist/__tests__/logger.test.js.map +0 -1
- package/dist/__tests__/nodes.test.d.ts +0 -2
- package/dist/__tests__/nodes.test.d.ts.map +0 -1
- package/dist/__tests__/nodes.test.js +0 -83
- package/dist/__tests__/nodes.test.js.map +0 -1
- package/dist/contracts.d.ts +0 -56
- package/dist/contracts.d.ts.map +0 -1
- package/dist/contracts.js +0 -2
- package/dist/contracts.js.map +0 -1
- package/dist/engine.d.ts +0 -38
- package/dist/engine.d.ts.map +0 -1
- package/dist/engine.js +0 -88
- package/dist/engine.js.map +0 -1
- package/dist/loader.d.ts +0 -26
- package/dist/loader.d.ts.map +0 -1
- package/dist/loader.js +0 -120
- package/dist/loader.js.map +0 -1
- package/src/__tests__/e2e.test.ts +0 -257
- package/src/__tests__/engine.test.ts +0 -305
- package/src/__tests__/loader.test.ts +0 -191
- package/src/contracts.ts +0 -71
- package/src/engine.ts +0 -145
- package/src/loader.ts +0 -152
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import { registerProvider, clearProviders, createProviders } from '../loader.js';
|
|
3
|
-
|
|
4
|
-
beforeEach(() => {
|
|
5
|
-
clearProviders();
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
describe('clearProviders', () => {
|
|
9
|
-
it('resets the registry so registered factories are no longer used', async () => {
|
|
10
|
-
const factory = vi.fn().mockReturnValue({
|
|
11
|
-
search: vi.fn().mockResolvedValue([{ content: 'custom', type: 'fact', source: 'test' }]),
|
|
12
|
-
store: vi.fn().mockResolvedValue(undefined),
|
|
13
|
-
});
|
|
14
|
-
registerProvider('@dot-ai/provider-file-memory', factory);
|
|
15
|
-
clearProviders();
|
|
16
|
-
|
|
17
|
-
const providers = await createProviders({ memory: { use: '@dot-ai/provider-file-memory' } });
|
|
18
|
-
// After clear, factory should not be called — noop provider is used
|
|
19
|
-
expect(factory).not.toHaveBeenCalled();
|
|
20
|
-
const memories = await providers.memory.search('query');
|
|
21
|
-
expect(memories).toEqual([]);
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('registerProvider + createProviders', () => {
|
|
26
|
-
it('uses registered memory factory', async () => {
|
|
27
|
-
const customMemory = {
|
|
28
|
-
search: vi.fn().mockResolvedValue([{ content: 'custom result', type: 'fact', source: 'test' }]),
|
|
29
|
-
store: vi.fn().mockResolvedValue(undefined),
|
|
30
|
-
};
|
|
31
|
-
registerProvider('@dot-ai/custom-memory', () => customMemory);
|
|
32
|
-
|
|
33
|
-
const providers = await createProviders({ memory: { use: '@dot-ai/custom-memory' } });
|
|
34
|
-
const results = await providers.memory.search('query');
|
|
35
|
-
expect(results[0]?.content).toBe('custom result');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('passes options to the factory', async () => {
|
|
39
|
-
const factory = vi.fn().mockReturnValue({
|
|
40
|
-
search: vi.fn().mockResolvedValue([]),
|
|
41
|
-
store: vi.fn().mockResolvedValue(undefined),
|
|
42
|
-
});
|
|
43
|
-
registerProvider('@dot-ai/opts-memory', factory);
|
|
44
|
-
|
|
45
|
-
await createProviders({ memory: { use: '@dot-ai/opts-memory', with: { url: 'http://test' } } });
|
|
46
|
-
expect(factory).toHaveBeenCalledWith({ url: 'http://test' });
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('supports async factory (returns Promise)', async () => {
|
|
50
|
-
const customMemory = {
|
|
51
|
-
search: vi.fn().mockResolvedValue([]),
|
|
52
|
-
store: vi.fn().mockResolvedValue(undefined),
|
|
53
|
-
};
|
|
54
|
-
registerProvider('@dot-ai/async-memory', async () => customMemory);
|
|
55
|
-
|
|
56
|
-
const providers = await createProviders({ memory: { use: '@dot-ai/async-memory' } });
|
|
57
|
-
expect(providers.memory).toBe(customMemory);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('registers and uses a skill provider', async () => {
|
|
61
|
-
const mockSkills = [{ name: 'my-skill', description: 'A skill', labels: ['test'] }];
|
|
62
|
-
registerProvider('@dot-ai/custom-skills', () => ({
|
|
63
|
-
list: vi.fn().mockResolvedValue(mockSkills),
|
|
64
|
-
match: vi.fn().mockResolvedValue([]),
|
|
65
|
-
load: vi.fn().mockResolvedValue(null),
|
|
66
|
-
}));
|
|
67
|
-
|
|
68
|
-
const providers = await createProviders({ skills: { use: '@dot-ai/custom-skills' } });
|
|
69
|
-
const skills = await providers.skills.list();
|
|
70
|
-
expect(skills).toEqual(mockSkills);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('registers and uses an identity provider', async () => {
|
|
74
|
-
const mockIdentities = [{ type: 'agents', content: 'I am Kiwi', source: 'file', priority: 1 }];
|
|
75
|
-
registerProvider('@dot-ai/custom-identity', () => ({
|
|
76
|
-
load: vi.fn().mockResolvedValue(mockIdentities),
|
|
77
|
-
}));
|
|
78
|
-
|
|
79
|
-
const providers = await createProviders({ identity: { use: '@dot-ai/custom-identity' } });
|
|
80
|
-
const identities = await providers.identity.load();
|
|
81
|
-
expect(identities).toEqual(mockIdentities);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe('auto-discovery via dynamic import', () => {
|
|
86
|
-
// NOTE: Dynamic import behavior is hard to mock reliably in vitest (import() is
|
|
87
|
-
// module-level). Auto-discovery with real packages is tested via E2E.
|
|
88
|
-
// The unit guarantee here is that an unknown provider name gracefully falls
|
|
89
|
-
// back to the noop implementation (i.e. tryImportProvider returns null for
|
|
90
|
-
// non-existent packages without throwing).
|
|
91
|
-
it('falls back to noop when provider package does not exist', async () => {
|
|
92
|
-
// '@dot-ai/nonexistent-provider' is not registered and cannot be imported
|
|
93
|
-
const providers = await createProviders({ memory: { use: '@dot-ai/nonexistent-provider' } });
|
|
94
|
-
const memories = await providers.memory.search('query');
|
|
95
|
-
expect(memories).toEqual([]);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
describe('createProviders — noop fallbacks', () => {
|
|
100
|
-
// Use non-existent provider names to ensure noop fallbacks are returned
|
|
101
|
-
// (auto-discovery would find real packages for default names like @dot-ai/provider-file-memory)
|
|
102
|
-
const noopConfig = {
|
|
103
|
-
memory: { use: '@dot-ai/nonexistent-memory' },
|
|
104
|
-
skills: { use: '@dot-ai/nonexistent-skills' },
|
|
105
|
-
identity: { use: '@dot-ai/nonexistent-identity' },
|
|
106
|
-
routing: { use: '@dot-ai/nonexistent-routing' },
|
|
107
|
-
tasks: { use: '@dot-ai/nonexistent-tasks' },
|
|
108
|
-
tools: { use: '@dot-ai/nonexistent-tools' },
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
it('returns noop memory provider when nothing registered', async () => {
|
|
112
|
-
const providers = await createProviders(noopConfig);
|
|
113
|
-
const memories = await providers.memory.search('any query');
|
|
114
|
-
expect(memories).toEqual([]);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('noop memory.store resolves without error', async () => {
|
|
118
|
-
const providers = await createProviders(noopConfig);
|
|
119
|
-
await expect(
|
|
120
|
-
providers.memory.store({ content: 'x', type: 'log' }),
|
|
121
|
-
).resolves.toBeUndefined();
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('noop skills.list returns empty array', async () => {
|
|
125
|
-
const providers = await createProviders(noopConfig);
|
|
126
|
-
expect(await providers.skills.list()).toEqual([]);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('noop skills.match returns empty array', async () => {
|
|
130
|
-
const providers = await createProviders(noopConfig);
|
|
131
|
-
expect(await providers.skills.match([])).toEqual([]);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('noop skills.load returns null', async () => {
|
|
135
|
-
const providers = await createProviders(noopConfig);
|
|
136
|
-
expect(await providers.skills.load('any-skill')).toBeNull();
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('noop identity.load returns empty array', async () => {
|
|
140
|
-
const providers = await createProviders(noopConfig);
|
|
141
|
-
expect(await providers.identity.load()).toEqual([]);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('noop routing.route returns a RoutingResult', async () => {
|
|
145
|
-
const providers = await createProviders(noopConfig);
|
|
146
|
-
const result = await providers.routing.route([]);
|
|
147
|
-
expect(result).toHaveProperty('model');
|
|
148
|
-
expect(result).toHaveProperty('reason');
|
|
149
|
-
expect(typeof result.model).toBe('string');
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('noop tasks.list returns empty array', async () => {
|
|
153
|
-
const providers = await createProviders(noopConfig);
|
|
154
|
-
expect(await providers.tasks.list()).toEqual([]);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('noop tasks.get returns null', async () => {
|
|
158
|
-
const providers = await createProviders(noopConfig);
|
|
159
|
-
expect(await providers.tasks.get('123')).toBeNull();
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('noop tasks.create returns a task with generated id', async () => {
|
|
163
|
-
const providers = await createProviders(noopConfig);
|
|
164
|
-
const task = await providers.tasks.create({ text: 'Do something', status: 'pending' });
|
|
165
|
-
expect(task).toHaveProperty('id');
|
|
166
|
-
expect(task.text).toBe('Do something');
|
|
167
|
-
expect(task.status).toBe('pending');
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('noop tasks.update returns a task with the patched fields', async () => {
|
|
171
|
-
const providers = await createProviders(noopConfig);
|
|
172
|
-
const task = await providers.tasks.update('abc', { status: 'done' });
|
|
173
|
-
expect(task.id).toBe('abc');
|
|
174
|
-
expect(task.status).toBe('done');
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('noop tools.list returns empty array', async () => {
|
|
178
|
-
const providers = await createProviders(noopConfig);
|
|
179
|
-
expect(await providers.tools.list()).toEqual([]);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('noop tools.match returns empty array', async () => {
|
|
183
|
-
const providers = await createProviders(noopConfig);
|
|
184
|
-
expect(await providers.tools.match([])).toEqual([]);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('noop tools.load returns null', async () => {
|
|
188
|
-
const providers = await createProviders(noopConfig);
|
|
189
|
-
expect(await providers.tools.load('any-tool')).toBeNull();
|
|
190
|
-
});
|
|
191
|
-
});
|
package/src/contracts.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
MemoryEntry,
|
|
3
|
-
Skill,
|
|
4
|
-
Identity,
|
|
5
|
-
Tool,
|
|
6
|
-
Task,
|
|
7
|
-
TaskFilter,
|
|
8
|
-
RoutingResult,
|
|
9
|
-
Label,
|
|
10
|
-
} from './types.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Memory provider — search and store memories.
|
|
14
|
-
* Implementation decides WHERE and HOW (files, DB, API, etc.)
|
|
15
|
-
*/
|
|
16
|
-
export interface MemoryProvider {
|
|
17
|
-
search(query: string, labels?: string[]): Promise<MemoryEntry[]>;
|
|
18
|
-
store(entry: Omit<MemoryEntry, 'source'>): Promise<void>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Skill provider — discover and load skills.
|
|
23
|
-
* Implementation decides WHERE skills come from (files, registry, API, etc.)
|
|
24
|
-
*/
|
|
25
|
-
export interface SkillProvider {
|
|
26
|
-
list(): Promise<Skill[]>;
|
|
27
|
-
match(labels: Label[]): Promise<Skill[]>;
|
|
28
|
-
load(name: string): Promise<string | null>; // returns content
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Identity provider — load identity documents.
|
|
33
|
-
* Implementation decides format and source.
|
|
34
|
-
*/
|
|
35
|
-
export interface IdentityProvider {
|
|
36
|
-
load(): Promise<Identity[]>;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Routing provider — decide which model to use.
|
|
41
|
-
* Implementation decides the logic (rules, LLM, etc.)
|
|
42
|
-
*/
|
|
43
|
-
export interface RoutingProvider {
|
|
44
|
-
route(labels: Label[], context?: Record<string, unknown>): Promise<RoutingResult>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Task provider — CRUD for tasks.
|
|
49
|
-
* Implementation decides storage (files, Cockpit API, Jira, etc.)
|
|
50
|
-
*/
|
|
51
|
-
export interface TaskProvider {
|
|
52
|
-
list(filter?: TaskFilter): Promise<Task[]>;
|
|
53
|
-
get(id: string): Promise<Task | null>;
|
|
54
|
-
create(task: Omit<Task, 'id'>): Promise<Task>;
|
|
55
|
-
update(id: string, patch: Partial<Task>): Promise<Task>;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Tool provider — discover and match tools.
|
|
60
|
-
* Implementation decides source (MCP config, files, registry, etc.)
|
|
61
|
-
*/
|
|
62
|
-
export interface ToolProvider {
|
|
63
|
-
list(): Promise<Tool[]>;
|
|
64
|
-
match(labels: Label[]): Promise<Tool[]>;
|
|
65
|
-
load(name: string): Promise<Tool | null>;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Factory function type for creating providers from config.
|
|
70
|
-
*/
|
|
71
|
-
export type ProviderFactory<T> = (options: Record<string, unknown>) => T | Promise<T>;
|
package/src/engine.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
MemoryProvider,
|
|
3
|
-
SkillProvider,
|
|
4
|
-
IdentityProvider,
|
|
5
|
-
RoutingProvider,
|
|
6
|
-
TaskProvider,
|
|
7
|
-
ToolProvider,
|
|
8
|
-
} from './contracts.js';
|
|
9
|
-
import type { EnrichedContext, Identity, Skill } from './types.js';
|
|
10
|
-
import type { Logger } from './logger.js';
|
|
11
|
-
import { extractLabels, buildVocabulary } from './labels.js';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* All providers needed by the engine.
|
|
15
|
-
*/
|
|
16
|
-
export interface Providers {
|
|
17
|
-
memory: MemoryProvider;
|
|
18
|
-
skills: SkillProvider;
|
|
19
|
-
identity: IdentityProvider;
|
|
20
|
-
routing: RoutingProvider;
|
|
21
|
-
tasks: TaskProvider;
|
|
22
|
-
tools: ToolProvider;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Cached data from boot phase. Reused across prompts.
|
|
27
|
-
*/
|
|
28
|
-
export interface BootCache {
|
|
29
|
-
identities: Identity[];
|
|
30
|
-
vocabulary: string[];
|
|
31
|
-
skills: Skill[];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Boot phase — run once per session.
|
|
36
|
-
* Loads identities, indexes skills/tools, builds label vocabulary.
|
|
37
|
-
*/
|
|
38
|
-
export async function boot(providers: Providers, logger?: Logger): Promise<BootCache> {
|
|
39
|
-
const start = performance.now();
|
|
40
|
-
|
|
41
|
-
const [identities, skills, tools] = await Promise.all([
|
|
42
|
-
providers.identity.load(),
|
|
43
|
-
providers.skills.list(),
|
|
44
|
-
providers.tools.list(),
|
|
45
|
-
]);
|
|
46
|
-
|
|
47
|
-
// Build vocabulary from skill labels, skill triggers (excluding meta-triggers), and tool labels
|
|
48
|
-
const META_TRIGGERS = new Set(['always', 'auto', 'manual', 'boot', 'heartbeat', 'pipeline', 'audit']);
|
|
49
|
-
const skillTriggers = skills.map((s) =>
|
|
50
|
-
(s.triggers ?? []).filter((t) => !META_TRIGGERS.has(t)),
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
const vocabulary = buildVocabulary(
|
|
54
|
-
[...skills.map((s) => s.labels), ...skillTriggers],
|
|
55
|
-
tools.map((t) => t.labels),
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
logger?.log({
|
|
59
|
-
timestamp: new Date().toISOString(),
|
|
60
|
-
level: 'info',
|
|
61
|
-
phase: 'boot',
|
|
62
|
-
event: 'boot_complete',
|
|
63
|
-
data: { identityCount: identities.length, skillCount: skills.length, vocabularySize: vocabulary.length },
|
|
64
|
-
durationMs: Math.round(performance.now() - start),
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return { identities, vocabulary, skills };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Enrich a prompt — run per prompt.
|
|
72
|
-
* Calls all providers to build an EnrichedContext.
|
|
73
|
-
*/
|
|
74
|
-
export async function enrich(
|
|
75
|
-
prompt: string,
|
|
76
|
-
providers: Providers,
|
|
77
|
-
cache: BootCache,
|
|
78
|
-
logger?: Logger,
|
|
79
|
-
): Promise<EnrichedContext> {
|
|
80
|
-
const start = performance.now();
|
|
81
|
-
|
|
82
|
-
// 1. Extract labels from prompt against known vocabulary
|
|
83
|
-
const labels = extractLabels(prompt, cache.vocabulary);
|
|
84
|
-
|
|
85
|
-
logger?.log({
|
|
86
|
-
timestamp: new Date().toISOString(),
|
|
87
|
-
level: 'info',
|
|
88
|
-
phase: 'enrich',
|
|
89
|
-
event: 'labels_extracted',
|
|
90
|
-
data: { labels: labels.map(l => l.name), vocabularySize: cache.vocabulary.length },
|
|
91
|
-
durationMs: Math.round(performance.now() - start),
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// 2. Search memory + match skills + match tools + route — all in parallel
|
|
95
|
-
const [memories, matchedSkills, matchedTools, routing] = await Promise.all([
|
|
96
|
-
providers.memory.search(prompt, labels.map((l) => l.name)),
|
|
97
|
-
providers.skills.match(labels),
|
|
98
|
-
providers.tools.match(labels),
|
|
99
|
-
providers.routing.route(labels),
|
|
100
|
-
]);
|
|
101
|
-
|
|
102
|
-
logger?.log({
|
|
103
|
-
timestamp: new Date().toISOString(),
|
|
104
|
-
level: 'info',
|
|
105
|
-
phase: 'enrich',
|
|
106
|
-
event: 'enrich_complete',
|
|
107
|
-
data: {
|
|
108
|
-
labelCount: labels.length,
|
|
109
|
-
memoryCount: memories.length,
|
|
110
|
-
skillCount: matchedSkills.length,
|
|
111
|
-
routing: routing.model,
|
|
112
|
-
},
|
|
113
|
-
durationMs: Math.round(performance.now() - start),
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
prompt,
|
|
118
|
-
labels,
|
|
119
|
-
identities: cache.identities,
|
|
120
|
-
memories,
|
|
121
|
-
skills: matchedSkills,
|
|
122
|
-
tools: matchedTools,
|
|
123
|
-
routing,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Learn phase — run after agent response.
|
|
129
|
-
* Stores learnings in memory.
|
|
130
|
-
*/
|
|
131
|
-
export async function learn(
|
|
132
|
-
response: string,
|
|
133
|
-
providers: Providers,
|
|
134
|
-
): Promise<void> {
|
|
135
|
-
const MAX_LEARN_LENGTH = 500;
|
|
136
|
-
const truncated = response.length > MAX_LEARN_LENGTH
|
|
137
|
-
? response.slice(0, MAX_LEARN_LENGTH) + '…'
|
|
138
|
-
: response;
|
|
139
|
-
|
|
140
|
-
await providers.memory.store({
|
|
141
|
-
content: truncated,
|
|
142
|
-
type: 'log',
|
|
143
|
-
date: new Date().toISOString().slice(0, 10),
|
|
144
|
-
});
|
|
145
|
-
}
|
package/src/loader.ts
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import type { DotAiConfig, Task } from './types.js';
|
|
2
|
-
import type {
|
|
3
|
-
MemoryProvider,
|
|
4
|
-
SkillProvider,
|
|
5
|
-
IdentityProvider,
|
|
6
|
-
RoutingProvider,
|
|
7
|
-
TaskProvider,
|
|
8
|
-
ToolProvider,
|
|
9
|
-
} from './contracts.js';
|
|
10
|
-
import type { Providers } from './engine.js';
|
|
11
|
-
import { resolveConfig } from './config.js';
|
|
12
|
-
/**
|
|
13
|
-
* Registry of provider factories.
|
|
14
|
-
* Adapters register their providers here before boot.
|
|
15
|
-
*/
|
|
16
|
-
const registry = new Map<string, (options: Record<string, unknown>) => unknown>();
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Register a provider factory.
|
|
20
|
-
* Call this before createProviders().
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* registerProvider('@dot-ai/cockpit-memory', (opts) => new CockpitMemory(opts.url));
|
|
24
|
-
*/
|
|
25
|
-
export function registerProvider(
|
|
26
|
-
name: string,
|
|
27
|
-
factory: (options: Record<string, unknown>) => unknown,
|
|
28
|
-
): void {
|
|
29
|
-
registry.set(name, factory);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Clear all registered providers.
|
|
34
|
-
* Useful for testing.
|
|
35
|
-
*/
|
|
36
|
-
export function clearProviders(): void {
|
|
37
|
-
registry.clear();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Register all default file-based providers.
|
|
42
|
-
* Call this at startup if you want file-based defaults available.
|
|
43
|
-
*/
|
|
44
|
-
export function registerDefaults(): void {
|
|
45
|
-
// Default providers are now separate packages (@dot-ai/provider-file-memory, etc.)
|
|
46
|
-
// They are resolved via auto-discovery in resolve() → tryImportProvider()
|
|
47
|
-
// No explicit registration needed — the package names match the config defaults.
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Create all providers from config.
|
|
52
|
-
* Falls back to no-op providers for any missing registration.
|
|
53
|
-
*/
|
|
54
|
-
export async function createProviders(config: DotAiConfig): Promise<Providers> {
|
|
55
|
-
const resolved = resolveConfig(config);
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
memory: await resolve<MemoryProvider>(resolved.memory.use, resolved.memory.with ?? {}, noopMemory),
|
|
59
|
-
skills: await resolve<SkillProvider>(resolved.skills.use, resolved.skills.with ?? {}, noopSkills),
|
|
60
|
-
identity: await resolve<IdentityProvider>(resolved.identity.use, resolved.identity.with ?? {}, noopIdentity),
|
|
61
|
-
routing: await resolve<RoutingProvider>(resolved.routing.use, resolved.routing.with ?? {}, noopRouting),
|
|
62
|
-
tasks: await resolve<TaskProvider>(resolved.tasks.use, resolved.tasks.with ?? {}, noopTasks),
|
|
63
|
-
tools: await resolve<ToolProvider>(resolved.tools.use, resolved.tools.with ?? {}, noopTools),
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async function resolve<T>(name: string, options: Record<string, unknown>, fallback: T): Promise<T> {
|
|
68
|
-
let factory = registry.get(name);
|
|
69
|
-
|
|
70
|
-
if (!factory) {
|
|
71
|
-
// Auto-discovery: try dynamic import
|
|
72
|
-
factory = await tryImportProvider(name);
|
|
73
|
-
if (factory) {
|
|
74
|
-
registry.set(name, factory); // Cache for next time
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (!factory) return fallback;
|
|
79
|
-
return factory(options) as T;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Try to import a provider package dynamically.
|
|
84
|
-
* Looks for: default export factory, createXxxProvider function, or XxxProvider class.
|
|
85
|
-
*/
|
|
86
|
-
async function tryImportProvider(
|
|
87
|
-
name: string,
|
|
88
|
-
): Promise<((options: Record<string, unknown>) => unknown) | undefined> {
|
|
89
|
-
try {
|
|
90
|
-
const mod = await import(name);
|
|
91
|
-
|
|
92
|
-
// 1. Check for default export (function)
|
|
93
|
-
if (typeof mod.default === 'function') {
|
|
94
|
-
return mod.default as (options: Record<string, unknown>) => unknown;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// 2. Check for createXxxProvider factory function
|
|
98
|
-
for (const [key, value] of Object.entries(mod)) {
|
|
99
|
-
if (key.startsWith('create') && key.endsWith('Provider') && typeof value === 'function') {
|
|
100
|
-
return value as (options: Record<string, unknown>) => unknown;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// 3. Check for XxxProvider class (constructor)
|
|
105
|
-
for (const [key, value] of Object.entries(mod)) {
|
|
106
|
-
if (key.endsWith('Provider') && typeof value === 'function') {
|
|
107
|
-
return (opts: Record<string, unknown>) => new (value as new (opts: Record<string, unknown>) => unknown)(opts);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return undefined;
|
|
112
|
-
} catch {
|
|
113
|
-
// Package not found or import error — not a problem, fall back to noop
|
|
114
|
-
return undefined;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// ── No-op providers (safe fallbacks) ────────────────────────────────────────
|
|
119
|
-
|
|
120
|
-
const noopMemory: MemoryProvider = {
|
|
121
|
-
async search(_query: string, _labels?: string[]) { return []; },
|
|
122
|
-
async store(_entry) {},
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const noopSkills: SkillProvider = {
|
|
126
|
-
async list() { return []; },
|
|
127
|
-
async match(_labels) { return []; },
|
|
128
|
-
async load(_name: string) { return null; },
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const noopIdentity: IdentityProvider = {
|
|
132
|
-
async load() { return []; },
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
const noopRouting: RoutingProvider = {
|
|
136
|
-
async route(_labels) { return { model: 'default', reason: 'no routing provider' }; },
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const noopTasks: TaskProvider = {
|
|
140
|
-
async list(_filter?) { return []; },
|
|
141
|
-
async get(_id: string) { return null; },
|
|
142
|
-
async create(task): Promise<Task> { return { id: crypto.randomUUID(), ...task }; },
|
|
143
|
-
async update(id: string, patch: Partial<Task>): Promise<Task> {
|
|
144
|
-
return { id, text: '', status: '', ...patch };
|
|
145
|
-
},
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const noopTools: ToolProvider = {
|
|
149
|
-
async list() { return []; },
|
|
150
|
-
async match(_labels) { return []; },
|
|
151
|
-
async load(_name: string) { return null; },
|
|
152
|
-
};
|