agent-nuvira 3.1.1 → 3.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/agents/agents/reasoner.d.ts +8 -0
- package/dist/agents/agents/reasoner.d.ts.map +1 -1
- package/dist/agents/agents/reasoner.js +53 -2
- package/dist/agents/agents/reasoner.js.map +1 -1
- package/dist/agents/agents/writer.d.ts +24 -0
- package/dist/agents/agents/writer.d.ts.map +1 -1
- package/dist/agents/agents/writer.js +194 -0
- package/dist/agents/agents/writer.js.map +1 -1
- package/dist/agents/composite-plan.d.ts +143 -0
- package/dist/agents/composite-plan.d.ts.map +1 -0
- package/dist/agents/composite-plan.js +399 -0
- package/dist/agents/composite-plan.js.map +1 -0
- package/dist/agents/long-form-plan.d.ts +156 -0
- package/dist/agents/long-form-plan.d.ts.map +1 -0
- package/dist/agents/long-form-plan.js +274 -0
- package/dist/agents/long-form-plan.js.map +1 -0
- package/dist/agents/orchestrator.d.ts +107 -0
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/orchestrator.js +501 -35
- package/dist/agents/orchestrator.js.map +1 -1
- package/dist/agents/prompt-assembly.d.ts +8 -0
- package/dist/agents/prompt-assembly.d.ts.map +1 -1
- package/dist/agents/prompt-assembly.js +17 -0
- package/dist/agents/prompt-assembly.js.map +1 -1
- package/dist/cli/chat.d.ts +27 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +133 -8
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/execute.d.ts +12 -0
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/execute.js +105 -2
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/models.d.ts.map +1 -1
- package/dist/cli/models.js +10 -0
- package/dist/cli/models.js.map +1 -1
- package/dist/cli/nlu.d.ts +8 -0
- package/dist/cli/nlu.d.ts.map +1 -1
- package/dist/cli/nlu.js +57 -0
- package/dist/cli/nlu.js.map +1 -1
- package/dist/cli/trace.d.ts.map +1 -1
- package/dist/cli/trace.js +27 -0
- package/dist/cli/trace.js.map +1 -1
- package/dist/gateway/gateway-log.d.ts +1 -1
- package/dist/gateway/gateway-log.d.ts.map +1 -1
- package/dist/gateway/gateway-log.js.map +1 -1
- package/dist/gateway/registry.d.ts +116 -1
- package/dist/gateway/registry.d.ts.map +1 -1
- package/dist/gateway/registry.js +575 -52
- package/dist/gateway/registry.js.map +1 -1
- package/dist/inference/model-entitlement.d.ts +46 -0
- package/dist/inference/model-entitlement.d.ts.map +1 -0
- package/dist/inference/model-entitlement.js +98 -0
- package/dist/inference/model-entitlement.js.map +1 -0
- package/dist/inference/tool-call-utils.d.ts.map +1 -1
- package/dist/inference/tool-call-utils.js +70 -1
- package/dist/inference/tool-call-utils.js.map +1 -1
- package/dist/learning/autonomy-policy.d.ts +334 -0
- package/dist/learning/autonomy-policy.d.ts.map +1 -0
- package/dist/learning/autonomy-policy.js +500 -0
- package/dist/learning/autonomy-policy.js.map +1 -0
- package/dist/learning/credential-fingerprint.d.ts +58 -0
- package/dist/learning/credential-fingerprint.d.ts.map +1 -0
- package/dist/learning/credential-fingerprint.js +126 -0
- package/dist/learning/credential-fingerprint.js.map +1 -0
- package/dist/learning/deferred-task.d.ts +159 -0
- package/dist/learning/deferred-task.d.ts.map +1 -0
- package/dist/learning/deferred-task.js +451 -0
- package/dist/learning/deferred-task.js.map +1 -0
- package/dist/learning/deliverable-class.d.ts +130 -0
- package/dist/learning/deliverable-class.d.ts.map +1 -0
- package/dist/learning/deliverable-class.js +432 -0
- package/dist/learning/deliverable-class.js.map +1 -0
- package/dist/learning/long-form.d.ts +252 -0
- package/dist/learning/long-form.d.ts.map +1 -0
- package/dist/learning/long-form.js +510 -0
- package/dist/learning/long-form.js.map +1 -0
- package/dist/learning/model-first-router.d.ts +17 -0
- package/dist/learning/model-first-router.d.ts.map +1 -1
- package/dist/learning/model-first-router.js +35 -0
- package/dist/learning/model-first-router.js.map +1 -1
- package/dist/learning/model-registry.d.ts +96 -4
- package/dist/learning/model-registry.d.ts.map +1 -1
- package/dist/learning/model-registry.js +128 -6
- package/dist/learning/model-registry.js.map +1 -1
- package/dist/learning/model-warmup.d.ts +97 -2
- package/dist/learning/model-warmup.d.ts.map +1 -1
- package/dist/learning/model-warmup.js +165 -60
- package/dist/learning/model-warmup.js.map +1 -1
- package/dist/learning/prompt-layers.d.ts +61 -0
- package/dist/learning/prompt-layers.d.ts.map +1 -0
- package/dist/learning/prompt-layers.js +140 -0
- package/dist/learning/prompt-layers.js.map +1 -0
- package/dist/learning/provider-limits.d.ts +66 -0
- package/dist/learning/provider-limits.d.ts.map +1 -0
- package/dist/learning/provider-limits.js +184 -0
- package/dist/learning/provider-limits.js.map +1 -0
- package/dist/learning/reasoning-trace.d.ts +36 -1
- package/dist/learning/reasoning-trace.d.ts.map +1 -1
- package/dist/learning/reasoning-trace.js +36 -2
- package/dist/learning/reasoning-trace.js.map +1 -1
- package/dist/learning/resilient-call.d.ts +36 -1
- package/dist/learning/resilient-call.d.ts.map +1 -1
- package/dist/learning/resilient-call.js +118 -8
- package/dist/learning/resilient-call.js.map +1 -1
- package/dist/learning/unattended-job.d.ts +293 -0
- package/dist/learning/unattended-job.d.ts.map +1 -0
- package/dist/learning/unattended-job.js +544 -0
- package/dist/learning/unattended-job.js.map +1 -0
- package/dist/learning/unattended-progress.d.ts +95 -0
- package/dist/learning/unattended-progress.d.ts.map +1 -0
- package/dist/learning/unattended-progress.js +147 -0
- package/dist/learning/unattended-progress.js.map +1 -0
- package/dist/learning/working-state.d.ts +109 -0
- package/dist/learning/working-state.d.ts.map +1 -0
- package/dist/learning/working-state.js +244 -0
- package/dist/learning/working-state.js.map +1 -0
- package/dist/nlu/conversation-gate.d.ts +46 -0
- package/dist/nlu/conversation-gate.d.ts.map +1 -1
- package/dist/nlu/conversation-gate.js +73 -6
- package/dist/nlu/conversation-gate.js.map +1 -1
- package/dist/nlu/intent-confirm.d.ts +82 -0
- package/dist/nlu/intent-confirm.d.ts.map +1 -0
- package/dist/nlu/intent-confirm.js +146 -0
- package/dist/nlu/intent-confirm.js.map +1 -0
- package/dist/nlu/learnings.d.ts +101 -0
- package/dist/nlu/learnings.d.ts.map +1 -0
- package/dist/nlu/learnings.js +283 -0
- package/dist/nlu/learnings.js.map +1 -0
- package/dist/tools/coding-tools.d.ts.map +1 -1
- package/dist/tools/coding-tools.js +95 -19
- package/dist/tools/coding-tools.js.map +1 -1
- package/dist/tools/edit-verification.d.ts +125 -0
- package/dist/tools/edit-verification.d.ts.map +1 -0
- package/dist/tools/edit-verification.js +237 -0
- package/dist/tools/edit-verification.js.map +1 -0
- package/dist/tools/git-tool.d.ts.map +1 -1
- package/dist/tools/git-tool.js +37 -4
- package/dist/tools/git-tool.js.map +1 -1
- package/dist/tools/registry.d.ts +30 -2
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +40 -11
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/run-cli.d.ts.map +1 -1
- package/dist/tools/run-cli.js +40 -13
- package/dist/tools/run-cli.js.map +1 -1
- package/dist/tools/run-terminal.d.ts +6 -1
- package/dist/tools/run-terminal.d.ts.map +1 -1
- package/dist/tools/run-terminal.js +158 -18
- package/dist/tools/run-terminal.js.map +1 -1
- package/dist/tools/tool-loop.d.ts +35 -0
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +157 -3
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/web-dashboard/chat-console.d.ts +35 -0
- package/dist/web-dashboard/chat-console.d.ts.map +1 -1
- package/dist/web-dashboard/chat-console.js +97 -18
- package/dist/web-dashboard/chat-console.js.map +1 -1
- package/dist/web-dashboard/chat-retry.d.ts +143 -0
- package/dist/web-dashboard/chat-retry.d.ts.map +1 -0
- package/dist/web-dashboard/chat-retry.js +227 -0
- package/dist/web-dashboard/chat-retry.js.map +1 -0
- package/dist/web-dashboard/server.d.ts +17 -0
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +200 -9
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +81 -4
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/web-dashboard/public/assets/{index-CQW0qv1r.js → index-kCUkORm7.js} +27 -27
- package/src/web-dashboard/public/assets/index-kCUkORm7.js.map +1 -0
- package/src/web-dashboard/public/index.html +1 -1
- package/src/web-dashboard/public/assets/index-CQW0qv1r.js.map +0 -1
|
@@ -33,6 +33,11 @@
|
|
|
33
33
|
import { isTrivialPrompt } from '../memory/provider.js';
|
|
34
34
|
import { parseRequestSync } from './parser.js';
|
|
35
35
|
import { isContentArtifactAsk, stripArtifactReferences } from './intent.js';
|
|
36
|
+
import { isAuthoredGoal } from '../learning/deliverable-class.js';
|
|
37
|
+
import { parseLongFormTarget } from '../learning/long-form.js';
|
|
38
|
+
// The learned corrections. A plain store (mtime-cached, no routing graph), so
|
|
39
|
+
// consulting it on every ask costs a comparison, not a read.
|
|
40
|
+
import { applyLearning, noteLearningApplied } from './learnings.js';
|
|
36
41
|
/**
|
|
37
42
|
* Verbs that are unambiguous coding TASKS when used in command position.
|
|
38
43
|
* Kept to verbs that are rarely used as nouns (unlike "update"/"remove"/
|
|
@@ -79,6 +84,42 @@ export function hasCodingAction(text) {
|
|
|
79
84
|
.replace(/^(?:(?:please|now|next|then|ok|okay|so|also|and)\s*,?\s*)+/i, '');
|
|
80
85
|
return TASK_VERB_AT_START.test(action) || TASK_VERB_AFTER_PREFIX.test(action);
|
|
81
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Is this a LONG-FORM authored deliverable — content the pipeline must build in
|
|
89
|
+
* bounded units rather than answer in one reply?
|
|
90
|
+
*
|
|
91
|
+
* WHY THIS EXISTS (live evidence): "write a 12 page story called Kharig Nights
|
|
92
|
+
* about a village boy who finds a lamp in a banyan root" was read as a
|
|
93
|
+
* CONVERSATIONAL question — the NLU maps `write` to a chat action — and answered
|
|
94
|
+
* in a single reply, bypassing the unit ledger entirely. For 12 pages that
|
|
95
|
+
* looked acceptable; for "write a 200 page book" it is fatal: the ask never
|
|
96
|
+
* reaches the machinery that decomposes it, so nothing measures progress,
|
|
97
|
+
* nothing resumes, and nothing continues unattended. A long-form deliverable is
|
|
98
|
+
* not a question, whatever verb introduces it.
|
|
99
|
+
*
|
|
100
|
+
* BOTH conditions are required:
|
|
101
|
+
* 1. an EXPLICIT magnitude (pages/chapters/words/sections) splitting into more
|
|
102
|
+
* than one unit — "write a story" keeps answering directly, and the
|
|
103
|
+
* DEFAULT chapter count invented for a bare "book" does not count as one;
|
|
104
|
+
* 2. the deliverable classifier reads the ask as authored content. Without
|
|
105
|
+
* this, "write a 20 page plan for my child" would be pushed into a pipeline
|
|
106
|
+
* whose authored path does not recognise it — reintroducing exactly the
|
|
107
|
+
* category error (plan a program for prose) this workstream exists to
|
|
108
|
+
* remove.
|
|
109
|
+
*/
|
|
110
|
+
export function isLongFormDeliverable(text) {
|
|
111
|
+
const t = String(text ?? '').trim();
|
|
112
|
+
if (!t)
|
|
113
|
+
return false;
|
|
114
|
+
const target = parseLongFormTarget(t);
|
|
115
|
+
if (!target || target.unitCount <= 1)
|
|
116
|
+
return false;
|
|
117
|
+
// `source` is the matched phrase ("100 pages") or a sentence describing a
|
|
118
|
+
// default — a default magnitude is not something the user asked for.
|
|
119
|
+
if (/^default\b/.test(target.source))
|
|
120
|
+
return false;
|
|
121
|
+
return isAuthoredGoal(t);
|
|
122
|
+
}
|
|
82
123
|
/**
|
|
83
124
|
* The P0.5 gate: return true when the ask is a conversational question that
|
|
84
125
|
* must be ANSWERED DIRECTLY and must NEVER run the multi-agent pipeline
|
|
@@ -95,6 +136,10 @@ export function isConversationalQuestion(text) {
|
|
|
95
136
|
return false;
|
|
96
137
|
if (isTrivialPrompt(t))
|
|
97
138
|
return true;
|
|
139
|
+
// A long-form deliverable outranks the NLU's chat mapping for `write`: the
|
|
140
|
+
// machinery that can actually finish it must be the one that receives it.
|
|
141
|
+
if (isLongFormDeliverable(t))
|
|
142
|
+
return false;
|
|
98
143
|
if (hasCodingAction(t))
|
|
99
144
|
return false;
|
|
100
145
|
const parsed = parseRequestSync(t);
|
|
@@ -122,15 +167,37 @@ export function isConversationalQuestion(text) {
|
|
|
122
167
|
* gateway does), so this costs nothing extra on the hot path.
|
|
123
168
|
*/
|
|
124
169
|
export function resolveAskKind(text, parsed) {
|
|
170
|
+
return explainAskKind(text, parsed).kind;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Resolve the route AND explain it — the same function `resolveAskKind` uses,
|
|
174
|
+
* split out so the CLI can say WHY a route differs from the rules. An override
|
|
175
|
+
* nobody can see is its own bug.
|
|
176
|
+
*
|
|
177
|
+
* A LEARNED correction outranks the rules: it exists because this exact ask was
|
|
178
|
+
* read wrong before and the model confirmed what it really is (see
|
|
179
|
+
* `intent-confirm.ts`), so the rules have already been shown to fail here. It is
|
|
180
|
+
* checked against the HEURISTIC verdict — a learning that agrees with the rules
|
|
181
|
+
* is not an override, and must not be reported as one.
|
|
182
|
+
*/
|
|
183
|
+
export function explainAskKind(text, parsed) {
|
|
125
184
|
const t = String(text ?? '').trim();
|
|
126
185
|
if (!t)
|
|
127
|
-
return 'chat';
|
|
186
|
+
return { kind: 'chat', base: 'chat' };
|
|
128
187
|
if (isTrivialPrompt(t))
|
|
129
|
-
return 'chat';
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
188
|
+
return { kind: 'chat', base: 'chat' };
|
|
189
|
+
const base = isLongFormDeliverable(t)
|
|
190
|
+
? 'pipeline'
|
|
191
|
+
: hasCodingAction(t)
|
|
192
|
+
? 'pipeline'
|
|
193
|
+
: (parsed ?? parseRequestSync(t)).action.run === 'pipeline'
|
|
194
|
+
? 'pipeline'
|
|
195
|
+
: 'chat';
|
|
196
|
+
const learned = applyLearning(t, base);
|
|
197
|
+
if (!learned)
|
|
198
|
+
return { kind: base, base };
|
|
199
|
+
noteLearningApplied(learned.learning.id);
|
|
200
|
+
return { kind: learned.kind, base, learning: learned.learning };
|
|
134
201
|
}
|
|
135
202
|
/**
|
|
136
203
|
* Is this ask a LOCAL CLI COMMAND aimed at the agent itself ("run nuvira
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-gate.js","sourceRoot":"","sources":["../../src/nlu/conversation-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAsB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"conversation-gate.js","sourceRoot":"","sources":["../../src/nlu/conversation-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent confirmation — the self-correction half of routing.
|
|
3
|
+
*
|
|
4
|
+
* THE PROBLEM. When a turn fails, the agent has exactly one reliable way to
|
|
5
|
+
* find out whether the failure was the WORLD's fault (no model, no quota) or its
|
|
6
|
+
* OWN (it read the request wrong and worked on the wrong thing): ask the model
|
|
7
|
+
* what the request actually is. Without that, a misreading is permanent — the
|
|
8
|
+
* same ask runs down the same wrong path on every future message, burning a
|
|
9
|
+
* pipeline run each time, and the user's only recourse is to rephrase.
|
|
10
|
+
*
|
|
11
|
+
* The rules it corrects are deterministic and cheap, which is why they are worth
|
|
12
|
+
* keeping, and blind to the object of a verb, which is why they need this. So the
|
|
13
|
+
* design is: keep the rules on the hot path, and let a CONFIRMED correction
|
|
14
|
+
* override them from then on (`learnings.ts`).
|
|
15
|
+
*
|
|
16
|
+
* THREE DELIBERATE RESTRAINTS
|
|
17
|
+
* 1. It runs only on a REPEATED failure. A single failure mostly says something
|
|
18
|
+
* about the world; probing on every one would spend a quota-limited model to
|
|
19
|
+
* audit a routing decision that was probably fine.
|
|
20
|
+
* 2. It is asked to answer with JSON and nothing else, but the reply is parsed
|
|
21
|
+
* defensively — a model that ignores the format yields NO correction rather
|
|
22
|
+
* than a guessed one.
|
|
23
|
+
* 3. Any error (no model, unparseable answer) means "no correction". Teaching
|
|
24
|
+
* the NLU from a failed probe would encode an outage as a rule, which is the
|
|
25
|
+
* worst possible outcome: the router would get worse exactly when the pool
|
|
26
|
+
* is down.
|
|
27
|
+
*/
|
|
28
|
+
import { type NluLearning } from './learnings.js';
|
|
29
|
+
import type { AskKind } from './conversation-gate.js';
|
|
30
|
+
/** What one confirmation established. */
|
|
31
|
+
export interface IntentConfirmResult {
|
|
32
|
+
/** The kind to act on now — the corrected one, or the routed one unchanged. */
|
|
33
|
+
kind: AskKind;
|
|
34
|
+
/** True when the model agreed with the original reading (or gave no verdict). */
|
|
35
|
+
agreed: boolean;
|
|
36
|
+
/** The model's one-line reason, when it gave one. */
|
|
37
|
+
reason?: string;
|
|
38
|
+
/** The learning written, when the reading was corrected. */
|
|
39
|
+
learning?: NluLearning;
|
|
40
|
+
/** True when the probe could not run (no model / unreadable answer). */
|
|
41
|
+
failed?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The audit prompt. Kept to a JSON contract with the decision space spelled out,
|
|
45
|
+
* because the model is being asked to judge a routing decision — not to answer
|
|
46
|
+
* the request. Answering it here would leak a second, contradictory answer into
|
|
47
|
+
* the conversation.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildIntentConfirmPrompt(ask: string, routed: AskKind): string;
|
|
50
|
+
/**
|
|
51
|
+
* Read a verdict out of the model's reply.
|
|
52
|
+
*
|
|
53
|
+
* Order matters: an explicit JSON `intent` field is authoritative, then a bare
|
|
54
|
+
* quoted token, then keyword scanning. Anything ambiguous returns no verdict
|
|
55
|
+
* (`understood: false`) so the caller keeps the route it had.
|
|
56
|
+
*/
|
|
57
|
+
export declare function parseIntentConfirmReply(raw: string): {
|
|
58
|
+
kind?: AskKind;
|
|
59
|
+
reason?: string;
|
|
60
|
+
understood: boolean;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Ask the model what this ask really needs, and record the correction when it
|
|
64
|
+
* disagrees with the route that just failed.
|
|
65
|
+
*
|
|
66
|
+
* @param callLLM A one-shot model call. Injected so the caller owns routing and
|
|
67
|
+
* tests stay deterministic — and so a probe never piggy-backs on the failover
|
|
68
|
+
* state of the turn that just died.
|
|
69
|
+
*/
|
|
70
|
+
export declare function confirmRoutedIntent(input: {
|
|
71
|
+
ask: string;
|
|
72
|
+
routed: AskKind;
|
|
73
|
+
callLLM: (prompt: string) => Promise<string>;
|
|
74
|
+
/** Record the correction as a learning (default: true). */
|
|
75
|
+
record?: boolean;
|
|
76
|
+
now?: number;
|
|
77
|
+
}): Promise<IntentConfirmResult>;
|
|
78
|
+
/** The line a sender sees when the audit CONFIRMS the reading. */
|
|
79
|
+
export declare function intentConfirmedNote(routed: AskKind): string;
|
|
80
|
+
/** The line a sender sees when the audit CORRECTED the reading. */
|
|
81
|
+
export declare function intentCorrectedNote(to: AskKind, reason?: string): string;
|
|
82
|
+
//# sourceMappingURL=intent-confirm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent-confirm.d.ts","sourceRoot":"","sources":["../../src/nlu/intent-confirm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,yCAAyC;AACzC,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,IAAI,EAAE,OAAO,CAAC;IACd,iFAAiF;IACjF,MAAM,EAAE,OAAO,CAAC;IAChB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAc7E;AAOD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CA0B7G;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAmC/B;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAI3D;AAED,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAKxE"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent confirmation — the self-correction half of routing.
|
|
3
|
+
*
|
|
4
|
+
* THE PROBLEM. When a turn fails, the agent has exactly one reliable way to
|
|
5
|
+
* find out whether the failure was the WORLD's fault (no model, no quota) or its
|
|
6
|
+
* OWN (it read the request wrong and worked on the wrong thing): ask the model
|
|
7
|
+
* what the request actually is. Without that, a misreading is permanent — the
|
|
8
|
+
* same ask runs down the same wrong path on every future message, burning a
|
|
9
|
+
* pipeline run each time, and the user's only recourse is to rephrase.
|
|
10
|
+
*
|
|
11
|
+
* The rules it corrects are deterministic and cheap, which is why they are worth
|
|
12
|
+
* keeping, and blind to the object of a verb, which is why they need this. So the
|
|
13
|
+
* design is: keep the rules on the hot path, and let a CONFIRMED correction
|
|
14
|
+
* override them from then on (`learnings.ts`).
|
|
15
|
+
*
|
|
16
|
+
* THREE DELIBERATE RESTRAINTS
|
|
17
|
+
* 1. It runs only on a REPEATED failure. A single failure mostly says something
|
|
18
|
+
* about the world; probing on every one would spend a quota-limited model to
|
|
19
|
+
* audit a routing decision that was probably fine.
|
|
20
|
+
* 2. It is asked to answer with JSON and nothing else, but the reply is parsed
|
|
21
|
+
* defensively — a model that ignores the format yields NO correction rather
|
|
22
|
+
* than a guessed one.
|
|
23
|
+
* 3. Any error (no model, unparseable answer) means "no correction". Teaching
|
|
24
|
+
* the NLU from a failed probe would encode an outage as a rule, which is the
|
|
25
|
+
* worst possible outcome: the router would get worse exactly when the pool
|
|
26
|
+
* is down.
|
|
27
|
+
*/
|
|
28
|
+
import { recordLearning } from './learnings.js';
|
|
29
|
+
/**
|
|
30
|
+
* The audit prompt. Kept to a JSON contract with the decision space spelled out,
|
|
31
|
+
* because the model is being asked to judge a routing decision — not to answer
|
|
32
|
+
* the request. Answering it here would leak a second, contradictory answer into
|
|
33
|
+
* the conversation.
|
|
34
|
+
*/
|
|
35
|
+
export function buildIntentConfirmPrompt(ask, routed) {
|
|
36
|
+
return [
|
|
37
|
+
'You are auditing ONE routing decision. Do not answer the request, do not explain the topic, do not add prose.',
|
|
38
|
+
'',
|
|
39
|
+
`The request was: """${ask.slice(0, 800)}"""`,
|
|
40
|
+
`It was routed as: ${routed === 'pipeline' ? '"coding-task" (the developer pipeline builds software)' : '"chat" (a direct written answer is produced)'}`,
|
|
41
|
+
'',
|
|
42
|
+
'Decide which one genuinely serves the sender:',
|
|
43
|
+
'- "chat": the sender wants knowledge, advice, content or an explanation delivered as text — a plan, routine, schedule, diet, story, lesson, letter, explanation, comparison, or ANY question. Producing a software project for this would be wrong.',
|
|
44
|
+
'- "coding-task": the sender wants software built or changed in a codebase — an app, script, API, test, fix, refactor, deploy.',
|
|
45
|
+
'',
|
|
46
|
+
'Reply with JSON only, exactly this shape:',
|
|
47
|
+
'{"intent":"chat"|"coding-task","reason":"<max 12 words>"}',
|
|
48
|
+
].join('\n');
|
|
49
|
+
}
|
|
50
|
+
/** Phrases that mean "the developer pipeline". */
|
|
51
|
+
const PIPELINE_TOKENS = ['coding-task', 'coding task', 'coding_task', 'pipeline', 'developer', 'software', 'code-task'];
|
|
52
|
+
/** Phrases that mean "answer it directly". */
|
|
53
|
+
const CHAT_TOKENS = ['"chat"', 'chat', 'answer', 'direct', 'prose', 'content'];
|
|
54
|
+
/**
|
|
55
|
+
* Read a verdict out of the model's reply.
|
|
56
|
+
*
|
|
57
|
+
* Order matters: an explicit JSON `intent` field is authoritative, then a bare
|
|
58
|
+
* quoted token, then keyword scanning. Anything ambiguous returns no verdict
|
|
59
|
+
* (`understood: false`) so the caller keeps the route it had.
|
|
60
|
+
*/
|
|
61
|
+
export function parseIntentConfirmReply(raw) {
|
|
62
|
+
const text = String(raw ?? '');
|
|
63
|
+
if (!text.trim())
|
|
64
|
+
return { understood: false };
|
|
65
|
+
// 1. An explicit JSON intent field.
|
|
66
|
+
const jsonMatch = /"intent"\s*:\s*"([^"]+)"/i.exec(text);
|
|
67
|
+
const reasonMatch = /"reason"\s*:\s*"([^"]*)"/i.exec(text);
|
|
68
|
+
const reason = reasonMatch?.[1]?.trim().slice(0, 200) || undefined;
|
|
69
|
+
if (jsonMatch) {
|
|
70
|
+
const value = jsonMatch[1].toLowerCase();
|
|
71
|
+
if (PIPELINE_TOKENS.includes(value) || /coding|code|pipeline|developer/.test(value)) {
|
|
72
|
+
return { kind: 'pipeline', reason, understood: true };
|
|
73
|
+
}
|
|
74
|
+
if (CHAT_TOKENS.includes(value) || /chat|answer/.test(value)) {
|
|
75
|
+
return { kind: 'chat', reason, understood: true };
|
|
76
|
+
}
|
|
77
|
+
return { understood: false, ...(reason ? { reason } : {}) };
|
|
78
|
+
}
|
|
79
|
+
// 2. A bare token, which is what a truncated or prose answer usually leaves.
|
|
80
|
+
const lower = text.toLowerCase();
|
|
81
|
+
const hasPipeline = /\bcoding[- _]?task\b|\bpipeline\b|\bdeveloper\b/.test(lower);
|
|
82
|
+
const hasChat = /(^|\W)chat(\W|$)|direct answer|answer directly|prose/.test(lower);
|
|
83
|
+
if (hasPipeline && !hasChat)
|
|
84
|
+
return { kind: 'pipeline', reason, understood: true };
|
|
85
|
+
if (hasChat && !hasPipeline)
|
|
86
|
+
return { kind: 'chat', reason, understood: true };
|
|
87
|
+
return { understood: false, ...(reason ? { reason } : {}) };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Ask the model what this ask really needs, and record the correction when it
|
|
91
|
+
* disagrees with the route that just failed.
|
|
92
|
+
*
|
|
93
|
+
* @param callLLM A one-shot model call. Injected so the caller owns routing and
|
|
94
|
+
* tests stay deterministic — and so a probe never piggy-backs on the failover
|
|
95
|
+
* state of the turn that just died.
|
|
96
|
+
*/
|
|
97
|
+
export async function confirmRoutedIntent(input) {
|
|
98
|
+
let raw = '';
|
|
99
|
+
try {
|
|
100
|
+
raw = await input.callLLM(buildIntentConfirmPrompt(input.ask, input.routed));
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// The probe is best-effort by contract: a failure means "no verdict".
|
|
104
|
+
return { kind: input.routed, agreed: true, failed: true };
|
|
105
|
+
}
|
|
106
|
+
const parsed = parseIntentConfirmReply(raw);
|
|
107
|
+
if (!parsed.understood || !parsed.kind || parsed.kind === input.routed) {
|
|
108
|
+
return {
|
|
109
|
+
kind: input.routed,
|
|
110
|
+
agreed: true,
|
|
111
|
+
...(parsed.reason ? { reason: parsed.reason } : {}),
|
|
112
|
+
...(parsed.understood ? {} : { failed: true }),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const result = {
|
|
116
|
+
kind: parsed.kind,
|
|
117
|
+
agreed: false,
|
|
118
|
+
...(parsed.reason ? { reason: parsed.reason } : {}),
|
|
119
|
+
};
|
|
120
|
+
if (input.record !== false) {
|
|
121
|
+
const learning = recordLearning({
|
|
122
|
+
text: input.ask,
|
|
123
|
+
from: input.routed,
|
|
124
|
+
to: parsed.kind,
|
|
125
|
+
...(parsed.reason ? { reason: parsed.reason } : {}),
|
|
126
|
+
...(input.now !== undefined ? { now: input.now } : {}),
|
|
127
|
+
});
|
|
128
|
+
if (learning)
|
|
129
|
+
result.learning = learning;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
/** The line a sender sees when the audit CONFIRMS the reading. */
|
|
134
|
+
export function intentConfirmedNote(routed) {
|
|
135
|
+
return routed === 'pipeline'
|
|
136
|
+
? '🧭 I double-checked what you asked for: building this is the right read, so the only problem is model availability.'
|
|
137
|
+
: '🧭 I double-checked what you asked for: this is a question to answer, not code to write, so the only problem is model availability.';
|
|
138
|
+
}
|
|
139
|
+
/** The line a sender sees when the audit CORRECTED the reading. */
|
|
140
|
+
export function intentCorrectedNote(to, reason) {
|
|
141
|
+
const why = reason ? ` (${reason})` : '';
|
|
142
|
+
return to === 'pipeline'
|
|
143
|
+
? `🧭 I re-read your request${why} — that one needs the build pipeline, not a written answer. Running it now.`
|
|
144
|
+
: `🧭 I re-read your request${why} — that's a question to answer, not code to write. Answering it directly now.`;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=intent-confirm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent-confirm.js","sourceRoot":"","sources":["../../src/nlu/intent-confirm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NLU learnings — the record of what the router READ WRONG, applied to the next
|
|
3
|
+
* ask that means the same thing.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS. Every routing mistake in this codebase had the same shape: a
|
|
6
|
+
* rule keyed off a surface word, the ask was quietly misread, and the mistake
|
|
7
|
+
* was indistinguishable from a fresh ask on the next message. An agent that
|
|
8
|
+
* cannot learn from a confirmed misreading is a frozen ruleset, not something
|
|
9
|
+
* that improves — which is precisely the complaint this module answers.
|
|
10
|
+
*
|
|
11
|
+
* A learning is written ONLY when a misreading has been CONFIRMED by the model
|
|
12
|
+
* (see `intent-confirm.ts`), never from a guess and never from a failure alone:
|
|
13
|
+
* a turn can fail for reasons that say nothing about its intent (quota, network,
|
|
14
|
+
* an oversized prompt), and teaching the router from those would make it worse
|
|
15
|
+
* with every outage. The correction is stored with the ask that earned it, so
|
|
16
|
+
* the store stays inspectable — a human can read exactly which asks were
|
|
17
|
+
* misread and how.
|
|
18
|
+
*
|
|
19
|
+
* MATCHING IS DELIBERATELY NARROW. A learning applies to the same ask, not to a
|
|
20
|
+
* similar-looking one: word order and repeated words are ignored (token set), but
|
|
21
|
+
* nothing else is. A loose match would be worse than no learning at all — the
|
|
22
|
+
* observed object-blindness ("create a *project plan*" vs "create a *plan* for
|
|
23
|
+
* my kid") is exactly the distinction a fuzzy matcher would erase.
|
|
24
|
+
*/
|
|
25
|
+
import type { AskKind } from './conversation-gate.js';
|
|
26
|
+
/** One confirmed correction of a routing reading. */
|
|
27
|
+
export interface NluLearning {
|
|
28
|
+
id: string;
|
|
29
|
+
/** Token-set signature of the ask this was learned from (see `signatureOf`). */
|
|
30
|
+
signature: string;
|
|
31
|
+
/** The ask, verbatim — so a stored learning is readable, not a token soup. */
|
|
32
|
+
example: string;
|
|
33
|
+
/** The kind the ask was read AS (the mistake). */
|
|
34
|
+
from: AskKind;
|
|
35
|
+
/** The kind it should have been (the correction). */
|
|
36
|
+
to: AskKind;
|
|
37
|
+
/** How the correction was established. */
|
|
38
|
+
source: 'intent-confirm';
|
|
39
|
+
recordedAt: number;
|
|
40
|
+
/** How many times this learning changed a routing decision. */
|
|
41
|
+
hits: number;
|
|
42
|
+
lastAppliedAt?: number;
|
|
43
|
+
/** The model's one-line reason, kept for the store's audit value. */
|
|
44
|
+
reason?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A token-set signature: lowercase, punctuation removed, stopwords dropped,
|
|
48
|
+
* deduped, sorted. Word order and repetition are intentionally invisible — the
|
|
49
|
+
* SAME ask phrased as "for class 4, create a plan" is the same request — while
|
|
50
|
+
* any word that carries meaning still distinguishes it.
|
|
51
|
+
*/
|
|
52
|
+
export declare function signatureOf(text: string | null | undefined): string;
|
|
53
|
+
/**
|
|
54
|
+
* Read the store, cached on mtime. This runs on the routing hot path (every
|
|
55
|
+
* inbound message), so a real file read per ask is not acceptable — and a
|
|
56
|
+
* stale cache is not either, since a learning is written by a DIFFERENT process
|
|
57
|
+
* in the dashboard/gateway case.
|
|
58
|
+
*/
|
|
59
|
+
export declare function loadLearnings(): NluLearning[];
|
|
60
|
+
/**
|
|
61
|
+
* Record a confirmed misreading.
|
|
62
|
+
*
|
|
63
|
+
* One entry per (signature, target): re-confirming the same correction refreshes
|
|
64
|
+
* the existing learning instead of accumulating duplicates, and a LATER
|
|
65
|
+
* correction that contradicts an earlier one replaces it — the newest confirmed
|
|
66
|
+
* verdict is the truth, and keeping both would leave the store self-contradictory.
|
|
67
|
+
*/
|
|
68
|
+
export declare function recordLearning(input: {
|
|
69
|
+
text: string;
|
|
70
|
+
from: AskKind;
|
|
71
|
+
to: AskKind;
|
|
72
|
+
reason?: string;
|
|
73
|
+
now?: number;
|
|
74
|
+
}): NluLearning | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* The learning that applies to this ask, if any.
|
|
77
|
+
*
|
|
78
|
+
* An exact signature match wins. Otherwise a near-identical ask is accepted —
|
|
79
|
+
* same object, one word added or removed — under all three guards above.
|
|
80
|
+
* Nothing looser: a wrong correction silently misroutes a request, which is the
|
|
81
|
+
* class of bug this store exists to fix.
|
|
82
|
+
*/
|
|
83
|
+
export declare function matchLearning(text: string | null | undefined): NluLearning | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Apply a learning to a verdict. Returns the corrected kind plus the learning
|
|
86
|
+
* that changed it, so the caller can report WHY the route differs from the
|
|
87
|
+
* rules (an unexplained override is its own bug).
|
|
88
|
+
*/
|
|
89
|
+
export declare function applyLearning(text: string | null | undefined, verdict: AskKind): {
|
|
90
|
+
kind: AskKind;
|
|
91
|
+
learning: NluLearning;
|
|
92
|
+
} | undefined;
|
|
93
|
+
/** Record one applied hit (best-effort; telemetry must not break routing). */
|
|
94
|
+
export declare function noteLearningApplied(id: string, now?: number): void;
|
|
95
|
+
/** Every stored learning, newest first (CLI / dashboard inspection). */
|
|
96
|
+
export declare function listLearnings(): NluLearning[];
|
|
97
|
+
/** Drop one learning (a correction that turned out wrong must be removable). */
|
|
98
|
+
export declare function removeLearning(id: string): boolean;
|
|
99
|
+
/** Test/ops escape hatch: forget everything. */
|
|
100
|
+
export declare function clearLearnings(): void;
|
|
101
|
+
//# sourceMappingURL=learnings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learnings.d.ts","sourceRoot":"","sources":["../../src/nlu/learnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,IAAI,EAAE,OAAO,CAAC;IACd,qDAAqD;IACrD,EAAE,EAAE,OAAO,CAAC;IACZ,0CAA0C;IAC1C,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAyBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAOnE;AAeD;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,WAAW,EAAE,CAkB7C;AA6BD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,WAAW,GAAG,SAAS,CA6B1B;AAwCD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAsBtF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,OAAO,EAAE,OAAO,GACf;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,GAAG,SAAS,CAKtD;AAED,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI,CAW9E;AAED,wEAAwE;AACxE,wBAAgB,aAAa,IAAI,WAAW,EAAE,CAE7C;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAMlD;AAED,gDAAgD;AAChD,wBAAgB,cAAc,IAAI,IAAI,CAErC"}
|