dialai 1.5.0 → 1.5.1
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/.claude/specs/poll-gate.md +269 -0
- package/dist/dialai/asl/choice-extractor.d.ts +60 -0
- package/dist/dialai/asl/choice-extractor.d.ts.map +1 -0
- package/dist/dialai/asl/choice-extractor.js +131 -0
- package/dist/dialai/asl/choice-extractor.js.map +1 -0
- package/dist/dialai/asl/index.d.ts +6 -0
- package/dist/dialai/asl/index.d.ts.map +1 -0
- package/dist/dialai/asl/index.js +9 -0
- package/dist/dialai/asl/index.js.map +1 -0
- package/dist/dialai/asl/interpreter.d.ts +6 -0
- package/dist/dialai/asl/interpreter.d.ts.map +1 -0
- package/dist/dialai/asl/interpreter.js +260 -0
- package/dist/dialai/asl/interpreter.js.map +1 -0
- package/dist/dialai/asl/jsonpath.d.ts +34 -0
- package/dist/dialai/asl/jsonpath.d.ts.map +1 -0
- package/dist/dialai/asl/jsonpath.js +229 -0
- package/dist/dialai/asl/jsonpath.js.map +1 -0
- package/dist/dialai/asl/types.d.ts +45 -0
- package/dist/dialai/asl/types.d.ts.map +1 -0
- package/dist/dialai/asl/types.js +2 -0
- package/dist/dialai/asl/types.js.map +1 -0
- package/dist/dialai/asl/validator.d.ts +17 -0
- package/dist/dialai/asl/validator.d.ts.map +1 -0
- package/dist/dialai/asl/validator.js +75 -0
- package/dist/dialai/asl/validator.js.map +1 -0
- package/dist/dialai/cli.js +0 -0
- package/dist/dialai/docs-loader.d.ts +6 -0
- package/dist/dialai/docs-loader.d.ts.map +1 -0
- package/dist/dialai/docs-loader.js +63 -0
- package/dist/dialai/docs-loader.js.map +1 -0
- package/dist/dialai/gate.d.ts +44 -0
- package/dist/dialai/gate.d.ts.map +1 -0
- package/dist/dialai/gate.js +169 -0
- package/dist/dialai/gate.js.map +1 -0
- package/dist/dialai/llm.d.ts.map +1 -1
- package/dist/dialai/llm.js +11 -2
- package/dist/dialai/llm.js.map +1 -1
- package/dist/dialai/mcp.js +0 -0
- package/dist/dialai/migrations/002-users-credits.d.ts +5 -0
- package/dist/dialai/migrations/002-users-credits.d.ts.map +1 -0
- package/dist/dialai/migrations/002-users-credits.js +30 -0
- package/dist/dialai/migrations/002-users-credits.js.map +1 -0
- package/dist/dialai/migrations/004-rename-round-to-evaluation.d.ts +8 -0
- package/dist/dialai/migrations/004-rename-round-to-evaluation.d.ts.map +1 -0
- package/dist/dialai/migrations/004-rename-round-to-evaluation.js +63 -0
- package/dist/dialai/migrations/004-rename-round-to-evaluation.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Poll Gate Spec
|
|
2
|
+
|
|
3
|
+
A poll is a gate that fans a question out to N diverse LLM models, collects their answers, and uses an arbiter to summarize consensus. The gate is the reusable infrastructure — which models, what judge, what threshold. Each question is just another invocation of that gate.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// Create the gate once — this is the HOW
|
|
7
|
+
await createGate({
|
|
8
|
+
gateId: "10-model-poll",
|
|
9
|
+
prompt: "Answer the following question accurately and concisely.",
|
|
10
|
+
transitions: { resolved: "Consensus answer found" },
|
|
11
|
+
specialists: [
|
|
12
|
+
{ specialistId: "claude-sonnet", role: "proposer", modelId: "anthropic/claude-sonnet-4-20250514" },
|
|
13
|
+
{ specialistId: "gpt-4o", role: "proposer", modelId: "openai/gpt-4o" },
|
|
14
|
+
{ specialistId: "gemini-flash", role: "proposer", modelId: "google/gemini-2.0-flash-001" },
|
|
15
|
+
{ specialistId: "llama-70b", role: "proposer", modelId: "meta-llama/llama-3.1-70b-instruct" },
|
|
16
|
+
{ specialistId: "mistral-large", role: "proposer", modelId: "mistralai/mistral-large-2411" },
|
|
17
|
+
{ specialistId: "deepseek-v3", role: "proposer", modelId: "deepseek/deepseek-chat-v3-0324" },
|
|
18
|
+
{ specialistId: "qwen-72b", role: "proposer", modelId: "qwen/qwen-2.5-72b-instruct" },
|
|
19
|
+
{ specialistId: "cohere-r-plus", role: "proposer", modelId: "cohere/command-r-plus-08-2024" },
|
|
20
|
+
{ specialistId: "claude-haiku", role: "proposer", modelId: "anthropic/claude-haiku-4-5-20251001" },
|
|
21
|
+
{ specialistId: "gpt-4o-mini", role: "proposer", modelId: "openai/gpt-4o-mini" },
|
|
22
|
+
{ specialistId: "judge", role: "arbiter" }
|
|
23
|
+
],
|
|
24
|
+
consensusThreshold: 0.5,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Ask questions — each is an invocation of the same gate
|
|
28
|
+
const r1 = await invokeGate("10-model-poll", { promptSuffix: "Who won the 2025 World Series?" });
|
|
29
|
+
const r2 = await invokeGate("10-model-poll", { promptSuffix: "What is the capital of Australia?" });
|
|
30
|
+
// r1.reasoning → "7/10 said Dodgers because X, 3/10 said Yankees because Y"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## How It Maps to DIAL 1.5
|
|
34
|
+
|
|
35
|
+
Built entirely from existing primitives. No engine, strategy, or store changes.
|
|
36
|
+
|
|
37
|
+
| Poll concept | DIAL 1.5 primitive |
|
|
38
|
+
|---|---|
|
|
39
|
+
| Gate definition | `MachineDefinition` (synthetic 2-state machine) |
|
|
40
|
+
| Gate identity (`gateId`) | `machineName` — scopes alignment + exemplars |
|
|
41
|
+
| Invoking a gate | `createSession` + `submitProposal` × N + `submitArbitration` |
|
|
42
|
+
| A question | `promptSuffix` appended to gate prompt |
|
|
43
|
+
| An evaluation | A session with one round |
|
|
44
|
+
| Each model's answer | `submitProposal({ sessionId, specialistId })` |
|
|
45
|
+
| The judge | `submitArbitration({ sessionId })` via custom `strategyFn` |
|
|
46
|
+
| Human correction | `submitArbitration({ sessionId, specialistId: human, transitionName })` |
|
|
47
|
+
| Learning | Alignment + exemplars accumulate under `gateId` across all questions |
|
|
48
|
+
|
|
49
|
+
The synthetic machine has two states:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
evaluate ──resolved──▶ done
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Every proposer picks `resolved` (there's only one transition). Their answer goes in `reasoning`. The arbiter reads all proposals' reasoning and determines consensus.
|
|
56
|
+
|
|
57
|
+
## What Gets Built
|
|
58
|
+
|
|
59
|
+
### New file: `src/dialai/gate.ts`
|
|
60
|
+
|
|
61
|
+
Two functions. Everything else is reused.
|
|
62
|
+
|
|
63
|
+
#### `createGate(definition: GateDefinition): GateDefinition`
|
|
64
|
+
|
|
65
|
+
Stores the gate definition in an in-memory registry (Map). Returns the definition. Phase 2 moves this to the store.
|
|
66
|
+
|
|
67
|
+
#### `invokeGate(gateId, context, runtimeSpecialists?): GateResult`
|
|
68
|
+
|
|
69
|
+
1. Look up gate definition from registry.
|
|
70
|
+
2. Build synthetic `MachineDefinition`:
|
|
71
|
+
- `machineName` = `gateId` (so alignment/exemplars scope to gate)
|
|
72
|
+
- `initialState` = `"evaluate"`, `goalState` = `"done"`
|
|
73
|
+
- `evaluate` state: prompt = `gate.prompt + context.promptSuffix`, transitions all target `"done"`, specialists from gate definition, threshold from gate
|
|
74
|
+
- `done` state: empty (terminal)
|
|
75
|
+
3. `createSession(machine, context.metaJson)` — session persisted in store.
|
|
76
|
+
4. Register specialists:
|
|
77
|
+
- From `runtimeSpecialists` if provided (for function refs that can't serialize).
|
|
78
|
+
- From `gate.specialists` (strategyFnName-based auto-registration, same as `runSession` does).
|
|
79
|
+
- Defaults (`firstAvailable` proposer + `firstProposal` arbiter) if none.
|
|
80
|
+
5. `Promise.all` → all proposers invoked concurrently via `submitProposal`.
|
|
81
|
+
6. `submitArbitration({ sessionId })` — arbiter evaluates all proposals.
|
|
82
|
+
7. Return `GateResult`.
|
|
83
|
+
|
|
84
|
+
### New types in `types.ts`
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
interface GateDefinition {
|
|
88
|
+
gateId: string;
|
|
89
|
+
prompt?: string;
|
|
90
|
+
transitions: Record<string, string | TransitionDefinition>;
|
|
91
|
+
specialists?: SpecialistDefinition[];
|
|
92
|
+
consensusThreshold?: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface GateContext {
|
|
96
|
+
metaJson?: Record<string, unknown>;
|
|
97
|
+
history?: TransitionRecord[];
|
|
98
|
+
promptSuffix?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
interface GateResult {
|
|
102
|
+
evaluationId: string;
|
|
103
|
+
gateId: string;
|
|
104
|
+
transitionName: string | null;
|
|
105
|
+
reasoning: string;
|
|
106
|
+
needsHuman: boolean;
|
|
107
|
+
proposals: Proposal[];
|
|
108
|
+
metaJson?: Record<string, unknown>;
|
|
109
|
+
costUSD?: number;
|
|
110
|
+
latencyMsec?: number;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
All field types are existing DIAL types. Three types total.
|
|
115
|
+
|
|
116
|
+
### Registry helpers
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
createGate(definition: GateDefinition): GateDefinition
|
|
120
|
+
getGate(gateId: string): GateDefinition
|
|
121
|
+
listGates(): GateDefinition[]
|
|
122
|
+
deleteGate(gateId: string): void
|
|
123
|
+
clearGateRegistry(): void
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
In-memory Map for Phase 1. Phase 2 adds store persistence.
|
|
127
|
+
|
|
128
|
+
### Exports in `index.ts`
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
export type { GateDefinition, GateContext, GateResult } from "./types.js";
|
|
132
|
+
export { createGate, getGate, listGates, deleteGate, clearGateRegistry, invokeGate } from "./gate.js";
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## The LLM-as-Judge Arbiter
|
|
136
|
+
|
|
137
|
+
The judge is a custom `strategyFn` on the arbiter — no framework changes needed. The consumer provides it via `runtimeSpecialists`:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const result = await invokeGate("10-model-poll", {
|
|
141
|
+
promptSuffix: "Who won the 2025 World Series?"
|
|
142
|
+
}, {
|
|
143
|
+
arbiter: {
|
|
144
|
+
specialistId: "judge",
|
|
145
|
+
machineName: "10-model-poll",
|
|
146
|
+
strategyFn: async (ctx: ArbiterContext): Promise<ArbiterStrategyResult> => {
|
|
147
|
+
const responses = ctx.proposals.map((p, i) =>
|
|
148
|
+
`Model ${i + 1} (${p.specialistId}): ${p.reasoning}`
|
|
149
|
+
).join("\n\n");
|
|
150
|
+
|
|
151
|
+
const { content } = await callLlm(
|
|
152
|
+
"anthropic/claude-sonnet-4-20250514",
|
|
153
|
+
"You are a consensus judge. Read all model responses to a question. " +
|
|
154
|
+
"Determine if there is meaningful agreement. " +
|
|
155
|
+
"Respond with JSON: { \"consensusReached\": true/false, " +
|
|
156
|
+
"\"winningProposalId\": \"<proposalId of best response>\", " +
|
|
157
|
+
"\"reasoning\": \"<narrative: how many agreed, what they said, why>\" }",
|
|
158
|
+
`Question: ${ctx.prompt}\n\n${ctx.proposals.length} models responded:\n\n${responses}`
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const parsed = JSON.parse(content);
|
|
162
|
+
return {
|
|
163
|
+
consensusReached: parsed.consensusReached,
|
|
164
|
+
winningProposalId: parsed.winningProposalId,
|
|
165
|
+
reasoning: parsed.reasoning,
|
|
166
|
+
};
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The judge reads all N proposals, clusters the answers semantically ("LA Dodgers" = "The Dodgers" = "Los Angeles Dodgers"), produces a narrative summary ("7/10 said Dodgers because they won in 5 games, 2 said Yankees, 1 said Mets"), and picks the best-articulated winning response.
|
|
173
|
+
|
|
174
|
+
This is a regular custom arbiter. The DIAL framework doesn't need to know it's backed by an LLM.
|
|
175
|
+
|
|
176
|
+
## How a Question Flows Through
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
1. Consumer calls: invokeGate("10-model-poll", { promptSuffix: "Who won the 2025 WS?" })
|
|
180
|
+
|
|
181
|
+
2. invokeGate builds synthetic machine:
|
|
182
|
+
machineName: "10-model-poll"
|
|
183
|
+
states:
|
|
184
|
+
evaluate:
|
|
185
|
+
prompt: "Answer the following question accurately and concisely.\n\nWho won the 2025 WS?"
|
|
186
|
+
transitions: { resolved: { target: "done", description: "Consensus answer found" } }
|
|
187
|
+
done: {}
|
|
188
|
+
|
|
189
|
+
3. createSession("10-model-poll", {}) → session with sessionId + roundId
|
|
190
|
+
|
|
191
|
+
4. Register 10 proposers + 1 arbiter under machineName "10-model-poll"
|
|
192
|
+
|
|
193
|
+
5. Promise.all → 10 concurrent submitProposal calls
|
|
194
|
+
Each proposer:
|
|
195
|
+
- Gets ProposerContext with prompt, transitions: { resolved → done }, exemplars
|
|
196
|
+
- LLM mode: contextFn builds context → callLlm → parses response
|
|
197
|
+
- Returns { transitionName: "resolved", toState: "done", reasoning: "The LA Dodgers won..." }
|
|
198
|
+
- Stored as Proposal in the round
|
|
199
|
+
|
|
200
|
+
6. submitArbitration({ sessionId })
|
|
201
|
+
- Loads all 10 proposals
|
|
202
|
+
- Calls judge arbiter strategyFn
|
|
203
|
+
- Judge LLM reads all 10 answers, determines consensus
|
|
204
|
+
- Returns { consensusReached: true, winningProposalId: "...", reasoning: "7/10 said Dodgers..." }
|
|
205
|
+
- If consensus: executes transition, session moves to "done"
|
|
206
|
+
- If no consensus: returns needsHuman
|
|
207
|
+
|
|
208
|
+
7. GateResult returned:
|
|
209
|
+
{ evaluationId, gateId: "10-model-poll", transitionName: "resolved",
|
|
210
|
+
reasoning: "7/10 said Dodgers...", needsHuman: false,
|
|
211
|
+
proposals: [all 10] }
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Human Override
|
|
215
|
+
|
|
216
|
+
When the judge says `needsHuman` (or a human disagrees with the consensus), the consumer can call `submitArbitration` directly on the session (the `evaluationId` in `GateResult` maps to the underlying `sessionId`):
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const result = await invokeGate("10-model-poll", { promptSuffix: "Who won the 2025 WS?" });
|
|
220
|
+
|
|
221
|
+
if (result.needsHuman) {
|
|
222
|
+
// Register a human specialist (once)
|
|
223
|
+
await registerProposer({
|
|
224
|
+
specialistId: "human-reviewer",
|
|
225
|
+
machineName: "10-model-poll",
|
|
226
|
+
isHuman: true,
|
|
227
|
+
strategyFnName: "firstAvailable",
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Human forces the answer using the evaluationId as sessionId
|
|
231
|
+
await submitArbitration({
|
|
232
|
+
sessionId: result.evaluationId,
|
|
233
|
+
specialistId: "human-reviewer",
|
|
234
|
+
transitionName: "resolved",
|
|
235
|
+
reasoning: "The correct answer is the LA Dodgers. They won in 5 games against the Yankees.",
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
This triggers the standard DIAL learning cycle:
|
|
241
|
+
- Alignment updated for all 10 proposers (did they agree with the human?)
|
|
242
|
+
- Exemplar captured (question context + all proposals + human's answer)
|
|
243
|
+
- Future invocations include this exemplar as a few-shot example
|
|
244
|
+
|
|
245
|
+
Over time, the gate collapses: models that consistently agree with humans earn high alignment, the arbiter's job gets easier, and eventually a champion model handles questions autonomously.
|
|
246
|
+
|
|
247
|
+
## What Doesn't Change
|
|
248
|
+
|
|
249
|
+
Nothing. The gate is built entirely from existing DIAL 1.5 primitives:
|
|
250
|
+
|
|
251
|
+
- `createSession` / `submitProposal` / `submitArbitration` — unchanged
|
|
252
|
+
- `registerProposer` / `registerArbiter` — unchanged
|
|
253
|
+
- Alignment tracking — unchanged (scoped by `machineName` = `gateId`)
|
|
254
|
+
- Exemplar system — unchanged (scoped by `machineName` = `gateId`)
|
|
255
|
+
- Store interface — unchanged
|
|
256
|
+
- Engine / tick loop — not used (gates use `Promise.all` for parallel fan-out)
|
|
257
|
+
- LLM integration — unchanged (proposers use `contextFn + modelId`, judge uses `callLlm` inside a `strategyFn`)
|
|
258
|
+
- Strategies — unchanged (consumer provides custom `strategyFn` for the judge)
|
|
259
|
+
|
|
260
|
+
## Files Touched
|
|
261
|
+
|
|
262
|
+
| File | Change |
|
|
263
|
+
|---|---|
|
|
264
|
+
| `src/dialai/types.ts` | Add 3 types: `GateDefinition`, `GateContext`, `GateResult` |
|
|
265
|
+
| `src/dialai/gate.ts` | **New file** — `createGate`, `invokeGate`, registry helpers |
|
|
266
|
+
| `src/dialai/index.ts` | Export new types + gate functions |
|
|
267
|
+
| `tests/unit/gate.test.ts` | Gate tests |
|
|
268
|
+
|
|
269
|
+
Zero changes to `api.ts`, `engine.ts`, `llm.ts`, `strategies.ts`, `store.ts`, `alignment.ts`, `exemplars.ts`.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { TransitionOption } from "./types.js";
|
|
2
|
+
interface ChoiceRule {
|
|
3
|
+
Variable?: string;
|
|
4
|
+
StringEquals?: string;
|
|
5
|
+
StringEqualsPath?: string;
|
|
6
|
+
StringLessThan?: string;
|
|
7
|
+
StringLessThanPath?: string;
|
|
8
|
+
StringGreaterThan?: string;
|
|
9
|
+
StringGreaterThanPath?: string;
|
|
10
|
+
StringLessThanEquals?: string;
|
|
11
|
+
StringLessThanEqualsPath?: string;
|
|
12
|
+
StringGreaterThanEquals?: string;
|
|
13
|
+
StringGreaterThanEqualsPath?: string;
|
|
14
|
+
StringMatches?: string;
|
|
15
|
+
NumericEquals?: number;
|
|
16
|
+
NumericEqualsPath?: string;
|
|
17
|
+
NumericLessThan?: number;
|
|
18
|
+
NumericLessThanPath?: string;
|
|
19
|
+
NumericGreaterThan?: number;
|
|
20
|
+
NumericGreaterThanPath?: string;
|
|
21
|
+
NumericLessThanEquals?: number;
|
|
22
|
+
NumericLessThanEqualsPath?: string;
|
|
23
|
+
NumericGreaterThanEquals?: number;
|
|
24
|
+
NumericGreaterThanEqualsPath?: string;
|
|
25
|
+
BooleanEquals?: boolean;
|
|
26
|
+
BooleanEqualsPath?: string;
|
|
27
|
+
TimestampEquals?: string;
|
|
28
|
+
TimestampEqualsPath?: string;
|
|
29
|
+
TimestampLessThan?: string;
|
|
30
|
+
TimestampLessThanPath?: string;
|
|
31
|
+
TimestampGreaterThan?: string;
|
|
32
|
+
TimestampGreaterThanPath?: string;
|
|
33
|
+
TimestampLessThanEquals?: string;
|
|
34
|
+
TimestampLessThanEqualsPath?: string;
|
|
35
|
+
TimestampGreaterThanEquals?: string;
|
|
36
|
+
TimestampGreaterThanEqualsPath?: string;
|
|
37
|
+
IsNull?: boolean;
|
|
38
|
+
IsPresent?: boolean;
|
|
39
|
+
IsNumeric?: boolean;
|
|
40
|
+
IsString?: boolean;
|
|
41
|
+
IsBoolean?: boolean;
|
|
42
|
+
IsTimestamp?: boolean;
|
|
43
|
+
And?: ChoiceRule[];
|
|
44
|
+
Or?: ChoiceRule[];
|
|
45
|
+
Not?: ChoiceRule;
|
|
46
|
+
Next?: string;
|
|
47
|
+
}
|
|
48
|
+
interface ChoiceState {
|
|
49
|
+
Type: "Choice";
|
|
50
|
+
Comment?: string;
|
|
51
|
+
Choices: ChoiceRule[];
|
|
52
|
+
Default?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Extract transition options from a Choice state.
|
|
56
|
+
* For $.transition StringEquals rules, uses the value as the transition name.
|
|
57
|
+
*/
|
|
58
|
+
export declare function extractTransitions(choiceState: ChoiceState): TransitionOption[];
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=choice-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choice-extractor.d.ts","sourceRoot":"","sources":["../../../src/dialai/asl/choice-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEpE,UAAU,UAAU;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACtC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC;IACnB,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,WAAW;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,GAAG,gBAAgB,EAAE,CA0B/E"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract transition options from a Choice state.
|
|
3
|
+
* For $.transition StringEquals rules, uses the value as the transition name.
|
|
4
|
+
*/
|
|
5
|
+
export function extractTransitions(choiceState) {
|
|
6
|
+
const transitions = [];
|
|
7
|
+
for (const rule of choiceState.Choices) {
|
|
8
|
+
const condition = extractCondition(rule);
|
|
9
|
+
const name = deriveTransitionName(rule, condition);
|
|
10
|
+
if (rule.Next) {
|
|
11
|
+
transitions.push({
|
|
12
|
+
name,
|
|
13
|
+
targetState: rule.Next,
|
|
14
|
+
condition,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// Add Default as a fallback option
|
|
19
|
+
if (choiceState.Default) {
|
|
20
|
+
transitions.push({
|
|
21
|
+
name: "default",
|
|
22
|
+
targetState: choiceState.Default,
|
|
23
|
+
condition: { operator: "default" },
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return transitions;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Derive a human-readable transition name from the rule.
|
|
30
|
+
* For $.transition StringEquals, use the value.
|
|
31
|
+
* Otherwise, generate a descriptive name.
|
|
32
|
+
*/
|
|
33
|
+
function deriveTransitionName(rule, condition) {
|
|
34
|
+
// Special case: $.transition StringEquals "value" -> use "value" as name
|
|
35
|
+
if (rule.Variable === "$.transition" &&
|
|
36
|
+
rule.StringEquals !== undefined) {
|
|
37
|
+
return rule.StringEquals;
|
|
38
|
+
}
|
|
39
|
+
// For compound rules, try to find a $.transition StringEquals in children
|
|
40
|
+
if (condition.children) {
|
|
41
|
+
for (const child of condition.children) {
|
|
42
|
+
if (child.variable === "$.transition" &&
|
|
43
|
+
child.operator === "StringEquals" &&
|
|
44
|
+
typeof child.value === "string") {
|
|
45
|
+
return child.value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Generate name from condition
|
|
50
|
+
if (condition.variable && condition.value !== undefined) {
|
|
51
|
+
return `${condition.operator}_${String(condition.value)}`;
|
|
52
|
+
}
|
|
53
|
+
return `to_${rule.Next}`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Extract a ChoiceCondition from a rule.
|
|
57
|
+
*/
|
|
58
|
+
function extractCondition(rule) {
|
|
59
|
+
// Compound rules
|
|
60
|
+
if (rule.And) {
|
|
61
|
+
return {
|
|
62
|
+
operator: "And",
|
|
63
|
+
children: rule.And.map(extractCondition),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (rule.Or) {
|
|
67
|
+
return {
|
|
68
|
+
operator: "Or",
|
|
69
|
+
children: rule.Or.map(extractCondition),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (rule.Not) {
|
|
73
|
+
return {
|
|
74
|
+
operator: "Not",
|
|
75
|
+
children: [extractCondition(rule.Not)],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// Simple comparison operators
|
|
79
|
+
const operators = [
|
|
80
|
+
"StringEquals",
|
|
81
|
+
"StringEqualsPath",
|
|
82
|
+
"StringLessThan",
|
|
83
|
+
"StringLessThanPath",
|
|
84
|
+
"StringGreaterThan",
|
|
85
|
+
"StringGreaterThanPath",
|
|
86
|
+
"StringLessThanEquals",
|
|
87
|
+
"StringLessThanEqualsPath",
|
|
88
|
+
"StringGreaterThanEquals",
|
|
89
|
+
"StringGreaterThanEqualsPath",
|
|
90
|
+
"StringMatches",
|
|
91
|
+
"NumericEquals",
|
|
92
|
+
"NumericEqualsPath",
|
|
93
|
+
"NumericLessThan",
|
|
94
|
+
"NumericLessThanPath",
|
|
95
|
+
"NumericGreaterThan",
|
|
96
|
+
"NumericGreaterThanPath",
|
|
97
|
+
"NumericLessThanEquals",
|
|
98
|
+
"NumericLessThanEqualsPath",
|
|
99
|
+
"NumericGreaterThanEquals",
|
|
100
|
+
"NumericGreaterThanEqualsPath",
|
|
101
|
+
"BooleanEquals",
|
|
102
|
+
"BooleanEqualsPath",
|
|
103
|
+
"TimestampEquals",
|
|
104
|
+
"TimestampEqualsPath",
|
|
105
|
+
"TimestampLessThan",
|
|
106
|
+
"TimestampLessThanPath",
|
|
107
|
+
"TimestampGreaterThan",
|
|
108
|
+
"TimestampGreaterThanPath",
|
|
109
|
+
"TimestampLessThanEquals",
|
|
110
|
+
"TimestampLessThanEqualsPath",
|
|
111
|
+
"TimestampGreaterThanEquals",
|
|
112
|
+
"TimestampGreaterThanEqualsPath",
|
|
113
|
+
"IsNull",
|
|
114
|
+
"IsPresent",
|
|
115
|
+
"IsNumeric",
|
|
116
|
+
"IsString",
|
|
117
|
+
"IsBoolean",
|
|
118
|
+
"IsTimestamp",
|
|
119
|
+
];
|
|
120
|
+
for (const op of operators) {
|
|
121
|
+
if (rule[op] !== undefined) {
|
|
122
|
+
return {
|
|
123
|
+
variable: rule.Variable,
|
|
124
|
+
operator: op,
|
|
125
|
+
value: rule[op],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { operator: "unknown" };
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=choice-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choice-extractor.js","sourceRoot":"","sources":["../../../src/dialai/asl/choice-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { DIALStateMachine, StateResult, TransitionOption, ChoiceCondition, TaskHandler, InterpreterConfig, ExecutionContext, } from "./types.js";
|
|
2
|
+
export { validateDIALStateMachine, parseDIALStateMachine, type ValidationResult, } from "./validator.js";
|
|
3
|
+
export { extractTransitions } from "./choice-extractor.js";
|
|
4
|
+
export { executeState } from "./interpreter.js";
|
|
5
|
+
export { getJsonPathValue, setJsonPathValue, applyInputPath, applyOutputPath, applyResultPath, applyParameters, applyResultSelector, } from "./jsonpath.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dialai/asl/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,gBAAgB,GACtB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAG3D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,mBAAmB,GACpB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Validator
|
|
2
|
+
export { validateDIALStateMachine, parseDIALStateMachine, } from "./validator.js";
|
|
3
|
+
// Choice extractor
|
|
4
|
+
export { extractTransitions } from "./choice-extractor.js";
|
|
5
|
+
// Interpreter
|
|
6
|
+
export { executeState } from "./interpreter.js";
|
|
7
|
+
// JSONPath utilities
|
|
8
|
+
export { getJsonPathValue, setJsonPathValue, applyInputPath, applyOutputPath, applyResultPath, applyParameters, applyResultSelector, } from "./jsonpath.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dialai/asl/index.ts"],"names":[],"mappings":"AAWA,YAAY;AACZ,OAAO,EACL,wBAAwB,EACxB,qBAAqB,GAEtB,MAAM,gBAAgB,CAAC;AAExB,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,cAAc;AACd,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,qBAAqB;AACrB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,mBAAmB,GACpB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DIALStateMachine, StateResult, InterpreterConfig, ExecutionContext } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Execute a single state in the state machine.
|
|
4
|
+
*/
|
|
5
|
+
export declare function executeState(machine: DIALStateMachine, stateName: string, context: ExecutionContext, config?: InterpreterConfig): Promise<StateResult>;
|
|
6
|
+
//# sourceMappingURL=interpreter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../../../src/dialai/asl/interpreter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAsCpB;;GAEG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,gBAAgB,EACzB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,gBAAgB,EACzB,MAAM,GAAE,iBAAsB,GAC7B,OAAO,CAAC,WAAW,CAAC,CA0BtB"}
|