@lokascript/framework 2.0.0 → 2.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.
- package/dist/aot/index.d.ts +1 -0
- package/dist/aot/index.d.ts.map +1 -1
- package/dist/aot/registry-bridge.d.ts +27 -0
- package/dist/aot/registry-bridge.d.ts.map +1 -0
- package/dist/api/create-dsl.d.ts.map +1 -1
- package/dist/api/dispatcher.d.ts +22 -0
- package/dist/api/dispatcher.d.ts.map +1 -1
- package/dist/api/domain-registry.d.ts +41 -0
- package/dist/api/domain-registry.d.ts.map +1 -1
- package/dist/api/index.js +1438 -21
- package/dist/api/index.js.map +1 -1
- package/dist/core/index.js +247 -10
- package/dist/core/index.js.map +1 -1
- package/dist/core/pattern-matching/index.js +74 -10
- package/dist/core/pattern-matching/index.js.map +1 -1
- package/dist/core/pattern-matching/pattern-matcher.d.ts.map +1 -1
- package/dist/core/tokenization/index.js +133 -0
- package/dist/core/tokenization/index.js.map +1 -1
- package/dist/core/tokenization/morphology/base-normalizer.d.ts +94 -0
- package/dist/core/tokenization/morphology/base-normalizer.d.ts.map +1 -0
- package/dist/core/tokenization/morphology/index.d.ts +3 -1
- package/dist/core/tokenization/morphology/index.d.ts.map +1 -1
- package/dist/core/types.d.ts +81 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +40 -0
- package/dist/core/types.js.map +1 -1
- package/dist/feedback/confidence-gate.d.ts +28 -0
- package/dist/feedback/confidence-gate.d.ts.map +1 -0
- package/dist/feedback/feedback-formatter.d.ts +21 -0
- package/dist/feedback/feedback-formatter.d.ts.map +1 -0
- package/dist/feedback/index.d.ts +11 -0
- package/dist/feedback/index.d.ts.map +1 -0
- package/dist/feedback/pattern-tracker.d.ts +47 -0
- package/dist/feedback/pattern-tracker.d.ts.map +1 -0
- package/dist/feedback/types.d.ts +113 -0
- package/dist/feedback/types.d.ts.map +1 -0
- package/dist/generation/index.js +2 -1
- package/dist/generation/index.js.map +1 -1
- package/dist/index.cjs +3264 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3223 -132
- package/dist/index.js.map +1 -1
- package/dist/ir/explicit-parser.d.ts +86 -0
- package/dist/ir/explicit-parser.d.ts.map +1 -0
- package/dist/ir/explicit-renderer.d.ts +34 -0
- package/dist/ir/explicit-renderer.d.ts.map +1 -0
- package/dist/ir/from-interchange.d.ts +51 -0
- package/dist/ir/from-interchange.d.ts.map +1 -0
- package/dist/ir/index.d.ts +31 -0
- package/dist/ir/index.d.ts.map +1 -0
- package/dist/ir/index.js +1934 -0
- package/dist/ir/index.js.map +1 -0
- package/dist/ir/json-schema.d.ts +40 -0
- package/dist/ir/json-schema.d.ts.map +1 -0
- package/dist/ir/protocol-json.d.ts +73 -0
- package/dist/ir/protocol-json.d.ts.map +1 -0
- package/dist/ir/references.d.ts +19 -0
- package/dist/ir/references.d.ts.map +1 -0
- package/dist/ir/to-runtime-ast.d.ts +53 -0
- package/dist/ir/to-runtime-ast.d.ts.map +1 -0
- package/dist/ir/types.d.ts +151 -0
- package/dist/ir/types.d.ts.map +1 -0
- package/dist/parsing/index.js +74 -10
- package/dist/parsing/index.js.map +1 -1
- package/dist/prompts/index.d.ts +9 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/prompt-generator.d.ts +49 -0
- package/dist/prompts/prompt-generator.d.ts.map +1 -0
- package/dist/prompts/types.d.ts +64 -0
- package/dist/prompts/types.d.ts.map +1 -0
- package/dist/schema/command-schema.d.ts +17 -0
- package/dist/schema/command-schema.d.ts.map +1 -1
- package/dist/schema/index.js.map +1 -1
- package/dist/testing/index.js +8673 -8260
- package/dist/testing/index.js.map +1 -1
- package/dist/training/index.d.ts +11 -0
- package/dist/training/index.d.ts.map +1 -0
- package/dist/training/jsonl-writer.d.ts +42 -0
- package/dist/training/jsonl-writer.d.ts.map +1 -0
- package/dist/training/schema-synthesizer.d.ts +20 -0
- package/dist/training/schema-synthesizer.d.ts.map +1 -0
- package/dist/training/types.d.ts +73 -0
- package/dist/training/types.d.ts.map +1 -0
- package/package.json +5 -1
- package/src/aot/index.ts +1 -0
- package/src/aot/registry-bridge.test.ts +104 -0
- package/src/aot/registry-bridge.ts +66 -0
- package/src/api/create-dsl.test.ts +306 -0
- package/src/api/create-dsl.ts +21 -0
- package/src/api/dispatcher.test.ts +66 -0
- package/src/api/dispatcher.ts +77 -9
- package/src/api/domain-registry.ts +120 -4
- package/src/core/pattern-matching/pattern-matcher.test.ts +131 -0
- package/src/core/pattern-matching/pattern-matcher.ts +102 -19
- package/src/core/tokenization/morphology/base-normalizer.ts +249 -0
- package/src/core/tokenization/morphology/index.ts +3 -1
- package/src/core/types.ts +147 -2
- package/src/feedback/confidence-gate.test.ts +111 -0
- package/src/feedback/confidence-gate.ts +70 -0
- package/src/feedback/feedback-formatter.test.ts +198 -0
- package/src/feedback/feedback-formatter.ts +298 -0
- package/src/feedback/index.ts +24 -0
- package/src/feedback/pattern-tracker.test.ts +198 -0
- package/src/feedback/pattern-tracker.ts +140 -0
- package/src/feedback/types.ts +149 -0
- package/src/generation/pattern-generator.ts +2 -2
- package/src/index.ts +29 -0
- package/src/integration/llm-lse-integration.test.ts +457 -0
- package/src/ir/conformance.test.ts +120 -0
- package/src/ir/explicit-parser.test.ts +612 -0
- package/src/ir/explicit-parser.ts +793 -0
- package/src/ir/explicit-renderer.test.ts +229 -0
- package/src/ir/explicit-renderer.ts +198 -0
- package/src/ir/from-interchange.test.ts +853 -0
- package/src/ir/from-interchange.ts +594 -0
- package/src/ir/index.ts +77 -0
- package/src/ir/json-schema.test.ts +281 -0
- package/src/ir/json-schema.ts +299 -0
- package/src/ir/protocol-json.test.ts +1187 -0
- package/src/ir/protocol-json.ts +751 -0
- package/src/ir/references.test.ts +38 -0
- package/src/ir/references.ts +33 -0
- package/src/ir/round-trip.test.ts +557 -0
- package/src/ir/to-runtime-ast.ts +203 -0
- package/src/ir/types.ts +191 -0
- package/src/prompts/index.ts +15 -0
- package/src/prompts/prompt-generator.test.ts +386 -0
- package/src/prompts/prompt-generator.ts +531 -0
- package/src/prompts/types.ts +89 -0
- package/src/schema/command-schema.ts +19 -0
- package/src/training/index.ts +13 -0
- package/src/training/jsonl-writer.test.ts +138 -0
- package/src/training/jsonl-writer.ts +67 -0
- package/src/training/schema-synthesizer.test.ts +250 -0
- package/src/training/schema-synthesizer.ts +306 -0
- package/src/training/types.ts +103 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Pattern Hit-Rate Tracker
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
6
|
+
import { PatternTracker } from './pattern-tracker';
|
|
7
|
+
import type { PatternEvent } from './types';
|
|
8
|
+
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Test Helpers
|
|
11
|
+
// =============================================================================
|
|
12
|
+
|
|
13
|
+
function makeEvent(overrides?: Partial<PatternEvent>): PatternEvent {
|
|
14
|
+
return {
|
|
15
|
+
timestamp: Date.now(),
|
|
16
|
+
domain: 'flow',
|
|
17
|
+
action: 'fetch',
|
|
18
|
+
language: 'en',
|
|
19
|
+
inputFormat: 'explicit',
|
|
20
|
+
confidence: 0.95,
|
|
21
|
+
outcome: 'accepted',
|
|
22
|
+
...overrides,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// PatternTracker
|
|
28
|
+
// =============================================================================
|
|
29
|
+
|
|
30
|
+
describe('PatternTracker', () => {
|
|
31
|
+
let tracker: PatternTracker;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
tracker = new PatternTracker();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// --- Basic recording ---
|
|
38
|
+
|
|
39
|
+
it('starts empty', () => {
|
|
40
|
+
expect(tracker.size).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('records events', () => {
|
|
44
|
+
tracker.record(makeEvent());
|
|
45
|
+
expect(tracker.size).toBe(1);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('records multiple events', () => {
|
|
49
|
+
tracker.record(makeEvent());
|
|
50
|
+
tracker.record(makeEvent({ action: 'toggle' }));
|
|
51
|
+
tracker.record(makeEvent({ action: 'add' }));
|
|
52
|
+
expect(tracker.size).toBe(3);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// --- Ring buffer ---
|
|
56
|
+
|
|
57
|
+
it('enforces ring buffer limit', () => {
|
|
58
|
+
const small = new PatternTracker(5);
|
|
59
|
+
for (let i = 0; i < 10; i++) {
|
|
60
|
+
small.record(makeEvent({ action: `action-${i}` }));
|
|
61
|
+
}
|
|
62
|
+
expect(small.size).toBe(5);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('keeps newest events when buffer overflows', () => {
|
|
66
|
+
const small = new PatternTracker(3);
|
|
67
|
+
for (let i = 0; i < 5; i++) {
|
|
68
|
+
small.record(makeEvent({ action: `action-${i}` }));
|
|
69
|
+
}
|
|
70
|
+
const summary = small.getSummary();
|
|
71
|
+
// Should only have action-2, action-3, action-4
|
|
72
|
+
expect(summary.byCommand['action-0']).toBeUndefined();
|
|
73
|
+
expect(summary.byCommand['action-1']).toBeUndefined();
|
|
74
|
+
expect(summary.byCommand['action-2']).toBeDefined();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// --- Hit rate by command ---
|
|
78
|
+
|
|
79
|
+
it('computes hit rate by command', () => {
|
|
80
|
+
tracker.record(makeEvent({ action: 'fetch', outcome: 'accepted' }));
|
|
81
|
+
tracker.record(makeEvent({ action: 'fetch', outcome: 'accepted' }));
|
|
82
|
+
tracker.record(makeEvent({ action: 'fetch', outcome: 'rejected' }));
|
|
83
|
+
tracker.record(makeEvent({ action: 'toggle', outcome: 'accepted' }));
|
|
84
|
+
|
|
85
|
+
const rates = tracker.getHitRateByCommand();
|
|
86
|
+
expect(rates['fetch'].attempts).toBe(3);
|
|
87
|
+
expect(rates['fetch'].successes).toBe(2);
|
|
88
|
+
expect(rates['fetch'].rate).toBeCloseTo(2 / 3);
|
|
89
|
+
expect(rates['toggle'].rate).toBe(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// --- Hit rate by language ---
|
|
93
|
+
|
|
94
|
+
it('computes hit rate by language', () => {
|
|
95
|
+
tracker.record(makeEvent({ language: 'en', outcome: 'accepted' }));
|
|
96
|
+
tracker.record(makeEvent({ language: 'en', outcome: 'rejected' }));
|
|
97
|
+
tracker.record(makeEvent({ language: 'ja', outcome: 'accepted' }));
|
|
98
|
+
|
|
99
|
+
const rates = tracker.getHitRateByLanguage();
|
|
100
|
+
expect(rates['en'].attempts).toBe(2);
|
|
101
|
+
expect(rates['en'].rate).toBe(0.5);
|
|
102
|
+
expect(rates['ja'].rate).toBe(1);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// --- Top failures ---
|
|
106
|
+
|
|
107
|
+
it('computes top failures by diagnostic code', () => {
|
|
108
|
+
tracker.record(makeEvent({ outcome: 'rejected', diagnosticCodes: ['missing-role'] }));
|
|
109
|
+
tracker.record(makeEvent({ outcome: 'rejected', diagnosticCodes: ['missing-role'] }));
|
|
110
|
+
tracker.record(makeEvent({ outcome: 'rejected', diagnosticCodes: ['unknown-command'] }));
|
|
111
|
+
|
|
112
|
+
const failures = tracker.getTopFailures();
|
|
113
|
+
expect(failures[0].code).toBe('missing-role');
|
|
114
|
+
expect(failures[0].count).toBe(2);
|
|
115
|
+
expect(failures[1].code).toBe('unknown-command');
|
|
116
|
+
expect(failures[1].count).toBe(1);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('tracks which actions trigger each failure', () => {
|
|
120
|
+
tracker.record(
|
|
121
|
+
makeEvent({ action: 'fetch', outcome: 'rejected', diagnosticCodes: ['missing-role'] })
|
|
122
|
+
);
|
|
123
|
+
tracker.record(
|
|
124
|
+
makeEvent({ action: 'toggle', outcome: 'rejected', diagnosticCodes: ['missing-role'] })
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const failures = tracker.getTopFailures();
|
|
128
|
+
expect(failures[0].actions).toContain('fetch');
|
|
129
|
+
expect(failures[0].actions).toContain('toggle');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('limits top failures to requested count', () => {
|
|
133
|
+
for (let i = 0; i < 20; i++) {
|
|
134
|
+
tracker.record(makeEvent({ outcome: 'rejected', diagnosticCodes: [`code-${i}`] }));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const failures = tracker.getTopFailures(5);
|
|
138
|
+
expect(failures.length).toBe(5);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('ignores non-rejected events for failures', () => {
|
|
142
|
+
tracker.record(makeEvent({ outcome: 'accepted', diagnosticCodes: ['some-code'] }));
|
|
143
|
+
const failures = tracker.getTopFailures();
|
|
144
|
+
expect(failures.length).toBe(0);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('ignores rejected events without diagnostic codes', () => {
|
|
148
|
+
tracker.record(makeEvent({ outcome: 'rejected' }));
|
|
149
|
+
const failures = tracker.getTopFailures();
|
|
150
|
+
expect(failures.length).toBe(0);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// --- Summary ---
|
|
154
|
+
|
|
155
|
+
it('produces a complete summary', () => {
|
|
156
|
+
tracker.record(makeEvent({ outcome: 'accepted' }));
|
|
157
|
+
tracker.record(makeEvent({ outcome: 'rejected', diagnosticCodes: ['err'] }));
|
|
158
|
+
tracker.record(makeEvent({ outcome: 'disambiguated' }));
|
|
159
|
+
|
|
160
|
+
const summary = tracker.getSummary();
|
|
161
|
+
expect(summary.totalEvents).toBe(3);
|
|
162
|
+
expect(summary.byOutcome['accepted']).toBe(1);
|
|
163
|
+
expect(summary.byOutcome['rejected']).toBe(1);
|
|
164
|
+
expect(summary.byOutcome['disambiguated']).toBe(1);
|
|
165
|
+
expect(summary.byCommand).toBeDefined();
|
|
166
|
+
expect(summary.byLanguage).toBeDefined();
|
|
167
|
+
expect(summary.topFailures.length).toBe(1);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// --- JSONL export ---
|
|
171
|
+
|
|
172
|
+
it('exports events as JSONL', () => {
|
|
173
|
+
tracker.record(makeEvent({ action: 'fetch' }));
|
|
174
|
+
tracker.record(makeEvent({ action: 'toggle' }));
|
|
175
|
+
|
|
176
|
+
const jsonl = tracker.exportJSONL();
|
|
177
|
+
const lines = jsonl.split('\n');
|
|
178
|
+
expect(lines.length).toBe(2);
|
|
179
|
+
|
|
180
|
+
const parsed0 = JSON.parse(lines[0]);
|
|
181
|
+
expect(parsed0.action).toBe('fetch');
|
|
182
|
+
const parsed1 = JSON.parse(lines[1]);
|
|
183
|
+
expect(parsed1.action).toBe('toggle');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('exports empty string when no events', () => {
|
|
187
|
+
expect(tracker.exportJSONL()).toBe('');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// --- Clear ---
|
|
191
|
+
|
|
192
|
+
it('clears all events', () => {
|
|
193
|
+
tracker.record(makeEvent());
|
|
194
|
+
tracker.record(makeEvent());
|
|
195
|
+
tracker.clear();
|
|
196
|
+
expect(tracker.size).toBe(0);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Hit-Rate Tracker
|
|
3
|
+
*
|
|
4
|
+
* Records pattern events in a ring buffer and computes hit-rate
|
|
5
|
+
* statistics by command, language, and diagnostic code. Patterns
|
|
6
|
+
* with high rejected/attempts ratios indicate miscalibrated confidence.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { PatternEvent, HitRate, PatternTrackerSummary, TopFailure } from './types';
|
|
10
|
+
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Public API
|
|
13
|
+
// =============================================================================
|
|
14
|
+
|
|
15
|
+
export class PatternTracker {
|
|
16
|
+
private events: PatternEvent[] = [];
|
|
17
|
+
private readonly maxEvents: number;
|
|
18
|
+
|
|
19
|
+
constructor(maxEvents: number = 1000) {
|
|
20
|
+
this.maxEvents = maxEvents;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Record a pattern event.
|
|
25
|
+
*/
|
|
26
|
+
record(event: PatternEvent): void {
|
|
27
|
+
this.events.push(event);
|
|
28
|
+
// Ring buffer: drop oldest when full
|
|
29
|
+
if (this.events.length > this.maxEvents) {
|
|
30
|
+
this.events = this.events.slice(this.events.length - this.maxEvents);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get hit rate by command action.
|
|
36
|
+
*/
|
|
37
|
+
getHitRateByCommand(): Record<string, HitRate> {
|
|
38
|
+
return this.computeHitRate(e => e.action);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get hit rate by language.
|
|
43
|
+
*/
|
|
44
|
+
getHitRateByLanguage(): Record<string, HitRate> {
|
|
45
|
+
return this.computeHitRate(e => e.language);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get the most frequent failure diagnostic codes.
|
|
50
|
+
*/
|
|
51
|
+
getTopFailures(limit: number = 10): TopFailure[] {
|
|
52
|
+
const codeMap = new Map<string, { count: number; actions: Set<string> }>();
|
|
53
|
+
|
|
54
|
+
for (const event of this.events) {
|
|
55
|
+
if (event.outcome !== 'rejected' || !event.diagnosticCodes) continue;
|
|
56
|
+
for (const code of event.diagnosticCodes) {
|
|
57
|
+
const entry = codeMap.get(code) || { count: 0, actions: new Set() };
|
|
58
|
+
entry.count++;
|
|
59
|
+
entry.actions.add(event.action);
|
|
60
|
+
codeMap.set(code, entry);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return Array.from(codeMap.entries())
|
|
65
|
+
.map(([code, { count, actions }]) => ({
|
|
66
|
+
code,
|
|
67
|
+
count,
|
|
68
|
+
actions: Array.from(actions),
|
|
69
|
+
}))
|
|
70
|
+
.sort((a, b) => b.count - a.count)
|
|
71
|
+
.slice(0, limit);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get a complete summary of tracking data.
|
|
76
|
+
*/
|
|
77
|
+
getSummary(): PatternTrackerSummary {
|
|
78
|
+
const byOutcome: Record<string, number> = {};
|
|
79
|
+
for (const event of this.events) {
|
|
80
|
+
byOutcome[event.outcome] = (byOutcome[event.outcome] || 0) + 1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
totalEvents: this.events.length,
|
|
85
|
+
byOutcome,
|
|
86
|
+
byCommand: this.getHitRateByCommand(),
|
|
87
|
+
byLanguage: this.getHitRateByLanguage(),
|
|
88
|
+
topFailures: this.getTopFailures(),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Export all events as JSONL.
|
|
94
|
+
*/
|
|
95
|
+
exportJSONL(): string {
|
|
96
|
+
return this.events.map(e => JSON.stringify(e)).join('\n');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get the number of recorded events.
|
|
101
|
+
*/
|
|
102
|
+
get size(): number {
|
|
103
|
+
return this.events.length;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Clear all events.
|
|
108
|
+
*/
|
|
109
|
+
clear(): void {
|
|
110
|
+
this.events = [];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Private
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
private computeHitRate(keyFn: (e: PatternEvent) => string): Record<string, HitRate> {
|
|
118
|
+
const map = new Map<string, { attempts: number; successes: number }>();
|
|
119
|
+
|
|
120
|
+
for (const event of this.events) {
|
|
121
|
+
const key = keyFn(event);
|
|
122
|
+
const entry = map.get(key) || { attempts: 0, successes: 0 };
|
|
123
|
+
entry.attempts++;
|
|
124
|
+
if (event.outcome === 'accepted') {
|
|
125
|
+
entry.successes++;
|
|
126
|
+
}
|
|
127
|
+
map.set(key, entry);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const result: Record<string, HitRate> = {};
|
|
131
|
+
for (const [key, { attempts, successes }] of map) {
|
|
132
|
+
result[key] = {
|
|
133
|
+
attempts,
|
|
134
|
+
successes,
|
|
135
|
+
rate: attempts > 0 ? successes / attempts : 0,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feedback Loop Types
|
|
3
|
+
*
|
|
4
|
+
* Types for structured error feedback, confidence-aware disambiguation,
|
|
5
|
+
* and pattern hit-rate tracking in the LLM ↔ LSE integration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { SemanticJSON } from '../ir/types';
|
|
9
|
+
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Structured Error Feedback (Level 1)
|
|
12
|
+
// =============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Structured feedback for an LSE validation attempt.
|
|
16
|
+
*/
|
|
17
|
+
export interface LSEFeedback {
|
|
18
|
+
/** Whether the input was accepted (no errors) */
|
|
19
|
+
readonly accepted: boolean;
|
|
20
|
+
|
|
21
|
+
/** The original input */
|
|
22
|
+
readonly input: {
|
|
23
|
+
readonly format: 'explicit' | 'json' | 'natural';
|
|
24
|
+
readonly text: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** Machine-actionable diagnostics */
|
|
28
|
+
readonly diagnostics: readonly FeedbackDiagnostic[];
|
|
29
|
+
|
|
30
|
+
/** Human-readable hints for retrying */
|
|
31
|
+
readonly hints: readonly string[];
|
|
32
|
+
|
|
33
|
+
/** Valid schema structure for the attempted command (if identifiable) */
|
|
34
|
+
readonly schema?: {
|
|
35
|
+
readonly action: string;
|
|
36
|
+
readonly requiredRoles: readonly string[];
|
|
37
|
+
readonly optionalRoles: readonly string[];
|
|
38
|
+
readonly roleDescriptions: Readonly<Record<string, string>>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** Corrected example (if fixable) */
|
|
42
|
+
readonly correctedExample?: {
|
|
43
|
+
readonly explicit: string;
|
|
44
|
+
readonly json: SemanticJSON;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A single diagnostic with machine-actionable fix type.
|
|
50
|
+
*/
|
|
51
|
+
export interface FeedbackDiagnostic {
|
|
52
|
+
readonly severity: 'error' | 'warning' | 'info';
|
|
53
|
+
readonly code: string;
|
|
54
|
+
readonly message: string;
|
|
55
|
+
readonly suggestion?: string;
|
|
56
|
+
readonly fixType?: FixType;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Machine-actionable fix type for LLM retry logic.
|
|
61
|
+
*/
|
|
62
|
+
export type FixType =
|
|
63
|
+
| 'missing_role'
|
|
64
|
+
| 'invalid_type'
|
|
65
|
+
| 'unknown_command'
|
|
66
|
+
| 'unknown_role'
|
|
67
|
+
| 'syntax_error';
|
|
68
|
+
|
|
69
|
+
// =============================================================================
|
|
70
|
+
// Confidence-Aware Disambiguation (Level 2)
|
|
71
|
+
// =============================================================================
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A disambiguation request presented when confidence is borderline.
|
|
75
|
+
*/
|
|
76
|
+
export interface DisambiguationRequest {
|
|
77
|
+
/** The original input that was ambiguous */
|
|
78
|
+
readonly input: string;
|
|
79
|
+
|
|
80
|
+
/** Candidate interpretations ranked by confidence */
|
|
81
|
+
readonly candidates: readonly DisambiguationCandidate[];
|
|
82
|
+
|
|
83
|
+
/** Human/LLM-readable disambiguation prompt */
|
|
84
|
+
readonly question: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* A single candidate interpretation.
|
|
89
|
+
*/
|
|
90
|
+
export interface DisambiguationCandidate {
|
|
91
|
+
/** Command action */
|
|
92
|
+
readonly action: string;
|
|
93
|
+
|
|
94
|
+
/** Confidence score */
|
|
95
|
+
readonly confidence: number;
|
|
96
|
+
|
|
97
|
+
/** Canonical LSE for this interpretation */
|
|
98
|
+
readonly explicit: string;
|
|
99
|
+
|
|
100
|
+
/** Human-readable description */
|
|
101
|
+
readonly description: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// =============================================================================
|
|
105
|
+
// Pattern Hit-Rate Instrumentation (Level 3)
|
|
106
|
+
// =============================================================================
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* A single pattern event for hit-rate tracking.
|
|
110
|
+
*/
|
|
111
|
+
export interface PatternEvent {
|
|
112
|
+
readonly timestamp: number;
|
|
113
|
+
readonly domain: string;
|
|
114
|
+
readonly action: string;
|
|
115
|
+
readonly language: string;
|
|
116
|
+
readonly inputFormat: 'explicit' | 'json' | 'natural';
|
|
117
|
+
readonly confidence: number;
|
|
118
|
+
readonly outcome: 'accepted' | 'rejected' | 'disambiguated';
|
|
119
|
+
readonly diagnosticCodes?: readonly string[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Hit-rate statistics for a category.
|
|
124
|
+
*/
|
|
125
|
+
export interface HitRate {
|
|
126
|
+
readonly attempts: number;
|
|
127
|
+
readonly successes: number;
|
|
128
|
+
readonly rate: number;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Summary of pattern tracking data.
|
|
133
|
+
*/
|
|
134
|
+
export interface PatternTrackerSummary {
|
|
135
|
+
readonly totalEvents: number;
|
|
136
|
+
readonly byOutcome: Readonly<Record<string, number>>;
|
|
137
|
+
readonly byCommand: Readonly<Record<string, HitRate>>;
|
|
138
|
+
readonly byLanguage: Readonly<Record<string, HitRate>>;
|
|
139
|
+
readonly topFailures: readonly TopFailure[];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* A frequently failing diagnostic code.
|
|
144
|
+
*/
|
|
145
|
+
export interface TopFailure {
|
|
146
|
+
readonly code: string;
|
|
147
|
+
readonly count: number;
|
|
148
|
+
readonly actions: readonly string[];
|
|
149
|
+
}
|
|
@@ -165,9 +165,9 @@ function addRoleWithMarker(
|
|
|
165
165
|
|
|
166
166
|
if (marker) {
|
|
167
167
|
const markerInfo = profile.roleMarkers?.[roleSpec.role];
|
|
168
|
-
//
|
|
168
|
+
// Priority: schema markerPosition → profile roleMarkers position → word-order default
|
|
169
169
|
const defaultPosition = profile.wordOrder === 'SOV' ? 'after' : 'before';
|
|
170
|
-
const position = markerInfo?.position ?? defaultPosition;
|
|
170
|
+
const position = roleSpec.markerPosition ?? markerInfo?.position ?? defaultPosition;
|
|
171
171
|
|
|
172
172
|
if (isOptional) {
|
|
173
173
|
// Optional role: wrap marker + role in optional group
|
package/src/index.ts
CHANGED
|
@@ -71,6 +71,12 @@ export type {
|
|
|
71
71
|
TokenStream,
|
|
72
72
|
LanguageTokenizer,
|
|
73
73
|
LanguagePattern,
|
|
74
|
+
// v1.2 types
|
|
75
|
+
Annotation,
|
|
76
|
+
ProtocolDiagnostic,
|
|
77
|
+
AsyncVariant,
|
|
78
|
+
MatchArm,
|
|
79
|
+
LSEEnvelope,
|
|
74
80
|
} from './core/types';
|
|
75
81
|
|
|
76
82
|
export type { CommandSchema, RoleSpec } from './schema';
|
|
@@ -135,12 +141,35 @@ export {
|
|
|
135
141
|
createLoopNode,
|
|
136
142
|
extractValue,
|
|
137
143
|
extractRoleValue,
|
|
144
|
+
// v1.2 factories
|
|
145
|
+
createTryNode,
|
|
146
|
+
createAsyncNode,
|
|
147
|
+
createMatchNode,
|
|
138
148
|
} from './core/types';
|
|
139
149
|
|
|
140
150
|
export { defineCommand, defineRole } from './schema';
|
|
141
151
|
export { createSimpleTokenizer } from './core/tokenization/base-tokenizer';
|
|
142
152
|
export type { SimpleTokenizerConfig } from './core/tokenization/base-tokenizer';
|
|
143
153
|
|
|
154
|
+
// Morphological normalization base class and types
|
|
155
|
+
export { BaseMorphologicalNormalizer } from './core/tokenization/morphology/base-normalizer';
|
|
156
|
+
export type {
|
|
157
|
+
ConjugationEnding,
|
|
158
|
+
NormalizerConfig,
|
|
159
|
+
} from './core/tokenization/morphology/base-normalizer';
|
|
160
|
+
|
|
161
|
+
// IR (Intermediate Representation) — explicit syntax, JSON conversion, reference validation
|
|
162
|
+
export * from './ir';
|
|
163
|
+
|
|
164
|
+
// LLM Prompt Generation — auto-generate system prompts from CommandSchema[]
|
|
165
|
+
export * from './prompts';
|
|
166
|
+
|
|
167
|
+
// Training Data Generation — synthesize (natural_language, LSE) pairs from schemas
|
|
168
|
+
export * from './training';
|
|
169
|
+
|
|
170
|
+
// Feedback Loop — structured errors, disambiguation, pattern tracking
|
|
171
|
+
export * from './feedback';
|
|
172
|
+
|
|
144
173
|
// Multi-statement parser
|
|
145
174
|
export { createMultiStatementParser, accumulateBlocks } from './parsing/multi-statement';
|
|
146
175
|
export type {
|