agent-nuvira 3.1.1 → 3.1.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/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +17 -2
- package/dist/cli/chat.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/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 +85 -1
- package/dist/gateway/registry.d.ts.map +1 -1
- package/dist/gateway/registry.js +438 -45
- package/dist/gateway/registry.js.map +1 -1
- 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/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/model-first-router.d.ts.map +1 -1
- package/dist/learning/model-first-router.js +8 -0
- package/dist/learning/model-first-router.js.map +1 -1
- package/dist/learning/model-registry.d.ts +30 -0
- package/dist/learning/model-registry.d.ts.map +1 -1
- package/dist/learning/model-registry.js +61 -0
- package/dist/learning/model-registry.js.map +1 -1
- package/dist/learning/resilient-call.d.ts.map +1 -1
- package/dist/learning/resilient-call.js +38 -3
- package/dist/learning/resilient-call.js.map +1 -1
- package/dist/nlu/conversation-gate.d.ts +22 -0
- package/dist/nlu/conversation-gate.d.ts.map +1 -1
- package/dist/nlu/conversation-gate.js +29 -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/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +16 -2
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/web-dashboard/chat-console.d.ts +29 -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 +219 -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 +120 -1
- package/dist/web-dashboard/server.js.map +1 -1
- package/package.json +1 -1
- package/src/web-dashboard/public/assets/{index-CQW0qv1r.js → index-Co7Hk2FT.js} +27 -27
- package/src/web-dashboard/public/assets/index-Co7Hk2FT.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
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* starved of execution.
|
|
32
32
|
*/
|
|
33
33
|
import { type ParsedRequest } from './parser.js';
|
|
34
|
+
import { type NluLearning } from './learnings.js';
|
|
34
35
|
/** True when the ask carries an unambiguous coding action (task, not question). */
|
|
35
36
|
export declare function hasCodingAction(text: string): boolean;
|
|
36
37
|
/**
|
|
@@ -68,6 +69,27 @@ export type AskKind = 'chat' | 'pipeline';
|
|
|
68
69
|
* gateway does), so this costs nothing extra on the hot path.
|
|
69
70
|
*/
|
|
70
71
|
export declare function resolveAskKind(text: string | null | undefined, parsed?: ParsedRequest): AskKind;
|
|
72
|
+
/** One routing verdict WITH the reason it differs from the rules. */
|
|
73
|
+
export interface AskKindExplanation {
|
|
74
|
+
/** The route to use. */
|
|
75
|
+
kind: AskKind;
|
|
76
|
+
/** What the deterministic rules alone would have said. */
|
|
77
|
+
base: AskKind;
|
|
78
|
+
/** The learned correction that overrode those rules, when there is one. */
|
|
79
|
+
learning?: NluLearning;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolve the route AND explain it — the same function `resolveAskKind` uses,
|
|
83
|
+
* split out so the CLI can say WHY a route differs from the rules. An override
|
|
84
|
+
* nobody can see is its own bug.
|
|
85
|
+
*
|
|
86
|
+
* A LEARNED correction outranks the rules: it exists because this exact ask was
|
|
87
|
+
* read wrong before and the model confirmed what it really is (see
|
|
88
|
+
* `intent-confirm.ts`), so the rules have already been shown to fail here. It is
|
|
89
|
+
* checked against the HEURISTIC verdict — a learning that agrees with the rules
|
|
90
|
+
* is not an override, and must not be reported as one.
|
|
91
|
+
*/
|
|
92
|
+
export declare function explainAskKind(text: string | null | undefined, parsed?: ParsedRequest): AskKindExplanation;
|
|
71
93
|
/**
|
|
72
94
|
* Is this ask a LOCAL CLI COMMAND aimed at the agent itself ("run nuvira
|
|
73
95
|
* gateway status", "agent-nuvira models", "buff gateway status")?
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-gate.d.ts","sourceRoot":"","sources":["../../src/nlu/conversation-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"conversation-gate.d.ts","sourceRoot":"","sources":["../../src/nlu/conversation-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAInE,OAAO,EAAsC,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AA0BtF,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAyBrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAOjF;AAED,uEAAuE;AACvE,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAET;AAED,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IACjC,wBAAwB;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,0DAA0D;IAC1D,IAAI,EAAE,OAAO,CAAC;IACd,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,MAAM,CAAC,EAAE,aAAa,GACrB,kBAAkB,CAepB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAM7E"}
|
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
import { isTrivialPrompt } from '../memory/provider.js';
|
|
34
34
|
import { parseRequestSync } from './parser.js';
|
|
35
35
|
import { isContentArtifactAsk, stripArtifactReferences } from './intent.js';
|
|
36
|
+
// The learned corrections. A plain store (mtime-cached, no routing graph), so
|
|
37
|
+
// consulting it on every ask costs a comparison, not a read.
|
|
38
|
+
import { applyLearning, noteLearningApplied } from './learnings.js';
|
|
36
39
|
/**
|
|
37
40
|
* Verbs that are unambiguous coding TASKS when used in command position.
|
|
38
41
|
* Kept to verbs that are rarely used as nouns (unlike "update"/"remove"/
|
|
@@ -122,15 +125,35 @@ export function isConversationalQuestion(text) {
|
|
|
122
125
|
* gateway does), so this costs nothing extra on the hot path.
|
|
123
126
|
*/
|
|
124
127
|
export function resolveAskKind(text, parsed) {
|
|
128
|
+
return explainAskKind(text, parsed).kind;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Resolve the route AND explain it — the same function `resolveAskKind` uses,
|
|
132
|
+
* split out so the CLI can say WHY a route differs from the rules. An override
|
|
133
|
+
* nobody can see is its own bug.
|
|
134
|
+
*
|
|
135
|
+
* A LEARNED correction outranks the rules: it exists because this exact ask was
|
|
136
|
+
* read wrong before and the model confirmed what it really is (see
|
|
137
|
+
* `intent-confirm.ts`), so the rules have already been shown to fail here. It is
|
|
138
|
+
* checked against the HEURISTIC verdict — a learning that agrees with the rules
|
|
139
|
+
* is not an override, and must not be reported as one.
|
|
140
|
+
*/
|
|
141
|
+
export function explainAskKind(text, parsed) {
|
|
125
142
|
const t = String(text ?? '').trim();
|
|
126
143
|
if (!t)
|
|
127
|
-
return 'chat';
|
|
144
|
+
return { kind: 'chat', base: 'chat' };
|
|
128
145
|
if (isTrivialPrompt(t))
|
|
129
|
-
return 'chat';
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
146
|
+
return { kind: 'chat', base: 'chat' };
|
|
147
|
+
const base = hasCodingAction(t)
|
|
148
|
+
? 'pipeline'
|
|
149
|
+
: (parsed ?? parseRequestSync(t)).action.run === 'pipeline'
|
|
150
|
+
? 'pipeline'
|
|
151
|
+
: 'chat';
|
|
152
|
+
const learned = applyLearning(t, base);
|
|
153
|
+
if (!learned)
|
|
154
|
+
return { kind: base, base };
|
|
155
|
+
noteLearningApplied(learned.learning.id);
|
|
156
|
+
return { kind: learned.kind, base, learning: learned.learning };
|
|
134
157
|
}
|
|
135
158
|
/**
|
|
136
159
|
* 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"}
|