@memberjunction/ai-agents 6.2.0-edge.1 → 6.2.0-edge.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/README.md +18 -0
- package/dist/AgentDecisionService.d.ts +90 -0
- package/dist/AgentDecisionService.d.ts.map +1 -0
- package/dist/AgentDecisionService.js +159 -0
- package/dist/AgentDecisionService.js.map +1 -0
- package/dist/AgentRunner.d.ts +9 -0
- package/dist/AgentRunner.d.ts.map +1 -1
- package/dist/AgentRunner.js +23 -7
- package/dist/AgentRunner.js.map +1 -1
- package/dist/ConversationCompactionManager.d.ts +7 -1
- package/dist/ConversationCompactionManager.d.ts.map +1 -1
- package/dist/ConversationCompactionManager.js +4 -1
- package/dist/ConversationCompactionManager.js.map +1 -1
- package/dist/KnowledgeAgent.d.ts.map +1 -1
- package/dist/KnowledgeAgent.js +6 -6
- package/dist/KnowledgeAgent.js.map +1 -1
- package/dist/PayloadFeedbackManager.d.ts +116 -14
- package/dist/PayloadFeedbackManager.d.ts.map +1 -1
- package/dist/PayloadFeedbackManager.js +229 -88
- package/dist/PayloadFeedbackManager.js.map +1 -1
- package/dist/agent-context-injector.d.ts +47 -3
- package/dist/agent-context-injector.d.ts.map +1 -1
- package/dist/agent-context-injector.js +77 -10
- package/dist/agent-context-injector.js.map +1 -1
- package/dist/agent-memory-context-builder.d.ts +13 -0
- package/dist/agent-memory-context-builder.d.ts.map +1 -1
- package/dist/agent-memory-context-builder.js +24 -5
- package/dist/agent-memory-context-builder.js.map +1 -1
- package/dist/agent-types/flow-agent-type.d.ts +97 -0
- package/dist/agent-types/flow-agent-type.d.ts.map +1 -1
- package/dist/agent-types/flow-agent-type.js +281 -24
- package/dist/agent-types/flow-agent-type.js.map +1 -1
- package/dist/agent-types/flow-graph-executor.d.ts +12 -1
- package/dist/agent-types/flow-graph-executor.d.ts.map +1 -1
- package/dist/agent-types/flow-graph-executor.js +25 -1
- package/dist/agent-types/flow-graph-executor.js.map +1 -1
- package/dist/agent-types/loop-agent-prompt-params.d.ts +239 -66
- package/dist/agent-types/loop-agent-prompt-params.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-prompt-params.js +47 -2
- package/dist/agent-types/loop-agent-prompt-params.js.map +1 -1
- package/dist/agent-types/loop-agent-response-type.d.ts +12 -1
- package/dist/agent-types/loop-agent-response-type.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-response-type.js.map +1 -1
- package/dist/agent-types/loop-agent-type.d.ts +26 -0
- package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
- package/dist/agent-types/loop-agent-type.js +115 -5
- package/dist/agent-types/loop-agent-type.js.map +1 -1
- package/dist/base-agent.d.ts +527 -10
- package/dist/base-agent.d.ts.map +1 -1
- package/dist/base-agent.js +1779 -110
- package/dist/base-agent.js.map +1 -1
- package/dist/catalog-narrowing.d.ts +136 -0
- package/dist/catalog-narrowing.d.ts.map +1 -0
- package/dist/catalog-narrowing.js +212 -0
- package/dist/catalog-narrowing.js.map +1 -0
- package/dist/decision-discovery.d.ts +401 -0
- package/dist/decision-discovery.d.ts.map +1 -0
- package/dist/decision-discovery.js +511 -0
- package/dist/decision-discovery.js.map +1 -0
- package/dist/finish-if-mode-warnings.d.ts +39 -0
- package/dist/finish-if-mode-warnings.d.ts.map +1 -0
- package/dist/finish-if-mode-warnings.js +78 -0
- package/dist/finish-if-mode-warnings.js.map +1 -0
- package/dist/finish-if-state.d.ts +72 -0
- package/dist/finish-if-state.d.ts.map +1 -0
- package/dist/finish-if-state.js +109 -0
- package/dist/finish-if-state.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/memory-manager-agent.d.ts +108 -2
- package/dist/memory-manager-agent.d.ts.map +1 -1
- package/dist/memory-manager-agent.js +172 -9
- package/dist/memory-manager-agent.js.map +1 -1
- package/dist/memory-note-gate.d.ts +208 -0
- package/dist/memory-note-gate.d.ts.map +1 -0
- package/dist/memory-note-gate.js +294 -0
- package/dist/memory-note-gate.js.map +1 -0
- package/dist/native-tools/action-tool-builder.d.ts +14 -0
- package/dist/native-tools/action-tool-builder.d.ts.map +1 -1
- package/dist/native-tools/action-tool-builder.js +62 -7
- package/dist/native-tools/action-tool-builder.js.map +1 -1
- package/dist/native-tools/control-tools.d.ts +17 -1
- package/dist/native-tools/control-tools.d.ts.map +1 -1
- package/dist/native-tools/control-tools.js +40 -3
- package/dist/native-tools/control-tools.js.map +1 -1
- package/dist/realtime/bridge-host-params.d.ts +22 -0
- package/dist/realtime/bridge-host-params.d.ts.map +1 -0
- package/dist/realtime/bridge-host-params.js +53 -0
- package/dist/realtime/bridge-host-params.js.map +1 -0
- package/dist/realtime/bridge-realtime-session-factory.d.ts +23 -2
- package/dist/realtime/bridge-realtime-session-factory.d.ts.map +1 -1
- package/dist/realtime/bridge-realtime-session-factory.js +22 -6
- package/dist/realtime/bridge-realtime-session-factory.js.map +1 -1
- package/dist/realtime/bridge-room-transcript-sink.d.ts.map +1 -1
- package/dist/realtime/bridge-room-transcript-sink.js +15 -9
- package/dist/realtime/bridge-room-transcript-sink.js.map +1 -1
- package/dist/realtime/bridge-session-transcript-sink.d.ts +37 -0
- package/dist/realtime/bridge-session-transcript-sink.d.ts.map +1 -0
- package/dist/realtime/bridge-session-transcript-sink.js +58 -0
- package/dist/realtime/bridge-session-transcript-sink.js.map +1 -0
- package/dist/realtime/realtime-client-session-service.d.ts +117 -12
- package/dist/realtime/realtime-client-session-service.d.ts.map +1 -1
- package/dist/realtime/realtime-client-session-service.js +162 -39
- package/dist/realtime/realtime-client-session-service.js.map +1 -1
- package/dist/realtime/realtime-coagent-resolution.d.ts +90 -0
- package/dist/realtime/realtime-coagent-resolution.d.ts.map +1 -0
- package/dist/realtime/realtime-coagent-resolution.js +186 -0
- package/dist/realtime/realtime-coagent-resolution.js.map +1 -0
- package/dist/realtime/realtime-delegation-narrator.d.ts +97 -0
- package/dist/realtime/realtime-delegation-narrator.d.ts.map +1 -0
- package/dist/realtime/realtime-delegation-narrator.js +162 -0
- package/dist/realtime/realtime-delegation-narrator.js.map +1 -0
- package/dist/realtime/realtime-session-runner.d.ts +2 -82
- package/dist/realtime/realtime-session-runner.d.ts.map +1 -1
- package/dist/realtime/realtime-session-runner.js +12 -187
- package/dist/realtime/realtime-session-runner.js.map +1 -1
- package/dist/realtime/realtime-vendor-resolution.d.ts +8 -3
- package/dist/realtime/realtime-vendor-resolution.d.ts.map +1 -1
- package/dist/realtime/realtime-vendor-resolution.js +3 -3
- package/dist/realtime/realtime-vendor-resolution.js.map +1 -1
- package/dist/rubric-evaluation-agent-runner.d.ts +2 -0
- package/dist/rubric-evaluation-agent-runner.d.ts.map +1 -0
- package/dist/rubric-evaluation-agent-runner.js +47 -0
- package/dist/rubric-evaluation-agent-runner.js.map +1 -0
- package/dist/self-check.d.ts +101 -0
- package/dist/self-check.d.ts.map +1 -0
- package/dist/self-check.js +74 -0
- package/dist/self-check.js.map +1 -0
- package/package.json +19 -18
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Decision discovery (typed-decision plan, Task 3.1): the pure half.
|
|
3
|
+
*
|
|
4
|
+
* When the user names no agent, a conversation manager such as Sage takes two turns to delegate: it
|
|
5
|
+
* calls Find Candidate Agents, then reads the rows and picks one. With the Loop prompt param
|
|
6
|
+
* `decisionDiscovery` on, `BaseAgent` instead asks one decision before the first prompt of a
|
|
7
|
+
* conversation's opening turn: a Choice over the agents the user may run, and a Likelihood that a
|
|
8
|
+
* specialist agent should handle the request. When both answers are confident, a `<suggested_agent>`
|
|
9
|
+
* system message reaches the first prompt, so the agent can delegate in its first turn. These helpers
|
|
10
|
+
* build the options and questions, judge the answers and format the message. The call, the
|
|
11
|
+
* `Agent discovery` step and the injection live on `BaseAgent`.
|
|
12
|
+
*
|
|
13
|
+
* It fails safe: after an error, a timeout, an unusable answer or an unsure one, nothing is injected
|
|
14
|
+
* and the agent behaves as it did before. A follow-up turn is never asked about (see
|
|
15
|
+
* {@link IsOpeningTurn}), so discovery never pulls the agent away from one it has already engaged.
|
|
16
|
+
*
|
|
17
|
+
* Known limitation, kept on purpose: the Likelihood does not name the options, so "none of these
|
|
18
|
+
* agents fits" cannot be expressed (see {@link DECISION_DISCOVERY_APPLIES_INSTRUCTIONS}).
|
|
19
|
+
*
|
|
20
|
+
* @module @memberjunction/ai-agents
|
|
21
|
+
*/
|
|
22
|
+
import { ApplyPlattCalibration } from '@memberjunction/ai';
|
|
23
|
+
import { ConversationUtility, DescribeAnsweringModel, FindDecisionCalibration } from '@memberjunction/ai-core-plus';
|
|
24
|
+
import { AIAgentPermissionHelper } from '@memberjunction/ai-engine-base';
|
|
25
|
+
import { IsPlainObject, NormalizeUUID, UUIDsEqual } from '@memberjunction/global';
|
|
26
|
+
/**
|
|
27
|
+
* The most options the Choice ever offers. It always applies: the limit is this, or the decision
|
|
28
|
+
* model's declared `MaxChoiceOptions` when that is smaller. A larger catalog is first narrowed to
|
|
29
|
+
* the limit by the semantic search Find Candidate Agents uses.
|
|
30
|
+
*/
|
|
31
|
+
export const DECISION_DISCOVERY_MAX_OPTIONS = 25;
|
|
32
|
+
/**
|
|
33
|
+
* The least **calibrated** confidence at which the suggestion is shown (see
|
|
34
|
+
* {@link DECISION_DISCOVERY_CALIBRATION}). Both the Choice's confidence and the Likelihood that any
|
|
35
|
+
* agent applies must reach it.
|
|
36
|
+
*
|
|
37
|
+
* Set from the agent-discovery Decision Eval (plan Task 3.1, 2026-09-29): 258 labelled requests, 198
|
|
38
|
+
* for one of 33 agents and 60 for none, three repeats per model, calibrated out of fold, and scored
|
|
39
|
+
* as production would, so an answer after {@link DECISION_DISCOVERY_TIMEOUT_MS} injects nothing. At a
|
|
40
|
+
* calibrated 0.85, Jev's suggestion covered 21.7% of the requests meant for an agent, and named the
|
|
41
|
+
* right agent for 95.3% of those it covered. It was shown for 5.0% of the requests meant for no agent,
|
|
42
|
+
* all of them multi-agent workflows. Every Jev discovery but the run's first, which loaded the
|
|
43
|
+
* embedding model, finished within the timeout. LLM Decision finished within it for at least 67.7% of
|
|
44
|
+
* requests, and covered at least 16.0% at 92.6% precision, shown for 5.0%. A wrong suggestion costs
|
|
45
|
+
* more than a missed one, which is only the two-turn flow the agent used before, so the threshold
|
|
46
|
+
* favours precision. On raw probabilities the old 0.7 almost never fired: Jev's raw any-applies
|
|
47
|
+
* Likelihood never passed 0.8, so it covered 6.9%.
|
|
48
|
+
*/
|
|
49
|
+
export const DECISION_DISCOVERY_MIN_CONFIDENCE = 0.85;
|
|
50
|
+
/**
|
|
51
|
+
* Platt calibration of the discovery answers, each tied to the exact model it was fitted on (see
|
|
52
|
+
* `FindDecisionCalibration` in `@memberjunction/ai-core-plus`): the MJ decision model that answered
|
|
53
|
+
* (`ModelName`, from `modelInfo.modelName`) and the model its driver reports behind it
|
|
54
|
+
* (`ResolvedModel`, from `DecisionResult.ResolvedModel`). A model's raw answers are not calibrated:
|
|
55
|
+
* Jev's raw any-applies Likelihood sits between 0.1 and 0.8 whatever the request. Any other model,
|
|
56
|
+
* including Jev at another version or `LLM Decision` answered by another chat model, is treated as
|
|
57
|
+
* unsure, so its answer suggests nothing.
|
|
58
|
+
*
|
|
59
|
+
* Fitted on the agent-discovery Decision Eval (2026-09-29; 258 requests, 3 repeats per model, 774
|
|
60
|
+
* answers each): the Choice's confidence against whether it named the labelled agent (594 answers
|
|
61
|
+
* to requests meant for an agent), and the Likelihood against whether the request was meant for an
|
|
62
|
+
* agent (all 774). Every fit converged (5 to 7 Newton iterations; a 60-digit refit agrees to 4
|
|
63
|
+
* places).
|
|
64
|
+
* - **Jev** at its pinned `APIName`, `typesafe/jev-1.13-20260917`, which it reports back as the
|
|
65
|
+
* resolved model.
|
|
66
|
+
* - **LLM Decision** when its chat model is GPT-OSS-120B, which answered all 774 of its runs.
|
|
67
|
+
*
|
|
68
|
+
* Refit, and add the new pair, whenever a model, its version, the questions or the catalog's shape
|
|
69
|
+
* changes.
|
|
70
|
+
*/
|
|
71
|
+
export const DECISION_DISCOVERY_CALIBRATION = Object.freeze([
|
|
72
|
+
Object.freeze({
|
|
73
|
+
ModelName: 'Jev',
|
|
74
|
+
ResolvedModel: 'typesafe/jev-1.13-20260917',
|
|
75
|
+
Calibration: Object.freeze({ Confidence: Object.freeze({ A: 0.4412, B: 0.4571 }), AnyApplies: Object.freeze({ A: 1.2469, B: 1.7700 }) })
|
|
76
|
+
}),
|
|
77
|
+
Object.freeze({
|
|
78
|
+
ModelName: 'LLM Decision',
|
|
79
|
+
ResolvedModel: 'GPT-OSS-120B',
|
|
80
|
+
Calibration: Object.freeze({ Confidence: Object.freeze({ A: 1.4301, B: -0.0755 }), AnyApplies: Object.freeze({ A: 0.7114, B: 0.9073 }) })
|
|
81
|
+
})
|
|
82
|
+
]);
|
|
83
|
+
/**
|
|
84
|
+
* The answers with the Choice's confidence and the Likelihood calibrated for the exact model that
|
|
85
|
+
* gave them ({@link DECISION_DISCOVERY_CALIBRATION}), or null when that model has no discovery
|
|
86
|
+
* calibration. Other answers, and the Choice's distribution, are returned as they are.
|
|
87
|
+
*
|
|
88
|
+
* @param answers - The raw answers, by question key.
|
|
89
|
+
* @param answeredBy - The decision model that answered, and the model behind it.
|
|
90
|
+
*/
|
|
91
|
+
export function CalibrateDiscoveryAnswers(answers, answeredBy) {
|
|
92
|
+
const calibration = FindDecisionCalibration(DECISION_DISCOVERY_CALIBRATION, answeredBy);
|
|
93
|
+
if (!calibration) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const calibrated = { ...answers };
|
|
97
|
+
const choice = answers[DECISION_DISCOVERY_AGENT_QUESTION];
|
|
98
|
+
if (choice?.Kind === 'Choice' && isFiniteNumber(choice.Confidence)) {
|
|
99
|
+
calibrated[DECISION_DISCOVERY_AGENT_QUESTION] = { ...choice, Confidence: ApplyPlattCalibration(choice.Confidence, calibration.Confidence) };
|
|
100
|
+
}
|
|
101
|
+
const applies = answers[DECISION_DISCOVERY_APPLIES_QUESTION];
|
|
102
|
+
if (applies?.Kind === 'Likelihood' && isFiniteNumber(applies.Probability)) {
|
|
103
|
+
calibrated[DECISION_DISCOVERY_APPLIES_QUESTION] = { ...applies, Probability: ApplyPlattCalibration(applies.Probability, calibration.AnyApplies) };
|
|
104
|
+
}
|
|
105
|
+
return calibrated;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The longest decision discovery may delay the run's first prompt. Past it the run moves on, the
|
|
109
|
+
* decision call is aborted, and nothing is injected.
|
|
110
|
+
*/
|
|
111
|
+
export const DECISION_DISCOVERY_TIMEOUT_MS = 1500;
|
|
112
|
+
/**
|
|
113
|
+
* The fewest options discovery asks about. Below it nothing is asked and nothing is suggested.
|
|
114
|
+
*
|
|
115
|
+
* Two options are not enough, although the Choice is well-formed: its probabilities sum to 1, so its
|
|
116
|
+
* top answer is at least 0.5 however poorly both agents fit, and the any-applies Likelihood cannot
|
|
117
|
+
* vouch for them (see {@link DECISION_DISCOVERY_APPLIES_INSTRUCTIONS}). A confidence threshold then
|
|
118
|
+
* sits only a little above chance. The discovery eval (#4892) offered every request dozens of
|
|
119
|
+
* options, so this bound leaves the measured case alone. With fewer options the agent falls back to
|
|
120
|
+
* Find Candidate Agents, as it would without discovery.
|
|
121
|
+
*/
|
|
122
|
+
export const DECISION_DISCOVERY_MIN_OPTIONS = 3;
|
|
123
|
+
/** The Choice's question key: which agent should handle the request. */
|
|
124
|
+
export const DECISION_DISCOVERY_AGENT_QUESTION = 'agent';
|
|
125
|
+
/** The Likelihood's question key: whether any of the agents should. */
|
|
126
|
+
export const DECISION_DISCOVERY_APPLIES_QUESTION = 'anyApplies';
|
|
127
|
+
/**
|
|
128
|
+
* The Likelihood's instructions. They stand on the request alone, because a driver may answer each
|
|
129
|
+
* question separately and never see the Choice's options.
|
|
130
|
+
*
|
|
131
|
+
* **Known limitation.** Because they name no agent, the Likelihood measures "is this specialist
|
|
132
|
+
* work?", not "does one of *these* agents fit?". A per-question driver, such as the Default
|
|
133
|
+
* Decision prompt's top-priority binding, answers each question on its own, so it never sees the
|
|
134
|
+
* options while answering this one. The Choice cannot say "none" either: its probabilities sum to
|
|
135
|
+
* 1 over the options it is given. So when the options leave out the agent the request needs (a host
|
|
136
|
+
* allow-list of a Billing and a Marketing agent, and a request for a legal review), both answers can
|
|
137
|
+
* still clear the threshold and suggest an agent that does not fit. The suggestion stays advisory,
|
|
138
|
+
* and the agent's prompt keeps the "unless the request clearly needs something else" escape.
|
|
139
|
+
*
|
|
140
|
+
* **Why the wording stays.** The discovery eval (#4892) measured, and the calibration (#4893)
|
|
141
|
+
* calibrated, exactly this question: its per-model Platt parameters and threshold hold only for this
|
|
142
|
+
* wording. Rewording it invalidates both, so the fix (quoting the options, or one Likelihood per
|
|
143
|
+
* option) waits for a re-measurement, tracked in #4938. Meanwhile {@link DECISION_DISCOVERY_MIN_OPTIONS} closes the
|
|
144
|
+
* worst case, two options, and leaves the measured case unchanged.
|
|
145
|
+
*/
|
|
146
|
+
export const DECISION_DISCOVERY_APPLIES_INSTRUCTIONS = 'This request asks for work that a specialist agent should do, rather than something the conversation manager should answer directly or plan as a multi-agent workflow.';
|
|
147
|
+
/** The entity the semantic search ranks when the catalog is over the limit, as Find Candidate Agents does. */
|
|
148
|
+
export const DECISION_DISCOVERY_SEARCH_ENTITY = 'MJ: AI Agents';
|
|
149
|
+
/**
|
|
150
|
+
* The `ExecuteAgentParams.data` key holding the host's catalog of agents the conversation manager
|
|
151
|
+
* may route to (`ConversationAgentRunner` sets it, narrowed to the host's `AllowedAgentIDs`).
|
|
152
|
+
*/
|
|
153
|
+
export const DECISION_DISCOVERY_HOST_AGENTS_KEY = 'ALL_AVAILABLE_AGENTS';
|
|
154
|
+
/** The most agent IDs the step records in a list, such as the agents left out for having no description. */
|
|
155
|
+
export const DECISION_DISCOVERY_MAX_RECORDED_IDS = 50;
|
|
156
|
+
/** A discovery that failed: nothing is injected. */
|
|
157
|
+
export function FailedDecisionDiscovery(reason) {
|
|
158
|
+
return { Injected: false, Succeeded: false, Reason: reason };
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Whether the `decisionDiscovery` setting is on in merged agent-type prompt params. Only `true` turns it
|
|
162
|
+
* on. Discovery runs only when the master switch, `decisionsEnabled`, is on as well: `BaseAgent` checks both.
|
|
163
|
+
*/
|
|
164
|
+
export function IsDecisionDiscoveryOn(promptParams) {
|
|
165
|
+
return promptParams?.decisionDiscovery === true;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Whether a run answers a conversation's opening request, the only turn discovery asks about: its
|
|
169
|
+
* messages hold exactly one user message. A follow-up turn carries the earlier requests in its
|
|
170
|
+
* history (or the summary of them, which also arrives as a user message), and may be continuing work
|
|
171
|
+
* with an agent already engaged, which a suggestion must not pull the agent away from. Assistant and
|
|
172
|
+
* system messages do not count, so a greeting before the first request still leaves it the opening
|
|
173
|
+
* turn. Read it from the messages the run started with, before the framework adds any.
|
|
174
|
+
*
|
|
175
|
+
* @param messages - The run's conversation messages, as the run received them.
|
|
176
|
+
*/
|
|
177
|
+
export function IsOpeningTurn(messages) {
|
|
178
|
+
return (messages ?? []).filter(m => m.role === 'user').length === 1;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Whether the request @mentions an agent other than the one running, in which case the user has
|
|
182
|
+
* already chosen and discovery does not run. It recognises both forms a mention takes by the time a
|
|
183
|
+
* run starts: the composer's `@{"_mode":"mention","type":"agent",...}` token, and the "@Agent Name"
|
|
184
|
+
* text `BaseAgent` converts that token to (or that the user typed). Names match whole, in any case.
|
|
185
|
+
* A mention of the running agent itself does not count: it names no one to delegate to.
|
|
186
|
+
*
|
|
187
|
+
* @param request - The run's opening request.
|
|
188
|
+
* @param agents - Every agent a mention could name.
|
|
189
|
+
* @param selfID - The running agent's ID.
|
|
190
|
+
*/
|
|
191
|
+
export function MentionsAgent(request, agents, selfID) {
|
|
192
|
+
if (!request.includes('@')) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
return mentionsAgentByToken(request, selfID)
|
|
196
|
+
|| agents.some(a => !UUIDsEqual(a.ID, selfID) && mentionsByName(request, a.Name));
|
|
197
|
+
}
|
|
198
|
+
function mentionsAgentByToken(text, selfID) {
|
|
199
|
+
return ConversationUtility.ParseSpecialContent(text)
|
|
200
|
+
.some(token => isAgentMention(token.content) && !UUIDsEqual(token.content.id, selfID));
|
|
201
|
+
}
|
|
202
|
+
function isAgentMention(content) {
|
|
203
|
+
return content._mode !== 'form' && content._mode !== 'attachment' && content.type === 'agent';
|
|
204
|
+
}
|
|
205
|
+
/** Whether `text` holds "@" + `name` as a whole mention: not inside a word or an email address. */
|
|
206
|
+
function mentionsByName(text, name) {
|
|
207
|
+
const needle = `@${(name ?? '').trim().toLowerCase()}`;
|
|
208
|
+
if (needle.length < 2) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
const haystack = text.toLowerCase();
|
|
212
|
+
for (let at = haystack.indexOf(needle); at >= 0; at = haystack.indexOf(needle, at + 1)) {
|
|
213
|
+
if (isMentionBoundary(haystack[at - 1]) && isMentionBoundary(haystack[at + needle.length])) {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
function isMentionBoundary(character) {
|
|
220
|
+
return character === undefined || !/[\w@]/.test(character);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* The Choice's options: one per agent with a description, in catalog order. An agent with a blank
|
|
224
|
+
* description is left out, because the decision model reads only descriptions and the decision
|
|
225
|
+
* primitive rejects an option without one.
|
|
226
|
+
*/
|
|
227
|
+
export function DecisionDiscoveryOptions(agents) {
|
|
228
|
+
return agents
|
|
229
|
+
.filter(a => hasDescription(a.Description))
|
|
230
|
+
.map(a => ({ ID: a.ID, Name: a.Name, Description: (a.Description ?? '').trim() }));
|
|
231
|
+
}
|
|
232
|
+
/** The IDs of the agents {@link DecisionDiscoveryOptions} leaves out for having a blank description, in catalog order. */
|
|
233
|
+
export function AgentsWithoutDescription(agents) {
|
|
234
|
+
return agents.filter(a => !hasDescription(a.Description)).map(a => a.ID);
|
|
235
|
+
}
|
|
236
|
+
function hasDescription(description) {
|
|
237
|
+
return (description ?? '').trim().length > 0;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* The agent IDs in the host's allow-list, when the run carries one: the `ID` of each entry of
|
|
241
|
+
* `data[`{@link DECISION_DISCOVERY_HOST_AGENTS_KEY}`]` when that is an array. `undefined` when it is
|
|
242
|
+
* absent or not an array. An empty array is an allow-list that allows no one.
|
|
243
|
+
*/
|
|
244
|
+
export function HostAllowedAgentIDs(data) {
|
|
245
|
+
const hostAgents = data?.[DECISION_DISCOVERY_HOST_AGENTS_KEY];
|
|
246
|
+
if (!Array.isArray(hostAgents)) {
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
return hostAgents
|
|
250
|
+
.map(entry => (IsPlainObject(entry) && typeof entry.ID === 'string' ? entry.ID : ''))
|
|
251
|
+
.filter(id => id.length > 0);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* The agents the host allows, in their original order, compared UUID-safely. Without an allow-list
|
|
255
|
+
* every agent is kept, and `agents` itself is returned.
|
|
256
|
+
*/
|
|
257
|
+
export function KeepHostAllowedAgents(agents, allowedIDs) {
|
|
258
|
+
if (!allowedIDs) {
|
|
259
|
+
return agents;
|
|
260
|
+
}
|
|
261
|
+
const allowed = new Set(allowedIDs.map(id => NormalizeUUID(id)));
|
|
262
|
+
return agents.filter(a => allowed.has(NormalizeUUID(a.ID)));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* The smallest option cap any of the decision prompt's models declares, or `undefined` when none
|
|
266
|
+
* does. The runner may answer with any of them after failover, so the smallest is the one they all
|
|
267
|
+
* accept. Anything but a positive number declares no cap.
|
|
268
|
+
*/
|
|
269
|
+
export function SmallestOptionCap(caps) {
|
|
270
|
+
const declared = caps.filter((cap) => typeof cap === 'number' && cap > 0);
|
|
271
|
+
return declared.length > 0 ? Math.min(...declared) : undefined;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* The most options the Choice may offer: {@link DECISION_DISCOVERY_MAX_OPTIONS}, or the model's
|
|
275
|
+
* declared cap when that is smaller. It always applies, declared cap or not. More options than this
|
|
276
|
+
* are narrowed first.
|
|
277
|
+
*/
|
|
278
|
+
export function DecisionOptionLimit(declaredCap) {
|
|
279
|
+
return declaredCap === undefined ? DECISION_DISCOVERY_MAX_OPTIONS : Math.min(DECISION_DISCOVERY_MAX_OPTIONS, declaredCap);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Keeps the options the semantic search returned, in its rank order, up to `limit`. An option the
|
|
283
|
+
* search did not return is dropped, and a result that is not an option (an agent the user may not
|
|
284
|
+
* run, say) is skipped.
|
|
285
|
+
*/
|
|
286
|
+
export function RankOptionsBySearch(options, rankedIDs, limit) {
|
|
287
|
+
const byID = new Map(options.map(o => [NormalizeUUID(o.ID), o]));
|
|
288
|
+
const kept = [];
|
|
289
|
+
for (const id of rankedIDs) {
|
|
290
|
+
const option = byID.get(NormalizeUUID(id));
|
|
291
|
+
if (option && !kept.includes(option)) {
|
|
292
|
+
kept.push(option);
|
|
293
|
+
}
|
|
294
|
+
if (kept.length >= limit) {
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return kept;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* The two questions, asked about the opening request in one call: a Choice over the options, whose
|
|
302
|
+
* values are agent IDs and whose descriptions are the agents' descriptions, and a Likelihood,
|
|
303
|
+
* {@link DECISION_DISCOVERY_APPLIES_INSTRUCTIONS}, that stands on the request alone.
|
|
304
|
+
*
|
|
305
|
+
* Neither can say that none of the options fits: the Likelihood never sees them, and the Choice's
|
|
306
|
+
* probabilities sum to 1 over them. The wording is what the discovery eval measured and calibrated,
|
|
307
|
+
* so it changes only with a re-measurement (see {@link DECISION_DISCOVERY_APPLIES_INSTRUCTIONS}).
|
|
308
|
+
*
|
|
309
|
+
* @param options - The agents to choose from.
|
|
310
|
+
*/
|
|
311
|
+
export function BuildDecisionDiscoveryQuestions(options) {
|
|
312
|
+
return {
|
|
313
|
+
[DECISION_DISCOVERY_AGENT_QUESTION]: {
|
|
314
|
+
Kind: 'Choice',
|
|
315
|
+
Instructions: 'Which agent should handle this request?',
|
|
316
|
+
Options: options.map(o => ({ Value: o.ID, Description: o.Description })),
|
|
317
|
+
},
|
|
318
|
+
[DECISION_DISCOVERY_APPLIES_QUESTION]: {
|
|
319
|
+
Kind: 'Likelihood',
|
|
320
|
+
Instructions: DECISION_DISCOVERY_APPLIES_INSTRUCTIONS,
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Judges the answers. Confident means the Choice's confidence and the Likelihood both reach
|
|
326
|
+
* `minConfidence`. An answer that is missing, of the wrong kind, not a finite number, or names no
|
|
327
|
+
* option gives no answer at all.
|
|
328
|
+
*/
|
|
329
|
+
export function JudgeDecisionDiscovery(answers, options, minConfidence = DECISION_DISCOVERY_MIN_CONFIDENCE) {
|
|
330
|
+
const choice = answers?.[DECISION_DISCOVERY_AGENT_QUESTION];
|
|
331
|
+
const applies = answers?.[DECISION_DISCOVERY_APPLIES_QUESTION];
|
|
332
|
+
if (choice?.Kind !== 'Choice' || !isFiniteNumber(choice.Confidence)) {
|
|
333
|
+
return { Confident: false, Reason: `the '${DECISION_DISCOVERY_AGENT_QUESTION}' answer was missing or had no confidence` };
|
|
334
|
+
}
|
|
335
|
+
if (applies?.Kind !== 'Likelihood' || !isFiniteNumber(applies.Probability)) {
|
|
336
|
+
return { Confident: false, Reason: `the '${DECISION_DISCOVERY_APPLIES_QUESTION}' answer was missing or was not a probability` };
|
|
337
|
+
}
|
|
338
|
+
const agent = options.find(o => UUIDsEqual(o.ID, choice.Value));
|
|
339
|
+
if (!agent) {
|
|
340
|
+
return { Confident: false, Reason: `the '${DECISION_DISCOVERY_AGENT_QUESTION}' answer '${choice.Value}' is not one of the options` };
|
|
341
|
+
}
|
|
342
|
+
const answer = {
|
|
343
|
+
Agent: agent,
|
|
344
|
+
Confidence: choice.Confidence,
|
|
345
|
+
AnyApplies: applies.Probability,
|
|
346
|
+
Probabilities: probabilitiesByName(choice.Probabilities, options),
|
|
347
|
+
};
|
|
348
|
+
const shortfalls = [
|
|
349
|
+
choice.Confidence < minConfidence ? `the agent confidence ${choice.Confidence.toFixed(2)} is below ${minConfidence}` : '',
|
|
350
|
+
applies.Probability < minConfidence ? `the probability that any agent applies, ${applies.Probability.toFixed(2)}, is below ${minConfidence}` : '',
|
|
351
|
+
].filter(s => s.length > 0);
|
|
352
|
+
return shortfalls.length === 0
|
|
353
|
+
? { Answer: answer, Confident: true }
|
|
354
|
+
: { Answer: answer, Confident: false, Reason: shortfalls.join('; ') };
|
|
355
|
+
}
|
|
356
|
+
function isFiniteNumber(value) {
|
|
357
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
358
|
+
}
|
|
359
|
+
function probabilitiesByName(probabilities, options) {
|
|
360
|
+
const byName = {};
|
|
361
|
+
for (const option of options) {
|
|
362
|
+
const probability = probabilities?.[option.ID];
|
|
363
|
+
if (typeof probability === 'number') {
|
|
364
|
+
byName[option.Name] = probability;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return byName;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* What a finished decision call means for the prompt: the suggestion when both **calibrated**
|
|
371
|
+
* answers are confident, otherwise nothing, with the reason. A failed call, or an answer that cannot
|
|
372
|
+
* be used, is a failed discovery. An answer from a model with no discovery calibration is unsure.
|
|
373
|
+
*/
|
|
374
|
+
export function DecisionDiscoveryFromResult(result, options, minConfidence = DECISION_DISCOVERY_MIN_CONFIDENCE) {
|
|
375
|
+
if (!result.success) {
|
|
376
|
+
return { Injected: false, Succeeded: false, Reason: result.errorMessage || 'the decision call failed', Result: result };
|
|
377
|
+
}
|
|
378
|
+
const raw = JudgeDecisionDiscovery(result.Answers, options, minConfidence);
|
|
379
|
+
if (!raw.Answer) {
|
|
380
|
+
return { Injected: false, Succeeded: false, Reason: raw.Reason, Result: result };
|
|
381
|
+
}
|
|
382
|
+
const answeredBy = { ModelName: result.modelInfo?.modelName, ResolvedModel: result.DecisionResult?.ResolvedModel };
|
|
383
|
+
const calibrated = CalibrateDiscoveryAnswers(result.Answers, answeredBy);
|
|
384
|
+
if (!calibrated) {
|
|
385
|
+
const described = DescribeAnsweringModel(answeredBy);
|
|
386
|
+
const reason = `the answering model ${described} has no discovery calibration, so its answer is treated as unsure`;
|
|
387
|
+
return { Injected: false, Succeeded: true, Reason: reason, Answer: raw.Answer, Result: result, UncalibratedModel: described };
|
|
388
|
+
}
|
|
389
|
+
const verdict = JudgeDecisionDiscovery(calibrated, options, minConfidence);
|
|
390
|
+
if (!verdict.Answer) {
|
|
391
|
+
return { Injected: false, Succeeded: false, Reason: verdict.Reason, Result: result };
|
|
392
|
+
}
|
|
393
|
+
if (!verdict.Confident) {
|
|
394
|
+
return { Injected: false, Succeeded: true, Reason: verdict.Reason, Answer: verdict.Answer, Result: result };
|
|
395
|
+
}
|
|
396
|
+
return {
|
|
397
|
+
Injected: true,
|
|
398
|
+
Succeeded: true,
|
|
399
|
+
Message: SuggestedAgentMessage(verdict.Answer.Agent, verdict.Answer.Confidence),
|
|
400
|
+
Answer: verdict.Answer,
|
|
401
|
+
Result: result,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
/** The system message placed before the first prompt when the answer is confident. */
|
|
405
|
+
export function SuggestedAgentMessage(agent, confidence) {
|
|
406
|
+
return [
|
|
407
|
+
'<suggested_agent>',
|
|
408
|
+
`A typed decision over the agents you may delegate to chose: ${agent.Name} — ${agent.Description}`,
|
|
409
|
+
`(confidence ${confidence.toFixed(2)}). Delegate to it directly unless the request clearly needs something else.`,
|
|
410
|
+
'</suggested_agent>',
|
|
411
|
+
].join('\n');
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Whether a provider can run `SearchEntity`. It is declared on `IRunViewProvider`, which every real
|
|
415
|
+
* provider implements alongside `IMetadataProvider`.
|
|
416
|
+
*/
|
|
417
|
+
export function CanSearchEntities(provider) {
|
|
418
|
+
return !!provider && 'SearchEntity' in provider && typeof provider.SearchEntity === 'function';
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* The agents a user may run, as Find Candidate Agents filters them: through
|
|
422
|
+
* {@link AIAgentPermissionHelper.FilterRunnableAgents} (Active, with run permission), in catalog order.
|
|
423
|
+
*
|
|
424
|
+
* @param agents - The catalog: `AIEngine.Instance.Agents`.
|
|
425
|
+
* @param contextUser - The user whose run permission decides.
|
|
426
|
+
*/
|
|
427
|
+
export async function DecisionDiscoveryRunnableAgents(agents, contextUser) {
|
|
428
|
+
return AIAgentPermissionHelper.FilterRunnableAgents(agents, contextUser);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* The agents this run may suggest: of the agents the user may run, the ones that can be discovered
|
|
432
|
+
* directly (the set Find Candidate Agents offers, through the same {@link AIAgentPermissionHelper}
|
|
433
|
+
* filter), minus the running agent itself. In catalog order.
|
|
434
|
+
*
|
|
435
|
+
* @param agents - The agents the user may run ({@link DecisionDiscoveryRunnableAgents}).
|
|
436
|
+
* @param runningAgentID - The agent running discovery.
|
|
437
|
+
*/
|
|
438
|
+
export function DecisionDiscoveryCatalog(agents, runningAgentID) {
|
|
439
|
+
return agents.filter(a => AIAgentPermissionHelper.IsDirectlyDiscoverable(a) && !UUIDsEqual(a.ID, runningAgentID));
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* The decision model's option cap: the smallest `Decision.MaxChoiceOptions` in the effective model
|
|
443
|
+
* configuration of the models the decision prompt is bound to, the setting `AIDecisionRunner`
|
|
444
|
+
* checks before its call. `undefined` when none declares one, or the prompt is not found.
|
|
445
|
+
*
|
|
446
|
+
* @param engine - The loaded engine: `AIEngine.Instance`.
|
|
447
|
+
* @param promptName - The decision prompt's name, matched whole in any case.
|
|
448
|
+
*/
|
|
449
|
+
export function DecisionPromptOptionCap(engine, promptName) {
|
|
450
|
+
const target = promptName.trim().toLowerCase();
|
|
451
|
+
const prompt = engine.Prompts.find(p => (p.Name ?? '').trim().toLowerCase() === target);
|
|
452
|
+
if (!prompt) {
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
const caps = engine.PromptModels
|
|
456
|
+
.filter(pm => UUIDsEqual(pm.PromptID, prompt.ID) && (pm.Status === 'Active' || pm.Status === 'Preview'))
|
|
457
|
+
.map(pm => {
|
|
458
|
+
const modelVendor = pm.VendorID
|
|
459
|
+
? engine.ModelVendors.find(mv => UUIDsEqual(mv.ModelID, pm.ModelID) && UUIDsEqual(mv.VendorID, pm.VendorID))
|
|
460
|
+
: undefined;
|
|
461
|
+
return engine.GetEffectiveModelConfiguration(pm.ModelID, modelVendor?.ID)?.Decision?.MaxChoiceOptions;
|
|
462
|
+
});
|
|
463
|
+
return SmallestOptionCap(caps);
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* The search Find Candidate Agents runs, for one request: hybrid over
|
|
467
|
+
* {@link DECISION_DISCOVERY_SEARCH_ENTITY}. Its similarity floor is not applied: the caller judges fit.
|
|
468
|
+
*
|
|
469
|
+
* @param provider - A provider that can search ({@link CanSearchEntities}).
|
|
470
|
+
* @param request - The request to rank agents for.
|
|
471
|
+
* @param contextUser - The user the search runs as.
|
|
472
|
+
*/
|
|
473
|
+
export function DecisionDiscoveryAgentSearch(provider, request, contextUser) {
|
|
474
|
+
return topK => provider.SearchEntity({
|
|
475
|
+
entityName: DECISION_DISCOVERY_SEARCH_ENTITY,
|
|
476
|
+
searchText: request,
|
|
477
|
+
options: { mode: 'hybrid', topK, minScore: 0, contextUser },
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* The Choice's options, rebuilt on every call and never cached: the agents in the permitted
|
|
482
|
+
* catalog ({@link DecisionDiscoveryCatalog}) that the host allows and that have a description.
|
|
483
|
+
* There are never more than {@link DecisionOptionLimit}: when there are, the semantic search narrows
|
|
484
|
+
* them first; if it cannot, `Error` says why.
|
|
485
|
+
*
|
|
486
|
+
* @param params - The permitted agents, the running agent, the host's allow-list, the option cap and the search.
|
|
487
|
+
*/
|
|
488
|
+
export async function BuildDecisionDiscoveryOptionSet(params) {
|
|
489
|
+
const catalog = KeepHostAllowedAgents(DecisionDiscoveryCatalog(params.Agents, params.RunningAgentID), params.HostAllowedIDs);
|
|
490
|
+
const options = DecisionDiscoveryOptions(catalog);
|
|
491
|
+
const limit = DecisionOptionLimit(params.DeclaredCap);
|
|
492
|
+
const set = {
|
|
493
|
+
Options: options,
|
|
494
|
+
CatalogSize: catalog.length,
|
|
495
|
+
HostAllowListSize: params.HostAllowedIDs?.length,
|
|
496
|
+
WithoutDescription: AgentsWithoutDescription(catalog),
|
|
497
|
+
OptionLimit: limit,
|
|
498
|
+
DeclaredOptionCap: params.DeclaredCap,
|
|
499
|
+
};
|
|
500
|
+
if (options.length <= limit) {
|
|
501
|
+
return set;
|
|
502
|
+
}
|
|
503
|
+
if (!params.Search) {
|
|
504
|
+
return { ...set, Options: [], NarrowedFrom: options.length,
|
|
505
|
+
Error: `${options.length} agents exceed the limit of ${limit} options, and the provider cannot run the semantic search that narrows them` };
|
|
506
|
+
}
|
|
507
|
+
// Over-fetching threefold for the permission filter, as Find Candidate Agents does.
|
|
508
|
+
const results = await params.Search(limit * 3);
|
|
509
|
+
return { ...set, Options: RankOptionsBySearch(options, results.map(r => r.recordId), limit), NarrowedFrom: options.length };
|
|
510
|
+
}
|
|
511
|
+
//# sourceMappingURL=decision-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision-discovery.js","sourceRoot":"","sources":["../src/decision-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** The most characters of a `finishIfMode` value that is not a mode a warning shows. */
|
|
2
|
+
export declare const FINISH_IF_MODE_WARNING_SHOWN_MAX = 100;
|
|
3
|
+
/** The most agent and value pairs {@link FinishIfModeWarnings} remembers as already reported. */
|
|
4
|
+
export declare const FINISH_IF_MODE_WARNINGS_REMEMBERED = 1000;
|
|
5
|
+
/**
|
|
6
|
+
* Decides when to warn that an agent's merged `finishIfMode` is set but is not one of the
|
|
7
|
+
* {@link FINISH_IF_MODES}: once per agent and value. `ResolveFinishIfMode` treats such a value as
|
|
8
|
+
* `'off'`, so without the warning a typo such as `"On"` or `"true"` would turn the agent's gates
|
|
9
|
+
* off without a word.
|
|
10
|
+
*
|
|
11
|
+
* The value can come from whoever starts a run, through its runtime prompt-param overrides, so
|
|
12
|
+
* both what is logged and what is remembered are bounded:
|
|
13
|
+
* - a warning shows at most {@link FINISH_IF_MODE_WARNING_SHOWN_MAX} characters of the value, and
|
|
14
|
+
* notes its full length when it is longer;
|
|
15
|
+
* - two values count as the same when their warnings would read the same, so a pair is
|
|
16
|
+
* remembered by a key of bounded size;
|
|
17
|
+
* - at most `maxRemembered` pairs are remembered, and the one seen least recently is dropped
|
|
18
|
+
* first. A dropped pair warns again the next time it is seen, which is harmless.
|
|
19
|
+
*/
|
|
20
|
+
export declare class FinishIfModeWarnings {
|
|
21
|
+
private readonly reported;
|
|
22
|
+
constructor(maxRemembered?: number);
|
|
23
|
+
/** How many agent and value pairs are remembered as reported. Never more than {@link MaxRemembered}. */
|
|
24
|
+
get Remembered(): number;
|
|
25
|
+
/** The most agent and value pairs remembered at once. */
|
|
26
|
+
get MaxRemembered(): number;
|
|
27
|
+
/**
|
|
28
|
+
* The warning to log for an agent's merged `finishIfMode`, or `undefined` when there is none
|
|
29
|
+
* to log: the value is absent, is a mode, or was reported for this agent already.
|
|
30
|
+
*/
|
|
31
|
+
WarningFor(agentID: string, agentName: string, value: unknown): string | undefined;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A `finishIfMode` value as its warning shows it. A string keeps its quotes, so `"true"` and
|
|
35
|
+
* `true` read differently. Anything else is shown as JSON. Either is cut to
|
|
36
|
+
* {@link FINISH_IF_MODE_WARNING_SHOWN_MAX} characters, and a longer one notes its full length.
|
|
37
|
+
*/
|
|
38
|
+
export declare function ShowFinishIfModeValue(value: unknown): string;
|
|
39
|
+
//# sourceMappingURL=finish-if-mode-warnings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finish-if-mode-warnings.d.ts","sourceRoot":"","sources":["../src/finish-if-mode-warnings.ts"],"names":[],"mappings":"AAGA,wFAAwF;AACxF,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAEpD,iGAAiG;AACjG,eAAO,MAAM,kCAAkC,OAAO,CAAC;AAEvD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,oBAAoB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;gBAExC,aAAa,GAAE,MAA2C;IAItE,wGAAwG;IACxG,IAAW,UAAU,IAAI,MAAM,CAE9B;IAED,yDAAyD;IACzD,IAAW,aAAa,IAAI,MAAM,CAEjC;IAED;;;OAGG;IACI,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS;CAc5F;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAU5D"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { MJLruCache } from '@memberjunction/global';
|
|
2
|
+
import { FINISH_IF_MODES, IsFinishIfMode } from './agent-types/loop-agent-prompt-params.js';
|
|
3
|
+
/** The most characters of a `finishIfMode` value that is not a mode a warning shows. */
|
|
4
|
+
export const FINISH_IF_MODE_WARNING_SHOWN_MAX = 100;
|
|
5
|
+
/** The most agent and value pairs {@link FinishIfModeWarnings} remembers as already reported. */
|
|
6
|
+
export const FINISH_IF_MODE_WARNINGS_REMEMBERED = 1000;
|
|
7
|
+
/**
|
|
8
|
+
* Decides when to warn that an agent's merged `finishIfMode` is set but is not one of the
|
|
9
|
+
* {@link FINISH_IF_MODES}: once per agent and value. `ResolveFinishIfMode` treats such a value as
|
|
10
|
+
* `'off'`, so without the warning a typo such as `"On"` or `"true"` would turn the agent's gates
|
|
11
|
+
* off without a word.
|
|
12
|
+
*
|
|
13
|
+
* The value can come from whoever starts a run, through its runtime prompt-param overrides, so
|
|
14
|
+
* both what is logged and what is remembered are bounded:
|
|
15
|
+
* - a warning shows at most {@link FINISH_IF_MODE_WARNING_SHOWN_MAX} characters of the value, and
|
|
16
|
+
* notes its full length when it is longer;
|
|
17
|
+
* - two values count as the same when their warnings would read the same, so a pair is
|
|
18
|
+
* remembered by a key of bounded size;
|
|
19
|
+
* - at most `maxRemembered` pairs are remembered, and the one seen least recently is dropped
|
|
20
|
+
* first. A dropped pair warns again the next time it is seen, which is harmless.
|
|
21
|
+
*/
|
|
22
|
+
export class FinishIfModeWarnings {
|
|
23
|
+
constructor(maxRemembered = FINISH_IF_MODE_WARNINGS_REMEMBERED) {
|
|
24
|
+
this.reported = new MJLruCache({ maxSize: maxRemembered });
|
|
25
|
+
}
|
|
26
|
+
/** How many agent and value pairs are remembered as reported. Never more than {@link MaxRemembered}. */
|
|
27
|
+
get Remembered() {
|
|
28
|
+
return this.reported.Size;
|
|
29
|
+
}
|
|
30
|
+
/** The most agent and value pairs remembered at once. */
|
|
31
|
+
get MaxRemembered() {
|
|
32
|
+
return this.reported.MaxSize;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The warning to log for an agent's merged `finishIfMode`, or `undefined` when there is none
|
|
36
|
+
* to log: the value is absent, is a mode, or was reported for this agent already.
|
|
37
|
+
*/
|
|
38
|
+
WarningFor(agentID, agentName, value) {
|
|
39
|
+
if (value === undefined || value === null || IsFinishIfMode(value)) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const shown = ShowFinishIfModeValue(value);
|
|
43
|
+
const key = `${agentID}\u0000${shown}`;
|
|
44
|
+
// Get also marks the pair as recently seen, so a value an agent keeps sending is not dropped.
|
|
45
|
+
if (this.reported.Get(key)) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
this.reported.Set(key, true);
|
|
49
|
+
const modes = FINISH_IF_MODES.map(mode => `'${mode}'`).join(', ');
|
|
50
|
+
return `Agent '${agentName}' has finishIfMode ${shown}, which is not one of ${modes}, so its finishIf gates are off. Mode names are case-sensitive.`;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A `finishIfMode` value as its warning shows it. A string keeps its quotes, so `"true"` and
|
|
55
|
+
* `true` read differently. Anything else is shown as JSON. Either is cut to
|
|
56
|
+
* {@link FINISH_IF_MODE_WARNING_SHOWN_MAX} characters, and a longer one notes its full length.
|
|
57
|
+
*/
|
|
58
|
+
export function ShowFinishIfModeValue(value) {
|
|
59
|
+
if (typeof value === 'string') {
|
|
60
|
+
// Cut before quoting, so a huge string is never copied whole.
|
|
61
|
+
const cut = value.slice(0, FINISH_IF_MODE_WARNING_SHOWN_MAX);
|
|
62
|
+
return value.length > cut.length ? `${JSON.stringify(cut)}… (${value.length} characters)` : JSON.stringify(cut);
|
|
63
|
+
}
|
|
64
|
+
const json = jsonOf(value);
|
|
65
|
+
return json.length > FINISH_IF_MODE_WARNING_SHOWN_MAX
|
|
66
|
+
? `${json.slice(0, FINISH_IF_MODE_WARNING_SHOWN_MAX)}… (${json.length} characters as JSON)`
|
|
67
|
+
: json;
|
|
68
|
+
}
|
|
69
|
+
/** A value as JSON, or as `String(value)` when it cannot be written as JSON. */
|
|
70
|
+
function jsonOf(value) {
|
|
71
|
+
try {
|
|
72
|
+
return JSON.stringify(value) ?? String(value);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return String(value);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=finish-if-mode-warnings.js.map
|