@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.
Files changed (131) hide show
  1. package/README.md +18 -0
  2. package/dist/AgentDecisionService.d.ts +90 -0
  3. package/dist/AgentDecisionService.d.ts.map +1 -0
  4. package/dist/AgentDecisionService.js +159 -0
  5. package/dist/AgentDecisionService.js.map +1 -0
  6. package/dist/AgentRunner.d.ts +9 -0
  7. package/dist/AgentRunner.d.ts.map +1 -1
  8. package/dist/AgentRunner.js +23 -7
  9. package/dist/AgentRunner.js.map +1 -1
  10. package/dist/ConversationCompactionManager.d.ts +7 -1
  11. package/dist/ConversationCompactionManager.d.ts.map +1 -1
  12. package/dist/ConversationCompactionManager.js +4 -1
  13. package/dist/ConversationCompactionManager.js.map +1 -1
  14. package/dist/KnowledgeAgent.d.ts.map +1 -1
  15. package/dist/KnowledgeAgent.js +6 -6
  16. package/dist/KnowledgeAgent.js.map +1 -1
  17. package/dist/PayloadFeedbackManager.d.ts +116 -14
  18. package/dist/PayloadFeedbackManager.d.ts.map +1 -1
  19. package/dist/PayloadFeedbackManager.js +229 -88
  20. package/dist/PayloadFeedbackManager.js.map +1 -1
  21. package/dist/agent-context-injector.d.ts +47 -3
  22. package/dist/agent-context-injector.d.ts.map +1 -1
  23. package/dist/agent-context-injector.js +77 -10
  24. package/dist/agent-context-injector.js.map +1 -1
  25. package/dist/agent-memory-context-builder.d.ts +13 -0
  26. package/dist/agent-memory-context-builder.d.ts.map +1 -1
  27. package/dist/agent-memory-context-builder.js +24 -5
  28. package/dist/agent-memory-context-builder.js.map +1 -1
  29. package/dist/agent-types/flow-agent-type.d.ts +97 -0
  30. package/dist/agent-types/flow-agent-type.d.ts.map +1 -1
  31. package/dist/agent-types/flow-agent-type.js +281 -24
  32. package/dist/agent-types/flow-agent-type.js.map +1 -1
  33. package/dist/agent-types/flow-graph-executor.d.ts +12 -1
  34. package/dist/agent-types/flow-graph-executor.d.ts.map +1 -1
  35. package/dist/agent-types/flow-graph-executor.js +25 -1
  36. package/dist/agent-types/flow-graph-executor.js.map +1 -1
  37. package/dist/agent-types/loop-agent-prompt-params.d.ts +239 -66
  38. package/dist/agent-types/loop-agent-prompt-params.d.ts.map +1 -1
  39. package/dist/agent-types/loop-agent-prompt-params.js +47 -2
  40. package/dist/agent-types/loop-agent-prompt-params.js.map +1 -1
  41. package/dist/agent-types/loop-agent-response-type.d.ts +12 -1
  42. package/dist/agent-types/loop-agent-response-type.d.ts.map +1 -1
  43. package/dist/agent-types/loop-agent-response-type.js.map +1 -1
  44. package/dist/agent-types/loop-agent-type.d.ts +26 -0
  45. package/dist/agent-types/loop-agent-type.d.ts.map +1 -1
  46. package/dist/agent-types/loop-agent-type.js +115 -5
  47. package/dist/agent-types/loop-agent-type.js.map +1 -1
  48. package/dist/base-agent.d.ts +527 -10
  49. package/dist/base-agent.d.ts.map +1 -1
  50. package/dist/base-agent.js +1779 -110
  51. package/dist/base-agent.js.map +1 -1
  52. package/dist/catalog-narrowing.d.ts +136 -0
  53. package/dist/catalog-narrowing.d.ts.map +1 -0
  54. package/dist/catalog-narrowing.js +212 -0
  55. package/dist/catalog-narrowing.js.map +1 -0
  56. package/dist/decision-discovery.d.ts +401 -0
  57. package/dist/decision-discovery.d.ts.map +1 -0
  58. package/dist/decision-discovery.js +511 -0
  59. package/dist/decision-discovery.js.map +1 -0
  60. package/dist/finish-if-mode-warnings.d.ts +39 -0
  61. package/dist/finish-if-mode-warnings.d.ts.map +1 -0
  62. package/dist/finish-if-mode-warnings.js +78 -0
  63. package/dist/finish-if-mode-warnings.js.map +1 -0
  64. package/dist/finish-if-state.d.ts +72 -0
  65. package/dist/finish-if-state.d.ts.map +1 -0
  66. package/dist/finish-if-state.js +109 -0
  67. package/dist/finish-if-state.js.map +1 -0
  68. package/dist/index.d.ts +10 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +11 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/memory-manager-agent.d.ts +108 -2
  73. package/dist/memory-manager-agent.d.ts.map +1 -1
  74. package/dist/memory-manager-agent.js +172 -9
  75. package/dist/memory-manager-agent.js.map +1 -1
  76. package/dist/memory-note-gate.d.ts +208 -0
  77. package/dist/memory-note-gate.d.ts.map +1 -0
  78. package/dist/memory-note-gate.js +294 -0
  79. package/dist/memory-note-gate.js.map +1 -0
  80. package/dist/native-tools/action-tool-builder.d.ts +14 -0
  81. package/dist/native-tools/action-tool-builder.d.ts.map +1 -1
  82. package/dist/native-tools/action-tool-builder.js +62 -7
  83. package/dist/native-tools/action-tool-builder.js.map +1 -1
  84. package/dist/native-tools/control-tools.d.ts +17 -1
  85. package/dist/native-tools/control-tools.d.ts.map +1 -1
  86. package/dist/native-tools/control-tools.js +40 -3
  87. package/dist/native-tools/control-tools.js.map +1 -1
  88. package/dist/realtime/bridge-host-params.d.ts +22 -0
  89. package/dist/realtime/bridge-host-params.d.ts.map +1 -0
  90. package/dist/realtime/bridge-host-params.js +53 -0
  91. package/dist/realtime/bridge-host-params.js.map +1 -0
  92. package/dist/realtime/bridge-realtime-session-factory.d.ts +23 -2
  93. package/dist/realtime/bridge-realtime-session-factory.d.ts.map +1 -1
  94. package/dist/realtime/bridge-realtime-session-factory.js +22 -6
  95. package/dist/realtime/bridge-realtime-session-factory.js.map +1 -1
  96. package/dist/realtime/bridge-room-transcript-sink.d.ts.map +1 -1
  97. package/dist/realtime/bridge-room-transcript-sink.js +15 -9
  98. package/dist/realtime/bridge-room-transcript-sink.js.map +1 -1
  99. package/dist/realtime/bridge-session-transcript-sink.d.ts +37 -0
  100. package/dist/realtime/bridge-session-transcript-sink.d.ts.map +1 -0
  101. package/dist/realtime/bridge-session-transcript-sink.js +58 -0
  102. package/dist/realtime/bridge-session-transcript-sink.js.map +1 -0
  103. package/dist/realtime/realtime-client-session-service.d.ts +117 -12
  104. package/dist/realtime/realtime-client-session-service.d.ts.map +1 -1
  105. package/dist/realtime/realtime-client-session-service.js +162 -39
  106. package/dist/realtime/realtime-client-session-service.js.map +1 -1
  107. package/dist/realtime/realtime-coagent-resolution.d.ts +90 -0
  108. package/dist/realtime/realtime-coagent-resolution.d.ts.map +1 -0
  109. package/dist/realtime/realtime-coagent-resolution.js +186 -0
  110. package/dist/realtime/realtime-coagent-resolution.js.map +1 -0
  111. package/dist/realtime/realtime-delegation-narrator.d.ts +97 -0
  112. package/dist/realtime/realtime-delegation-narrator.d.ts.map +1 -0
  113. package/dist/realtime/realtime-delegation-narrator.js +162 -0
  114. package/dist/realtime/realtime-delegation-narrator.js.map +1 -0
  115. package/dist/realtime/realtime-session-runner.d.ts +2 -82
  116. package/dist/realtime/realtime-session-runner.d.ts.map +1 -1
  117. package/dist/realtime/realtime-session-runner.js +12 -187
  118. package/dist/realtime/realtime-session-runner.js.map +1 -1
  119. package/dist/realtime/realtime-vendor-resolution.d.ts +8 -3
  120. package/dist/realtime/realtime-vendor-resolution.d.ts.map +1 -1
  121. package/dist/realtime/realtime-vendor-resolution.js +3 -3
  122. package/dist/realtime/realtime-vendor-resolution.js.map +1 -1
  123. package/dist/rubric-evaluation-agent-runner.d.ts +2 -0
  124. package/dist/rubric-evaluation-agent-runner.d.ts.map +1 -0
  125. package/dist/rubric-evaluation-agent-runner.js +47 -0
  126. package/dist/rubric-evaluation-agent-runner.js.map +1 -0
  127. package/dist/self-check.d.ts +101 -0
  128. package/dist/self-check.d.ts.map +1 -0
  129. package/dist/self-check.js +74 -0
  130. package/dist/self-check.js.map +1 -0
  131. 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