taias 0.9.2 → 0.9.3

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/index.js DELETED
@@ -1,547 +0,0 @@
1
- // src/flow.ts
2
- function defineFlow(flowId, builder) {
3
- const steps = [];
4
- const flowBuilder = {
5
- step(match, input) {
6
- if (typeof input === "function") {
7
- steps.push({ kind: "handler", match, handler: input });
8
- } else {
9
- steps.push({
10
- kind: "logic",
11
- statement: {
12
- match,
13
- decision: input
14
- }
15
- });
16
- }
17
- }
18
- };
19
- builder(flowBuilder);
20
- return {
21
- id: flowId,
22
- steps
23
- };
24
- }
25
-
26
- // src/uiAffordances/types.ts
27
- function normalizeBinding(input) {
28
- if ("toolName" in input) return { key: "nextTool", value: input.toolName };
29
- return { key: input.key, value: input.value };
30
- }
31
- function makeBindingKey(slot, binding) {
32
- return `${slot}::${binding.key}::${binding.value}`;
33
- }
34
-
35
- // src/uiAffordances/indexing.ts
36
- function buildRegistryIndex(registry) {
37
- const byBindingKey = /* @__PURE__ */ new Map();
38
- const slots = /* @__PURE__ */ new Set();
39
- const slotKeyMap = /* @__PURE__ */ new Map();
40
- if (!registry) return { byBindingKey, slots, slotKeyMap };
41
- for (const h of registry.handles) {
42
- slots.add(h.slot);
43
- const existingKey = slotKeyMap.get(h.slot);
44
- if (existingKey && existingKey !== h.bindsTo.key) {
45
- throw new Error(
46
- `[Taias] Slot "${h.slot}" has handles bound to different keys: "${existingKey}" and "${h.bindsTo.key}". All handles for a slot must use the same decision field.`
47
- );
48
- }
49
- slotKeyMap.set(h.slot, h.bindsTo.key);
50
- byBindingKey.set(makeBindingKey(h.slot, h.bindsTo), h);
51
- }
52
- return { byBindingKey, slots, slotKeyMap };
53
- }
54
-
55
- // src/uiAffordances/select.ts
56
- function selectUiAffordances(decision, index, opts = {}) {
57
- const devMode = !!opts.devMode;
58
- const warn = opts.onWarn ?? (() => {
59
- });
60
- const selections = {};
61
- for (const slot of index.slots) {
62
- const field = index.slotKeyMap.get(slot);
63
- if (!field) continue;
64
- const value = decision[field];
65
- if (!value) continue;
66
- const k = makeBindingKey(slot, { key: field, value });
67
- const handle = index.byBindingKey.get(k);
68
- if (!handle) {
69
- if (devMode) warn(`[Taias] No affordance for slot "${slot}" when ${field}="${value}"`);
70
- continue;
71
- }
72
- selections[slot] = {
73
- handleId: handle.handleId,
74
- bindsTo: handle.bindsTo
75
- };
76
- }
77
- return selections;
78
- }
79
-
80
- // src/debugSubscriber.ts
81
- function formatContext(context) {
82
- const parts = [];
83
- if (context.toolName) parts.push(`toolName=${context.toolName}`);
84
- if (context.params) parts.push(`params=${JSON.stringify(context.params)}`);
85
- if (context.result) parts.push(`result=${JSON.stringify(context.result)}`);
86
- return parts.length > 0 ? parts.join(", ") : "(empty)";
87
- }
88
- function formatContextLabel(context) {
89
- if (context.toolName) return context.toolName;
90
- if (context.params) return `params:${JSON.stringify(context.params)}`;
91
- if (context.result) return `result:${JSON.stringify(context.result)}`;
92
- return "(empty)";
93
- }
94
- function createDebugSubscriber(options) {
95
- const format = options?.format ?? "default";
96
- const log = options?.logger ?? console.log;
97
- if (format === "compact") {
98
- return (event) => {
99
- const { trace, context } = event;
100
- const label = formatContextLabel(context);
101
- if (!trace.matched) {
102
- log(`[Taias] ${label} \u2192 no match (${trace.candidatesEvaluated} evaluated)`);
103
- return;
104
- }
105
- const decisionSummary = event.decision ? Object.entries(event.decision).map(([k, v]) => `${k}=${v}`).join(", ") : "null";
106
- log(
107
- `[Taias] ${label} \u2192 ${decisionSummary} (${trace.phase}, step ${trace.matchedStepIndex}, ${trace.candidatesEvaluated} evaluated)`
108
- );
109
- };
110
- }
111
- return (event) => {
112
- const { trace, context } = event;
113
- const lines = [];
114
- lines.push("\u250C\u2500 Taias Resolve \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
115
- lines.push(`\u2502 Flow: ${event.flowId}`);
116
- lines.push(`\u2502 Context: ${formatContext(context)}`);
117
- lines.push("\u2502");
118
- if (!trace.matched) {
119
- lines.push("\u2502 Result: NO MATCH");
120
- lines.push(`\u2502 Candidates evaluated: ${trace.candidatesEvaluated}`);
121
- } else {
122
- lines.push(`\u2502 Matched: step ${trace.matchedStepIndex} (${trace.matchedStepKind})`);
123
- lines.push(`\u2502 Phase: ${trace.phase}`);
124
- if (trace.resolutionPath.length > 0) {
125
- lines.push(`\u2502 Resolution path: ${trace.resolutionPath.join(" \u2192 ")}`);
126
- }
127
- lines.push(`\u2502 Candidates evaluated: ${trace.candidatesEvaluated}`);
128
- if (trace.matchedStepMatch) {
129
- lines.push(`\u2502 Match condition: ${JSON.stringify(trace.matchedStepMatch)}`);
130
- }
131
- }
132
- lines.push("\u2502");
133
- if (event.decision) {
134
- const fields = Object.entries(event.decision).map(([k, v]) => `${k}=${v}`).join(", ");
135
- lines.push(`\u2502 Decision: ${fields}`);
136
- } else {
137
- lines.push("\u2502 Decision: null");
138
- }
139
- if (event.affordances) {
140
- lines.push(`\u2502 Advice: ${event.affordances.advice.slice(0, 80)}${event.affordances.advice.length > 80 ? "..." : ""}`);
141
- }
142
- lines.push(`\u2502 Duration: ${event.durationMs.toFixed(2)}ms`);
143
- if (trace.evaluations) {
144
- lines.push("\u2502");
145
- lines.push("\u2502 Detailed evaluations:");
146
- for (const evaluation of trace.evaluations) {
147
- const icon = evaluation.result === "matched" ? "\u2713" : "\u2717";
148
- lines.push(`\u2502 ${icon} step ${evaluation.stepIndex}: ${evaluation.result}`);
149
- if (evaluation.fieldResults) {
150
- for (const [field, fr] of Object.entries(evaluation.fieldResults)) {
151
- const fieldIcon = fr.passed ? "\u2713" : "\u2717";
152
- lines.push(`\u2502 ${fieldIcon} ${field}: ${JSON.stringify(fr.condition)} vs ${JSON.stringify(fr.actual)}`);
153
- }
154
- }
155
- }
156
- }
157
- lines.push("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
158
- log(lines.join("\n"));
159
- };
160
- }
161
-
162
- // src/createTaias.ts
163
- function generateAdvice(nextTool) {
164
- return `FOR THE BEST USER EXPERIENCE, TELL THE USER TO USE THE ${nextTool} TOOL NEXT!!!!!`;
165
- }
166
- function evaluateCondition(condition, value) {
167
- if ("is" in condition) return value === condition.is;
168
- if ("isNot" in condition) return value !== condition.isNot;
169
- return false;
170
- }
171
- function evaluateMatch(match, ctx) {
172
- if (match.toolName && !evaluateCondition(match.toolName, ctx.toolName)) return false;
173
- if (match.params) {
174
- if (!ctx.params) return false;
175
- for (const [key, condition] of Object.entries(match.params)) {
176
- if (!evaluateCondition(condition, ctx.params[key])) return false;
177
- }
178
- }
179
- if (match.result) {
180
- if (!ctx.result) return false;
181
- for (const [key, condition] of Object.entries(match.result)) {
182
- if (!evaluateCondition(condition, ctx.result[key])) return false;
183
- }
184
- }
185
- return true;
186
- }
187
- function evaluateMatchDetailed(match, ctx) {
188
- const fieldResults = {};
189
- let allPassed = true;
190
- if (match.toolName) {
191
- const actual = ctx.toolName;
192
- const passed = evaluateCondition(match.toolName, actual);
193
- fieldResults["toolName"] = { condition: match.toolName, actual, passed };
194
- if (!passed) allPassed = false;
195
- }
196
- if (match.params) {
197
- if (!ctx.params) {
198
- for (const [key, condition] of Object.entries(match.params)) {
199
- fieldResults[`params.${key}`] = { condition, actual: void 0, passed: false };
200
- }
201
- allPassed = false;
202
- } else {
203
- for (const [key, condition] of Object.entries(match.params)) {
204
- const actual = ctx.params[key];
205
- const passed = evaluateCondition(condition, actual);
206
- fieldResults[`params.${key}`] = { condition, actual, passed };
207
- if (!passed) allPassed = false;
208
- }
209
- }
210
- }
211
- if (match.result) {
212
- if (!ctx.result) {
213
- for (const [key, condition] of Object.entries(match.result)) {
214
- fieldResults[`result.${key}`] = { condition, actual: void 0, passed: false };
215
- }
216
- allPassed = false;
217
- } else {
218
- for (const [key, condition] of Object.entries(match.result)) {
219
- const actual = ctx.result[key];
220
- const passed = evaluateCondition(condition, actual);
221
- fieldResults[`result.${key}`] = { condition, actual, passed };
222
- if (!passed) allPassed = false;
223
- }
224
- }
225
- }
226
- return { passed: allPassed, fieldResults };
227
- }
228
- function extractIsConditions(match) {
229
- const conditions = [];
230
- if (match.toolName && "is" in match.toolName) {
231
- conditions.push({ path: "toolName", value: match.toolName.is });
232
- }
233
- if (match.params) {
234
- for (const [key, cond] of Object.entries(match.params)) {
235
- if ("is" in cond) conditions.push({ path: `params.${key}`, value: cond.is });
236
- }
237
- }
238
- if (match.result) {
239
- for (const [key, cond] of Object.entries(match.result)) {
240
- if ("is" in cond) conditions.push({ path: `result.${key}`, value: cond.is });
241
- }
242
- }
243
- return conditions;
244
- }
245
- function hasConditionOnField(match, path) {
246
- if (path === "toolName") return !!match.toolName;
247
- if (path.startsWith("params.")) return !!match.params?.[path.slice(7)];
248
- if (path.startsWith("result.")) return !!match.result?.[path.slice(7)];
249
- return false;
250
- }
251
- function getContextValue(ctx, path) {
252
- if (path === "toolName") return ctx.toolName;
253
- if (path.startsWith("params.")) return ctx.params?.[path.slice(7)];
254
- if (path.startsWith("result.")) return ctx.result?.[path.slice(7)];
255
- return void 0;
256
- }
257
- function getMatch(step) {
258
- return step.kind === "logic" ? step.statement.match : step.match;
259
- }
260
- function serializeMatch(match) {
261
- return JSON.stringify(match);
262
- }
263
- function createTaias(options) {
264
- const {
265
- flow,
266
- affordances,
267
- devMode = false,
268
- debug = false,
269
- tracing = "summary",
270
- onMissingStep,
271
- onWarn
272
- } = options;
273
- const warn = onWarn ?? ((msg) => console.warn(msg));
274
- const detailed = tracing === "detailed";
275
- if (devMode) {
276
- const seenKeys = /* @__PURE__ */ new Set();
277
- for (const step of flow.steps) {
278
- const key = serializeMatch(getMatch(step));
279
- if (seenKeys.has(key)) {
280
- throw new Error(
281
- `Taias: Duplicate match condition in flow '${flow.id}'. Each step must have a unique match condition. Duplicate: ${key}`
282
- );
283
- }
284
- seenKeys.add(key);
285
- }
286
- }
287
- const fieldIndexes = /* @__PURE__ */ new Map();
288
- const indexableStepIndices = [];
289
- const broadStepIndices = [];
290
- for (let i = 0; i < flow.steps.length; i++) {
291
- const match = getMatch(flow.steps[i]);
292
- const isConditions = extractIsConditions(match);
293
- if (isConditions.length === 0) {
294
- broadStepIndices.push(i);
295
- continue;
296
- }
297
- indexableStepIndices.push(i);
298
- for (const { path, value } of isConditions) {
299
- let fieldIndex = fieldIndexes.get(path);
300
- if (!fieldIndex) {
301
- fieldIndex = { valueMap: /* @__PURE__ */ new Map(), unconstrained: [] };
302
- fieldIndexes.set(path, fieldIndex);
303
- }
304
- let stepList = fieldIndex.valueMap.get(value);
305
- if (!stepList) {
306
- stepList = [];
307
- fieldIndex.valueMap.set(value, stepList);
308
- }
309
- stepList.push(i);
310
- }
311
- }
312
- for (const [fieldPath, fieldIndex] of fieldIndexes) {
313
- for (const i of indexableStepIndices) {
314
- if (!hasConditionOnField(getMatch(flow.steps[i]), fieldPath)) {
315
- fieldIndex.unconstrained.push(i);
316
- }
317
- }
318
- }
319
- const hasBroadSteps = broadStepIndices.length > 0;
320
- const registryIndex = buildRegistryIndex(affordances);
321
- const listeners = /* @__PURE__ */ new Map();
322
- function emit(event, data) {
323
- const handlers = listeners.get(event);
324
- if (handlers) {
325
- for (const handler of handlers) handler(data);
326
- }
327
- }
328
- function on(event, handler) {
329
- let set = listeners.get(event);
330
- if (!set) {
331
- set = /* @__PURE__ */ new Set();
332
- listeners.set(event, set);
333
- }
334
- set.add(handler);
335
- }
336
- function off(event, handler) {
337
- listeners.get(event)?.delete(handler);
338
- }
339
- if (debug) {
340
- const debugOpts = typeof debug === "object" ? debug : void 0;
341
- on("resolve", createDebugSubscriber(debugOpts));
342
- }
343
- return {
344
- async resolve(ctx) {
345
- const startTime = performance.now();
346
- const timestamp = Date.now();
347
- let matchedStep;
348
- let matchedStepIndex = null;
349
- let matchPhase = null;
350
- const resolutionPath = [];
351
- let candidatesEvaluated = 0;
352
- const evaluations = detailed ? [] : void 0;
353
- function tryMatch(idx) {
354
- candidatesEvaluated++;
355
- const step = flow.steps[idx];
356
- const match = getMatch(step);
357
- if (detailed) {
358
- const { passed, fieldResults } = evaluateMatchDetailed(match, ctx);
359
- evaluations.push({
360
- stepIndex: idx,
361
- match,
362
- result: passed ? "matched" : "no-match",
363
- fieldResults
364
- });
365
- return passed;
366
- }
367
- return evaluateMatch(match, ctx);
368
- }
369
- const applicableFieldPaths = [];
370
- for (const fieldPath of fieldIndexes.keys()) {
371
- const ctxValue = getContextValue(ctx, fieldPath);
372
- if (ctxValue !== void 0) {
373
- applicableFieldPaths.push(fieldPath);
374
- }
375
- }
376
- resolutionPath.push(...applicableFieldPaths);
377
- if (applicableFieldPaths.length > 0) {
378
- let candidates = null;
379
- for (const fieldPath of applicableFieldPaths) {
380
- const fieldIndex = fieldIndexes.get(fieldPath);
381
- const ctxValue = getContextValue(ctx, fieldPath);
382
- const fieldCandidates = /* @__PURE__ */ new Set();
383
- const indexed = fieldIndex.valueMap.get(ctxValue);
384
- if (indexed) {
385
- for (const idx of indexed) fieldCandidates.add(idx);
386
- }
387
- for (const idx of fieldIndex.unconstrained) {
388
- fieldCandidates.add(idx);
389
- }
390
- if (candidates === null) {
391
- candidates = fieldCandidates;
392
- } else {
393
- for (const idx of candidates) {
394
- if (!fieldCandidates.has(idx)) candidates.delete(idx);
395
- }
396
- }
397
- }
398
- if (candidates && candidates.size > 0) {
399
- const sorted = [...candidates].sort((a, b) => a - b);
400
- for (const idx of sorted) {
401
- if (tryMatch(idx)) {
402
- matchedStep = flow.steps[idx];
403
- matchedStepIndex = idx;
404
- matchPhase = "indexed";
405
- break;
406
- }
407
- }
408
- }
409
- } else if (indexableStepIndices.length > 0) {
410
- for (const idx of indexableStepIndices) {
411
- if (tryMatch(idx)) {
412
- matchedStep = flow.steps[idx];
413
- matchedStepIndex = idx;
414
- matchPhase = "indexed";
415
- break;
416
- }
417
- }
418
- }
419
- if (!matchedStep && hasBroadSteps) {
420
- for (const idx of broadStepIndices) {
421
- if (tryMatch(idx)) {
422
- matchedStep = flow.steps[idx];
423
- matchedStepIndex = idx;
424
- matchPhase = "broad";
425
- break;
426
- }
427
- }
428
- }
429
- const trace = {
430
- matched: !!matchedStep,
431
- matchedStepIndex,
432
- matchedStepKind: matchedStep?.kind ?? null,
433
- matchedStepMatch: matchedStep ? getMatch(matchedStep) : null,
434
- phase: matchPhase,
435
- resolutionPath,
436
- candidatesEvaluated,
437
- ...evaluations !== void 0 ? { evaluations } : {}
438
- };
439
- if (!matchedStep) {
440
- onMissingStep?.(ctx);
441
- emit("resolve", {
442
- flowId: flow.id,
443
- timestamp,
444
- durationMs: performance.now() - startTime,
445
- context: ctx,
446
- trace,
447
- decision: null,
448
- affordances: null
449
- });
450
- return null;
451
- }
452
- let result;
453
- if (matchedStep.kind === "logic") {
454
- result = matchedStep.statement.decision;
455
- } else {
456
- result = await matchedStep.handler(ctx);
457
- }
458
- if (!result) {
459
- emit("resolve", {
460
- flowId: flow.id,
461
- timestamp,
462
- durationMs: performance.now() - startTime,
463
- context: ctx,
464
- trace,
465
- decision: null,
466
- affordances: null
467
- });
468
- return null;
469
- }
470
- if (devMode && result.nextTool === "") {
471
- warn(`Taias: nextTool for tool '${ctx.toolName}' is empty.`);
472
- }
473
- const decision = { ...result };
474
- const selections = selectUiAffordances(decision, registryIndex, {
475
- devMode,
476
- onWarn: warn
477
- });
478
- const advice = generateAdvice(result.nextTool);
479
- emit("resolve", {
480
- flowId: flow.id,
481
- timestamp,
482
- durationMs: performance.now() - startTime,
483
- context: ctx,
484
- trace,
485
- decision,
486
- affordances: { advice, selections }
487
- });
488
- return { advice, decision, selections };
489
- },
490
- on,
491
- off
492
- };
493
- }
494
-
495
- // src/uiAffordances/defineAffordances.ts
496
- function defineAffordances(builder) {
497
- const handles = [];
498
- const registrar = new Proxy({}, {
499
- get(_, slot) {
500
- return (handleId, bindsTo) => {
501
- handles.push({
502
- slot,
503
- handleId,
504
- bindsTo: normalizeBinding(bindsTo)
505
- });
506
- };
507
- }
508
- });
509
- builder(registrar);
510
- return { handles };
511
- }
512
-
513
- // src/uiAffordances/mergeAffordances.ts
514
- function mergeAffordances(registries, opts = {}) {
515
- const devMode = !!opts.devMode;
516
- const warn = opts.onWarn ?? (() => {
517
- });
518
- const merged = { handles: registries.flatMap((r) => r.handles) };
519
- if (!devMode) return merged;
520
- const seenHandleIds = /* @__PURE__ */ new Set();
521
- for (const h of merged.handles) {
522
- if (seenHandleIds.has(h.handleId)) {
523
- throw new Error(`[Taias] Duplicate handleId "${h.handleId}"`);
524
- }
525
- seenHandleIds.add(h.handleId);
526
- }
527
- const seenTriples = /* @__PURE__ */ new Set();
528
- for (const h of merged.handles) {
529
- const k = makeBindingKey(h.slot, h.bindsTo);
530
- if (seenTriples.has(k)) {
531
- throw new Error(
532
- `[Taias] Ambiguous affordance: slot "${h.slot}" has multiple handles bound to (${h.bindsTo.key}="${h.bindsTo.value}")`
533
- );
534
- }
535
- seenTriples.add(k);
536
- }
537
- warn(`[Taias] Loaded ${merged.handles.length} UI affordance handles`);
538
- return merged;
539
- }
540
- export {
541
- createDebugSubscriber,
542
- createTaias,
543
- defineAffordances,
544
- defineFlow,
545
- mergeAffordances
546
- };
547
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/flow.ts","../src/uiAffordances/types.ts","../src/uiAffordances/indexing.ts","../src/uiAffordances/select.ts","../src/debugSubscriber.ts","../src/createTaias.ts","../src/uiAffordances/defineAffordances.ts","../src/uiAffordances/mergeAffordances.ts"],"sourcesContent":["import type { FlowBuilder, FlowDefinition, FlowStep, MatchCondition, StepInput } from \"./types\";\n\n/**\n * Define a flow with its steps.\n *\n * @param flowId - Unique identifier for the flow\n * @param builder - Callback that receives a FlowBuilder to define steps\n * @returns A FlowDefinition object\n *\n * @example Logic statement matching on toolName\n * ```ts\n * const onboardRepoFlow = defineFlow(\"onboard_repo\", (flow) => {\n * flow.step({ toolName: { is: \"scan_repo\" } }, { nextTool: \"configure_app\" });\n * });\n * ```\n *\n * @example Matching on params and result\n * ```ts\n * flow.step(\n * { toolName: { is: \"scan_repo\" }, params: { language: { is: \"python\" } } },\n * { nextTool: \"configure_python\" },\n * );\n * flow.step(\n * { result: { hasConfig: { is: true } } },\n * { nextTool: \"review_config\" },\n * );\n * ```\n *\n * @example isNot operator\n * ```ts\n * flow.step({ toolName: { isNot: \"abort_session\" } }, { nextTool: \"continue_flow\" });\n * ```\n */\nexport function defineFlow(\n flowId: string,\n builder: (flow: FlowBuilder) => void\n): FlowDefinition {\n const steps: FlowStep[] = [];\n\n const flowBuilder: FlowBuilder = {\n step(match: MatchCondition, input: StepInput): void {\n if (typeof input === \"function\") {\n steps.push({ kind: \"handler\", match, handler: input });\n } else {\n steps.push({\n kind: \"logic\",\n statement: {\n match,\n decision: input,\n },\n });\n }\n },\n };\n\n builder(flowBuilder);\n\n return {\n id: flowId,\n steps,\n };\n}\n","/**\n * Default slots for backwards compatibility.\n * Users can define custom slots by passing a type parameter.\n */\nexport type DefaultSlots = \"primaryCta\" | \"secondaryCta\" | \"widgetVariant\";\n\n/**\n * Alias for backwards compatibility in exports.\n * @deprecated Use DefaultSlots or define your own slot type\n */\nexport type CanonicalSlot = DefaultSlots;\n\nexport type Binding = {\n key: string;\n value: string;\n};\n\n/**\n * Input format for registering affordance bindings.\n * - { toolName } is shorthand for { key: \"nextTool\", value: toolName }\n * - { key, value } is the generalized form for custom bindings\n */\nexport type BindingInput = { toolName: string } | { key: string; value: string };\n\n/**\n * A registered UI affordance handle.\n * Generic over slot type S for custom slot support.\n */\nexport type HandleRegistration<S extends string = DefaultSlots> = {\n slot: S;\n handleId: string;\n bindsTo: Binding;\n};\n\nexport type Selection = {\n handleId: string;\n bindsTo: Binding;\n};\n\n/**\n * UI selections keyed by slot name.\n * Generic over slot type S for custom slot support.\n */\nexport type UiSelections<S extends string = DefaultSlots> = Partial<Record<S, Selection>>;\n\n/**\n * Collection of registered handles.\n * Generic over slot type S for custom slot support.\n */\nexport type AffordanceRegistry<S extends string = DefaultSlots> = {\n handles: HandleRegistration<S>[];\n};\n\nexport function normalizeBinding(input: BindingInput): Binding {\n if (\"toolName\" in input) return { key: \"nextTool\", value: input.toolName };\n return { key: input.key, value: input.value };\n}\n\n/**\n * Creates a binding key for indexing.\n * Accepts any string for slot to support custom slots.\n */\nexport function makeBindingKey(slot: string, binding: Binding): string {\n return `${slot}::${binding.key}::${binding.value}`;\n}\n","import type { AffordanceRegistry, DefaultSlots, HandleRegistration } from \"./types\";\nimport { makeBindingKey } from \"./types\";\n\n/**\n * Index structure for efficient affordance lookup.\n * Generic over slot type S for custom slot support.\n */\nexport type RegistryIndex<S extends string = DefaultSlots> = {\n byBindingKey: Map<string, HandleRegistration<S>>;\n slots: Set<S>;\n /** Inferred decision field for each slot, derived from handle bindings. */\n slotKeyMap: Map<S, string>;\n};\n\n/**\n * Build an index from a registry for efficient lookup during selection.\n * Tracks which slots have registered handles and infers the decision field\n * for each slot from its handle bindings.\n *\n * @throws Error if handles for the same slot bind to different keys\n */\nexport function buildRegistryIndex<S extends string = DefaultSlots>(\n registry?: AffordanceRegistry<S>\n): RegistryIndex<S> {\n const byBindingKey = new Map<string, HandleRegistration<S>>();\n const slots = new Set<S>();\n const slotKeyMap = new Map<S, string>();\n\n if (!registry) return { byBindingKey, slots, slotKeyMap };\n\n for (const h of registry.handles) {\n slots.add(h.slot);\n\n // Infer and validate slot key\n const existingKey = slotKeyMap.get(h.slot);\n if (existingKey && existingKey !== h.bindsTo.key) {\n throw new Error(\n `[Taias] Slot \"${h.slot}\" has handles bound to different keys: \"${existingKey}\" and \"${h.bindsTo.key}\". ` +\n `All handles for a slot must use the same decision field.`\n );\n }\n slotKeyMap.set(h.slot, h.bindsTo.key);\n\n byBindingKey.set(makeBindingKey(h.slot, h.bindsTo), h);\n }\n\n return { byBindingKey, slots, slotKeyMap };\n}\n","import type { Decision } from \"../types\";\nimport type { DefaultSlots, UiSelections } from \"./types\";\nimport type { RegistryIndex } from \"./indexing\";\nimport { makeBindingKey } from \"./types\";\n\nexport type SelectOptions = {\n devMode?: boolean;\n onWarn?: (msg: string) => void;\n};\n\n/**\n * Select UI affordances based on flow decision.\n * Uses the inferred decision field for each slot from the registry index.\n */\nexport function selectUiAffordances<S extends string = DefaultSlots>(\n decision: Decision,\n index: RegistryIndex<S>,\n opts: SelectOptions = {}\n): UiSelections<S> {\n const devMode = !!opts.devMode;\n const warn = opts.onWarn ?? (() => {});\n\n const selections: UiSelections<S> = {};\n\n for (const slot of index.slots) {\n // Use inferred key from handle bindings\n const field = index.slotKeyMap.get(slot);\n if (!field) continue;\n\n const value = decision[field];\n if (!value) continue;\n\n const k = makeBindingKey(slot, { key: field, value });\n const handle = index.byBindingKey.get(k);\n\n if (!handle) {\n if (devMode) warn(`[Taias] No affordance for slot \"${slot}\" when ${field}=\"${value}\"`);\n continue;\n }\n\n (selections as Record<string, unknown>)[slot] = {\n handleId: handle.handleId,\n bindsTo: handle.bindsTo,\n };\n }\n\n return selections;\n}\n","import type { ResolveEvent, TaiasContext, DebugOptions } from \"./types\";\n\nexport type DebugSubscriberOptions = DebugOptions;\n\nfunction formatContext(context: TaiasContext): string {\n const parts: string[] = [];\n if (context.toolName) parts.push(`toolName=${context.toolName}`);\n if (context.params) parts.push(`params=${JSON.stringify(context.params)}`);\n if (context.result) parts.push(`result=${JSON.stringify(context.result)}`);\n return parts.length > 0 ? parts.join(\", \") : \"(empty)\";\n}\n\nfunction formatContextLabel(context: TaiasContext): string {\n if (context.toolName) return context.toolName;\n if (context.params) return `params:${JSON.stringify(context.params)}`;\n if (context.result) return `result:${JSON.stringify(context.result)}`;\n return \"(empty)\";\n}\n\n/**\n * Create a debug subscriber for Taias resolve events.\n *\n * Returns a handler function suitable for `taias.on(\"resolve\", handler)`.\n *\n * - \"default\" format: multi-line breakdown of context, trace, decision, and affordances.\n * - \"compact\" format: single line per resolve call.\n */\nexport function createDebugSubscriber(\n options?: DebugSubscriberOptions\n): (event: ResolveEvent) => void {\n const format = options?.format ?? \"default\";\n const log = options?.logger ?? console.log;\n\n if (format === \"compact\") {\n return (event: ResolveEvent) => {\n const { trace, context } = event;\n const label = formatContextLabel(context);\n\n if (!trace.matched) {\n log(`[Taias] ${label} → no match (${trace.candidatesEvaluated} evaluated)`);\n return;\n }\n\n const decisionSummary = event.decision\n ? Object.entries(event.decision).map(([k, v]) => `${k}=${v}`).join(\", \")\n : \"null\";\n\n log(\n `[Taias] ${label} → ${decisionSummary} (${trace.phase}, step ${trace.matchedStepIndex}, ${trace.candidatesEvaluated} evaluated)`\n );\n };\n }\n\n return (event: ResolveEvent) => {\n const { trace, context } = event;\n const lines: string[] = [];\n\n lines.push(\"┌─ Taias Resolve ─────────────────────────────\");\n lines.push(`│ Flow: ${event.flowId}`);\n lines.push(`│ Context: ${formatContext(context)}`);\n\n lines.push(\"│\");\n\n if (!trace.matched) {\n lines.push(\"│ Result: NO MATCH\");\n lines.push(`│ Candidates evaluated: ${trace.candidatesEvaluated}`);\n } else {\n lines.push(`│ Matched: step ${trace.matchedStepIndex} (${trace.matchedStepKind})`);\n lines.push(`│ Phase: ${trace.phase}`);\n\n if (trace.resolutionPath.length > 0) {\n lines.push(`│ Resolution path: ${trace.resolutionPath.join(\" → \")}`);\n }\n\n lines.push(`│ Candidates evaluated: ${trace.candidatesEvaluated}`);\n\n if (trace.matchedStepMatch) {\n lines.push(`│ Match condition: ${JSON.stringify(trace.matchedStepMatch)}`);\n }\n }\n\n lines.push(\"│\");\n\n if (event.decision) {\n const fields = Object.entries(event.decision).map(([k, v]) => `${k}=${v}`).join(\", \");\n lines.push(`│ Decision: ${fields}`);\n } else {\n lines.push(\"│ Decision: null\");\n }\n\n if (event.affordances) {\n lines.push(`│ Advice: ${event.affordances.advice.slice(0, 80)}${event.affordances.advice.length > 80 ? \"...\" : \"\"}`);\n }\n\n lines.push(`│ Duration: ${event.durationMs.toFixed(2)}ms`);\n\n if (trace.evaluations) {\n lines.push(\"│\");\n lines.push(\"│ Detailed evaluations:\");\n for (const evaluation of trace.evaluations) {\n const icon = evaluation.result === \"matched\" ? \"✓\" : \"✗\";\n lines.push(`│ ${icon} step ${evaluation.stepIndex}: ${evaluation.result}`);\n\n if (evaluation.fieldResults) {\n for (const [field, fr] of Object.entries(evaluation.fieldResults)) {\n const fieldIcon = fr.passed ? \"✓\" : \"✗\";\n lines.push(`│ ${fieldIcon} ${field}: ${JSON.stringify(fr.condition)} vs ${JSON.stringify(fr.actual)}`);\n }\n }\n }\n }\n\n lines.push(\"└──────────────────────────────────────────────\");\n\n log(lines.join(\"\\n\"));\n };\n}\n","import type { Affordances, Condition, FlowStep, MatchCondition, StepDecision, Taias, TaiasContext, TaiasOptions, Decision, ResolveEvent, ResolveTrace, StepEvaluation } from \"./types\";\nimport type { DefaultSlots } from \"./uiAffordances/types\";\nimport { buildRegistryIndex } from \"./uiAffordances/indexing\";\nimport { selectUiAffordances } from \"./uiAffordances/select\";\nimport { createDebugSubscriber } from \"./debugSubscriber\";\n\n/**\n * Generate advice text for a given next tool.\n */\nfunction generateAdvice(nextTool: string): string {\n return `FOR THE BEST USER EXPERIENCE, TELL THE USER TO USE THE ${nextTool} TOOL NEXT!!!!!`;\n}\n\n// ---------------------------------------------------------------------------\n// Condition evaluation\n// ---------------------------------------------------------------------------\n\n/**\n * Evaluate a single Condition against a value using strict equality.\n */\nfunction evaluateCondition(condition: Condition, value: unknown): boolean {\n if (\"is\" in condition) return value === condition.is;\n if (\"isNot\" in condition) return value !== condition.isNot;\n return false;\n}\n\n/**\n * Evaluate a full MatchCondition against a TaiasContext.\n * All present conditions must be satisfied (logical AND).\n *\n * - toolName: compared directly against ctx.toolName\n * - params: subset match -- each specified key is checked against ctx.params\n * - result: subset match -- each specified key is checked against ctx.result\n *\n * If a step specifies params/result conditions but the context doesn't\n * include params/result, the step does not match.\n */\nfunction evaluateMatch(match: MatchCondition, ctx: TaiasContext): boolean {\n if (match.toolName && !evaluateCondition(match.toolName, ctx.toolName)) return false;\n\n if (match.params) {\n if (!ctx.params) return false;\n for (const [key, condition] of Object.entries(match.params)) {\n if (!evaluateCondition(condition, ctx.params[key])) return false;\n }\n }\n\n if (match.result) {\n if (!ctx.result) return false;\n for (const [key, condition] of Object.entries(match.result)) {\n if (!evaluateCondition(condition, ctx.result[key])) return false;\n }\n }\n\n return true;\n}\n\n/**\n * Evaluate a full MatchCondition and return per-field breakdown.\n * Used when detailed tracing is enabled.\n */\nfunction evaluateMatchDetailed(match: MatchCondition, ctx: TaiasContext): {\n passed: boolean;\n fieldResults: Record<string, { condition: Condition; actual: unknown; passed: boolean }>;\n} {\n const fieldResults: Record<string, { condition: Condition; actual: unknown; passed: boolean }> = {};\n let allPassed = true;\n\n if (match.toolName) {\n const actual = ctx.toolName;\n const passed = evaluateCondition(match.toolName, actual);\n fieldResults[\"toolName\"] = { condition: match.toolName, actual, passed };\n if (!passed) allPassed = false;\n }\n\n if (match.params) {\n if (!ctx.params) {\n for (const [key, condition] of Object.entries(match.params)) {\n fieldResults[`params.${key}`] = { condition, actual: undefined, passed: false };\n }\n allPassed = false;\n } else {\n for (const [key, condition] of Object.entries(match.params)) {\n const actual = ctx.params[key];\n const passed = evaluateCondition(condition, actual);\n fieldResults[`params.${key}`] = { condition, actual, passed };\n if (!passed) allPassed = false;\n }\n }\n }\n\n if (match.result) {\n if (!ctx.result) {\n for (const [key, condition] of Object.entries(match.result)) {\n fieldResults[`result.${key}`] = { condition, actual: undefined, passed: false };\n }\n allPassed = false;\n } else {\n for (const [key, condition] of Object.entries(match.result)) {\n const actual = ctx.result[key];\n const passed = evaluateCondition(condition, actual);\n fieldResults[`result.${key}`] = { condition, actual, passed };\n if (!passed) allPassed = false;\n }\n }\n }\n\n return { passed: allPassed, fieldResults };\n}\n\n// ---------------------------------------------------------------------------\n// Per-field indexing\n// ---------------------------------------------------------------------------\n\ninterface FieldIndex {\n valueMap: Map<unknown, number[]>;\n unconstrained: number[];\n}\n\n/**\n * Extract all `is` conditions from a match condition as field-path / value pairs.\n */\nfunction extractIsConditions(match: MatchCondition): Array<{ path: string; value: unknown }> {\n const conditions: Array<{ path: string; value: unknown }> = [];\n if (match.toolName && \"is\" in match.toolName) {\n conditions.push({ path: \"toolName\", value: match.toolName.is });\n }\n if (match.params) {\n for (const [key, cond] of Object.entries(match.params)) {\n if (\"is\" in cond) conditions.push({ path: `params.${key}`, value: cond.is });\n }\n }\n if (match.result) {\n for (const [key, cond] of Object.entries(match.result)) {\n if (\"is\" in cond) conditions.push({ path: `result.${key}`, value: cond.is });\n }\n }\n return conditions;\n}\n\n/**\n * Check whether a match condition has a condition on a given field path.\n */\nfunction hasConditionOnField(match: MatchCondition, path: string): boolean {\n if (path === \"toolName\") return !!match.toolName;\n if (path.startsWith(\"params.\")) return !!match.params?.[path.slice(7)];\n if (path.startsWith(\"result.\")) return !!match.result?.[path.slice(7)];\n return false;\n}\n\n/**\n * Get the value from a TaiasContext for a given field path.\n */\nfunction getContextValue(ctx: TaiasContext, path: string): unknown {\n if (path === \"toolName\") return ctx.toolName;\n if (path.startsWith(\"params.\")) return ctx.params?.[path.slice(7)];\n if (path.startsWith(\"result.\")) return ctx.result?.[path.slice(7)];\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Step access helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Get the match condition from a FlowStep.\n *\n * - Logic-based steps: match comes from statement.match\n * - Handler-based steps (backwards compatibility): match is stored directly on the step\n */\nfunction getMatch(step: FlowStep): MatchCondition {\n return step.kind === \"logic\" ? step.statement.match : step.match;\n}\n\n/**\n * Serialize a MatchCondition into a stable string for duplicate detection.\n */\nfunction serializeMatch(match: MatchCondition): string {\n return JSON.stringify(match);\n}\n\n/**\n * createTaias constructs a decision engine.\n *\n * Taias resolves context into a generalized Decision object,\n * and then manifests that decision into concrete affordances:\n *\n * - LLM guidance (advice)\n * - UI affordance selections\n *\n * Flow logic is expressed as logic statements -- structured data that\n * Taias understands. (Handler functions remain as a backwards-compatible\n * escape hatch.)\n *\n * Flow logic determines *what should happen next*.\n * UI affordances determine *how that decision appears in the interface*.\n *\n * This file is the boundary where:\n *\n * Inputs -> Decision -> Manifestations\n *\n * are unified into a single resolve() call.\n *\n * @example\n * ```ts\n * const taias = createTaias({ flow, affordances });\n * ```\n */\nexport function createTaias<S extends string = DefaultSlots>(\n options: TaiasOptions<S>\n): Taias<S> {\n const {\n flow,\n affordances,\n devMode = false,\n debug = false,\n tracing = \"summary\",\n onMissingStep,\n onWarn,\n } = options;\n\n const warn = onWarn ?? ((msg: string) => console.warn(msg));\n const detailed = tracing === \"detailed\";\n\n // Dev mode: Check for duplicate match conditions.\n if (devMode) {\n const seenKeys = new Set<string>();\n for (const step of flow.steps) {\n const key = serializeMatch(getMatch(step));\n if (seenKeys.has(key)) {\n throw new Error(\n `Taias: Duplicate match condition in flow '${flow.id}'. Each step must have a unique match condition. Duplicate: ${key}`\n );\n }\n seenKeys.add(key);\n }\n }\n\n // -----------------------------------------------------------------------\n // Build per-field indexes\n // -----------------------------------------------------------------------\n\n const fieldIndexes = new Map<string, FieldIndex>();\n const indexableStepIndices: number[] = [];\n const broadStepIndices: number[] = [];\n\n for (let i = 0; i < flow.steps.length; i++) {\n const match = getMatch(flow.steps[i]);\n const isConditions = extractIsConditions(match);\n\n if (isConditions.length === 0) {\n broadStepIndices.push(i);\n continue;\n }\n\n indexableStepIndices.push(i);\n\n for (const { path, value } of isConditions) {\n let fieldIndex = fieldIndexes.get(path);\n if (!fieldIndex) {\n fieldIndex = { valueMap: new Map(), unconstrained: [] };\n fieldIndexes.set(path, fieldIndex);\n }\n let stepList = fieldIndex.valueMap.get(value);\n if (!stepList) {\n stepList = [];\n fieldIndex.valueMap.set(value, stepList);\n }\n stepList.push(i);\n }\n }\n\n // Build unconstrained sets: for each field index, find indexable steps\n // that don't have a condition on that field.\n for (const [fieldPath, fieldIndex] of fieldIndexes) {\n for (const i of indexableStepIndices) {\n if (!hasConditionOnField(getMatch(flow.steps[i]), fieldPath)) {\n fieldIndex.unconstrained.push(i);\n }\n }\n }\n\n const hasBroadSteps = broadStepIndices.length > 0;\n\n // Build affordance index once (if provided)\n const registryIndex = buildRegistryIndex<S>(affordances);\n\n // -----------------------------------------------------------------------\n // Event emitter\n // -----------------------------------------------------------------------\n\n const listeners = new Map<string, Set<Function>>();\n\n function emit<E extends string>(event: E, data: unknown): void {\n const handlers = listeners.get(event);\n if (handlers) {\n for (const handler of handlers) handler(data);\n }\n }\n\n function on(event: string, handler: Function): void {\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n set.add(handler);\n }\n\n function off(event: string, handler: Function): void {\n listeners.get(event)?.delete(handler);\n }\n\n if (debug) {\n const debugOpts = typeof debug === \"object\" ? debug : undefined;\n on(\"resolve\", createDebugSubscriber(debugOpts));\n }\n\n return {\n async resolve(ctx: TaiasContext): Promise<Affordances<S> | null> {\n const startTime = performance.now();\n const timestamp = Date.now();\n\n let matchedStep: FlowStep | undefined;\n let matchedStepIndex: number | null = null;\n let matchPhase: \"indexed\" | \"broad\" | null = null;\n const resolutionPath: string[] = [];\n let candidatesEvaluated = 0;\n const evaluations: StepEvaluation[] | undefined = detailed ? [] : undefined;\n\n // Evaluate a candidate step and track it for tracing.\n // In detailed mode, uses evaluateMatchDetailed to capture per-field\n // outcomes; in summary mode, uses the cheaper evaluateMatch.\n function tryMatch(idx: number): boolean {\n candidatesEvaluated++;\n const step = flow.steps[idx];\n const match = getMatch(step);\n\n if (detailed) {\n const { passed, fieldResults } = evaluateMatchDetailed(match, ctx);\n evaluations!.push({\n stepIndex: idx,\n match,\n result: passed ? \"matched\" : \"no-match\",\n fieldResults,\n });\n return passed;\n }\n\n return evaluateMatch(match, ctx);\n }\n\n // Phase 1: Find candidates from per-field indexes via intersection\n const applicableFieldPaths: string[] = [];\n for (const fieldPath of fieldIndexes.keys()) {\n const ctxValue = getContextValue(ctx, fieldPath);\n if (ctxValue !== undefined) {\n applicableFieldPaths.push(fieldPath);\n }\n }\n\n resolutionPath.push(...applicableFieldPaths);\n\n if (applicableFieldPaths.length > 0) {\n // Build candidate sets for each applicable field and intersect\n let candidates: Set<number> | null = null;\n\n for (const fieldPath of applicableFieldPaths) {\n const fieldIndex = fieldIndexes.get(fieldPath)!;\n const ctxValue = getContextValue(ctx, fieldPath);\n\n const fieldCandidates = new Set<number>();\n\n // Indexed matches for this field's value\n const indexed = fieldIndex.valueMap.get(ctxValue);\n if (indexed) {\n for (const idx of indexed) fieldCandidates.add(idx);\n }\n\n // Unconstrained steps (don't care about this field)\n for (const idx of fieldIndex.unconstrained) {\n fieldCandidates.add(idx);\n }\n\n if (candidates === null) {\n candidates = fieldCandidates;\n } else {\n // Intersect\n for (const idx of candidates) {\n if (!fieldCandidates.has(idx)) candidates.delete(idx);\n }\n }\n }\n\n // Evaluate full conditions on narrowed candidates (definition order)\n if (candidates && candidates.size > 0) {\n const sorted = [...candidates].sort((a, b) => a - b);\n for (const idx of sorted) {\n if (tryMatch(idx)) {\n matchedStep = flow.steps[idx];\n matchedStepIndex = idx;\n matchPhase = \"indexed\";\n break;\n }\n }\n }\n } else if (indexableStepIndices.length > 0) {\n // Context has no fields that match any index -- evaluate all\n // indexable steps that are unconstrained on everything\n // (i.e., steps with is conditions on fields not present in context).\n // evaluateMatch handles this correctly.\n for (const idx of indexableStepIndices) {\n if (tryMatch(idx)) {\n matchedStep = flow.steps[idx];\n matchedStepIndex = idx;\n matchPhase = \"indexed\";\n break;\n }\n }\n }\n\n // Phase 2: If no indexed match, evaluate broad steps\n if (!matchedStep && hasBroadSteps) {\n for (const idx of broadStepIndices) {\n if (tryMatch(idx)) {\n matchedStep = flow.steps[idx];\n matchedStepIndex = idx;\n matchPhase = \"broad\";\n break;\n }\n }\n }\n\n // Construct the trace and emit event on every exit path (no-match,\n // handler-returns-null, and successful match). Subscribers always\n // get complete visibility into every resolve() call.\n const trace: ResolveTrace = {\n matched: !!matchedStep,\n matchedStepIndex,\n matchedStepKind: matchedStep?.kind ?? null,\n matchedStepMatch: matchedStep ? getMatch(matchedStep) : null,\n phase: matchPhase,\n resolutionPath,\n candidatesEvaluated,\n ...(evaluations !== undefined ? { evaluations } : {}),\n };\n\n if (!matchedStep) {\n onMissingStep?.(ctx);\n\n emit(\"resolve\", {\n flowId: flow.id,\n timestamp,\n durationMs: performance.now() - startTime,\n context: ctx,\n trace,\n decision: null,\n affordances: null,\n } satisfies ResolveEvent<S>);\n\n return null;\n }\n\n // Evaluate the step based on its kind\n let result: StepDecision | null;\n\n if (matchedStep.kind === \"logic\") {\n result = matchedStep.statement.decision;\n } else {\n result = await matchedStep.handler(ctx);\n }\n\n if (!result) {\n emit(\"resolve\", {\n flowId: flow.id,\n timestamp,\n durationMs: performance.now() - startTime,\n context: ctx,\n trace,\n decision: null,\n affordances: null,\n } satisfies ResolveEvent<S>);\n\n return null;\n }\n\n if (devMode && result.nextTool === \"\") {\n warn(`Taias: nextTool for tool '${ctx.toolName}' is empty.`);\n }\n\n const decision: Decision = { ...result };\n\n const selections = selectUiAffordances<S>(decision, registryIndex, {\n devMode,\n onWarn: warn,\n });\n\n const advice = generateAdvice(result.nextTool);\n\n emit(\"resolve\", {\n flowId: flow.id,\n timestamp,\n durationMs: performance.now() - startTime,\n context: ctx,\n trace,\n decision,\n affordances: { advice, selections },\n } satisfies ResolveEvent<S>);\n\n return { advice, decision, selections };\n },\n\n on: on as Taias<S>[\"on\"],\n off: off as Taias<S>[\"off\"],\n };\n}\n","import type {\n AffordanceRegistry,\n BindingInput,\n DefaultSlots,\n HandleRegistration,\n} from \"./types\";\nimport { normalizeBinding } from \"./types\";\n\n/**\n * Mapped type that creates a registration method for each slot in S.\n * This enables fully typed custom slots via generics.\n */\nexport type AffordanceRegistrar<S extends string = DefaultSlots> = {\n [K in S]: (handleId: string, bindsTo: BindingInput) => void;\n};\n\n/**\n * Define UI affordances for a widget using a builder pattern.\n *\n * @example Default slots (backwards compatible)\n * ```ts\n * const affordances = defineAffordances((r) => {\n * r.primaryCta(\"cta.recommend\", { toolName: \"get_recommendations\" });\n * r.widgetVariant(\"variant.discovery\", { toolName: \"get_recommendations\" });\n * });\n * ```\n *\n * @example Custom slots (fully type-safe)\n * ```ts\n * type MySlots = \"primaryCta\" | \"contentArea\" | \"headerStyle\";\n * const affordances = defineAffordances<MySlots>((r) => {\n * r.primaryCta(\"cta.create\", { toolName: \"createUser\" });\n * r.contentArea(\"content.form\", { key: \"contentArea\", value: \"email-form\" });\n * r.headerStyle(\"header.progress\", { key: \"headerStyle\", value: \"step-1\" });\n * });\n * ```\n */\nexport function defineAffordances<S extends string = DefaultSlots>(\n builder: (r: AffordanceRegistrar<S>) => void\n): AffordanceRegistry<S> {\n const handles: HandleRegistration<S>[] = [];\n\n // Proxy creates methods on-the-fly for any slot name.\n // TypeScript ensures only valid slot names (from S) are called.\n const registrar = new Proxy({} as AffordanceRegistrar<S>, {\n get(_, slot: string) {\n return (handleId: string, bindsTo: BindingInput) => {\n handles.push({\n slot: slot as S,\n handleId,\n bindsTo: normalizeBinding(bindsTo),\n });\n };\n },\n });\n\n builder(registrar);\n return { handles };\n}\n","import type { AffordanceRegistry, DefaultSlots } from \"./types\";\nimport { makeBindingKey } from \"./types\";\n\nexport type MergeAffordancesOptions = {\n devMode?: boolean;\n onWarn?: (msg: string) => void;\n};\n\n/**\n * Merge multiple affordance registries into one.\n * Generic over slot type S for custom slot support.\n *\n * @example Default slots\n * ```ts\n * const merged = mergeAffordances([widgetA, widgetB]);\n * ```\n *\n * @example Custom slots\n * ```ts\n * type MySlots = \"primaryCta\" | \"contentArea\";\n * const merged = mergeAffordances<MySlots>([widgetA, widgetB]);\n * ```\n */\nexport function mergeAffordances<S extends string = DefaultSlots>(\n registries: AffordanceRegistry<S>[],\n opts: MergeAffordancesOptions = {}\n): AffordanceRegistry<S> {\n const devMode = !!opts.devMode;\n const warn = opts.onWarn ?? (() => {});\n\n const merged: AffordanceRegistry<S> = { handles: registries.flatMap((r) => r.handles) };\n\n if (!devMode) return merged;\n\n // Check for duplicate handleIds\n const seenHandleIds = new Set<string>();\n for (const h of merged.handles) {\n if (seenHandleIds.has(h.handleId)) {\n throw new Error(`[Taias] Duplicate handleId \"${h.handleId}\"`);\n }\n seenHandleIds.add(h.handleId);\n }\n\n // Check for ambiguous bindings (same slot + key + value)\n const seenTriples = new Set<string>();\n for (const h of merged.handles) {\n const k = makeBindingKey(h.slot, h.bindsTo);\n if (seenTriples.has(k)) {\n throw new Error(\n `[Taias] Ambiguous affordance: slot \"${h.slot}\" has multiple handles bound to (${h.bindsTo.key}=\"${h.bindsTo.value}\")`\n );\n }\n seenTriples.add(k);\n }\n\n warn(`[Taias] Loaded ${merged.handles.length} UI affordance handles`);\n return merged;\n}\n"],"mappings":"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","names":[]}