dialai 1.0.0 → 1.2.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 (34) hide show
  1. package/.claude/skills/dial-machine/SKILL.md +401 -0
  2. package/.claude/skills/dial-machine/references/api-reference.md +515 -0
  3. package/.claude/skills/dial-machine/references/patterns.md +628 -0
  4. package/.claude/skills/spec-for-ralph/SKILL.md +542 -0
  5. package/.claude/specs/llm-audit-log.md +280 -0
  6. package/LICENSE +1 -1
  7. package/README.md +1 -1
  8. package/dist/dialai/api.d.ts +2 -6
  9. package/dist/dialai/api.d.ts.map +1 -1
  10. package/dist/dialai/api.js +22 -6
  11. package/dist/dialai/api.js.map +1 -1
  12. package/dist/dialai/llm.d.ts +6 -4
  13. package/dist/dialai/llm.d.ts.map +1 -1
  14. package/dist/dialai/llm.js +96 -31
  15. package/dist/dialai/llm.js.map +1 -1
  16. package/dist/dialai/migrations/002-llm-audit-log.d.ts +8 -0
  17. package/dist/dialai/migrations/002-llm-audit-log.d.ts.map +1 -0
  18. package/dist/dialai/migrations/002-llm-audit-log.js +41 -0
  19. package/dist/dialai/migrations/002-llm-audit-log.js.map +1 -0
  20. package/dist/dialai/migrations/migrate.d.ts.map +1 -1
  21. package/dist/dialai/migrations/migrate.js +2 -0
  22. package/dist/dialai/migrations/migrate.js.map +1 -1
  23. package/dist/dialai/store-memory.d.ts.map +1 -1
  24. package/dist/dialai/store-memory.js +22 -0
  25. package/dist/dialai/store-memory.js.map +1 -1
  26. package/dist/dialai/store-postgres.d.ts.map +1 -1
  27. package/dist/dialai/store-postgres.js +54 -1
  28. package/dist/dialai/store-postgres.js.map +1 -1
  29. package/dist/dialai/store.d.ts +3 -1
  30. package/dist/dialai/store.d.ts.map +1 -1
  31. package/dist/dialai/store.js.map +1 -1
  32. package/dist/dialai/types.d.ts +54 -0
  33. package/dist/dialai/types.d.ts.map +1 -1
  34. package/package.json +3 -2
@@ -0,0 +1,515 @@
1
+ # DIAL API Reference
2
+
3
+ Complete API types and function signatures for the `dialai` library. All exports are available from the top-level `"dialai"` package.
4
+
5
+ ## Core Types
6
+
7
+ ### `MachineDefinition`
8
+
9
+ ```typescript
10
+ interface MachineDefinition {
11
+ machineName: string; // Unique identifier for this machine type
12
+ initialState: string; // State where sessions start
13
+ goalState: string; // Rest state where the session is headed
14
+ states: Record<string, StateDefinition>; // Map of state names to definitions
15
+ specialists?: SpecialistDefinition[]; // Optional machine-level specialists
16
+ consensusThreshold?: number; // Default consensus threshold (0-1)
17
+ }
18
+ ```
19
+
20
+ ### `StateDefinition`
21
+
22
+ ```typescript
23
+ interface StateDefinition {
24
+ prompt?: string; // Decision prompt for this state
25
+ transitions?: Record<string, string>; // Map of transition names to target states
26
+ consensusThreshold?: number; // Override threshold for this state
27
+ specialists?: SpecialistDefinition[]; // Per-state specialist declarations
28
+ }
29
+ ```
30
+
31
+ ### `Session`
32
+
33
+ ```typescript
34
+ interface Session {
35
+ sessionId: string; // UUID generated at creation
36
+ machineName: string; // Name of the machine being run
37
+ currentState: string; // Current state in the machine
38
+ currentRoundId: string; // ID of the current decision round
39
+ machine: MachineDefinition; // The full machine definition
40
+ history: TransitionRecord[]; // All executed transitions in order
41
+ createdAt: Date; // When the session was created
42
+ metaJson?: Record<string, unknown>; // Arbitrary session-level metadata
43
+ }
44
+ ```
45
+
46
+ ### `TransitionRecord`
47
+
48
+ ```typescript
49
+ interface TransitionRecord {
50
+ transitionName: string; // Name of the transition taken
51
+ reasoning: string; // Why this transition was chosen
52
+ executionTimestamp: Date; // When the transition was executed
53
+ metaJson?: Record<string, unknown>; // Arbitrary metadata from the winning proposal
54
+ }
55
+ ```
56
+
57
+ ## Specialist Types
58
+
59
+ ### `SpecialistDefinition`
60
+
61
+ Used in machine JSON for declaring specialists:
62
+
63
+ ```typescript
64
+ interface SpecialistDefinition {
65
+ role: "proposer" | "arbiter";
66
+ specialistId: string;
67
+ machineName?: string; // Defaults to the machine's machineName
68
+ isHuman?: boolean;
69
+ disabled?: boolean; // Per-state: registered but not solicited
70
+ strategyFn?: string;
71
+ strategyFnName?: string; // Built-in strategy name
72
+ strategyWebhookUrl?: string;
73
+ contextFn?: string;
74
+ contextWebhookUrl?: string;
75
+ modelId?: string;
76
+ webhookTokenName?: string;
77
+ threshold?: number;
78
+ }
79
+ ```
80
+
81
+ ### `Proposer`
82
+
83
+ ```typescript
84
+ interface Proposer {
85
+ role: "proposer";
86
+ specialistId: string;
87
+ machineName: string;
88
+ isHuman?: boolean;
89
+ enabled?: boolean; // Default true
90
+ strategyFn?: (ctx: ProposerContext) => Promise<ProposerStrategyResult>;
91
+ strategyFnName?: string;
92
+ strategyWebhookUrl?: string;
93
+ contextFn?: (ctx: ProposerContext) => Promise<string>;
94
+ contextWebhookUrl?: string;
95
+ modelId?: string;
96
+ webhookTokenName?: string;
97
+ threshold?: number;
98
+ }
99
+ ```
100
+
101
+ ### `Arbiter`
102
+
103
+ ```typescript
104
+ interface Arbiter {
105
+ role: "arbiter";
106
+ specialistId: string;
107
+ machineName: string;
108
+ enabled?: boolean; // Default true
109
+ strategyFn?: (ctx: ArbiterContext) => Promise<ArbiterStrategyResult>;
110
+ strategyFnName?: string;
111
+ strategyWebhookUrl?: string;
112
+ webhookTokenName?: string;
113
+ threshold?: number;
114
+ }
115
+ ```
116
+
117
+ ### `ProposerStrategyResult`
118
+
119
+ ```typescript
120
+ interface ProposerStrategyResult {
121
+ transitionName: string;
122
+ toState: string;
123
+ reasoning: string;
124
+ costUSD?: number; // Cost in USD to generate this result
125
+ latencyMsec?: number; // Time in milliseconds to generate
126
+ numInputTokens?: number; // Input tokens used
127
+ numOutputTokens?: number; // Output tokens used
128
+ }
129
+ ```
130
+
131
+ When returned from a strategy function, these optional metrics are merged into the resulting `Proposal`. Metrics passed via `SubmitProposalOptions` take precedence over strategy-returned values.
132
+
133
+ ### `ArbiterStrategyResult`
134
+
135
+ ```typescript
136
+ interface ArbiterStrategyResult {
137
+ consensusReached: boolean;
138
+ winningProposalId?: string;
139
+ reasoning: string;
140
+ }
141
+ ```
142
+
143
+ ## Context Types
144
+
145
+ ### `ProposerContext`
146
+
147
+ Provided to proposer strategy functions:
148
+
149
+ ```typescript
150
+ interface ProposerContext {
151
+ sessionId: string;
152
+ currentState: string;
153
+ prompt: string; // Decision prompt for this state
154
+ transitions: Record<string, string>; // Available transitions (name -> target)
155
+ history: TransitionRecord[]; // All previous transitions
156
+ metaJson?: Record<string, unknown>; // Session-level metadata
157
+ }
158
+ ```
159
+
160
+ ### `ArbiterContext`
161
+
162
+ Provided to arbiter strategy functions:
163
+
164
+ ```typescript
165
+ interface ArbiterContext {
166
+ sessionId: string;
167
+ roundId: string;
168
+ currentState: string;
169
+ prompt: string;
170
+ machineName: string;
171
+ proposals: Proposal[]; // All proposals in this round
172
+ alignmentScores?: Record<string, number>; // Alignment scores by specialistId
173
+ humanGoldExamples?: HumanGoldExample[]; // Human gold examples
174
+ history: TransitionRecord[];
175
+ threshold?: number; // Configured threshold for this arbiter
176
+ metaJson?: Record<string, unknown>;
177
+ }
178
+ ```
179
+
180
+ ## Decision Types
181
+
182
+ ### `Proposal`
183
+
184
+ ```typescript
185
+ interface Proposal {
186
+ proposalId: string; // UUID generated on creation
187
+ sessionId: string;
188
+ roundId: string;
189
+ specialistId: string; // Who submitted this proposal
190
+ isHuman: boolean;
191
+ transitionName: string; // The transition being proposed
192
+ toState: string; // Target state of the transition
193
+ reasoning: string;
194
+ metaJson?: Record<string, unknown>;
195
+ costUSD?: number; // Cost in USD to generate
196
+ latencyMsec?: number; // Time in milliseconds to generate
197
+ numInputTokens?: number;
198
+ numOutputTokens?: number;
199
+ createdAt: Date;
200
+ }
201
+ ```
202
+
203
+ ### `ConsensusResult`
204
+
205
+ ```typescript
206
+ interface ConsensusResult {
207
+ consensusReached: boolean;
208
+ winningProposalId?: string; // Set if consensus reached
209
+ reasoning: string;
210
+ }
211
+ ```
212
+
213
+ ### `ArbitrationResult`
214
+
215
+ Returned by `submitArbitration()`:
216
+
217
+ ```typescript
218
+ interface ArbitrationResult {
219
+ arbitrationId: string;
220
+ sessionId: string;
221
+ roundId: string;
222
+ specialistId?: string;
223
+ stale: boolean; // True if roundId doesn't match current
224
+ guardsPass: boolean; // True if all guards passed
225
+ guardReason: string; // Explanation if guards failed
226
+ winningProposalId?: string;
227
+ transitionName?: string;
228
+ toState?: string;
229
+ reasoning?: string;
230
+ executed: boolean; // Whether transition was executed
231
+ isHuman: boolean; // Whether this was a human-forced decision
232
+ metaJson?: Record<string, unknown>;
233
+ costUSD?: number;
234
+ latencyMsec?: number;
235
+ numInputTokens?: number;
236
+ numOutputTokens?: number;
237
+ }
238
+ ```
239
+
240
+ ## Registration Options
241
+
242
+ ### `RegisterProposerOptions`
243
+
244
+ Exactly one execution mode is required. Forbidden combinations are validated at registration time.
245
+
246
+ ```typescript
247
+ interface RegisterProposerOptions {
248
+ specialistId: string; // Required: unique identifier
249
+ machineName: string; // Required: which machine
250
+
251
+ isHuman?: boolean;
252
+
253
+ // Execution mode (exactly one required):
254
+ strategyFn?: (ctx: ProposerContext) => Promise<ProposerStrategyResult>;
255
+ strategyFnName?: string; // Built-in strategy name
256
+ strategyWebhookUrl?: string; // External webhook URL
257
+
258
+ // LLM-based modes:
259
+ modelId?: string; // Required with contextFn or contextWebhookUrl
260
+ contextFn?: (ctx: ProposerContext) => Promise<string>;
261
+ contextWebhookUrl?: string;
262
+
263
+ webhookTokenName?: string; // Required with webhook URLs
264
+ threshold?: number; // Strategy-specific threshold
265
+ }
266
+ ```
267
+
268
+ **Five execution modes:**
269
+ 1. `strategyFn` — local async function that returns `ProposerStrategyResult`
270
+ 2. `strategyFnName` — name of a built-in strategy (`firstAvailable`, `lastAvailable`, `random`)
271
+ 3. `strategyWebhookUrl` + `webhookTokenName` — external HTTP endpoint
272
+ 4. `contextFn` + `modelId` — local function provides context string, DIAL calls the LLM
273
+ 5. `contextWebhookUrl` + `modelId` + `webhookTokenName` — webhook provides context, DIAL calls the LLM
274
+
275
+ ### `RegisterArbiterOptions`
276
+
277
+ ```typescript
278
+ interface RegisterArbiterOptions {
279
+ specialistId: string; // Required: unique identifier
280
+ machineName: string; // Required: which machine
281
+
282
+ // Execution mode (exactly one required):
283
+ strategyFn?: (ctx: ArbiterContext) => Promise<ArbiterStrategyResult>;
284
+ strategyFnName?: string; // Built-in strategy name
285
+ strategyWebhookUrl?: string; // External webhook URL
286
+
287
+ webhookTokenName?: string; // Required with webhook URLs
288
+ threshold?: number; // Strategy-specific threshold
289
+ }
290
+ ```
291
+
292
+ **Three execution modes:**
293
+ 1. `strategyFn` — local async function
294
+ 2. `strategyFnName` — name of a built-in strategy (`firstProposal`, `alignmentMargin`)
295
+ 3. `strategyWebhookUrl` + `webhookTokenName` — external HTTP endpoint
296
+
297
+ ### `SubmitProposalOptions`
298
+
299
+ ```typescript
300
+ interface SubmitProposalOptions {
301
+ sessionId: string; // Required
302
+ specialistId: string; // Required
303
+ roundId?: string; // Defaults to session's currentRoundId
304
+ transitionName?: string; // If omitted, invokes registered strategy
305
+ reasoning?: string;
306
+ metaJson?: Record<string, unknown>;
307
+ costUSD?: number;
308
+ latencyMsec?: number;
309
+ numInputTokens?: number;
310
+ numOutputTokens?: number;
311
+ }
312
+ ```
313
+
314
+ ### `SubmitArbitrationOptions`
315
+
316
+ ```typescript
317
+ interface SubmitArbitrationOptions {
318
+ sessionId: string; // Required
319
+ roundId?: string; // Defaults to session's currentRoundId
320
+ specialistId?: string; // Who is calling
321
+ transitionName?: string; // Force this transition (human only)
322
+ reasoning?: string;
323
+ metaJson?: Record<string, unknown>;
324
+ costUSD?: number;
325
+ latencyMsec?: number;
326
+ numInputTokens?: number;
327
+ numOutputTokens?: number;
328
+ }
329
+ ```
330
+
331
+ ## Function Signatures
332
+
333
+ ### Session Management
334
+
335
+ ```typescript
336
+ // Create a new session from a machine definition
337
+ async function createSession(
338
+ machine: MachineDefinition,
339
+ metaJson?: Record<string, unknown>
340
+ ): Promise<Session>;
341
+
342
+ // Get a session by ID (throws if not found)
343
+ async function getSession(sessionId: string): Promise<Session>;
344
+
345
+ // Get all sessions
346
+ async function getSessions(): Promise<Session[]>;
347
+ ```
348
+
349
+ ### Specialist Registration
350
+
351
+ ```typescript
352
+ // Register a proposer (throws if specialistId already exists)
353
+ async function registerProposer(opts: RegisterProposerOptions): Promise<Proposer>;
354
+
355
+ // Register an arbiter (throws if specialistId already exists)
356
+ async function registerArbiter(opts: RegisterArbiterOptions): Promise<Arbiter>;
357
+ ```
358
+
359
+ ### Decision Cycle
360
+
361
+ ```typescript
362
+ // Submit a proposal (invokes strategy if transitionName omitted)
363
+ async function submitProposal(opts: SubmitProposalOptions): Promise<Proposal>;
364
+
365
+ // Evaluate consensus (read-only, does not execute transitions)
366
+ async function evaluateConsensus(sessionId: string): Promise<ConsensusResult>;
367
+
368
+ // Evaluate consensus and execute transition if reached
369
+ async function submitArbitration(opts: SubmitArbitrationOptions): Promise<ArbitrationResult>;
370
+
371
+ // Execute a state transition directly
372
+ async function executeTransition(
373
+ sessionId: string,
374
+ transitionName: string,
375
+ toState: string,
376
+ reasoning?: string
377
+ ): Promise<Session>;
378
+ ```
379
+
380
+ ### Engine
381
+
382
+ ```typescript
383
+ // Run a machine to completion (creates session, registers defaults, loops tick)
384
+ async function runSession(machine: MachineDefinition): Promise<Session>;
385
+
386
+ // Global heartbeat: one atomic step per active session
387
+ async function tick(): Promise<TickResult[]>;
388
+
389
+ // Select the highest-alignment proposer above threshold
390
+ async function selectChampion(
391
+ machineName: string,
392
+ threshold: number,
393
+ proposers?: Proposer[],
394
+ state?: string
395
+ ): Promise<string | undefined>;
396
+ ```
397
+
398
+ ### Store
399
+
400
+ ```typescript
401
+ // Reset all state (sessions, specialists, proposals, alignment records, etc.)
402
+ async function clear(): Promise<void>;
403
+ ```
404
+
405
+ ### Monitoring
406
+
407
+ ```typescript
408
+ // Compute collapse metrics for a machine
409
+ async function getCollapseMetrics(
410
+ machineName: string,
411
+ state?: string
412
+ ): Promise<CollapseMetrics>;
413
+ ```
414
+
415
+ ## Built-in Strategies
416
+
417
+ ### Proposer Strategies
418
+
419
+ | Name | Behavior |
420
+ |---|---|
421
+ | `firstAvailable` | Returns the first transition in `ctx.transitions` |
422
+ | `lastAvailable` | Returns the last transition in `ctx.transitions` |
423
+ | `random` | Returns a randomly selected transition |
424
+
425
+ All throw if no transitions are available.
426
+
427
+ ### Arbiter Strategies
428
+
429
+ | Name | Behavior |
430
+ |---|---|
431
+ | `firstProposal` | Accepts the first proposal by creation timestamp |
432
+ | `alignmentMargin` | Alignment-weighted margin consensus |
433
+
434
+ **`alignmentMargin` details:**
435
+ - Single proposal with `threshold <= 1`: auto-approves
436
+ - Multiple proposals: groups by `transitionName`, scores each group by summing proposer alignment scores
437
+ - `margin = (leaderScore - runnerUpScore) / totalAlignment`
438
+ - Consensus when `margin >= threshold` (default threshold = 1, requiring unanimity)
439
+ - Cold start (all alignment scores = 0): no consensus, human input required
440
+ - Winner: highest-alignment proposer in the winning transition group
441
+
442
+ ## Monitoring Types
443
+
444
+ ### `CollapseMetrics`
445
+
446
+ ```typescript
447
+ interface CollapseMetrics {
448
+ machineName: string;
449
+ totalDecisions: number;
450
+ humanDecisions: number;
451
+ aiDecisions: number;
452
+ collapseRatio: number; // aiDecisions / totalDecisions
453
+ recentCollapseRatio: number; // Collapse ratio for recent decisions
454
+ averageConsensusMargin: number;
455
+ alignmentScores: Record<string, number>;
456
+ specialists: SpecialistMetrics[];
457
+ signals: Signal[]; // Actionable signals (info/warning/action)
458
+ }
459
+ ```
460
+
461
+ ### `AlignmentRecord`
462
+
463
+ ```typescript
464
+ interface AlignmentRecord {
465
+ specialistId: string;
466
+ machineName: string;
467
+ state?: string; // When present, alignment is per-state
468
+ matchingChoices: number;
469
+ totalComparisons: number;
470
+ alignmentScore: number; // Wilson score lower bound
471
+ lastUpdated: Date;
472
+ }
473
+ ```
474
+
475
+ ### `Exemplar`
476
+
477
+ ```typescript
478
+ interface Exemplar {
479
+ exemplarId: string;
480
+ machineName: string;
481
+ state: string;
482
+ context: ProposerContext; // Session context at decision time
483
+ humanTransitionName: string;
484
+ humanToState: string;
485
+ proposals: Proposal[]; // All proposals that were available
486
+ createdAt: Date;
487
+ }
488
+ ```
489
+
490
+ ### `TickResult`
491
+
492
+ ```typescript
493
+ type TickStatus = "solicited" | "advanced" | "needs_human";
494
+
495
+ interface TickResult {
496
+ sessionId: string;
497
+ machineName: string;
498
+ status: TickStatus;
499
+ currentState: string;
500
+ specialistId?: string; // Set when status === "solicited"
501
+ previousState?: string; // Set when status === "advanced"
502
+ transitionName?: string; // Set when status === "advanced"
503
+ reasoning?: string; // Set when status === "advanced"
504
+ }
505
+ ```
506
+
507
+ ## Environment Variables
508
+
509
+ | Variable | Default | Description |
510
+ |---|---|---|
511
+ | `DIALAI_BASE_URL` | `""` | Remote DIAL server URL (proxy mode) |
512
+ | `DIALAI_PORT` | — | Port for HTTP server mode |
513
+ | `DIALAI_API_TOKEN` | `""` | Bearer token for HTTP server and proxy mode |
514
+ | `DIALAI_LLM_BASE_URL` | `"https://openrouter.ai/api/v1"` | OpenAI-compatible LLM endpoint |
515
+ | `OPENROUTER_API_TOKEN` | `""` | API token for OpenRouter or compatible provider |