agentfootprint 9.30.0 → 9.32.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/AGENTS.md +1 -1
- package/CLAUDE.md +6 -2
- package/ai-instructions/claude-code/SKILL.md +1 -1
- package/dist/adapters/identity/jwks.js +18 -0
- package/dist/adapters/identity/jwks.js.map +1 -1
- package/dist/adapters/llm/BrowserOpenAIProvider.js +5 -3
- package/dist/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/adapters/llm/OpenAIProvider.js +74 -2
- package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/adapters/llm/azureUrl.js +48 -0
- package/dist/adapters/llm/azureUrl.js.map +1 -0
- package/dist/adapters/llm/createProvider.js +25 -6
- package/dist/adapters/llm/createProvider.js.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/artifacts/gcsArtifacts.js +20 -0
- package/dist/artifacts/gcsArtifacts.js.map +1 -1
- package/dist/esm/adapters/identity/jwks.d.ts +18 -0
- package/dist/esm/adapters/identity/jwks.js +18 -0
- package/dist/esm/adapters/identity/jwks.js.map +1 -1
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.js +5 -3
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/esm/adapters/llm/OpenAIProvider.d.ts +15 -2
- package/dist/esm/adapters/llm/OpenAIProvider.js +74 -2
- package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/esm/adapters/llm/azureUrl.d.ts +36 -0
- package/dist/esm/adapters/llm/azureUrl.js +43 -0
- package/dist/esm/adapters/llm/azureUrl.js.map +1 -0
- package/dist/esm/adapters/llm/createProvider.d.ts +5 -1
- package/dist/esm/adapters/llm/createProvider.js +25 -6
- package/dist/esm/adapters/llm/createProvider.js.map +1 -1
- package/dist/esm/adapters/types.d.ts +30 -2
- package/dist/esm/adapters/types.js.map +1 -1
- package/dist/esm/artifacts/gcsArtifacts.d.ts +20 -0
- package/dist/esm/artifacts/gcsArtifacts.js +20 -0
- package/dist/esm/artifacts/gcsArtifacts.js.map +1 -1
- package/dist/esm/events/payloads.d.ts +36 -0
- package/dist/esm/events/registry.d.ts +3 -1
- package/dist/esm/events/registry.js +2 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/hosting/admission.d.ts +25 -0
- package/dist/esm/hosting/admission.js +25 -0
- package/dist/esm/hosting/admission.js.map +1 -1
- package/dist/esm/hosting/envelope.d.ts +10 -0
- package/dist/esm/hosting/envelope.js +10 -0
- package/dist/esm/hosting/envelope.js.map +1 -1
- package/dist/esm/hosting/index.d.ts +1 -0
- package/dist/esm/hosting/index.js.map +1 -1
- package/dist/esm/hosting/ingressRecord.d.ts +177 -0
- package/dist/esm/hosting/ingressRecord.js +246 -0
- package/dist/esm/hosting/ingressRecord.js.map +1 -0
- package/dist/esm/hosting/standingAgent.js +50 -1
- package/dist/esm/hosting/standingAgent.js.map +1 -1
- package/dist/esm/hosting/types.d.ts +31 -0
- package/dist/esm/hosting/types.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillExamples.d.ts +168 -0
- package/dist/esm/lib/injection-engine/skillExamples.js +435 -0
- package/dist/esm/lib/injection-engine/skillExamples.js.map +1 -0
- package/dist/esm/lib/injection-engine/skillGraph.d.ts +63 -0
- package/dist/esm/lib/injection-engine/skillGraph.js +40 -2
- package/dist/esm/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillGraphCheckup.d.ts +25 -2
- package/dist/esm/lib/injection-engine/skillGraphCheckup.js +11 -2
- package/dist/esm/lib/injection-engine/skillGraphCheckup.js.map +1 -1
- package/dist/esm/lib/injection-engine/skillMatch.d.ts +7 -0
- package/dist/esm/lib/injection-engine/skillMatch.js +9 -4
- package/dist/esm/lib/injection-engine/skillMatch.js.map +1 -1
- package/dist/esm/lib/mcp/gatewayTransport.d.ts +52 -0
- package/dist/esm/lib/mcp/gatewayTransport.js +1 -0
- package/dist/esm/lib/mcp/gatewayTransport.js.map +1 -1
- package/dist/esm/lib/mcp/mcpClient.js +8 -1
- package/dist/esm/lib/mcp/mcpClient.js.map +1 -1
- package/dist/esm/lib/mcp/types.d.ts +10 -0
- package/dist/esm/observe.js +2 -1
- package/dist/esm/observe.js.map +1 -1
- package/dist/esm/recorders/core/ResilienceRecorder.d.ts +8 -7
- package/dist/esm/recorders/core/ResilienceRecorder.js +9 -7
- package/dist/esm/recorders/core/ResilienceRecorder.js.map +1 -1
- package/dist/esm/recorders/core/resilienceHooks.d.ts +1 -0
- package/dist/esm/recorders/core/resilienceHooks.js +13 -0
- package/dist/esm/recorders/core/resilienceHooks.js.map +1 -1
- package/dist/esm/resilience/withCircuitBreaker.d.ts +27 -7
- package/dist/esm/resilience/withCircuitBreaker.js +53 -19
- package/dist/esm/resilience/withCircuitBreaker.js.map +1 -1
- package/dist/esm/resilience/withFallback.d.ts +11 -0
- package/dist/esm/resilience/withFallback.js +11 -0
- package/dist/esm/resilience/withFallback.js.map +1 -1
- package/dist/esm/resilience/withRetry.d.ts +12 -0
- package/dist/esm/resilience/withRetry.js +12 -0
- package/dist/esm/resilience/withRetry.js.map +1 -1
- package/dist/esm/security/PermissionPolicy.d.ts +22 -0
- package/dist/esm/security/PermissionPolicy.js +22 -0
- package/dist/esm/security/PermissionPolicy.js.map +1 -1
- package/dist/events/registry.js +2 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/hosting/admission.js +25 -0
- package/dist/hosting/admission.js.map +1 -1
- package/dist/hosting/envelope.js +10 -0
- package/dist/hosting/envelope.js.map +1 -1
- package/dist/hosting/index.js.map +1 -1
- package/dist/hosting/ingressRecord.js +250 -0
- package/dist/hosting/ingressRecord.js.map +1 -0
- package/dist/hosting/standingAgent.js +50 -1
- package/dist/hosting/standingAgent.js.map +1 -1
- package/dist/hosting/types.js.map +1 -1
- package/dist/lib/injection-engine/skillExamples.js +440 -0
- package/dist/lib/injection-engine/skillExamples.js.map +1 -0
- package/dist/lib/injection-engine/skillGraph.js +40 -2
- package/dist/lib/injection-engine/skillGraph.js.map +1 -1
- package/dist/lib/injection-engine/skillGraphCheckup.js +11 -2
- package/dist/lib/injection-engine/skillGraphCheckup.js.map +1 -1
- package/dist/lib/injection-engine/skillMatch.js +11 -5
- package/dist/lib/injection-engine/skillMatch.js.map +1 -1
- package/dist/lib/mcp/gatewayTransport.js +1 -0
- package/dist/lib/mcp/gatewayTransport.js.map +1 -1
- package/dist/lib/mcp/mcpClient.js +8 -1
- package/dist/lib/mcp/mcpClient.js.map +1 -1
- package/dist/observe.js +2 -1
- package/dist/observe.js.map +1 -1
- package/dist/recorders/core/ResilienceRecorder.js +9 -7
- package/dist/recorders/core/ResilienceRecorder.js.map +1 -1
- package/dist/recorders/core/resilienceHooks.js +13 -0
- package/dist/recorders/core/resilienceHooks.js.map +1 -1
- package/dist/resilience/withCircuitBreaker.js +53 -19
- package/dist/resilience/withCircuitBreaker.js.map +1 -1
- package/dist/resilience/withFallback.js +11 -0
- package/dist/resilience/withFallback.js.map +1 -1
- package/dist/resilience/withRetry.js +12 -0
- package/dist/resilience/withRetry.js.map +1 -1
- package/dist/security/PermissionPolicy.js +22 -0
- package/dist/security/PermissionPolicy.js.map +1 -1
- package/dist/types/adapters/identity/jwks.d.ts +18 -0
- package/dist/types/adapters/identity/jwks.d.ts.map +1 -1
- package/dist/types/adapters/llm/BrowserOpenAIProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/OpenAIProvider.d.ts +15 -2
- package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/azureUrl.d.ts +37 -0
- package/dist/types/adapters/llm/azureUrl.d.ts.map +1 -0
- package/dist/types/adapters/llm/createProvider.d.ts +5 -1
- package/dist/types/adapters/llm/createProvider.d.ts.map +1 -1
- package/dist/types/adapters/types.d.ts +30 -2
- package/dist/types/adapters/types.d.ts.map +1 -1
- package/dist/types/artifacts/gcsArtifacts.d.ts +20 -0
- package/dist/types/artifacts/gcsArtifacts.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +36 -0
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +3 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/hosting/admission.d.ts +25 -0
- package/dist/types/hosting/admission.d.ts.map +1 -1
- package/dist/types/hosting/envelope.d.ts +10 -0
- package/dist/types/hosting/envelope.d.ts.map +1 -1
- package/dist/types/hosting/index.d.ts +1 -0
- package/dist/types/hosting/index.d.ts.map +1 -1
- package/dist/types/hosting/ingressRecord.d.ts +178 -0
- package/dist/types/hosting/ingressRecord.d.ts.map +1 -0
- package/dist/types/hosting/standingAgent.d.ts.map +1 -1
- package/dist/types/hosting/types.d.ts +31 -0
- package/dist/types/hosting/types.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillExamples.d.ts +169 -0
- package/dist/types/lib/injection-engine/skillExamples.d.ts.map +1 -0
- package/dist/types/lib/injection-engine/skillGraph.d.ts +63 -0
- package/dist/types/lib/injection-engine/skillGraph.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillGraphCheckup.d.ts +25 -2
- package/dist/types/lib/injection-engine/skillGraphCheckup.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/skillMatch.d.ts +7 -0
- package/dist/types/lib/injection-engine/skillMatch.d.ts.map +1 -1
- package/dist/types/lib/mcp/gatewayTransport.d.ts +52 -0
- package/dist/types/lib/mcp/gatewayTransport.d.ts.map +1 -1
- package/dist/types/lib/mcp/types.d.ts +10 -0
- package/dist/types/lib/mcp/types.d.ts.map +1 -1
- package/dist/types/observe.d.ts.map +1 -1
- package/dist/types/recorders/core/ResilienceRecorder.d.ts +8 -7
- package/dist/types/recorders/core/ResilienceRecorder.d.ts.map +1 -1
- package/dist/types/recorders/core/resilienceHooks.d.ts +1 -0
- package/dist/types/recorders/core/resilienceHooks.d.ts.map +1 -1
- package/dist/types/resilience/withCircuitBreaker.d.ts +27 -7
- package/dist/types/resilience/withCircuitBreaker.d.ts.map +1 -1
- package/dist/types/resilience/withFallback.d.ts +11 -0
- package/dist/types/resilience/withFallback.d.ts.map +1 -1
- package/dist/types/resilience/withRetry.d.ts +12 -0
- package/dist/types/resilience/withRetry.d.ts.map +1 -1
- package/dist/types/security/PermissionPolicy.d.ts +22 -0
- package/dist/types/security/PermissionPolicy.d.ts.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skillExamples — the EXAMPLES side of a start rule: the phrasings a rule says
|
|
3
|
+
* it claims, and the three things a build-time check-up can then PROVE about
|
|
4
|
+
* them by RUNNING the compiled matchers instead of comparing them.
|
|
5
|
+
*
|
|
6
|
+
* ## Why this exists (two field failures, one evening)
|
|
7
|
+
*
|
|
8
|
+
* `compareMatchers` (skillMatch.ts) answers only what matcher-vs-matcher
|
|
9
|
+
* analysis can prove, and says so out loud: two DIFFERENT regex sources return
|
|
10
|
+
* `undefined` ("regex intersection is not decided here — only identity is
|
|
11
|
+
* provable"). That honesty left two real production failures unreportable:
|
|
12
|
+
*
|
|
13
|
+
* A. SHADOWING BY DIFFERENT REGEXES — an earlier rule matching one product
|
|
14
|
+
* name sat above an inventory rule whose matcher is a longer alternation.
|
|
15
|
+
* A real phrase ("what's running on <host-looking-name>") was claimed by
|
|
16
|
+
* the earlier rule, so the later rule could never win on its own
|
|
17
|
+
* phrasings. Two different regexes: the check-up was correctly silent.
|
|
18
|
+
* B. ABSENCE — a second phrase matched NO rule at all, fell through to the
|
|
19
|
+
* model tier, and the model picked the wrong skill because an array name
|
|
20
|
+
* looked like a hostname. Not shadowing: absence. No amount of
|
|
21
|
+
* matcher-vs-matcher analysis can ever catch it.
|
|
22
|
+
*
|
|
23
|
+
* A declared example turns both into arithmetic. Run the compiled predicates
|
|
24
|
+
* over one concrete phrase, in declaration order, exactly as the cold start
|
|
25
|
+
* does — and the answer is a WITNESS, not a theory: this phrase, this rule,
|
|
26
|
+
* this winner. No regex intersection is decided anywhere in this file.
|
|
27
|
+
*
|
|
28
|
+
* ## The tier difference (read this before writing `examples` anywhere)
|
|
29
|
+
*
|
|
30
|
+
* Two different lists spell the same author-facing sentence — "the phrasings
|
|
31
|
+
* this rule claims" — and they have DIFFERENT RUNTIME ROLES:
|
|
32
|
+
*
|
|
33
|
+
* • TIER 2, `match: { intent, examples }` — SCORING material. The classifier
|
|
34
|
+
* reads those examples AT RUN TIME to judge every new message
|
|
35
|
+
* (`skillIntent.ts`); they are part of how the graph routes.
|
|
36
|
+
* • TIER 1, a rule-level `examples: [...]` (this file) — TEST material. Read
|
|
37
|
+
* at BUILD time by the check-up and fed to nothing, ever. They do not
|
|
38
|
+
* widen, soften or otherwise touch matching: a rule with examples routes
|
|
39
|
+
* byte-identically to the same rule without them.
|
|
40
|
+
*
|
|
41
|
+
* One rule may not carry both lists (a teaching refusal names the difference):
|
|
42
|
+
* two example lists with two different jobs under one rule is exactly the
|
|
43
|
+
* confusion this note exists to prevent.
|
|
44
|
+
*
|
|
45
|
+
* ## The two start laws, and why one of them is only a WARNING
|
|
46
|
+
*
|
|
47
|
+
* Which rule claims a phrase is decided by one of TWO laws, and the graph does
|
|
48
|
+
* not know which one it will be mounted under:
|
|
49
|
+
*
|
|
50
|
+
* • the declaration-order COLD WALK (`makeResolveCursor`, the default mount)
|
|
51
|
+
* returns at the first entry with no condition or the first whose condition
|
|
52
|
+
* passes — so an UNCONDITIONAL entry claims every message from its position
|
|
53
|
+
* onward;
|
|
54
|
+
* • the turn-start CASCADE's tier 1 (`firstRuleMatch`, skillIntent.ts) reads
|
|
55
|
+
* the CONDITIONAL non-intent entries only — an unconditional entry is a
|
|
56
|
+
* default, not a rule, and never wins the turn there. That cascade is
|
|
57
|
+
* mounted by `.classify()` AND by `.skillGraph(g, { continuity:
|
|
58
|
+
* 'conversation' })`, and continuity is an AGENT-MOUNT option that does not
|
|
59
|
+
* exist yet when this check runs.
|
|
60
|
+
*
|
|
61
|
+
* The two laws differ in exactly one place: whether an unconditional entry
|
|
62
|
+
* claims. So when the earlier claimant is unconditional, the check-up cannot
|
|
63
|
+
* say which law will apply — it reports BOTH readings as a WARNING
|
|
64
|
+
* (`example-shadowed-by-default`) instead of asserting one as an ERROR. A
|
|
65
|
+
* check-up that disagrees with the router is worse than no check-up: the router
|
|
66
|
+
* really does start that turn on the later rule under a `continuity:
|
|
67
|
+
* 'conversation'` mount. The ERROR (`example-shadowed-by-earlier`) is kept for
|
|
68
|
+
* what both laws agree on.
|
|
69
|
+
*
|
|
70
|
+
* ## The context a rule is judged in, and what that makes provable
|
|
71
|
+
*
|
|
72
|
+
* Every predicate here runs on ONE context: {@link coldContext} — iteration 1,
|
|
73
|
+
* the phrase as `userMessage`, empty `history`, no cursor. That is a real
|
|
74
|
+
* context (the first iteration of a turn), but it is not the only one a start
|
|
75
|
+
* rule ever sees: turn 2 of a conversation also starts cold in cursor terms
|
|
76
|
+
* while carrying HISTORY. So:
|
|
77
|
+
*
|
|
78
|
+
* • a DATA matcher (`match:`) reads `userMessage` and nothing else, so a
|
|
79
|
+
* no-match here is a no-match under every context — ERROR;
|
|
80
|
+
* • an opaque `when` may legitimately be gated on conversation state
|
|
81
|
+
* (`ctx.history.length > 0`) and claim the phrase on a later turn — the
|
|
82
|
+
* check cannot run that turn, so a no-match is a WARNING, and the message
|
|
83
|
+
* names the context it judged under rather than leaving the author to guess.
|
|
84
|
+
*
|
|
85
|
+
* A THROW stays an ERROR either way: a predicate must be pure and total, and
|
|
86
|
+
* the context it threw on is one every turn 1 really hands it.
|
|
87
|
+
*
|
|
88
|
+
* ## The boundary, and why it is on the report itself
|
|
89
|
+
*
|
|
90
|
+
* These checks prove things about the phrases the author DECLARED and nothing
|
|
91
|
+
* about phrases nobody wrote. No warning is NOT proof of coverage. That
|
|
92
|
+
* sentence ships as {@link EXAMPLES_BOUNDARY} on `GraphCheckup.notes` —
|
|
93
|
+
* visible wherever the graph reports its problems — because a reader who meets
|
|
94
|
+
* it only in prose docs will meet a clean report first.
|
|
95
|
+
*
|
|
96
|
+
* Composed into `graph.checkup()` by `skillGraph.ts`, exactly like
|
|
97
|
+
* `skillContract`/`skillIntent`/`skillVocabulary`: this module owns the rule
|
|
98
|
+
* AND its boundaries, and reports in the shared `GraphProblem` voice.
|
|
99
|
+
*/
|
|
100
|
+
import type { InjectionContext } from './types.js';
|
|
101
|
+
import { type SkillMatchData } from './skillMatch.js';
|
|
102
|
+
import type { GraphProblem } from './skillGraphCheckup.js';
|
|
103
|
+
/**
|
|
104
|
+
* The statement the check-up makes about its own reach, carried on
|
|
105
|
+
* `GraphCheckup.notes` whenever any rule declared examples. Same voice as the
|
|
106
|
+
* ingress ticket's "absence of a refusal is not consent": a clean report is
|
|
107
|
+
* evidence about the phrases you wrote, and about nothing else.
|
|
108
|
+
*/
|
|
109
|
+
export declare const EXAMPLES_BOUNDARY: string;
|
|
110
|
+
/** The note added when declaration order does not decide the turn start, so
|
|
111
|
+
* only the order-independent check (self-match) could run. */
|
|
112
|
+
export declare const EXAMPLES_ORDER_NOT_CHECKED: string;
|
|
113
|
+
/**
|
|
114
|
+
* The slice of an entry declaration this module reads — structural, so
|
|
115
|
+
* `skillGraph.ts`'s module-private `EntryDecl` satisfies it unchanged (the
|
|
116
|
+
* same trick `skillIntent.ts` uses).
|
|
117
|
+
*/
|
|
118
|
+
export interface ExampleRuleDecl {
|
|
119
|
+
readonly id: string;
|
|
120
|
+
/** The compiled condition (from `match:`) or the author's `when`. Absent on
|
|
121
|
+
* an unconditional entry and on an intent rule (no sync predicate). */
|
|
122
|
+
readonly when?: (ctx: InjectionContext) => boolean;
|
|
123
|
+
/** The serializable matcher behind `when`, when declared as data — quoted
|
|
124
|
+
* back in the messages, and the one way to spot the intent arm. */
|
|
125
|
+
readonly match?: SkillMatchData;
|
|
126
|
+
/** The phrasings this rule claims (build-time TEST material). */
|
|
127
|
+
readonly examples?: readonly string[];
|
|
128
|
+
}
|
|
129
|
+
/** What {@link checkStartRuleExamples} found, plus what it wants to say about
|
|
130
|
+
* its own reach. Both empty when no rule declared examples. */
|
|
131
|
+
export interface ExamplesCheckup {
|
|
132
|
+
readonly problems: readonly GraphProblem[];
|
|
133
|
+
readonly notes: readonly string[];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Validate a rule-level `examples` list at DECLARATION time, refusing every
|
|
137
|
+
* shape whose check-up answer could only mislead — each refusal naming the fix:
|
|
138
|
+
*
|
|
139
|
+
* • not an array / an EMPTY array — nothing to prove, and a check-up that
|
|
140
|
+
* passes in silence reads as coverage;
|
|
141
|
+
* • a non-string or blank entry — there is no phrase to run a matcher on;
|
|
142
|
+
* • examples on an UNCONDITIONAL entry — it claims every message, so every
|
|
143
|
+
* example passes by construction and proves nothing;
|
|
144
|
+
* • examples beside `match: { intent, examples }` — two lists, two jobs (see
|
|
145
|
+
* the tier note in this file's header).
|
|
146
|
+
*
|
|
147
|
+
* Returns a frozen copy (or `undefined` when nothing was declared), so the
|
|
148
|
+
* stored list cannot drift from the validated one.
|
|
149
|
+
*/
|
|
150
|
+
export declare function validateStartRuleExamples(examples: unknown, where: string, rule: {
|
|
151
|
+
readonly hasCondition: boolean;
|
|
152
|
+
readonly isIntent: boolean;
|
|
153
|
+
}): readonly string[] | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Run the three example properties. Pure, and byte-identically silent when no
|
|
156
|
+
* rule declared examples (one `Array.some` and out).
|
|
157
|
+
*
|
|
158
|
+
* `orderDecides` mirrors the gate the pairwise rule checks already use
|
|
159
|
+
* (`!exclusiveEntries || hasClassifier`): declaration order decides the turn
|
|
160
|
+
* start under the default form and under a classifier's tier 1, and does NOT
|
|
161
|
+
* under a scorer or `.entryByRead()`. Where it does not hold, only the
|
|
162
|
+
* order-independent property (self-match) is claimed and a note says so.
|
|
163
|
+
*/
|
|
164
|
+
export declare function checkStartRuleExamples(input: {
|
|
165
|
+
readonly entries: readonly ExampleRuleDecl[];
|
|
166
|
+
readonly orderDecides: boolean;
|
|
167
|
+
readonly hasClassifier: boolean;
|
|
168
|
+
}): ExamplesCheckup;
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skillExamples — the EXAMPLES side of a start rule: the phrasings a rule says
|
|
3
|
+
* it claims, and the three things a build-time check-up can then PROVE about
|
|
4
|
+
* them by RUNNING the compiled matchers instead of comparing them.
|
|
5
|
+
*
|
|
6
|
+
* ## Why this exists (two field failures, one evening)
|
|
7
|
+
*
|
|
8
|
+
* `compareMatchers` (skillMatch.ts) answers only what matcher-vs-matcher
|
|
9
|
+
* analysis can prove, and says so out loud: two DIFFERENT regex sources return
|
|
10
|
+
* `undefined` ("regex intersection is not decided here — only identity is
|
|
11
|
+
* provable"). That honesty left two real production failures unreportable:
|
|
12
|
+
*
|
|
13
|
+
* A. SHADOWING BY DIFFERENT REGEXES — an earlier rule matching one product
|
|
14
|
+
* name sat above an inventory rule whose matcher is a longer alternation.
|
|
15
|
+
* A real phrase ("what's running on <host-looking-name>") was claimed by
|
|
16
|
+
* the earlier rule, so the later rule could never win on its own
|
|
17
|
+
* phrasings. Two different regexes: the check-up was correctly silent.
|
|
18
|
+
* B. ABSENCE — a second phrase matched NO rule at all, fell through to the
|
|
19
|
+
* model tier, and the model picked the wrong skill because an array name
|
|
20
|
+
* looked like a hostname. Not shadowing: absence. No amount of
|
|
21
|
+
* matcher-vs-matcher analysis can ever catch it.
|
|
22
|
+
*
|
|
23
|
+
* A declared example turns both into arithmetic. Run the compiled predicates
|
|
24
|
+
* over one concrete phrase, in declaration order, exactly as the cold start
|
|
25
|
+
* does — and the answer is a WITNESS, not a theory: this phrase, this rule,
|
|
26
|
+
* this winner. No regex intersection is decided anywhere in this file.
|
|
27
|
+
*
|
|
28
|
+
* ## The tier difference (read this before writing `examples` anywhere)
|
|
29
|
+
*
|
|
30
|
+
* Two different lists spell the same author-facing sentence — "the phrasings
|
|
31
|
+
* this rule claims" — and they have DIFFERENT RUNTIME ROLES:
|
|
32
|
+
*
|
|
33
|
+
* • TIER 2, `match: { intent, examples }` — SCORING material. The classifier
|
|
34
|
+
* reads those examples AT RUN TIME to judge every new message
|
|
35
|
+
* (`skillIntent.ts`); they are part of how the graph routes.
|
|
36
|
+
* • TIER 1, a rule-level `examples: [...]` (this file) — TEST material. Read
|
|
37
|
+
* at BUILD time by the check-up and fed to nothing, ever. They do not
|
|
38
|
+
* widen, soften or otherwise touch matching: a rule with examples routes
|
|
39
|
+
* byte-identically to the same rule without them.
|
|
40
|
+
*
|
|
41
|
+
* One rule may not carry both lists (a teaching refusal names the difference):
|
|
42
|
+
* two example lists with two different jobs under one rule is exactly the
|
|
43
|
+
* confusion this note exists to prevent.
|
|
44
|
+
*
|
|
45
|
+
* ## The two start laws, and why one of them is only a WARNING
|
|
46
|
+
*
|
|
47
|
+
* Which rule claims a phrase is decided by one of TWO laws, and the graph does
|
|
48
|
+
* not know which one it will be mounted under:
|
|
49
|
+
*
|
|
50
|
+
* • the declaration-order COLD WALK (`makeResolveCursor`, the default mount)
|
|
51
|
+
* returns at the first entry with no condition or the first whose condition
|
|
52
|
+
* passes — so an UNCONDITIONAL entry claims every message from its position
|
|
53
|
+
* onward;
|
|
54
|
+
* • the turn-start CASCADE's tier 1 (`firstRuleMatch`, skillIntent.ts) reads
|
|
55
|
+
* the CONDITIONAL non-intent entries only — an unconditional entry is a
|
|
56
|
+
* default, not a rule, and never wins the turn there. That cascade is
|
|
57
|
+
* mounted by `.classify()` AND by `.skillGraph(g, { continuity:
|
|
58
|
+
* 'conversation' })`, and continuity is an AGENT-MOUNT option that does not
|
|
59
|
+
* exist yet when this check runs.
|
|
60
|
+
*
|
|
61
|
+
* The two laws differ in exactly one place: whether an unconditional entry
|
|
62
|
+
* claims. So when the earlier claimant is unconditional, the check-up cannot
|
|
63
|
+
* say which law will apply — it reports BOTH readings as a WARNING
|
|
64
|
+
* (`example-shadowed-by-default`) instead of asserting one as an ERROR. A
|
|
65
|
+
* check-up that disagrees with the router is worse than no check-up: the router
|
|
66
|
+
* really does start that turn on the later rule under a `continuity:
|
|
67
|
+
* 'conversation'` mount. The ERROR (`example-shadowed-by-earlier`) is kept for
|
|
68
|
+
* what both laws agree on.
|
|
69
|
+
*
|
|
70
|
+
* ## The context a rule is judged in, and what that makes provable
|
|
71
|
+
*
|
|
72
|
+
* Every predicate here runs on ONE context: {@link coldContext} — iteration 1,
|
|
73
|
+
* the phrase as `userMessage`, empty `history`, no cursor. That is a real
|
|
74
|
+
* context (the first iteration of a turn), but it is not the only one a start
|
|
75
|
+
* rule ever sees: turn 2 of a conversation also starts cold in cursor terms
|
|
76
|
+
* while carrying HISTORY. So:
|
|
77
|
+
*
|
|
78
|
+
* • a DATA matcher (`match:`) reads `userMessage` and nothing else, so a
|
|
79
|
+
* no-match here is a no-match under every context — ERROR;
|
|
80
|
+
* • an opaque `when` may legitimately be gated on conversation state
|
|
81
|
+
* (`ctx.history.length > 0`) and claim the phrase on a later turn — the
|
|
82
|
+
* check cannot run that turn, so a no-match is a WARNING, and the message
|
|
83
|
+
* names the context it judged under rather than leaving the author to guess.
|
|
84
|
+
*
|
|
85
|
+
* A THROW stays an ERROR either way: a predicate must be pure and total, and
|
|
86
|
+
* the context it threw on is one every turn 1 really hands it.
|
|
87
|
+
*
|
|
88
|
+
* ## The boundary, and why it is on the report itself
|
|
89
|
+
*
|
|
90
|
+
* These checks prove things about the phrases the author DECLARED and nothing
|
|
91
|
+
* about phrases nobody wrote. No warning is NOT proof of coverage. That
|
|
92
|
+
* sentence ships as {@link EXAMPLES_BOUNDARY} on `GraphCheckup.notes` —
|
|
93
|
+
* visible wherever the graph reports its problems — because a reader who meets
|
|
94
|
+
* it only in prose docs will meet a clean report first.
|
|
95
|
+
*
|
|
96
|
+
* Composed into `graph.checkup()` by `skillGraph.ts`, exactly like
|
|
97
|
+
* `skillContract`/`skillIntent`/`skillVocabulary`: this module owns the rule
|
|
98
|
+
* AND its boundaries, and reports in the shared `GraphProblem` voice.
|
|
99
|
+
*/
|
|
100
|
+
import { plainMatchCaption } from './skillMatch.js';
|
|
101
|
+
/**
|
|
102
|
+
* The statement the check-up makes about its own reach, carried on
|
|
103
|
+
* `GraphCheckup.notes` whenever any rule declared examples. Same voice as the
|
|
104
|
+
* ingress ticket's "absence of a refusal is not consent": a clean report is
|
|
105
|
+
* evidence about the phrases you wrote, and about nothing else.
|
|
106
|
+
*/
|
|
107
|
+
export const EXAMPLES_BOUNDARY = 'These example checks prove things about the phrases you DECLARED and nothing about ' +
|
|
108
|
+
'phrases nobody wrote — no warning here is not proof of coverage.';
|
|
109
|
+
/** The note added when declaration order does not decide the turn start, so
|
|
110
|
+
* only the order-independent check (self-match) could run. */
|
|
111
|
+
export const EXAMPLES_ORDER_NOT_CHECKED = 'Shadowing and coverage were NOT checked for the declared examples: this graph picks its ' +
|
|
112
|
+
'entry with a scorer / by model read, so declaration order does not decide the turn start. ' +
|
|
113
|
+
"Each rule's own matcher was still run against its own examples.";
|
|
114
|
+
const NOTHING = Object.freeze({
|
|
115
|
+
problems: Object.freeze([]),
|
|
116
|
+
notes: Object.freeze([]),
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* Validate a rule-level `examples` list at DECLARATION time, refusing every
|
|
120
|
+
* shape whose check-up answer could only mislead — each refusal naming the fix:
|
|
121
|
+
*
|
|
122
|
+
* • not an array / an EMPTY array — nothing to prove, and a check-up that
|
|
123
|
+
* passes in silence reads as coverage;
|
|
124
|
+
* • a non-string or blank entry — there is no phrase to run a matcher on;
|
|
125
|
+
* • examples on an UNCONDITIONAL entry — it claims every message, so every
|
|
126
|
+
* example passes by construction and proves nothing;
|
|
127
|
+
* • examples beside `match: { intent, examples }` — two lists, two jobs (see
|
|
128
|
+
* the tier note in this file's header).
|
|
129
|
+
*
|
|
130
|
+
* Returns a frozen copy (or `undefined` when nothing was declared), so the
|
|
131
|
+
* stored list cannot drift from the validated one.
|
|
132
|
+
*/
|
|
133
|
+
export function validateStartRuleExamples(examples, where, rule) {
|
|
134
|
+
if (examples === undefined)
|
|
135
|
+
return undefined;
|
|
136
|
+
if (!Array.isArray(examples) || examples.length === 0) {
|
|
137
|
+
throw new Error(`skillGraph: ${where} declares an \`examples\` list this library cannot honor. ` +
|
|
138
|
+
`\`examples\` is the phrasings this rule CLAIMS — a non-empty array of non-empty ` +
|
|
139
|
+
`strings, e.g. examples: ['where is my refund']. They are read at build time by ` +
|
|
140
|
+
`\`graph.checkup()\` and fed to nothing at run time. ` +
|
|
141
|
+
`${Array.isArray(examples)
|
|
142
|
+
? 'An empty list declares nothing to prove, so the check-up would pass in silence ' +
|
|
143
|
+
'and you would read that as coverage. '
|
|
144
|
+
: ''}List at least one phrasing, or drop the field.`);
|
|
145
|
+
}
|
|
146
|
+
const bad = examples.findIndex((e) => typeof e !== 'string' || e.trim().length === 0);
|
|
147
|
+
if (bad >= 0) {
|
|
148
|
+
throw new Error(`skillGraph: ${where} declares \`examples[${bad}]\` = ${JSON.stringify(examples[bad])}, which is not a usable phrasing. Every example must be a NON-EMPTY string — the ` +
|
|
149
|
+
`words a user would really type, which the check-up runs this rule's matcher ` +
|
|
150
|
+
`against. Fix that entry, or drop it.`);
|
|
151
|
+
}
|
|
152
|
+
if (rule.isIntent) {
|
|
153
|
+
throw new Error(`skillGraph: ${where} declares \`match: { intent, examples }\` AND a rule-level ` +
|
|
154
|
+
`\`examples\` list. One rule cannot carry two example lists with two different ` +
|
|
155
|
+
`jobs: the examples INSIDE \`match: { intent, examples }\` are SCORING material — ` +
|
|
156
|
+
`the classifier reads them at RUN time to judge new messages — while a rule-level ` +
|
|
157
|
+
`\`examples\` list is TEST material, read only at build time by the check-up and ` +
|
|
158
|
+
`fed to nothing. Keep the phrasings inside \`match: { intent, examples }\` (they ` +
|
|
159
|
+
`are already audited by \`graph.checkupIntents()\`), and drop the rule-level list.`);
|
|
160
|
+
}
|
|
161
|
+
if (!rule.hasCondition) {
|
|
162
|
+
throw new Error(`skillGraph: ${where} declares \`examples\` but neither \`match\` nor \`when\`. An ` +
|
|
163
|
+
`unconditional entry claims EVERY message (the cold start returns at the first ` +
|
|
164
|
+
`entry with no condition), so every example on it passes by construction and ` +
|
|
165
|
+
`proves nothing. Give this entry a \`match\` (a RegExp, { keywords: [...] } or ` +
|
|
166
|
+
`{ all: [...] }) or a \`when\`, or move the examples to the rule that really ` +
|
|
167
|
+
`claims those phrasings.`);
|
|
168
|
+
}
|
|
169
|
+
return Object.freeze([...examples]);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Run the three example properties. Pure, and byte-identically silent when no
|
|
173
|
+
* rule declared examples (one `Array.some` and out).
|
|
174
|
+
*
|
|
175
|
+
* `orderDecides` mirrors the gate the pairwise rule checks already use
|
|
176
|
+
* (`!exclusiveEntries || hasClassifier`): declaration order decides the turn
|
|
177
|
+
* start under the default form and under a classifier's tier 1, and does NOT
|
|
178
|
+
* under a scorer or `.entryByRead()`. Where it does not hold, only the
|
|
179
|
+
* order-independent property (self-match) is claimed and a note says so.
|
|
180
|
+
*/
|
|
181
|
+
export function checkStartRuleExamples(input) {
|
|
182
|
+
const { entries, orderDecides, hasClassifier } = input;
|
|
183
|
+
if (!entries.some((e) => e.examples !== undefined && e.examples.length > 0))
|
|
184
|
+
return NOTHING;
|
|
185
|
+
// WHO CAN CLAIM A PHRASE — both routing laws, mirrored, not re-invented (see
|
|
186
|
+
// this file's header). Intent entries never claim synchronously in either
|
|
187
|
+
// (no predicate at all), so neither set carries them.
|
|
188
|
+
//
|
|
189
|
+
// • COLD WALK (`makeResolveCursor`, the default mount): every non-intent
|
|
190
|
+
// entry, unconditional ones included — they claim everything from their
|
|
191
|
+
// position onward.
|
|
192
|
+
// • CASCADE tier 1 (`firstRuleMatch`, mounted by `.classify()` OR by
|
|
193
|
+
// `continuity: 'conversation'`): the CONDITIONAL non-intent entries only.
|
|
194
|
+
//
|
|
195
|
+
// With a classifier the cascade is certain, so it is the only law consulted.
|
|
196
|
+
// Without one, EITHER may be mounted — both are computed, and where they
|
|
197
|
+
// disagree the report says so instead of picking one.
|
|
198
|
+
const nonIntent = entries
|
|
199
|
+
.map((entry, index) => ({ entry, index }))
|
|
200
|
+
.filter(({ entry }) => entry.match?.kind !== 'intent');
|
|
201
|
+
const ruleClaimants = nonIntent.filter(({ entry }) => entry.when !== undefined);
|
|
202
|
+
const claimUnderCascade = (phrase) => ruleClaimants.find(({ entry }) => runsOn(entry, phrase) === 'match');
|
|
203
|
+
const claimUnderColdWalk = (phrase) => nonIntent.find(({ entry }) => runsOn(entry, phrase) === 'match');
|
|
204
|
+
const problems = [];
|
|
205
|
+
for (const [index, entry] of entries.entries()) {
|
|
206
|
+
const examples = entry.examples;
|
|
207
|
+
if (examples === undefined || examples.length === 0)
|
|
208
|
+
continue;
|
|
209
|
+
for (const phrase of examples) {
|
|
210
|
+
// (a) SELF-MATCH — the cheapest of the three, and order-independent: a
|
|
211
|
+
// rule that does not claim its own example is a defect at build time.
|
|
212
|
+
// Severity follows PROVABILITY (see the header): a data matcher reads
|
|
213
|
+
// the user message and nothing else, so its no-match holds under every
|
|
214
|
+
// context — ERROR. An opaque `when` may be gated on conversation state
|
|
215
|
+
// and claim the phrase on a later turn, which this check cannot run —
|
|
216
|
+
// WARNING, with the judged context named. A throw is an ERROR either
|
|
217
|
+
// way: turn 1 really hands it that context.
|
|
218
|
+
const own = runsOn(entry, phrase);
|
|
219
|
+
if (own !== 'match') {
|
|
220
|
+
const provable = own === 'threw' || entry.match !== undefined;
|
|
221
|
+
problems.push({
|
|
222
|
+
kind: provable ? 'error' : 'warning',
|
|
223
|
+
code: 'example-misses-own-rule',
|
|
224
|
+
message: selfMissMessage(entry, phrase, own),
|
|
225
|
+
skill: entry.id,
|
|
226
|
+
example: phrase,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
if (!orderDecides)
|
|
230
|
+
continue;
|
|
231
|
+
// The mounted-by-default reading. With a classifier the cascade is
|
|
232
|
+
// certain, so it IS the walk; the second law is consulted only where the
|
|
233
|
+
// two can differ (an unconditional claimant, below) — a predicate is run
|
|
234
|
+
// no more often than the answer needs.
|
|
235
|
+
const winner = hasClassifier ? claimUnderCascade(phrase) : claimUnderColdWalk(phrase);
|
|
236
|
+
// (c) UNCLAIMED — the strong case: no rule claims the phrase at all, so
|
|
237
|
+
// the deterministic layer declines and the turn falls onward. WARNING,
|
|
238
|
+
// not an error: the run is not broken — the next tier (a classifier, or
|
|
239
|
+
// the model) may well answer correctly, and the library cannot prove
|
|
240
|
+
// otherwise. What it CAN prove is that nothing declared claims it.
|
|
241
|
+
if (winner === undefined) {
|
|
242
|
+
problems.push({
|
|
243
|
+
kind: 'warning',
|
|
244
|
+
code: 'example-unclaimed',
|
|
245
|
+
message: `No start rule claims the example "${phrase}" (declared on "${entry.id}") — every ` +
|
|
246
|
+
`rule's condition was run against it in declaration order on ${COLD_CONTEXT_PHRASE} ` +
|
|
247
|
+
`and none matched, so a turn phrased that way ${hasClassifier
|
|
248
|
+
? 'falls past tier 1 to the classifier, and on a near-tie to a menu the model ' +
|
|
249
|
+
'resolves'
|
|
250
|
+
: 'starts on no entry and falls through to the model tier, which picks a skill ' +
|
|
251
|
+
'by name'}. Widen "${entry.id}"'s ${entry.match === undefined ? 'predicate' : 'matcher'} to cover the phrase, or add a rule that claims ` +
|
|
252
|
+
`it. (This proves coverage for the phrases you declared and for no others — a ` +
|
|
253
|
+
`phrasing nobody wrote is not checked.)`,
|
|
254
|
+
skill: entry.id,
|
|
255
|
+
example: phrase,
|
|
256
|
+
});
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
// A winner LATER than the owner means the owner rejected its own example —
|
|
260
|
+
// already reported as `example-misses-own-rule` above, which names the
|
|
261
|
+
// defect. Nothing further is provable that the first problem did not say.
|
|
262
|
+
if (winner.index >= index)
|
|
263
|
+
continue;
|
|
264
|
+
// (b) SHADOWED-BY-EARLIER — proof by witness, where matcher-vs-matcher
|
|
265
|
+
// analysis has to stay silent (two different regexes). ERROR: two of
|
|
266
|
+
// the author's own declarations contradict each other about ONE
|
|
267
|
+
// phrase they both wrote, and the turn start is decided — wrongly,
|
|
268
|
+
// by the author's own account. (`rules-shadowed-by-order` stays a
|
|
269
|
+
// warning because it reasons about ALL possible messages, where a
|
|
270
|
+
// deliberately dead fallback is a legitimate design; here the author
|
|
271
|
+
// personally wrote the phrase this rule claims.)
|
|
272
|
+
//
|
|
273
|
+
// The ERROR is claimed only where BOTH start laws agree. A CONDITIONAL
|
|
274
|
+
// claimant is one both laws read, and it is the first match under the
|
|
275
|
+
// cold walk, so no unconditional entry preceded it and the cascade
|
|
276
|
+
// reads the identical prefix — the two laws cannot disagree here.
|
|
277
|
+
if (winner.entry.when !== undefined) {
|
|
278
|
+
problems.push({
|
|
279
|
+
kind: 'error',
|
|
280
|
+
code: 'example-shadowed-by-earlier',
|
|
281
|
+
message: `Start rule for "${entry.id}" declares the example "${phrase}", but the EARLIER ` +
|
|
282
|
+
`rule for "${winner.entry.id}" claims it first (${describeCondition(winner.entry)} matches the phrase) — the first matching rule in declaration order wins the ` +
|
|
283
|
+
`turn start, so that message starts on "${winner.entry.id}", never on ` +
|
|
284
|
+
`"${entry.id}". Reorder the rules (declare "${entry.id}" before ` +
|
|
285
|
+
`"${winner.entry.id}"), or narrow "${winner.entry.id}"'s matcher so it stops ` +
|
|
286
|
+
`claiming this phrasing. (Proved by running BOTH compiled matchers on the ` +
|
|
287
|
+
`phrase — no regex intersection was decided.)`,
|
|
288
|
+
skill: entry.id,
|
|
289
|
+
from: winner.entry.id,
|
|
290
|
+
to: entry.id,
|
|
291
|
+
example: phrase,
|
|
292
|
+
});
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
// The claimant is UNCONDITIONAL — the ONE place the two start laws differ
|
|
296
|
+
// (only the cold walk lets a default claim). `hasClassifier` cannot be
|
|
297
|
+
// true here: the cascade set carries conditional entries only. So the
|
|
298
|
+
// OTHER law is consulted now, and both readings are reported.
|
|
299
|
+
const byRules = claimUnderCascade(phrase);
|
|
300
|
+
if (byRules !== undefined && byRules.index < index) {
|
|
301
|
+
// Both laws still agree on the OUTCOME the author cares about — the
|
|
302
|
+
// turn does not start on this rule — so the ERROR stands, and the
|
|
303
|
+
// message names each law's claimant rather than one of them. `from`
|
|
304
|
+
// carries the default mount's claimant (the reading a graph gets when
|
|
305
|
+
// nothing else is configured); the message names the other in full.
|
|
306
|
+
problems.push({
|
|
307
|
+
kind: 'error',
|
|
308
|
+
code: 'example-shadowed-by-earlier',
|
|
309
|
+
message: `Start rule for "${entry.id}" declares the example "${phrase}", but an earlier ` +
|
|
310
|
+
`entry claims it under BOTH start laws, so that message never starts on ` +
|
|
311
|
+
`"${entry.id}". Mounted the default way (continuity: 'turn'), the ` +
|
|
312
|
+
`declaration-order cold start stops at "${winner.entry.id}", which ` +
|
|
313
|
+
`${describeCondition(winner.entry)}. Mounted with a classifier or with ` +
|
|
314
|
+
`continuity: 'conversation', the turn-start cascade reads the conditional rules ` +
|
|
315
|
+
`only, and "${byRules.entry.id}" claims it first ` +
|
|
316
|
+
`(${describeCondition(byRules.entry)} matches the phrase). Declare "${entry.id}" ` +
|
|
317
|
+
`before both, or narrow "${byRules.entry.id}"'s matcher and give ` +
|
|
318
|
+
`"${winner.entry.id}" a condition (or declare it last — a default entry belongs ` +
|
|
319
|
+
`after the rules it must not swallow). (Proved by running the declared conditions ` +
|
|
320
|
+
`on the phrase in declaration order, under both laws — no regex intersection was ` +
|
|
321
|
+
`decided.)`,
|
|
322
|
+
skill: entry.id,
|
|
323
|
+
from: winner.entry.id,
|
|
324
|
+
to: entry.id,
|
|
325
|
+
example: phrase,
|
|
326
|
+
});
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
// (b′) SHADOWED-BY-DEFAULT — the laws DISAGREE, and which one applies is
|
|
330
|
+
// decided at AGENT MOUNT (`continuity`), not in this graph. WARNING,
|
|
331
|
+
// naming both readings: asserting either as an error would put the
|
|
332
|
+
// check-up in disagreement with the router it claims to describe —
|
|
333
|
+
// the cascade really does start that turn on this rule.
|
|
334
|
+
problems.push({
|
|
335
|
+
kind: 'warning',
|
|
336
|
+
code: 'example-shadowed-by-default',
|
|
337
|
+
message: `Start rule for "${entry.id}" declares the example "${phrase}", and which entry ` +
|
|
338
|
+
`claims it depends on how this graph is MOUNTED — the graph alone cannot decide it, ` +
|
|
339
|
+
`so this is a warning, not an error. The earlier entry "${winner.entry.id}" declares ` +
|
|
340
|
+
`no \`match\` and no \`when\`, so under the declaration-order cold start (the ` +
|
|
341
|
+
`default mount, continuity: 'turn') it claims every message from its position ` +
|
|
342
|
+
`onward and that turn starts on "${winner.entry.id}". Mounted with a classifier or ` +
|
|
343
|
+
`with continuity: 'conversation', the turn-start cascade's tier 1 reads the ` +
|
|
344
|
+
`CONDITIONAL rules only — an unconditional entry is a default, not a rule — so ` +
|
|
345
|
+
`"${winner.entry.id}" is skipped and the turn starts on ${byRules === undefined
|
|
346
|
+
? 'no entry at all, falling onward to the next tier'
|
|
347
|
+
: `"${byRules.entry.id}"`}. Make the two readings agree: declare "${entry.id}" before ` +
|
|
348
|
+
`"${winner.entry.id}", give "${winner.entry.id}" a \`match\`/\`when\`, or declare ` +
|
|
349
|
+
`it last (a default entry belongs after the rules) — an always-on procedure beside ` +
|
|
350
|
+
`the graph is what .steering(...) / .skill(...) are for. (Proved by running the ` +
|
|
351
|
+
`declared conditions on the phrase in declaration order under both laws; ` +
|
|
352
|
+
`"${winner.entry.id}" declares none, so the cold walk stops there by construction.)`,
|
|
353
|
+
skill: entry.id,
|
|
354
|
+
from: winner.entry.id,
|
|
355
|
+
to: entry.id,
|
|
356
|
+
example: phrase,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
problems,
|
|
362
|
+
notes: orderDecides ? [EXAMPLES_BOUNDARY] : [EXAMPLES_ORDER_NOT_CHECKED, EXAMPLES_BOUNDARY],
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Run one entry's condition over one phrase, on a COLD-START context — the
|
|
367
|
+
* context a turn's first iteration really hands a start rule: iteration 1, the
|
|
368
|
+
* phrase as `userMessage`, no history, no cursor, no tool results. A throw is
|
|
369
|
+
* reported as `'threw'` and treated as a no-match by every caller, which is
|
|
370
|
+
* exactly what the cursor resolver does with it at run time (so a claim made
|
|
371
|
+
* here stays true of the run).
|
|
372
|
+
*
|
|
373
|
+
* An entry with NO condition matches everything: that is the cold walk's law
|
|
374
|
+
* (`if (!e.when) return { to: e.id }`), not a shortcut.
|
|
375
|
+
*/
|
|
376
|
+
function runsOn(entry, phrase) {
|
|
377
|
+
if (entry.when === undefined)
|
|
378
|
+
return 'match';
|
|
379
|
+
try {
|
|
380
|
+
return entry.when(coldContext(phrase)) ? 'match' : 'no-match';
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
return 'threw';
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function coldContext(userMessage) {
|
|
387
|
+
return { iteration: 1, userMessage, history: [], activatedInjectionIds: [] };
|
|
388
|
+
}
|
|
389
|
+
/** The one context every predicate here is judged on, spelled out for the
|
|
390
|
+
* reader of a message — a check that names its own inputs can be argued with;
|
|
391
|
+
* one that hides them can only be guessed at. Kept as ONE string so every
|
|
392
|
+
* message describes the SAME context {@link coldContext} really builds. */
|
|
393
|
+
const COLD_CONTEXT_PHRASE = 'a COLD-START context (iteration 1, the phrase as `userMessage`, empty `history`, no ' +
|
|
394
|
+
'cursor and no activated injections)';
|
|
395
|
+
/** The `example-misses-own-rule` sentence. Two readings, and the message says
|
|
396
|
+
* which one it is: a data matcher's no-match holds under every context, an
|
|
397
|
+
* opaque `when`'s holds only under the context it was run on. */
|
|
398
|
+
function selfMissMessage(entry, phrase, own) {
|
|
399
|
+
const head = `Start rule for "${entry.id}" declares the example "${phrase}", but `;
|
|
400
|
+
if (own === 'threw') {
|
|
401
|
+
return (`${head}${describeCondition(entry)} THREW when run on ${COLD_CONTEXT_PHRASE} — a ` +
|
|
402
|
+
`predicate must be pure and total, and a turn's first iteration really hands it that ` +
|
|
403
|
+
`context, so it throws in production too. Routing treats a throw as no-match (this ` +
|
|
404
|
+
`check does the same), so the rule cannot claim the phrasing it says it claims. Make ` +
|
|
405
|
+
`the predicate total (guard the fields it reads), or move the example to the rule that ` +
|
|
406
|
+
`really claims the phrase. (Proved by running this rule's own predicate on that context.)`);
|
|
407
|
+
}
|
|
408
|
+
if (entry.match !== undefined) {
|
|
409
|
+
return (`${head}${describeCondition(entry)} does not match it — so the rule cannot claim the ` +
|
|
410
|
+
`phrasing it says it claims. Fix the matcher so it covers the phrase, or move the ` +
|
|
411
|
+
`example to the rule that really claims it. (Proved by running this rule's own compiled ` +
|
|
412
|
+
`matcher on the phrase: a data matcher reads the user message and nothing else, so no ` +
|
|
413
|
+
`conversation state makes it true later.)`);
|
|
414
|
+
}
|
|
415
|
+
return (`${head}${describeCondition(entry)} returned false when run on ${COLD_CONTEXT_PHRASE} — the ` +
|
|
416
|
+
`context a turn's FIRST iteration hands a start rule. A \`when\` predicate is opaque code ` +
|
|
417
|
+
`and may legitimately be gated on conversation state (e.g. \`ctx.history.length > 0\`) and ` +
|
|
418
|
+
`claim this phrase on a LATER turn, which this check cannot run — that is why this is a ` +
|
|
419
|
+
`warning and not the error a data matcher gets. If the rule is meant to claim the phrase ` +
|
|
420
|
+
`at the START of a turn, fix the predicate; if it is gated on conversation state, move the ` +
|
|
421
|
+
`example to the rule that claims the phrase cold — a rule-level \`examples\` list is only ` +
|
|
422
|
+
`ever run on the context named above. (Proved by running this rule's own predicate on it.)`);
|
|
423
|
+
}
|
|
424
|
+
/** How a rule's condition is named in a message: the data matcher quoted back,
|
|
425
|
+
* the honest word for opaque code — or, for an entry that declares neither,
|
|
426
|
+
* what having no condition MEANS. Naming a `when` predicate an unconditional
|
|
427
|
+
* entry does not have is how a report describes a graph nobody wrote. */
|
|
428
|
+
function describeCondition(entry) {
|
|
429
|
+
if (entry.match !== undefined)
|
|
430
|
+
return `its matcher \`${plainMatchCaption(entry.match)}\``;
|
|
431
|
+
return entry.when === undefined
|
|
432
|
+
? 'declares no `match` and no `when`, so it claims every message'
|
|
433
|
+
: 'its `when` predicate';
|
|
434
|
+
}
|
|
435
|
+
//# sourceMappingURL=skillExamples.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillExamples.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/skillExamples.ts"],"names":[],"mappings":"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"}
|