trellis 2.0.8 → 2.0.13

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 (42) hide show
  1. package/README.md +279 -116
  2. package/dist/cli/index.js +655 -4
  3. package/dist/core/index.js +471 -2
  4. package/dist/embeddings/index.js +5 -1
  5. package/dist/{index-s603ev6w.js → index-5b01h414.js} +1 -1
  6. package/dist/index-5m0g9r0y.js +1100 -0
  7. package/dist/{index-zf6htvnm.js → index-7gvjxt27.js} +166 -2
  8. package/dist/index-hybgxe40.js +1174 -0
  9. package/dist/index.js +7 -2
  10. package/dist/transformers.node-bx3q9d7k.js +33130 -0
  11. package/package.json +9 -4
  12. package/src/cli/index.ts +939 -0
  13. package/src/core/agents/harness.ts +380 -0
  14. package/src/core/agents/index.ts +18 -0
  15. package/src/core/agents/types.ts +90 -0
  16. package/src/core/index.ts +85 -2
  17. package/src/core/kernel/trellis-kernel.ts +593 -0
  18. package/src/core/ontology/builtins.ts +248 -0
  19. package/src/core/ontology/index.ts +34 -0
  20. package/src/core/ontology/registry.ts +209 -0
  21. package/src/core/ontology/types.ts +124 -0
  22. package/src/core/ontology/validator.ts +382 -0
  23. package/src/core/persist/backend.ts +10 -0
  24. package/src/core/persist/sqlite-backend.ts +298 -0
  25. package/src/core/plugins/index.ts +17 -0
  26. package/src/core/plugins/registry.ts +322 -0
  27. package/src/core/plugins/types.ts +126 -0
  28. package/src/core/query/datalog.ts +188 -0
  29. package/src/core/query/engine.ts +370 -0
  30. package/src/core/query/index.ts +34 -0
  31. package/src/core/query/parser.ts +481 -0
  32. package/src/core/query/types.ts +200 -0
  33. package/src/embeddings/auto-embed.ts +248 -0
  34. package/src/embeddings/index.ts +7 -0
  35. package/src/embeddings/model.ts +21 -4
  36. package/src/embeddings/types.ts +8 -1
  37. package/src/index.ts +9 -0
  38. package/src/sync/http-transport.ts +144 -0
  39. package/src/sync/index.ts +11 -0
  40. package/src/sync/multi-repo.ts +200 -0
  41. package/src/sync/ws-transport.ts +145 -0
  42. package/dist/index-5bhe57y9.js +0 -326
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Agent Harness — Runtime for managing agent definitions, runs, and decisions.
3
+ *
4
+ * Loads agent definitions from the graph (TrellisKernel), manages tool
5
+ * registrations, executes runs, and records decision traces as kernel entities.
6
+ *
7
+ * @module trellis/core/agents
8
+ */
9
+
10
+ import type { TrellisKernel } from '../kernel/trellis-kernel.js';
11
+ import type {
12
+ AgentDef,
13
+ ToolDef,
14
+ ToolHandler,
15
+ ToolResult,
16
+ AgentRun,
17
+ DecisionTrace,
18
+ RunStatus,
19
+ AgentHarnessConfig,
20
+ } from './types.js';
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // Agent Harness
24
+ // ---------------------------------------------------------------------------
25
+
26
+ export class AgentHarness {
27
+ private kernel: TrellisKernel;
28
+ private toolHandlers: Map<string, ToolHandler> = new Map();
29
+ private config: AgentHarnessConfig;
30
+ private runCounter: number = 0;
31
+
32
+ constructor(kernel: TrellisKernel, config?: AgentHarnessConfig) {
33
+ this.kernel = kernel;
34
+ this.config = {
35
+ recordDecisions: true,
36
+ maxDecisionsPerRun: 100,
37
+ ...config,
38
+ };
39
+ }
40
+
41
+ // -------------------------------------------------------------------------
42
+ // Agent CRUD (via kernel entities)
43
+ // -------------------------------------------------------------------------
44
+
45
+ async createAgent(
46
+ def: Omit<AgentDef, 'id' | 'capabilities' | 'tools'> & {
47
+ id?: string;
48
+ capabilities?: string[];
49
+ tools?: string[];
50
+ },
51
+ ): Promise<AgentDef> {
52
+ const id = def.id ?? `agent:${def.name.toLowerCase().replace(/\s+/g, '-')}`;
53
+ await this.kernel.createEntity(id, 'Agent', {
54
+ name: def.name,
55
+ ...(def.description ? { description: def.description } : {}),
56
+ ...(def.model ? { model: def.model } : {}),
57
+ ...(def.provider ? { provider: def.provider } : {}),
58
+ ...(def.systemPrompt ? { systemPrompt: def.systemPrompt } : {}),
59
+ status: def.status ?? 'active',
60
+ });
61
+
62
+ // Add capability links
63
+ if (def.capabilities) {
64
+ for (const cap of def.capabilities) {
65
+ await this.kernel.addLink(id, 'hasCapability', cap);
66
+ }
67
+ }
68
+
69
+ // Add tool links
70
+ if (def.tools) {
71
+ for (const tool of def.tools) {
72
+ await this.kernel.addLink(id, 'hasTool', tool);
73
+ }
74
+ }
75
+
76
+ return this.getAgent(id)!;
77
+ }
78
+
79
+ getAgent(id: string): AgentDef | null {
80
+ const entity = this.kernel.getEntity(id);
81
+ if (!entity || entity.type !== 'Agent') return null;
82
+
83
+ const store = this.kernel.getStore();
84
+ const capLinks = store.getLinksByEntityAndAttribute(id, 'hasCapability');
85
+ const toolLinks = store.getLinksByEntityAndAttribute(id, 'hasTool');
86
+
87
+ return {
88
+ id: entity.id,
89
+ name: String(entity.facts.find((f) => f.a === 'name')?.v ?? ''),
90
+ description: entity.facts.find((f) => f.a === 'description')?.v as
91
+ | string
92
+ | undefined,
93
+ model: entity.facts.find((f) => f.a === 'model')?.v as string | undefined,
94
+ provider: entity.facts.find((f) => f.a === 'provider')?.v as
95
+ | string
96
+ | undefined,
97
+ systemPrompt: entity.facts.find((f) => f.a === 'systemPrompt')?.v as
98
+ | string
99
+ | undefined,
100
+ status:
101
+ (entity.facts.find((f) => f.a === 'status')?.v as AgentDef['status']) ??
102
+ 'active',
103
+ capabilities: capLinks.map((l) => l.e2),
104
+ tools: toolLinks.map((l) => l.e2),
105
+ };
106
+ }
107
+
108
+ listAgents(status?: AgentDef['status']): AgentDef[] {
109
+ const entities = this.kernel.listEntities(
110
+ 'Agent',
111
+ status ? { status } : undefined,
112
+ );
113
+ return entities
114
+ .map((e) => this.getAgent(e.id))
115
+ .filter((a): a is AgentDef => a !== null);
116
+ }
117
+
118
+ // -------------------------------------------------------------------------
119
+ // Tool registration
120
+ // -------------------------------------------------------------------------
121
+
122
+ async registerTool(
123
+ def: Omit<ToolDef, 'id'> & { id?: string },
124
+ handler: ToolHandler,
125
+ ): Promise<string> {
126
+ const id = def.id ?? `tool:${def.name.toLowerCase().replace(/\s+/g, '-')}`;
127
+
128
+ // Create tool entity if it doesn't exist
129
+ if (!this.kernel.getEntity(id)) {
130
+ await this.kernel.createEntity(id, 'Tool', {
131
+ name: def.name,
132
+ ...(def.description ? { description: def.description } : {}),
133
+ ...(def.schema ? { schema: def.schema } : {}),
134
+ ...(def.endpoint ? { endpoint: def.endpoint } : {}),
135
+ });
136
+ }
137
+
138
+ this.toolHandlers.set(id, handler);
139
+ return id;
140
+ }
141
+
142
+ getToolHandler(toolId: string): ToolHandler | undefined {
143
+ return this.toolHandlers.get(toolId);
144
+ }
145
+
146
+ listTools(): ToolDef[] {
147
+ return this.kernel.listEntities('Tool').map((e) => ({
148
+ id: e.id,
149
+ name: String(e.facts.find((f) => f.a === 'name')?.v ?? ''),
150
+ description: e.facts.find((f) => f.a === 'description')?.v as
151
+ | string
152
+ | undefined,
153
+ schema: e.facts.find((f) => f.a === 'schema')?.v as string | undefined,
154
+ endpoint: e.facts.find((f) => f.a === 'endpoint')?.v as
155
+ | string
156
+ | undefined,
157
+ }));
158
+ }
159
+
160
+ // -------------------------------------------------------------------------
161
+ // Run management
162
+ // -------------------------------------------------------------------------
163
+
164
+ async startRun(agentId: string, input?: string): Promise<string> {
165
+ const agent = this.getAgent(agentId);
166
+ if (!agent) throw new Error(`Agent "${agentId}" not found.`);
167
+
168
+ // Ensure unique run IDs even when called in rapid succession
169
+ const runId = `run:${agentId.replace('agent:', '')}:${Date.now()}:${++this.runCounter}`;
170
+ await this.kernel.createEntity(runId, 'AgentRun', {
171
+ startedAt: new Date().toISOString(),
172
+ status: 'running',
173
+ ...(input ? { input } : {}),
174
+ });
175
+ await this.kernel.addLink(runId, 'executedBy', agentId);
176
+
177
+ return runId;
178
+ }
179
+
180
+ async completeRun(
181
+ runId: string,
182
+ output?: string,
183
+ tokenCount?: number,
184
+ ): Promise<void> {
185
+ const updates: Record<string, any> = {
186
+ status: 'completed',
187
+ completedAt: new Date().toISOString(),
188
+ };
189
+ if (output) updates.output = output;
190
+ if (tokenCount !== undefined) updates.tokenCount = tokenCount;
191
+ await this.kernel.updateEntity(runId, updates);
192
+ }
193
+
194
+ async failRun(runId: string, error: string): Promise<void> {
195
+ await this.kernel.updateEntity(runId, {
196
+ status: 'failed',
197
+ completedAt: new Date().toISOString(),
198
+ output: `Error: ${error}`,
199
+ });
200
+ }
201
+
202
+ getRun(runId: string): AgentRun | null {
203
+ const entity = this.kernel.getEntity(runId);
204
+ if (!entity || entity.type !== 'AgentRun') return null;
205
+
206
+ const store = this.kernel.getStore();
207
+ const agentLink = store.getLinksByEntityAndAttribute(runId, 'executedBy');
208
+ const agentId = agentLink[0]?.e2 ?? '';
209
+
210
+ // Get decisions for this run
211
+ const decisionLinks = store.getLinksByAttribute('belongsToRun');
212
+ const decisionIds = decisionLinks
213
+ .filter((l) => l.e2 === runId)
214
+ .map((l) => l.e1);
215
+ const decisions = decisionIds
216
+ .map((did) => this._buildDecisionTrace(did))
217
+ .filter(Boolean) as DecisionTrace[];
218
+
219
+ const get = (a: string) => entity.facts.find((f) => f.a === a)?.v;
220
+
221
+ return {
222
+ id: runId,
223
+ agentId,
224
+ startedAt: String(get('startedAt') ?? ''),
225
+ completedAt: get('completedAt') as string | undefined,
226
+ status: (get('status') as RunStatus) ?? 'running',
227
+ input: get('input') as string | undefined,
228
+ output: get('output') as string | undefined,
229
+ tokenCount: get('tokenCount') as number | undefined,
230
+ decisions,
231
+ };
232
+ }
233
+
234
+ listRuns(agentId?: string): AgentRun[] {
235
+ const runs = this.kernel.listEntities('AgentRun');
236
+ return runs
237
+ .map((e) => this.getRun(e.id))
238
+ .filter((r): r is AgentRun => r !== null)
239
+ .filter((r) => !agentId || r.agentId === agentId)
240
+ .sort(
241
+ (a, b) =>
242
+ new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime(),
243
+ );
244
+ }
245
+
246
+ // -------------------------------------------------------------------------
247
+ // Decision trace recording
248
+ // -------------------------------------------------------------------------
249
+
250
+ async recordDecision(
251
+ runId: string,
252
+ toolName: string,
253
+ input?: Record<string, unknown>,
254
+ output?: string,
255
+ opts?: {
256
+ rationale?: string;
257
+ alternatives?: string[];
258
+ relatedEntities?: string[];
259
+ },
260
+ ): Promise<string> {
261
+ const run = this.getRun(runId);
262
+ if (!run) throw new Error(`Run "${runId}" not found.`);
263
+
264
+ const decId = `decision:${runId.replace('run:', '')}:${Date.now()}`;
265
+ await this.kernel.createEntity(decId, 'DecisionTrace', {
266
+ toolName,
267
+ timestamp: new Date().toISOString(),
268
+ ...(input ? { input: JSON.stringify(input) } : {}),
269
+ ...(output ? { output } : {}),
270
+ ...(opts?.rationale ? { rationale: opts.rationale } : {}),
271
+ ...(opts?.alternatives
272
+ ? { alternatives: JSON.stringify(opts.alternatives) }
273
+ : {}),
274
+ });
275
+
276
+ // Link decision to run and agent
277
+ await this.kernel.addLink(decId, 'belongsToRun', runId);
278
+ await this.kernel.addLink(decId, 'madeBy', run.agentId);
279
+
280
+ // Link to related entities
281
+ if (opts?.relatedEntities) {
282
+ for (const eid of opts.relatedEntities) {
283
+ await this.kernel.addLink(decId, 'relatedTo', eid);
284
+ }
285
+ }
286
+
287
+ return decId;
288
+ }
289
+
290
+ /**
291
+ * Invoke a registered tool within a run, auto-recording a decision trace.
292
+ */
293
+ async invokeTool(
294
+ runId: string,
295
+ toolId: string,
296
+ input: Record<string, unknown>,
297
+ opts?: { rationale?: string; relatedEntities?: string[] },
298
+ ): Promise<ToolResult> {
299
+ const handler = this.toolHandlers.get(toolId);
300
+ if (!handler)
301
+ throw new Error(`No handler registered for tool "${toolId}".`);
302
+
303
+ const result = await handler(input);
304
+
305
+ if (this.config.recordDecisions) {
306
+ const toolEntity = this.kernel.getEntity(toolId);
307
+ const toolName = toolEntity
308
+ ? String(toolEntity.facts.find((f) => f.a === 'name')?.v ?? toolId)
309
+ : toolId;
310
+
311
+ await this.recordDecision(
312
+ runId,
313
+ toolName,
314
+ input,
315
+ result.success ? String(result.output ?? '') : `Error: ${result.error}`,
316
+ opts,
317
+ );
318
+ }
319
+
320
+ return result;
321
+ }
322
+
323
+ getDecisionChain(entityId: string): DecisionTrace[] {
324
+ const store = this.kernel.getStore();
325
+ const links = store.getLinksByAttribute('relatedTo');
326
+ const decisionIds = links.filter((l) => l.e2 === entityId).map((l) => l.e1);
327
+ return decisionIds
328
+ .map((did) => this._buildDecisionTrace(did))
329
+ .filter(Boolean) as DecisionTrace[];
330
+ }
331
+
332
+ // -------------------------------------------------------------------------
333
+ // Internal helpers
334
+ // -------------------------------------------------------------------------
335
+
336
+ private _buildDecisionTrace(decId: string): DecisionTrace | null {
337
+ const entity = this.kernel.getEntity(decId);
338
+ if (!entity) return null;
339
+
340
+ const get = (a: string) => entity.facts.find((f) => f.a === a)?.v;
341
+ const store = this.kernel.getStore();
342
+
343
+ const runLink = store.getLinksByEntityAndAttribute(decId, 'belongsToRun');
344
+ const agentLink = store.getLinksByEntityAndAttribute(decId, 'madeBy');
345
+ const relatedLinks = store.getLinksByEntityAndAttribute(decId, 'relatedTo');
346
+
347
+ let inputParsed: Record<string, unknown> | undefined;
348
+ const inputRaw = get('input') as string | undefined;
349
+ if (inputRaw) {
350
+ try {
351
+ inputParsed = JSON.parse(inputRaw);
352
+ } catch {
353
+ inputParsed = { raw: inputRaw };
354
+ }
355
+ }
356
+
357
+ let alternatives: string[] | undefined;
358
+ const altRaw = get('alternatives') as string | undefined;
359
+ if (altRaw) {
360
+ try {
361
+ alternatives = JSON.parse(altRaw);
362
+ } catch {
363
+ alternatives = [altRaw];
364
+ }
365
+ }
366
+
367
+ return {
368
+ id: decId,
369
+ runId: runLink[0]?.e2 ?? '',
370
+ agentId: agentLink[0]?.e2 ?? '',
371
+ toolName: String(get('toolName') ?? ''),
372
+ input: inputParsed,
373
+ output: get('output') as string | undefined,
374
+ rationale: get('rationale') as string | undefined,
375
+ alternatives,
376
+ timestamp: String(get('timestamp') ?? ''),
377
+ relatedEntities: relatedLinks.map((l) => l.e2),
378
+ };
379
+ }
380
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Agent System — Public API Surface
3
+ *
4
+ * @module trellis/core/agents
5
+ */
6
+
7
+ export { AgentHarness } from './harness.js';
8
+
9
+ export type {
10
+ AgentDef,
11
+ ToolDef,
12
+ ToolHandler,
13
+ ToolResult,
14
+ AgentRun,
15
+ DecisionTrace,
16
+ RunStatus,
17
+ AgentHarnessConfig,
18
+ } from './types.js';
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Agent System Types
3
+ *
4
+ * Types for the generic agent harness that loads agent definitions
5
+ * from the graph, manages runs, and records decision traces.
6
+ *
7
+ * @module trellis/core/agents
8
+ */
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Agent definition (stored as graph entities)
12
+ // ---------------------------------------------------------------------------
13
+
14
+ export interface AgentDef {
15
+ id: string;
16
+ name: string;
17
+ description?: string;
18
+ model?: string;
19
+ provider?: string;
20
+ systemPrompt?: string;
21
+ status: 'active' | 'inactive' | 'deprecated';
22
+ capabilities: string[];
23
+ tools: string[];
24
+ }
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // Tool definition
28
+ // ---------------------------------------------------------------------------
29
+
30
+ export interface ToolDef {
31
+ id: string;
32
+ name: string;
33
+ description?: string;
34
+ schema?: string;
35
+ endpoint?: string;
36
+ }
37
+
38
+ export type ToolHandler = (input: Record<string, unknown>) => Promise<ToolResult>;
39
+
40
+ export interface ToolResult {
41
+ success: boolean;
42
+ output: unknown;
43
+ error?: string;
44
+ }
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Agent run
48
+ // ---------------------------------------------------------------------------
49
+
50
+ export type RunStatus = 'running' | 'completed' | 'failed' | 'cancelled';
51
+
52
+ export interface AgentRun {
53
+ id: string;
54
+ agentId: string;
55
+ startedAt: string;
56
+ completedAt?: string;
57
+ status: RunStatus;
58
+ input?: string;
59
+ output?: string;
60
+ tokenCount?: number;
61
+ decisions: DecisionTrace[];
62
+ }
63
+
64
+ // ---------------------------------------------------------------------------
65
+ // Decision trace (kernel-native, not VCS-dependent)
66
+ // ---------------------------------------------------------------------------
67
+
68
+ export interface DecisionTrace {
69
+ id: string;
70
+ runId: string;
71
+ agentId: string;
72
+ toolName: string;
73
+ input?: Record<string, unknown>;
74
+ output?: string;
75
+ rationale?: string;
76
+ alternatives?: string[];
77
+ timestamp: string;
78
+ relatedEntities?: string[];
79
+ }
80
+
81
+ // ---------------------------------------------------------------------------
82
+ // Harness config
83
+ // ---------------------------------------------------------------------------
84
+
85
+ export interface AgentHarnessConfig {
86
+ /** Whether to auto-record decision traces on tool invocations. */
87
+ recordDecisions?: boolean;
88
+ /** Maximum decisions per run before auto-stopping. */
89
+ maxDecisionsPerRun?: number;
90
+ }
package/src/core/index.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * TrellisVCS Core — EAV Store, Kernel Types, Middleware
2
+ * TrellisVCS Core — EAV Store, Kernel, Persistence, Middleware
3
3
  *
4
4
  * Inlined from trellis-core for single-package publish.
5
- * Consumers: `import { EAVStore, Fact } from 'trellis/core'`
5
+ * Consumers: `import { EAVStore, Fact, TrellisKernel } from 'trellis/core'`
6
6
  *
7
7
  * @module trellis/core
8
8
  */
@@ -33,3 +33,86 @@ export type {
33
33
  MiddlewareContext,
34
34
  OpMiddlewareNext,
35
35
  } from './kernel/middleware.js';
36
+
37
+ // SQLite backend
38
+ export { SqliteKernelBackend } from './persist/sqlite-backend.js';
39
+
40
+ // Query engine
41
+ export {
42
+ QueryEngine,
43
+ parseQuery,
44
+ parseRule,
45
+ parseSimple,
46
+ DatalogRuntime,
47
+ } from './query/index.js';
48
+ export type {
49
+ Query,
50
+ Pattern,
51
+ FactPattern,
52
+ LinkPattern,
53
+ Term,
54
+ Variable,
55
+ Literal,
56
+ Filter,
57
+ FilterOp,
58
+ Aggregate,
59
+ OrderBy,
60
+ Bindings,
61
+ DatalogRule,
62
+ } from './query/index.js';
63
+
64
+ // Ontology system
65
+ export {
66
+ OntologyRegistry,
67
+ validateEntity,
68
+ validateStore,
69
+ createValidationMiddleware,
70
+ } from './ontology/index.js';
71
+ export {
72
+ projectOntology,
73
+ teamOntology,
74
+ agentOntology,
75
+ builtinOntologies,
76
+ } from './ontology/index.js';
77
+ export type {
78
+ AttrType,
79
+ AttributeDef,
80
+ RelationDef,
81
+ EntityDef,
82
+ OntologySchema,
83
+ ValidationError,
84
+ ValidationResult,
85
+ } from './ontology/index.js';
86
+
87
+ // Agent system
88
+ export { AgentHarness } from './agents/index.js';
89
+ export type {
90
+ AgentDef,
91
+ ToolDef,
92
+ ToolHandler,
93
+ ToolResult,
94
+ AgentRun,
95
+ DecisionTrace,
96
+ RunStatus,
97
+ AgentHarnessConfig,
98
+ } from './agents/index.js';
99
+
100
+ // Plugin system
101
+ export { PluginRegistry, EventBus } from './plugins/index.js';
102
+ export type {
103
+ PluginDef,
104
+ PluginContext,
105
+ PluginManifest,
106
+ EventCallback,
107
+ EventHandler,
108
+ WellKnownEvent,
109
+ WorkspaceConfig,
110
+ } from './plugins/index.js';
111
+
112
+ // TrellisKernel — generic graph kernel
113
+ export { TrellisKernel } from './kernel/trellis-kernel.js';
114
+ export type {
115
+ KernelConfig,
116
+ MutateResult,
117
+ EntityRecord,
118
+ } from './kernel/trellis-kernel.js';