trellis 2.0.8 → 2.0.10

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 (41) hide show
  1. package/dist/cli/index.js +655 -4
  2. package/dist/core/index.js +470 -2
  3. package/dist/embeddings/index.js +5 -1
  4. package/dist/{index-s603ev6w.js → index-5b01h414.js} +1 -1
  5. package/dist/index-5m0g9r0y.js +1100 -0
  6. package/dist/{index-zf6htvnm.js → index-7gvjxt27.js} +166 -2
  7. package/dist/index-hybgxe40.js +1174 -0
  8. package/dist/index.js +7 -2
  9. package/dist/transformers.node-bx3q9d7k.js +33130 -0
  10. package/package.json +4 -3
  11. package/src/cli/index.ts +939 -0
  12. package/src/core/agents/harness.ts +336 -0
  13. package/src/core/agents/index.ts +18 -0
  14. package/src/core/agents/types.ts +90 -0
  15. package/src/core/index.ts +85 -2
  16. package/src/core/kernel/trellis-kernel.ts +593 -0
  17. package/src/core/ontology/builtins.ts +248 -0
  18. package/src/core/ontology/index.ts +34 -0
  19. package/src/core/ontology/registry.ts +209 -0
  20. package/src/core/ontology/types.ts +124 -0
  21. package/src/core/ontology/validator.ts +382 -0
  22. package/src/core/persist/backend.ts +10 -0
  23. package/src/core/persist/sqlite-backend.ts +298 -0
  24. package/src/core/plugins/index.ts +17 -0
  25. package/src/core/plugins/registry.ts +322 -0
  26. package/src/core/plugins/types.ts +126 -0
  27. package/src/core/query/datalog.ts +188 -0
  28. package/src/core/query/engine.ts +370 -0
  29. package/src/core/query/index.ts +34 -0
  30. package/src/core/query/parser.ts +481 -0
  31. package/src/core/query/types.ts +200 -0
  32. package/src/embeddings/auto-embed.ts +248 -0
  33. package/src/embeddings/index.ts +7 -0
  34. package/src/embeddings/model.ts +21 -4
  35. package/src/embeddings/types.ts +8 -1
  36. package/src/index.ts +9 -0
  37. package/src/sync/http-transport.ts +144 -0
  38. package/src/sync/index.ts +11 -0
  39. package/src/sync/multi-repo.ts +200 -0
  40. package/src/sync/ws-transport.ts +145 -0
  41. package/dist/index-5bhe57y9.js +0 -326
@@ -0,0 +1,336 @@
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
+
31
+ constructor(kernel: TrellisKernel, config?: AgentHarnessConfig) {
32
+ this.kernel = kernel;
33
+ this.config = {
34
+ recordDecisions: true,
35
+ maxDecisionsPerRun: 100,
36
+ ...config,
37
+ };
38
+ }
39
+
40
+ // -------------------------------------------------------------------------
41
+ // Agent CRUD (via kernel entities)
42
+ // -------------------------------------------------------------------------
43
+
44
+ async createAgent(def: Omit<AgentDef, 'id' | 'capabilities' | 'tools'> & {
45
+ id?: string;
46
+ capabilities?: string[];
47
+ tools?: string[];
48
+ }): Promise<AgentDef> {
49
+ const id = def.id ?? `agent:${def.name.toLowerCase().replace(/\s+/g, '-')}`;
50
+ await this.kernel.createEntity(id, 'Agent', {
51
+ name: def.name,
52
+ ...(def.description ? { description: def.description } : {}),
53
+ ...(def.model ? { model: def.model } : {}),
54
+ ...(def.provider ? { provider: def.provider } : {}),
55
+ ...(def.systemPrompt ? { systemPrompt: def.systemPrompt } : {}),
56
+ status: def.status ?? 'active',
57
+ });
58
+
59
+ // Add capability links
60
+ if (def.capabilities) {
61
+ for (const cap of def.capabilities) {
62
+ await this.kernel.addLink(id, 'hasCapability', cap);
63
+ }
64
+ }
65
+
66
+ // Add tool links
67
+ if (def.tools) {
68
+ for (const tool of def.tools) {
69
+ await this.kernel.addLink(id, 'hasTool', tool);
70
+ }
71
+ }
72
+
73
+ return this.getAgent(id)!;
74
+ }
75
+
76
+ getAgent(id: string): AgentDef | null {
77
+ const entity = this.kernel.getEntity(id);
78
+ if (!entity || entity.type !== 'Agent') return null;
79
+
80
+ const store = this.kernel.getStore();
81
+ const capLinks = store.getLinksByEntityAndAttribute(id, 'hasCapability');
82
+ const toolLinks = store.getLinksByEntityAndAttribute(id, 'hasTool');
83
+
84
+ return {
85
+ id: entity.id,
86
+ name: String(entity.facts.find((f) => f.a === 'name')?.v ?? ''),
87
+ description: entity.facts.find((f) => f.a === 'description')?.v as string | undefined,
88
+ model: entity.facts.find((f) => f.a === 'model')?.v as string | undefined,
89
+ provider: entity.facts.find((f) => f.a === 'provider')?.v as string | undefined,
90
+ systemPrompt: entity.facts.find((f) => f.a === 'systemPrompt')?.v as string | undefined,
91
+ status: (entity.facts.find((f) => f.a === 'status')?.v as AgentDef['status']) ?? 'active',
92
+ capabilities: capLinks.map((l) => l.e2),
93
+ tools: toolLinks.map((l) => l.e2),
94
+ };
95
+ }
96
+
97
+ listAgents(status?: AgentDef['status']): AgentDef[] {
98
+ const entities = this.kernel.listEntities('Agent', status ? { status } : undefined);
99
+ return entities
100
+ .map((e) => this.getAgent(e.id))
101
+ .filter((a): a is AgentDef => a !== null);
102
+ }
103
+
104
+ // -------------------------------------------------------------------------
105
+ // Tool registration
106
+ // -------------------------------------------------------------------------
107
+
108
+ async registerTool(def: Omit<ToolDef, 'id'> & { id?: string }, handler: ToolHandler): Promise<string> {
109
+ const id = def.id ?? `tool:${def.name.toLowerCase().replace(/\s+/g, '-')}`;
110
+
111
+ // Create tool entity if it doesn't exist
112
+ if (!this.kernel.getEntity(id)) {
113
+ await this.kernel.createEntity(id, 'Tool', {
114
+ name: def.name,
115
+ ...(def.description ? { description: def.description } : {}),
116
+ ...(def.schema ? { schema: def.schema } : {}),
117
+ ...(def.endpoint ? { endpoint: def.endpoint } : {}),
118
+ });
119
+ }
120
+
121
+ this.toolHandlers.set(id, handler);
122
+ return id;
123
+ }
124
+
125
+ getToolHandler(toolId: string): ToolHandler | undefined {
126
+ return this.toolHandlers.get(toolId);
127
+ }
128
+
129
+ listTools(): ToolDef[] {
130
+ return this.kernel.listEntities('Tool').map((e) => ({
131
+ id: e.id,
132
+ name: String(e.facts.find((f) => f.a === 'name')?.v ?? ''),
133
+ description: e.facts.find((f) => f.a === 'description')?.v as string | undefined,
134
+ schema: e.facts.find((f) => f.a === 'schema')?.v as string | undefined,
135
+ endpoint: e.facts.find((f) => f.a === 'endpoint')?.v as string | undefined,
136
+ }));
137
+ }
138
+
139
+ // -------------------------------------------------------------------------
140
+ // Run management
141
+ // -------------------------------------------------------------------------
142
+
143
+ async startRun(agentId: string, input?: string): Promise<string> {
144
+ const agent = this.getAgent(agentId);
145
+ if (!agent) throw new Error(`Agent "${agentId}" not found.`);
146
+
147
+ const runId = `run:${agentId.replace('agent:', '')}:${Date.now()}`;
148
+ await this.kernel.createEntity(runId, 'AgentRun', {
149
+ startedAt: new Date().toISOString(),
150
+ status: 'running',
151
+ ...(input ? { input } : {}),
152
+ });
153
+ await this.kernel.addLink(runId, 'executedBy', agentId);
154
+
155
+ return runId;
156
+ }
157
+
158
+ async completeRun(runId: string, output?: string, tokenCount?: number): Promise<void> {
159
+ const updates: Record<string, any> = {
160
+ status: 'completed',
161
+ completedAt: new Date().toISOString(),
162
+ };
163
+ if (output) updates.output = output;
164
+ if (tokenCount !== undefined) updates.tokenCount = tokenCount;
165
+ await this.kernel.updateEntity(runId, updates);
166
+ }
167
+
168
+ async failRun(runId: string, error: string): Promise<void> {
169
+ await this.kernel.updateEntity(runId, {
170
+ status: 'failed',
171
+ completedAt: new Date().toISOString(),
172
+ output: `Error: ${error}`,
173
+ });
174
+ }
175
+
176
+ getRun(runId: string): AgentRun | null {
177
+ const entity = this.kernel.getEntity(runId);
178
+ if (!entity || entity.type !== 'AgentRun') return null;
179
+
180
+ const store = this.kernel.getStore();
181
+ const agentLink = store.getLinksByEntityAndAttribute(runId, 'executedBy');
182
+ const agentId = agentLink[0]?.e2 ?? '';
183
+
184
+ // Get decisions for this run
185
+ const decisionLinks = store.getLinksByAttribute('belongsToRun');
186
+ const decisionIds = decisionLinks.filter((l) => l.e2 === runId).map((l) => l.e1);
187
+ const decisions = decisionIds.map((did) => this._buildDecisionTrace(did)).filter(Boolean) as DecisionTrace[];
188
+
189
+ const get = (a: string) => entity.facts.find((f) => f.a === a)?.v;
190
+
191
+ return {
192
+ id: runId,
193
+ agentId,
194
+ startedAt: String(get('startedAt') ?? ''),
195
+ completedAt: get('completedAt') as string | undefined,
196
+ status: (get('status') as RunStatus) ?? 'running',
197
+ input: get('input') as string | undefined,
198
+ output: get('output') as string | undefined,
199
+ tokenCount: get('tokenCount') as number | undefined,
200
+ decisions,
201
+ };
202
+ }
203
+
204
+ listRuns(agentId?: string): AgentRun[] {
205
+ const runs = this.kernel.listEntities('AgentRun');
206
+ return runs
207
+ .map((e) => this.getRun(e.id))
208
+ .filter((r): r is AgentRun => r !== null)
209
+ .filter((r) => !agentId || r.agentId === agentId)
210
+ .sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime());
211
+ }
212
+
213
+ // -------------------------------------------------------------------------
214
+ // Decision trace recording
215
+ // -------------------------------------------------------------------------
216
+
217
+ async recordDecision(
218
+ runId: string,
219
+ toolName: string,
220
+ input?: Record<string, unknown>,
221
+ output?: string,
222
+ opts?: {
223
+ rationale?: string;
224
+ alternatives?: string[];
225
+ relatedEntities?: string[];
226
+ },
227
+ ): Promise<string> {
228
+ const run = this.getRun(runId);
229
+ if (!run) throw new Error(`Run "${runId}" not found.`);
230
+
231
+ const decId = `decision:${runId.replace('run:', '')}:${Date.now()}`;
232
+ await this.kernel.createEntity(decId, 'DecisionTrace', {
233
+ toolName,
234
+ timestamp: new Date().toISOString(),
235
+ ...(input ? { input: JSON.stringify(input) } : {}),
236
+ ...(output ? { output } : {}),
237
+ ...(opts?.rationale ? { rationale: opts.rationale } : {}),
238
+ ...(opts?.alternatives ? { alternatives: JSON.stringify(opts.alternatives) } : {}),
239
+ });
240
+
241
+ // Link decision to run and agent
242
+ await this.kernel.addLink(decId, 'belongsToRun', runId);
243
+ await this.kernel.addLink(decId, 'madeBy', run.agentId);
244
+
245
+ // Link to related entities
246
+ if (opts?.relatedEntities) {
247
+ for (const eid of opts.relatedEntities) {
248
+ await this.kernel.addLink(decId, 'relatedTo', eid);
249
+ }
250
+ }
251
+
252
+ return decId;
253
+ }
254
+
255
+ /**
256
+ * Invoke a registered tool within a run, auto-recording a decision trace.
257
+ */
258
+ async invokeTool(
259
+ runId: string,
260
+ toolId: string,
261
+ input: Record<string, unknown>,
262
+ opts?: { rationale?: string; relatedEntities?: string[] },
263
+ ): Promise<ToolResult> {
264
+ const handler = this.toolHandlers.get(toolId);
265
+ if (!handler) throw new Error(`No handler registered for tool "${toolId}".`);
266
+
267
+ const result = await handler(input);
268
+
269
+ if (this.config.recordDecisions) {
270
+ const toolEntity = this.kernel.getEntity(toolId);
271
+ const toolName = toolEntity
272
+ ? String(toolEntity.facts.find((f) => f.a === 'name')?.v ?? toolId)
273
+ : toolId;
274
+
275
+ await this.recordDecision(
276
+ runId,
277
+ toolName,
278
+ input,
279
+ result.success ? String(result.output ?? '') : `Error: ${result.error}`,
280
+ opts,
281
+ );
282
+ }
283
+
284
+ return result;
285
+ }
286
+
287
+ getDecisionChain(entityId: string): DecisionTrace[] {
288
+ const store = this.kernel.getStore();
289
+ const links = store.getLinksByAttribute('relatedTo');
290
+ const decisionIds = links.filter((l) => l.e2 === entityId).map((l) => l.e1);
291
+ return decisionIds
292
+ .map((did) => this._buildDecisionTrace(did))
293
+ .filter(Boolean) as DecisionTrace[];
294
+ }
295
+
296
+ // -------------------------------------------------------------------------
297
+ // Internal helpers
298
+ // -------------------------------------------------------------------------
299
+
300
+ private _buildDecisionTrace(decId: string): DecisionTrace | null {
301
+ const entity = this.kernel.getEntity(decId);
302
+ if (!entity) return null;
303
+
304
+ const get = (a: string) => entity.facts.find((f) => f.a === a)?.v;
305
+ const store = this.kernel.getStore();
306
+
307
+ const runLink = store.getLinksByEntityAndAttribute(decId, 'belongsToRun');
308
+ const agentLink = store.getLinksByEntityAndAttribute(decId, 'madeBy');
309
+ const relatedLinks = store.getLinksByEntityAndAttribute(decId, 'relatedTo');
310
+
311
+ let inputParsed: Record<string, unknown> | undefined;
312
+ const inputRaw = get('input') as string | undefined;
313
+ if (inputRaw) {
314
+ try { inputParsed = JSON.parse(inputRaw); } catch { inputParsed = { raw: inputRaw }; }
315
+ }
316
+
317
+ let alternatives: string[] | undefined;
318
+ const altRaw = get('alternatives') as string | undefined;
319
+ if (altRaw) {
320
+ try { alternatives = JSON.parse(altRaw); } catch { alternatives = [altRaw]; }
321
+ }
322
+
323
+ return {
324
+ id: decId,
325
+ runId: runLink[0]?.e2 ?? '',
326
+ agentId: agentLink[0]?.e2 ?? '',
327
+ toolName: String(get('toolName') ?? ''),
328
+ input: inputParsed,
329
+ output: get('output') as string | undefined,
330
+ rationale: get('rationale') as string | undefined,
331
+ alternatives,
332
+ timestamp: String(get('timestamp') ?? ''),
333
+ relatedEntities: relatedLinks.map((l) => l.e2),
334
+ };
335
+ }
336
+ }
@@ -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';