@elizaos/agent 2.0.0-alpha.192 → 2.0.0-alpha.196
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/apps/app-lifeops/src/action.d.ts.map +1 -1
- package/apps/app-lifeops/src/action.js +21 -2
- package/apps/app-lifeops/src/actions/app-blocker.d.ts +3 -1
- package/apps/app-lifeops/src/actions/app-blocker.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/app-blocker.js +2 -0
- package/apps/app-lifeops/src/actions/calendar.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/calendar.js +140 -7
- package/apps/app-lifeops/src/actions/computer-use.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/computer-use.js +248 -17
- package/apps/app-lifeops/src/actions/cross-channel-send.d.ts +3 -1
- package/apps/app-lifeops/src/actions/cross-channel-send.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/cross-channel-send.js +1 -0
- package/apps/app-lifeops/src/actions/dossier.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/dossier.js +51 -34
- package/apps/app-lifeops/src/actions/gmail.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/gmail.js +5 -0
- package/apps/app-lifeops/src/actions/inbox.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/inbox.js +8 -1
- package/apps/app-lifeops/src/actions/life.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/life.extractor.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/life.extractor.js +103 -4
- package/apps/app-lifeops/src/actions/life.js +8 -0
- package/apps/app-lifeops/src/actions/non-actionable-request.d.ts +6 -0
- package/apps/app-lifeops/src/actions/non-actionable-request.d.ts.map +1 -0
- package/apps/app-lifeops/src/actions/non-actionable-request.js +33 -0
- package/apps/app-lifeops/src/actions/password-manager.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/password-manager.js +11 -2
- package/apps/app-lifeops/src/actions/relationships.d.ts +3 -1
- package/apps/app-lifeops/src/actions/relationships.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/relationships.js +167 -11
- package/apps/app-lifeops/src/actions/remote-desktop.js +1 -1
- package/apps/app-lifeops/src/actions/screen-time.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/screen-time.js +8 -2
- package/apps/app-lifeops/src/actions/start-remote-session.js +1 -1
- package/apps/app-lifeops/src/actions/subscriptions.d.ts +5 -0
- package/apps/app-lifeops/src/actions/subscriptions.d.ts.map +1 -0
- package/apps/app-lifeops/src/actions/subscriptions.js +251 -0
- package/apps/app-lifeops/src/actions/twilio-call.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/twilio-call.js +48 -3
- package/apps/app-lifeops/src/actions/update-owner-profile.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/update-owner-profile.js +2 -1
- package/apps/app-lifeops/src/actions/website-blocker.d.ts +6 -2
- package/apps/app-lifeops/src/actions/website-blocker.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/website-blocker.js +38 -0
- package/apps/app-lifeops/src/actions/x-read.d.ts.map +1 -1
- package/apps/app-lifeops/src/actions/x-read.js +27 -3
- package/apps/app-lifeops/src/dossier/action.d.ts.map +1 -1
- package/apps/app-lifeops/src/dossier/action.js +8 -7
- package/apps/app-lifeops/src/followup/actions/listOverdueFollowups.d.ts.map +1 -1
- package/apps/app-lifeops/src/followup/actions/listOverdueFollowups.js +1 -0
- package/apps/app-lifeops/src/followup/actions/markFollowupDone.d.ts.map +1 -1
- package/apps/app-lifeops/src/followup/actions/markFollowupDone.js +2 -1
- package/apps/app-lifeops/src/followup/actions/setFollowupThreshold.d.ts.map +1 -1
- package/apps/app-lifeops/src/followup/actions/setFollowupThreshold.js +2 -1
- package/apps/app-lifeops/src/lifeops/calendly-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/calendly-client.js +4 -2
- package/apps/app-lifeops/src/lifeops/discord-browser-scraper.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/discord-browser-scraper.js +6 -5
- package/apps/app-lifeops/src/lifeops/password-manager-bridge.d.ts +1 -1
- package/apps/app-lifeops/src/lifeops/password-manager-bridge.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/password-manager-bridge.js +84 -6
- package/apps/app-lifeops/src/lifeops/remote-desktop.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/remote-desktop.js +30 -0
- package/apps/app-lifeops/src/lifeops/repository.d.ts +15 -0
- package/apps/app-lifeops/src/lifeops/repository.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/repository.js +330 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-discord.js +222 -42
- package/apps/app-lifeops/src/lifeops/service-mixin-subscriptions.d.ts +2 -0
- package/apps/app-lifeops/src/lifeops/service-mixin-subscriptions.d.ts.map +1 -0
- package/apps/app-lifeops/src/lifeops/service-mixin-subscriptions.js +763 -0
- package/apps/app-lifeops/src/lifeops/service.d.ts +63 -0
- package/apps/app-lifeops/src/lifeops/service.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service.js +2 -1
- package/apps/app-lifeops/src/lifeops/subscriptions-playbooks.d.ts +54 -0
- package/apps/app-lifeops/src/lifeops/subscriptions-playbooks.d.ts.map +1 -0
- package/apps/app-lifeops/src/lifeops/subscriptions-playbooks.js +213 -0
- package/apps/app-lifeops/src/lifeops/subscriptions-types.d.ts +80 -0
- package/apps/app-lifeops/src/lifeops/subscriptions-types.d.ts.map +1 -0
- package/apps/app-lifeops/src/lifeops/twilio.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/twilio.js +4 -2
- package/apps/app-lifeops/src/lifeops/whatsapp-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/whatsapp-client.js +4 -2
- package/apps/app-lifeops/src/lifeops/x-poster.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/x-poster.js +12 -6
- package/apps/app-lifeops/src/lifeops/x-reader.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/x-reader.js +7 -5
- package/apps/app-lifeops/src/plugin.d.ts.map +1 -1
- package/apps/app-lifeops/src/plugin.js +31 -24
- package/apps/app-lifeops/src/provider.d.ts.map +1 -1
- package/apps/app-lifeops/src/provider.js +4 -4
- package/apps/app-lifeops/src/providers/inbox-triage.js +2 -2
- package/apps/app-lifeops/src/providers/lifeops.d.ts.map +1 -1
- package/apps/app-lifeops/src/providers/lifeops.js +19 -10
- package/apps/app-lifeops/src/providers/website-blocker.js +1 -1
- package/apps/app-lifeops/src/public.d.ts +4 -0
- package/apps/app-lifeops/src/public.d.ts.map +1 -0
- package/apps/app-lifeops/src/public.js +3 -0
- package/apps/app-lifeops/src/routes/plugin.d.ts +18 -0
- package/apps/app-lifeops/src/routes/plugin.d.ts.map +1 -0
- package/apps/app-lifeops/src/routes/plugin.js +270 -0
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/blockUntilTaskComplete.d.ts.map +1 -1
- package/apps/app-lifeops/src/website-blocker/chat-integration/actions/blockUntilTaskComplete.js +18 -2
- package/apps/app-training/src/core/training-orchestrator.d.ts.map +1 -1
- package/apps/app-training/src/core/training-orchestrator.js +4 -0
- package/apps/app-training/src/services/training-trigger.d.ts +32 -18
- package/apps/app-training/src/services/training-trigger.d.ts.map +1 -1
- package/apps/app-training/src/services/training-trigger.js +10 -1
- package/package.json +4 -4
- package/packages/agent/src/actions/browser-session.d.ts +3 -0
- package/packages/agent/src/actions/browser-session.d.ts.map +1 -0
- package/packages/agent/src/actions/browser-session.js +207 -0
- package/packages/agent/src/actions/context-signal.d.ts +1 -1
- package/packages/agent/src/actions/context-signal.d.ts.map +1 -1
- package/packages/agent/src/actions/context-signal.js +1 -1
- package/packages/agent/src/actions/extract-page.d.ts +3 -0
- package/packages/agent/src/actions/extract-page.d.ts.map +1 -0
- package/packages/agent/src/actions/extract-page.js +124 -0
- package/packages/agent/src/actions/grounded-action-reply.js +1 -1
- package/packages/agent/src/actions/recent-conversation-texts.d.ts +9 -0
- package/packages/agent/src/actions/recent-conversation-texts.d.ts.map +1 -0
- package/packages/agent/src/actions/recent-conversation-texts.js +81 -0
- package/packages/agent/src/actions/set-user-name.js +1 -1
- package/packages/agent/src/actions/web-search.d.ts +4 -10
- package/packages/agent/src/actions/web-search.d.ts.map +1 -1
- package/packages/agent/src/actions/web-search.js +89 -19
- package/packages/agent/src/api/binance-skill-helpers.d.ts.map +1 -1
- package/packages/agent/src/api/binance-skill-helpers.js +1 -1
- package/packages/agent/src/api/chat-augmentation.d.ts +1 -20
- package/packages/agent/src/api/chat-augmentation.d.ts.map +1 -1
- package/packages/agent/src/api/chat-augmentation.js +2 -110
- package/packages/agent/src/api/conversation-metadata.d.ts +9 -0
- package/packages/agent/src/api/conversation-metadata.d.ts.map +1 -0
- package/packages/agent/src/api/conversation-metadata.js +98 -0
- package/packages/agent/src/api/conversation-routes.d.ts.map +1 -1
- package/packages/agent/src/api/conversation-routes.js +40 -9
- package/packages/agent/src/api/lifeops-browser-packaging.d.ts +1 -1
- package/packages/agent/src/api/lifeops-browser-packaging.d.ts.map +1 -1
- package/packages/agent/src/api/lifeops-browser-packaging.js +1 -1
- package/packages/agent/src/api/permissions-routes.js +1 -1
- package/packages/agent/src/api/server-helpers-auth.js +1 -1
- package/packages/agent/src/api/server-helpers.d.ts +2 -1
- package/packages/agent/src/api/server-helpers.d.ts.map +1 -1
- package/packages/agent/src/api/server-helpers.js +2 -110
- package/packages/agent/src/api/server-types.d.ts +14 -0
- package/packages/agent/src/api/server-types.d.ts.map +1 -1
- package/packages/agent/src/api/server.d.ts.map +1 -1
- package/packages/agent/src/api/server.js +3 -13
- package/packages/agent/src/api/workbench-routes.d.ts.map +1 -1
- package/packages/agent/src/api/workbench-routes.js +0 -14
- package/packages/agent/src/auth/credentials.d.ts.map +1 -1
- package/packages/agent/src/auth/credentials.js +8 -0
- package/packages/agent/src/config/zod-schema.d.ts +2 -2
- package/packages/agent/src/config/zod-schema.providers-core.d.ts +3 -3
- package/packages/agent/src/providers/automation-terminal-bridge.d.ts +3 -0
- package/packages/agent/src/providers/automation-terminal-bridge.d.ts.map +1 -0
- package/packages/agent/src/providers/automation-terminal-bridge.js +71 -0
- package/packages/agent/src/providers/index.d.ts +1 -0
- package/packages/agent/src/providers/index.d.ts.map +1 -1
- package/packages/agent/src/providers/index.js +1 -0
- package/packages/agent/src/providers/recent-conversations.d.ts.map +1 -1
- package/packages/agent/src/providers/recent-conversations.js +5 -0
- package/packages/agent/src/providers/relevant-conversations.d.ts.map +1 -1
- package/packages/agent/src/providers/relevant-conversations.js +5 -0
- package/packages/agent/src/providers/user-name.d.ts.map +1 -1
- package/packages/agent/src/providers/user-name.js +1 -1
- package/packages/agent/src/runtime/eliza-plugin.d.ts.map +1 -1
- package/packages/agent/src/runtime/eliza-plugin.js +6 -0
- package/packages/agent/src/runtime/plugin-resolver.d.ts.map +1 -1
- package/packages/agent/src/runtime/plugin-resolver.js +115 -0
- package/packages/agent/src/services/browser-workspace-types.d.ts +5 -1
- package/packages/agent/src/services/browser-workspace-types.d.ts.map +1 -1
- package/packages/agent/src/services/browser-workspace.d.ts.map +1 -1
- package/packages/agent/src/services/browser-workspace.js +178 -7
- package/packages/agent/src/services/coding-agent-context.d.ts +4 -4
- package/packages/agent/src/services/escalation.d.ts +0 -11
- package/packages/agent/src/services/escalation.d.ts.map +1 -1
- package/packages/agent/src/services/escalation.js +19 -58
- package/packages/agent/src/services/hosted-tools.d.ts +70 -0
- package/packages/agent/src/services/hosted-tools.d.ts.map +1 -0
- package/packages/agent/src/services/hosted-tools.js +87 -0
- package/packages/agent/src/services/owner-name.d.ts +4 -0
- package/packages/agent/src/services/owner-name.d.ts.map +1 -0
- package/packages/agent/src/services/owner-name.js +46 -0
- package/packages/agent/src/services/registry-client-queries.d.ts +1 -1
- package/packages/agent/src/services/registry-client-queries.js +1 -1
- package/packages/agent/src/services/registry-client-types.d.ts +1 -1
- package/packages/agent/src/services/stream-manager.d.ts +1 -1
- package/packages/app-core/src/config/boot-config-store.d.ts +1 -1
- package/packages/app-core/src/config/boot-config-store.d.ts.map +1 -1
- package/packages/shared/src/contracts/lifeops.d.ts +26 -0
- package/packages/shared/src/contracts/lifeops.d.ts.map +1 -1
- package/packages/shared/src/contracts/lifeops.js +28 -0
- package/packages/typescript/src/actions.d.ts.map +1 -1
- package/packages/typescript/src/actions.js +12 -0
- package/packages/typescript/src/features/advanced-capabilities/actions/scheduleFollowUp.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/actions/scheduleFollowUp.js +8 -2
- package/packages/typescript/src/features/advanced-capabilities/providers/settings.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/providers/settings.js +11 -3
- package/packages/typescript/src/features/basic-capabilities/providers/actions.d.ts.map +1 -1
- package/packages/typescript/src/features/basic-capabilities/providers/actions.js +23 -1
- package/packages/typescript/src/features/basic-capabilities/providers/non-actionable-chatter.d.ts +5 -0
- package/packages/typescript/src/features/basic-capabilities/providers/non-actionable-chatter.d.ts.map +1 -0
- package/packages/typescript/src/features/basic-capabilities/providers/non-actionable-chatter.js +22 -0
- package/packages/typescript/src/features/basic-capabilities/providers/providers.d.ts.map +1 -1
- package/packages/typescript/src/features/basic-capabilities/providers/providers.js +10 -5
- package/packages/typescript/src/features/knowledge/documents-provider.d.ts.map +1 -1
- package/packages/typescript/src/features/knowledge/documents-provider.js +1 -0
- package/packages/typescript/src/features/shared/schedule-follow-up-response.d.ts +10 -0
- package/packages/typescript/src/features/shared/schedule-follow-up-response.d.ts.map +1 -0
- package/packages/typescript/src/features/shared/schedule-follow-up-response.js +49 -0
- package/packages/typescript/src/features/trajectories/TrajectoriesService.d.ts +1 -0
- package/packages/typescript/src/features/trajectories/TrajectoriesService.d.ts.map +1 -1
- package/packages/typescript/src/features/trajectories/TrajectoriesService.js +21 -2
- package/packages/typescript/src/features/trust/providers/settings.d.ts.map +1 -1
- package/packages/typescript/src/features/trust/providers/settings.js +11 -1
- package/packages/typescript/src/prompts.d.ts +4 -4
- package/packages/typescript/src/prompts.d.ts.map +1 -1
- package/packages/typescript/src/prompts.js +10 -2
- package/packages/typescript/src/schemas/character.d.ts +3 -3
- package/packages/typescript/src/services/message.d.ts +1 -0
- package/packages/typescript/src/services/message.d.ts.map +1 -1
- package/packages/typescript/src/services/message.js +483 -18
- package/packages/typescript/src/types/components.d.ts +6 -0
- package/packages/typescript/src/types/components.d.ts.map +1 -1
- package/packages/typescript/src/utils/context-routing.d.ts.map +1 -1
- package/packages/typescript/src/utils/context-routing.js +5 -1
- package/packages/typescript/src/utils/toon.d.ts.map +1 -1
- package/packages/typescript/src/utils/toon.js +23 -2
- package/packages/typescript/src/utils.d.ts +1 -0
- package/packages/typescript/src/utils.d.ts.map +1 -1
- package/packages/typescript/src/utils.js +1 -0
- package/apps/app-lifeops/src/types/app-blocker-settings-card.d.ts +0 -2
- package/apps/app-lifeops/src/types/app-blocker-settings-card.d.ts.map +0 -1
- package/apps/app-lifeops/src/types/index.d.ts +0 -3
- package/apps/app-lifeops/src/types/index.d.ts.map +0 -1
- package/apps/app-lifeops/src/types/index.js +0 -1
- package/apps/app-lifeops/src/types/website-blocker-settings-card.d.ts +0 -2
- package/apps/app-lifeops/src/types/website-blocker-settings-card.d.ts.map +0 -1
- package/apps/app-lifeops/src/types/website-blocker-settings-card.js +0 -1
- /package/apps/app-lifeops/src/{types/app-blocker-settings-card.js → lifeops/subscriptions-types.js} +0 -0
|
@@ -13,7 +13,7 @@ import { EventType } from "../types/events";
|
|
|
13
13
|
import { ModelType } from "../types/model";
|
|
14
14
|
import { incomingPipelineHookContext, modelStreamChunkPipelineHookContext, outgoingPipelineHookContext, parallelWithShouldRespondPipelineHookContext, preShouldRespondPipelineHookContext, } from "../types/pipeline-hooks";
|
|
15
15
|
import { asUUID, ChannelType, ContentType } from "../types/primitives";
|
|
16
|
-
import { composePromptFromState, getLocalServerUrl, parseBooleanFromText, parseKeyValueXml, truncateToCompleteSentence, } from "../utils";
|
|
16
|
+
import { composePromptFromState, getLocalServerUrl, parseBooleanFromText, parseJSONObjectFromText, parseKeyValueXml, truncateToCompleteSentence, } from "../utils";
|
|
17
17
|
import { AVAILABLE_CONTEXTS_STATE_KEY, attachAvailableContexts, CONTEXT_ROUTING_STATE_KEY, mergeContextRouting, parseContextRoutingMetadata, setContextRoutingMetadata, } from "../utils/context-routing";
|
|
18
18
|
import { createStreamingContext, MarkableExtractor, ResponseStreamExtractor, } from "../utils/streaming";
|
|
19
19
|
import { extractFirstSentence, hasFirstSentence, } from "../utils/text-splitting";
|
|
@@ -28,6 +28,7 @@ export const RESERVED_XML_KEYS = new Set([
|
|
|
28
28
|
"simple",
|
|
29
29
|
"providers",
|
|
30
30
|
]);
|
|
31
|
+
const PLANNER_CONTROL_ACTIONS = new Set(["REPLY", "RESPOND", "IGNORE", "STOP"].map(normalizeActionIdentifier));
|
|
31
32
|
function escapeRegex(value) {
|
|
32
33
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33
34
|
}
|
|
@@ -197,12 +198,157 @@ function normalizePlannerActions(parsedXml, runtime) {
|
|
|
197
198
|
const finalActions = !runtime.isActionPlanningEnabled() && normalizedActions.length > 1
|
|
198
199
|
? [normalizedActions[0]]
|
|
199
200
|
: normalizedActions;
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
const actionLookup = buildRuntimeActionLookup(runtime);
|
|
202
|
+
const validActions = finalActions.filter((actionName) => {
|
|
203
|
+
const normalized = normalizeActionIdentifier(actionName);
|
|
204
|
+
if (!normalized) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
if (PLANNER_CONTROL_ACTIONS.has(normalized)) {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
const resolvedAction = resolveRuntimeAction(actionLookup, actionName);
|
|
211
|
+
if (resolvedAction) {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
runtime.logger.warn({
|
|
215
|
+
src: "service:message",
|
|
216
|
+
actionName,
|
|
217
|
+
}, "Dropping unknown planner action");
|
|
218
|
+
return false;
|
|
219
|
+
});
|
|
220
|
+
if (validActions.length > 0) {
|
|
221
|
+
return validActions;
|
|
202
222
|
}
|
|
203
223
|
const replyText = typeof parsedXml.text === "string" ? parsedXml.text.trim() : "";
|
|
204
224
|
return replyText.length > 0 ? ["REPLY"] : ["IGNORE"];
|
|
205
225
|
}
|
|
226
|
+
function normalizePlannerProviders(parsedXml, runtime) {
|
|
227
|
+
const rawProviders = parsedXml.providers;
|
|
228
|
+
const providerNames = (() => {
|
|
229
|
+
if (typeof rawProviders === "string") {
|
|
230
|
+
const trimmedProviders = rawProviders.trim();
|
|
231
|
+
if ((trimmedProviders.startsWith("[") && trimmedProviders.endsWith("]")) ||
|
|
232
|
+
(trimmedProviders.startsWith("{") && trimmedProviders.endsWith("}"))) {
|
|
233
|
+
try {
|
|
234
|
+
const parsedJson = JSON.parse(trimmedProviders);
|
|
235
|
+
if (Array.isArray(parsedJson)) {
|
|
236
|
+
return parsedJson
|
|
237
|
+
.map((providerName) => String(providerName).trim())
|
|
238
|
+
.filter((providerName) => providerName.length > 0);
|
|
239
|
+
}
|
|
240
|
+
if (typeof parsedJson === "object" &&
|
|
241
|
+
parsedJson !== null &&
|
|
242
|
+
Array.isArray(parsedJson.providers)) {
|
|
243
|
+
return (parsedJson.providers
|
|
244
|
+
.map((providerName) => String(providerName).trim())
|
|
245
|
+
.filter((providerName) => providerName.length > 0));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
// Fall through to XML/comma parsing below.
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (rawProviders.includes("<provider>") ||
|
|
253
|
+
rawProviders.includes("<provider ")) {
|
|
254
|
+
const providers = Array.from(rawProviders.matchAll(/<provider>([\s\S]*?)<\/provider>/g))
|
|
255
|
+
.map((match) => match[1]?.trim() ?? "")
|
|
256
|
+
.filter((providerName) => providerName.length > 0);
|
|
257
|
+
if (providers.length > 0) {
|
|
258
|
+
return providers;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return rawProviders
|
|
262
|
+
.split(/[\n,;]/)
|
|
263
|
+
.map((providerName) => providerName.replace(/^[\s"'[\](){}]+|[\s"'[\](){}]+$/g, ""))
|
|
264
|
+
.map((providerName) => providerName.trim())
|
|
265
|
+
.filter((providerName) => providerName.length > 0);
|
|
266
|
+
}
|
|
267
|
+
if (Array.isArray(rawProviders)) {
|
|
268
|
+
return rawProviders
|
|
269
|
+
.map((providerName) => String(providerName).trim())
|
|
270
|
+
.filter((providerName) => providerName.length > 0);
|
|
271
|
+
}
|
|
272
|
+
return [];
|
|
273
|
+
})();
|
|
274
|
+
if (!runtime) {
|
|
275
|
+
return providerNames;
|
|
276
|
+
}
|
|
277
|
+
const providerLookup = new Map();
|
|
278
|
+
for (const provider of runtime.providers ?? []) {
|
|
279
|
+
const normalized = normalizeActionIdentifier(provider.name);
|
|
280
|
+
if (!normalized || providerLookup.has(normalized)) {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
providerLookup.set(normalized, provider.name);
|
|
284
|
+
}
|
|
285
|
+
const normalizedProviders = providerNames
|
|
286
|
+
.map((providerName) => {
|
|
287
|
+
const canonicalProvider = providerLookup.get(normalizeActionIdentifier(providerName));
|
|
288
|
+
if (canonicalProvider) {
|
|
289
|
+
return canonicalProvider;
|
|
290
|
+
}
|
|
291
|
+
runtime.logger.warn({
|
|
292
|
+
src: "service:message",
|
|
293
|
+
providerName,
|
|
294
|
+
}, "Dropping unknown planner provider");
|
|
295
|
+
return "";
|
|
296
|
+
})
|
|
297
|
+
.filter((providerName) => providerName.length > 0);
|
|
298
|
+
if (normalizedProviders.length === 0) {
|
|
299
|
+
return normalizedProviders;
|
|
300
|
+
}
|
|
301
|
+
const providerDefinitions = new Map((runtime.providers ?? []).map((provider) => [
|
|
302
|
+
normalizeActionIdentifier(provider.name),
|
|
303
|
+
provider,
|
|
304
|
+
]));
|
|
305
|
+
const expandedProviders = [...normalizedProviders];
|
|
306
|
+
const seenProviders = new Set(expandedProviders.map((providerName) => normalizeActionIdentifier(providerName)));
|
|
307
|
+
for (let index = 0; index < expandedProviders.length; index += 1) {
|
|
308
|
+
const providerName = expandedProviders[index];
|
|
309
|
+
const providerDefinition = providerDefinitions.get(normalizeActionIdentifier(providerName));
|
|
310
|
+
const companionProviders = providerDefinition?.companionProviders ?? [];
|
|
311
|
+
for (const companionProvider of companionProviders) {
|
|
312
|
+
const canonicalCompanion = providerLookup.get(normalizeActionIdentifier(companionProvider));
|
|
313
|
+
if (!canonicalCompanion) {
|
|
314
|
+
runtime.logger.warn({
|
|
315
|
+
src: "service:message",
|
|
316
|
+
providerName,
|
|
317
|
+
companionProvider,
|
|
318
|
+
}, "Dropping unknown companion provider");
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
const normalizedCompanion = normalizeActionIdentifier(canonicalCompanion);
|
|
322
|
+
if (seenProviders.has(normalizedCompanion)) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
seenProviders.add(normalizedCompanion);
|
|
326
|
+
expandedProviders.push(canonicalCompanion);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return expandedProviders;
|
|
330
|
+
}
|
|
331
|
+
const CORE_RESPONSE_STATE_PROVIDERS = [
|
|
332
|
+
"ENTITIES",
|
|
333
|
+
"CHARACTER",
|
|
334
|
+
"RECENT_MESSAGES",
|
|
335
|
+
"ACTIONS",
|
|
336
|
+
"PROVIDERS",
|
|
337
|
+
];
|
|
338
|
+
const STRUCTURED_RESPONSE_STATE_PROVIDERS = ["ACTIONS", "PROVIDERS"];
|
|
339
|
+
const FOCUSED_PROVIDER_REPLY_STATE_PROVIDERS = ["CHARACTER", "RECENT_MESSAGES"];
|
|
340
|
+
function composeResponseState(runtime, message, skipCache = false) {
|
|
341
|
+
return runtime.composeState(message, CORE_RESPONSE_STATE_PROVIDERS, true, skipCache);
|
|
342
|
+
}
|
|
343
|
+
function composeStructuredResponseState(runtime, message, skipCache = false) {
|
|
344
|
+
return runtime.composeState(message, STRUCTURED_RESPONSE_STATE_PROVIDERS, false, skipCache);
|
|
345
|
+
}
|
|
346
|
+
function composeProviderGroundedResponseState(runtime, message, providers, skipCache = false) {
|
|
347
|
+
return runtime.composeState(message, [...CORE_RESPONSE_STATE_PROVIDERS, ...providers], false, skipCache);
|
|
348
|
+
}
|
|
349
|
+
function composeFocusedProviderReplyState(runtime, message, providers, skipCache = false) {
|
|
350
|
+
return runtime.composeState(message, [...FOCUSED_PROVIDER_REPLY_STATE_PROVIDERS, ...providers], true, skipCache);
|
|
351
|
+
}
|
|
206
352
|
/**
|
|
207
353
|
* Escape Handlebars syntax in a string to prevent template injection.
|
|
208
354
|
*
|
|
@@ -334,6 +480,193 @@ function isStopResponse(responseContent) {
|
|
|
334
480
|
function normalizeActionIdentifier(actionName) {
|
|
335
481
|
return actionName.trim().toUpperCase().replace(/_/g, "");
|
|
336
482
|
}
|
|
483
|
+
const PROVIDER_FOLLOWUP_PASSIVE_ACTIONS = new Set(["REPLY", "RESPOND", "NONE"].map(normalizeActionIdentifier));
|
|
484
|
+
function shouldRunProviderFollowup(responseContent) {
|
|
485
|
+
if (!responseContent?.providers?.length) {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
const normalizedActions = (responseContent.actions ?? [])
|
|
489
|
+
.map((actionName) => typeof actionName === "string"
|
|
490
|
+
? normalizeActionIdentifier(actionName)
|
|
491
|
+
: "")
|
|
492
|
+
.filter((actionName) => actionName.length > 0);
|
|
493
|
+
if (normalizedActions.length === 0) {
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
return normalizedActions.every((actionName) => PROVIDER_FOLLOWUP_PASSIVE_ACTIONS.has(actionName));
|
|
497
|
+
}
|
|
498
|
+
function buildProviderFollowupPrompt(basePrompt) {
|
|
499
|
+
return `${basePrompt}
|
|
500
|
+
|
|
501
|
+
[PROVIDER FOLLOW-UP]
|
|
502
|
+
The requested providers have already been executed, and their grounded results are now present in context above.
|
|
503
|
+
Use those provider results to produce the final reply and/or action plan for this turn.
|
|
504
|
+
Do not ask for the same providers again.
|
|
505
|
+
If the provider results fully answer the user, reply directly.
|
|
506
|
+
If KNOWLEDGE contains a direct answer, prefer that grounded answer even when AVAILABLE_DOCUMENTS lists multiple files.
|
|
507
|
+
Do not ask "which file?" when the grounded KNOWLEDGE result already resolves the request.`;
|
|
508
|
+
}
|
|
509
|
+
function shouldAttemptProviderRescue(responseContent) {
|
|
510
|
+
if (!responseContent) {
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
if ((responseContent.providers?.length ?? 0) > 0) {
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
const normalizedActions = (responseContent.actions ?? [])
|
|
517
|
+
.map((actionName) => typeof actionName === "string"
|
|
518
|
+
? normalizeActionIdentifier(actionName)
|
|
519
|
+
: "")
|
|
520
|
+
.filter((actionName) => actionName.length > 0);
|
|
521
|
+
if (normalizedActions.length === 0) {
|
|
522
|
+
return true;
|
|
523
|
+
}
|
|
524
|
+
return normalizedActions.every((actionName) => PROVIDER_FOLLOWUP_PASSIVE_ACTIONS.has(actionName));
|
|
525
|
+
}
|
|
526
|
+
function buildProviderSelectionPrompt(draftReply) {
|
|
527
|
+
const trimmedDraftReply = draftReply?.trim() ?? "";
|
|
528
|
+
const draftReplySection = trimmedDraftReply.length > 0
|
|
529
|
+
? `draft_reply:\n${trimmedDraftReply.replace(/<\/response>/gi, "<\\/response>")}\n\n`
|
|
530
|
+
: "";
|
|
531
|
+
const draftReplyRules = trimmedDraftReply.length > 0
|
|
532
|
+
? [
|
|
533
|
+
"- if the draft reply asks the user to resend, restate, or clarify information that may already exist in provider context, choose the relevant providers instead of sending the draft reply as-is",
|
|
534
|
+
'- when the recent conversation already identifies a prior upload or knowledge-base question, prefer grounded provider lookup over asking "which file?" again',
|
|
535
|
+
]
|
|
536
|
+
: [];
|
|
537
|
+
return `task: Decide whether any providers should be called before sending the assistant's reply.
|
|
538
|
+
|
|
539
|
+
available provider catalog:
|
|
540
|
+
{{providers}}
|
|
541
|
+
|
|
542
|
+
recent conversation:
|
|
543
|
+
{{recentMessages}}
|
|
544
|
+
|
|
545
|
+
${draftReplySection}rules[${4 + draftReplyRules.length}]:
|
|
546
|
+
- choose providers only when they can supply grounded information needed before the assistant replies
|
|
547
|
+
- uploaded files, documents, prior uploads, and knowledge-base questions should use the relevant providers before asking the user to resend the material
|
|
548
|
+
- if the user asks about an uploaded file or document and AVAILABLE_DOCUMENTS is available, prefer AVAILABLE_DOCUMENTS together with KNOWLEDGE before sending any clarification reply
|
|
549
|
+
- return an empty providers field when no provider lookup is needed
|
|
550
|
+
- do not include actions, text, or thought in the output
|
|
551
|
+
${draftReplyRules.join("\n")}
|
|
552
|
+
|
|
553
|
+
output:
|
|
554
|
+
Return JSON or XML containing only provider names. No prose before or after it. No <think>.
|
|
555
|
+
|
|
556
|
+
Examples:
|
|
557
|
+
- user asks: "what is the qa codeword from the uploaded file?"
|
|
558
|
+
draft reply: "Which file are you referring to?"
|
|
559
|
+
output: {"providers":["AVAILABLE_DOCUMENTS","KNOWLEDGE"]}
|
|
560
|
+
- user asks: "what is the qa codeword from the uploaded file?"
|
|
561
|
+
draft reply: "I don't have the file in my context. Which file contains the QA codeword?"
|
|
562
|
+
output: {"providers":["AVAILABLE_DOCUMENTS","KNOWLEDGE"]}
|
|
563
|
+
- user asks: "thanks, that's all"
|
|
564
|
+
draft reply: "Glad to help."
|
|
565
|
+
output: {"providers":[]}`;
|
|
566
|
+
}
|
|
567
|
+
async function recoverProvidersForTurn(args) {
|
|
568
|
+
const prompt = composePromptFromState({
|
|
569
|
+
state: args.state,
|
|
570
|
+
template: buildProviderSelectionPrompt(args.draftReply),
|
|
571
|
+
});
|
|
572
|
+
try {
|
|
573
|
+
const result = await args.runtime.useModel(ModelType.TEXT_LARGE, {
|
|
574
|
+
prompt,
|
|
575
|
+
...(args.attachments ? { attachments: args.attachments } : {}),
|
|
576
|
+
});
|
|
577
|
+
const rawResponse = typeof result === "string" ? result : "";
|
|
578
|
+
const parsed = parseKeyValueXml(rawResponse) ??
|
|
579
|
+
parseJSONObjectFromText(rawResponse);
|
|
580
|
+
const normalizedProviders = normalizePlannerProviders(parsed ?? { providers: rawResponse }, args.runtime);
|
|
581
|
+
if (normalizedProviders.length > 0) {
|
|
582
|
+
return normalizedProviders;
|
|
583
|
+
}
|
|
584
|
+
const shouldUseKnowledge = await shouldUseKnowledgeProviders(args.runtime, args.state, args.attachments);
|
|
585
|
+
return shouldUseKnowledge ? ["AVAILABLE_DOCUMENTS", "KNOWLEDGE"] : [];
|
|
586
|
+
}
|
|
587
|
+
catch (error) {
|
|
588
|
+
args.runtime.logger.warn({
|
|
589
|
+
src: "service:message",
|
|
590
|
+
error: error instanceof Error ? error.message : String(error),
|
|
591
|
+
}, "Provider rescue model call failed");
|
|
592
|
+
return [];
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
function buildGroundedFallbackReplyPrompt() {
|
|
596
|
+
return `task: Write the next assistant reply using grounded context.
|
|
597
|
+
|
|
598
|
+
grounded context:
|
|
599
|
+
{{providers}}
|
|
600
|
+
|
|
601
|
+
recent conversation:
|
|
602
|
+
{{recentMessages}}
|
|
603
|
+
|
|
604
|
+
rules[5]:
|
|
605
|
+
- answer directly from grounded context when it fully answers the user
|
|
606
|
+
- do not ask the user to resend, rename, or specify a file if grounded document or knowledge context already answers the request
|
|
607
|
+
- do not say you cannot access the file when grounded context is already present above
|
|
608
|
+
- if KNOWLEDGE contains a direct answer, prefer that grounded answer even when AVAILABLE_DOCUMENTS lists multiple files
|
|
609
|
+
- if grounded context is still insufficient, say exactly what is missing
|
|
610
|
+
- return only the reply text
|
|
611
|
+
|
|
612
|
+
output:
|
|
613
|
+
Plain text only. No XML, JSON, TOON, bullets, or <think>.`;
|
|
614
|
+
}
|
|
615
|
+
function buildKnowledgeProviderDecisionPrompt() {
|
|
616
|
+
return `task: Decide whether the assistant should consult uploaded-document or knowledge providers before replying.
|
|
617
|
+
|
|
618
|
+
available provider catalog:
|
|
619
|
+
{{providers}}
|
|
620
|
+
|
|
621
|
+
recent conversation:
|
|
622
|
+
{{recentMessages}}
|
|
623
|
+
|
|
624
|
+
rules[5]:
|
|
625
|
+
- return true when the user is asking about an uploaded file, document, prior upload, or knowledge-base content
|
|
626
|
+
- return true when the answer is likely already stored in uploaded documents or semantic knowledge search
|
|
627
|
+
- when AVAILABLE_DOCUMENTS or KNOWLEDGE is available and the user refers to an uploaded file or prior upload, return true
|
|
628
|
+
- return false for generic chat, thanks, or requests that clearly do not depend on uploaded or knowledge-base content
|
|
629
|
+
- return only the structured output, with no prose
|
|
630
|
+
|
|
631
|
+
output:
|
|
632
|
+
Return JSON or XML only.
|
|
633
|
+
|
|
634
|
+
Examples:
|
|
635
|
+
- user asks: "what is the qa codeword from the uploaded file?" -> {"useKnowledgeProviders":true}
|
|
636
|
+
- user asks: "thanks, that's all" -> {"useKnowledgeProviders":false}`;
|
|
637
|
+
}
|
|
638
|
+
async function shouldUseKnowledgeProviders(runtime, state, attachments) {
|
|
639
|
+
const prompt = composePromptFromState({
|
|
640
|
+
state,
|
|
641
|
+
template: buildKnowledgeProviderDecisionPrompt(),
|
|
642
|
+
});
|
|
643
|
+
try {
|
|
644
|
+
const result = await runtime.useModel(ModelType.TEXT_LARGE, {
|
|
645
|
+
prompt,
|
|
646
|
+
...(attachments ? { attachments } : {}),
|
|
647
|
+
});
|
|
648
|
+
const rawResponse = typeof result === "string" ? result : "";
|
|
649
|
+
const parsed = parseKeyValueXml(rawResponse) ??
|
|
650
|
+
parseJSONObjectFromText(rawResponse);
|
|
651
|
+
const value = parsed?.useKnowledgeProviders ??
|
|
652
|
+
parsed?.use_knowledge_providers ??
|
|
653
|
+
rawResponse;
|
|
654
|
+
if (typeof value === "boolean") {
|
|
655
|
+
return value;
|
|
656
|
+
}
|
|
657
|
+
if (typeof value === "string") {
|
|
658
|
+
return value.trim().toLowerCase() === "true";
|
|
659
|
+
}
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
catch (error) {
|
|
663
|
+
runtime.logger.warn({
|
|
664
|
+
src: "service:message",
|
|
665
|
+
error: error instanceof Error ? error.message : String(error),
|
|
666
|
+
}, "Knowledge provider decision model call failed");
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
337
670
|
function buildRuntimeActionLookup(runtime) {
|
|
338
671
|
const actionMap = new Map();
|
|
339
672
|
for (const action of runtime.actions ?? []) {
|
|
@@ -728,6 +1061,16 @@ function prepareShouldRespondState(state) {
|
|
|
728
1061
|
text: providersText,
|
|
729
1062
|
};
|
|
730
1063
|
}
|
|
1064
|
+
function isBenchmarkMode(state) {
|
|
1065
|
+
const benchmarkFlag = state.values?.benchmark_has_context;
|
|
1066
|
+
if (typeof benchmarkFlag === "boolean") {
|
|
1067
|
+
return benchmarkFlag;
|
|
1068
|
+
}
|
|
1069
|
+
if (typeof benchmarkFlag === "string") {
|
|
1070
|
+
return parseBooleanFromText(benchmarkFlag);
|
|
1071
|
+
}
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
731
1074
|
/**
|
|
732
1075
|
* Default implementation of the MessageService interface.
|
|
733
1076
|
* This service handles the complete message processing pipeline including:
|
|
@@ -1322,7 +1665,7 @@ export class DefaultMessageService {
|
|
|
1322
1665
|
}
|
|
1323
1666
|
const promptAttachments = resolvePromptAttachments(message.content.attachments);
|
|
1324
1667
|
// Compose initial state (after incoming hooks so providers/actions text matches this turn)
|
|
1325
|
-
let state = await runtime
|
|
1668
|
+
let state = await composeResponseState(runtime, message);
|
|
1326
1669
|
state = attachAvailableContexts(state, runtime);
|
|
1327
1670
|
const metadata = typeof message.content.metadata === "object" &&
|
|
1328
1671
|
message.content.metadata !== null
|
|
@@ -1392,7 +1735,7 @@ export class DefaultMessageService {
|
|
|
1392
1735
|
runtime.stateCache.delete(message.id);
|
|
1393
1736
|
runtime.stateCache.delete(`${message.id}_action_results`);
|
|
1394
1737
|
}
|
|
1395
|
-
state = await runtime
|
|
1738
|
+
state = await composeResponseState(runtime, message);
|
|
1396
1739
|
state = attachAvailableContexts(state, runtime);
|
|
1397
1740
|
}
|
|
1398
1741
|
let responseContent = null;
|
|
@@ -1445,8 +1788,44 @@ export class DefaultMessageService {
|
|
|
1445
1788
|
if (responseContent && message.id) {
|
|
1446
1789
|
responseContent.inReplyTo = createUniqueUuid(runtime, message.id);
|
|
1447
1790
|
}
|
|
1791
|
+
const providerStateValues = {
|
|
1792
|
+
[AVAILABLE_CONTEXTS_STATE_KEY]: state.values?.[AVAILABLE_CONTEXTS_STATE_KEY],
|
|
1793
|
+
[CONTEXT_ROUTING_STATE_KEY]: state.values?.[CONTEXT_ROUTING_STATE_KEY],
|
|
1794
|
+
};
|
|
1448
1795
|
if (responseContent?.providers && responseContent.providers.length > 0) {
|
|
1449
|
-
state = await runtime
|
|
1796
|
+
state = withContextRoutingValues(await composeProviderGroundedResponseState(runtime, message, responseContent.providers), providerStateValues);
|
|
1797
|
+
}
|
|
1798
|
+
if (responseContent && shouldRunProviderFollowup(responseContent)) {
|
|
1799
|
+
const providerFollowupState = responseContent.providers && responseContent.providers.length > 0
|
|
1800
|
+
? withContextRoutingValues(await composeFocusedProviderReplyState(runtime, message, responseContent.providers), providerStateValues)
|
|
1801
|
+
: state;
|
|
1802
|
+
runtime.logger.info({
|
|
1803
|
+
src: "service:message",
|
|
1804
|
+
providers: responseContent.providers ?? [],
|
|
1805
|
+
actions: responseContent.actions ?? [],
|
|
1806
|
+
}, "Running provider follow-up pass");
|
|
1807
|
+
const providerContinuation = await this.runSingleShotCore(runtime, message, providerFollowupState, opts, responseId, promptAttachments, {
|
|
1808
|
+
precomposedState: providerFollowupState,
|
|
1809
|
+
failureStage: "answering from requested provider results",
|
|
1810
|
+
providerFollowup: true,
|
|
1811
|
+
});
|
|
1812
|
+
responseContent = providerContinuation.responseContent;
|
|
1813
|
+
responseMessages = providerContinuation.responseMessages;
|
|
1814
|
+
state = providerContinuation.state;
|
|
1815
|
+
mode = providerContinuation.mode;
|
|
1816
|
+
if (responseContent && message.id) {
|
|
1817
|
+
responseContent.inReplyTo = createUniqueUuid(runtime, message.id);
|
|
1818
|
+
}
|
|
1819
|
+
runtime.logger.info({
|
|
1820
|
+
src: "service:message",
|
|
1821
|
+
finalActions: responseContent?.actions ?? [],
|
|
1822
|
+
finalProviders: responseContent?.providers ?? [],
|
|
1823
|
+
hasText: typeof responseContent?.text === "string" &&
|
|
1824
|
+
responseContent.text.length > 0,
|
|
1825
|
+
}, "Provider follow-up pass completed");
|
|
1826
|
+
if (responseContent?.providers && responseContent.providers.length > 0) {
|
|
1827
|
+
state = withContextRoutingValues(await runtime.composeState(message, responseContent.providers, false, false), providerStateValues);
|
|
1828
|
+
}
|
|
1450
1829
|
}
|
|
1451
1830
|
// Save response memory to database.
|
|
1452
1831
|
// - simple mode: persists after hooks in the branch below.
|
|
@@ -1623,7 +2002,9 @@ export class DefaultMessageService {
|
|
|
1623
2002
|
return [];
|
|
1624
2003
|
}, responseMessages);
|
|
1625
2004
|
await runEvaluate();
|
|
1626
|
-
if (opts.continueAfterActions &&
|
|
2005
|
+
if (opts.continueAfterActions &&
|
|
2006
|
+
message.id &&
|
|
2007
|
+
!isBenchmarkMode(state)) {
|
|
1627
2008
|
const taskCompletion = await runtime.getCache(getTaskCompletionCacheKey(message.id));
|
|
1628
2009
|
await runtime.deleteCache(getTaskCompletionCacheKey(message.id));
|
|
1629
2010
|
if (taskCompletion?.assessed &&
|
|
@@ -1935,7 +2316,6 @@ export class DefaultMessageService {
|
|
|
1935
2316
|
shouldRespond: false,
|
|
1936
2317
|
skipEvaluation: true,
|
|
1937
2318
|
reason: "no room context",
|
|
1938
|
-
primaryContext: "general",
|
|
1939
2319
|
};
|
|
1940
2320
|
}
|
|
1941
2321
|
function normalizeEnvList(value) {
|
|
@@ -1976,7 +2356,6 @@ export class DefaultMessageService {
|
|
|
1976
2356
|
shouldRespond: true,
|
|
1977
2357
|
skipEvaluation: true,
|
|
1978
2358
|
reason: `private channel: ${roomType}`,
|
|
1979
|
-
primaryContext: "general",
|
|
1980
2359
|
};
|
|
1981
2360
|
}
|
|
1982
2361
|
// 2. Specific sources (e.g., client_chat): always respond
|
|
@@ -1985,7 +2364,6 @@ export class DefaultMessageService {
|
|
|
1985
2364
|
shouldRespond: true,
|
|
1986
2365
|
skipEvaluation: true,
|
|
1987
2366
|
reason: `whitelisted source: ${sourceStr}`,
|
|
1988
|
-
primaryContext: "general",
|
|
1989
2367
|
};
|
|
1990
2368
|
}
|
|
1991
2369
|
// 3. Platform mentions and replies: always respond
|
|
@@ -1996,7 +2374,6 @@ export class DefaultMessageService {
|
|
|
1996
2374
|
shouldRespond: true,
|
|
1997
2375
|
skipEvaluation: true,
|
|
1998
2376
|
reason: `platform ${mentionType}`,
|
|
1999
|
-
primaryContext: "general",
|
|
2000
2377
|
};
|
|
2001
2378
|
}
|
|
2002
2379
|
// 4. Mixed-address messages should still reach the agent when the text
|
|
@@ -2006,7 +2383,6 @@ export class DefaultMessageService {
|
|
|
2006
2383
|
shouldRespond: true,
|
|
2007
2384
|
skipEvaluation: true,
|
|
2008
2385
|
reason: "text address with tagged participants",
|
|
2009
|
-
primaryContext: "general",
|
|
2010
2386
|
};
|
|
2011
2387
|
}
|
|
2012
2388
|
// 5. Clear self-modification requests should bypass the ignore-biased
|
|
@@ -2262,7 +2638,7 @@ export class DefaultMessageService {
|
|
|
2262
2638
|
responseContent.inReplyTo = createUniqueUuid(runtime, message.id);
|
|
2263
2639
|
}
|
|
2264
2640
|
if (responseContent.providers && responseContent.providers.length > 0) {
|
|
2265
|
-
accumulatedState = withActionResults(withContextRoutingValues(await runtime
|
|
2641
|
+
accumulatedState = withActionResults(withContextRoutingValues(await composeProviderGroundedResponseState(runtime, message, responseContent.providers), contextRoutingStateValues), traceActionResults);
|
|
2266
2642
|
}
|
|
2267
2643
|
else {
|
|
2268
2644
|
accumulatedState = withActionResults(continuation.state, traceActionResults);
|
|
@@ -2359,7 +2735,7 @@ export class DefaultMessageService {
|
|
|
2359
2735
|
responseContent.inReplyTo = createUniqueUuid(runtime, message.id);
|
|
2360
2736
|
}
|
|
2361
2737
|
if (responseContent.providers && responseContent.providers.length > 0) {
|
|
2362
|
-
accumulatedState = withTaskCompletion(withActionResults(withContextRoutingValues(await runtime
|
|
2738
|
+
accumulatedState = withTaskCompletion(withActionResults(withContextRoutingValues(await composeProviderGroundedResponseState(runtime, message, responseContent.providers), contextRoutingStateValues), initialActionResults), taskCompletion);
|
|
2363
2739
|
}
|
|
2364
2740
|
else {
|
|
2365
2741
|
accumulatedState = withTaskCompletion(withActionResults(continuation.state, initialActionResults), taskCompletion);
|
|
@@ -2439,7 +2815,7 @@ export class DefaultMessageService {
|
|
|
2439
2815
|
async runSingleShotCore(runtime, message, state, opts, responseId, promptAttachments, overrides) {
|
|
2440
2816
|
state =
|
|
2441
2817
|
overrides?.precomposedState ??
|
|
2442
|
-
(await runtime
|
|
2818
|
+
(await composeStructuredResponseState(runtime, message));
|
|
2443
2819
|
if (!state.values?.actionNames) {
|
|
2444
2820
|
runtime.logger.warn({ src: "service:message" }, "actionNames data missing from state");
|
|
2445
2821
|
}
|
|
@@ -2456,8 +2832,11 @@ export class DefaultMessageService {
|
|
|
2456
2832
|
const optimizedResponseService = runtime.getService(OPTIMIZED_PROMPT_SERVICE);
|
|
2457
2833
|
const baselineResponseTemplate = runtime.character.templates?.messageHandlerTemplate ||
|
|
2458
2834
|
messageHandlerTemplate;
|
|
2459
|
-
|
|
2835
|
+
let prompt = overrides?.prompt ||
|
|
2460
2836
|
resolveOptimizedPrompt(optimizedResponseService, "response", baselineResponseTemplate);
|
|
2837
|
+
if (overrides?.providerFollowup) {
|
|
2838
|
+
prompt = buildProviderFollowupPrompt(prompt);
|
|
2839
|
+
}
|
|
2461
2840
|
// Use dynamicPromptExecFromState for structured output with validation
|
|
2462
2841
|
setTrajectoryPurpose("response");
|
|
2463
2842
|
const parsedXml = await runtime.dynamicPromptExecFromState({
|
|
@@ -2484,6 +2863,13 @@ export class DefaultMessageService {
|
|
|
2484
2863
|
validateField: false,
|
|
2485
2864
|
streamField: false,
|
|
2486
2865
|
},
|
|
2866
|
+
{
|
|
2867
|
+
field: "providers",
|
|
2868
|
+
description: "Optional provider names to call before the final reply or action. Use an empty field when no provider lookup is needed.",
|
|
2869
|
+
required: false,
|
|
2870
|
+
validateField: false,
|
|
2871
|
+
streamField: false,
|
|
2872
|
+
},
|
|
2487
2873
|
// WHY streamField: true? This is the user-facing output - stream it!
|
|
2488
2874
|
// WHY validateField default? At level 1, we want to validate text integrity
|
|
2489
2875
|
{
|
|
@@ -2515,7 +2901,7 @@ export class DefaultMessageService {
|
|
|
2515
2901
|
...parsedXml,
|
|
2516
2902
|
thought: String(parsedXml.thought || ""),
|
|
2517
2903
|
actions: finalActions,
|
|
2518
|
-
providers:
|
|
2904
|
+
providers: normalizePlannerProviders(parsedXml, runtime),
|
|
2519
2905
|
text: String(parsedXml.text || ""),
|
|
2520
2906
|
simple: parsedXml.simple === true || parsedXml.simple === "true",
|
|
2521
2907
|
};
|
|
@@ -2590,6 +2976,10 @@ Output ONLY the continuation, starting immediately after the last character abov
|
|
|
2590
2976
|
}
|
|
2591
2977
|
else {
|
|
2592
2978
|
runtime.logger.warn({ src: "service:message" }, "dynamicPromptExecFromState returned null");
|
|
2979
|
+
const groundedFallback = await this.tryGroundedFallbackReply(runtime, message, state, responseId, promptAttachments);
|
|
2980
|
+
if (groundedFallback) {
|
|
2981
|
+
return groundedFallback;
|
|
2982
|
+
}
|
|
2593
2983
|
return await this.buildStructuredFailureReply(runtime, message, state, responseId, overrides?.failureStage ?? "preparing the reply");
|
|
2594
2984
|
}
|
|
2595
2985
|
}
|
|
@@ -2601,6 +2991,23 @@ Output ONLY the continuation, starting immediately after the last character abov
|
|
|
2601
2991
|
mode: "none",
|
|
2602
2992
|
};
|
|
2603
2993
|
}
|
|
2994
|
+
if (!overrides?.providerFollowup &&
|
|
2995
|
+
shouldAttemptProviderRescue(responseContent)) {
|
|
2996
|
+
const rescuedProviders = await recoverProvidersForTurn({
|
|
2997
|
+
runtime,
|
|
2998
|
+
state,
|
|
2999
|
+
draftReply: String(responseContent.text || ""),
|
|
3000
|
+
attachments: promptAttachments,
|
|
3001
|
+
});
|
|
3002
|
+
if (rescuedProviders.length > 0) {
|
|
3003
|
+
runtime.logger.info({
|
|
3004
|
+
src: "service:message",
|
|
3005
|
+
rescuedProviders,
|
|
3006
|
+
originalActions: responseContent.actions ?? [],
|
|
3007
|
+
}, "Selected providers during reply rescue pass");
|
|
3008
|
+
responseContent.providers = rescuedProviders;
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
2604
3011
|
// Action parameter repair (Python parity):
|
|
2605
3012
|
// If the model selected actions with required parameters but omitted <params>,
|
|
2606
3013
|
// do a second pass asking for ONLY a <params> block.
|
|
@@ -2669,8 +3076,8 @@ Output ONLY the continuation, starting immediately after the last character abov
|
|
|
2669
3076
|
responseContent.params = repairParsed.params;
|
|
2670
3077
|
}
|
|
2671
3078
|
}
|
|
3079
|
+
const benchmarkMode = isBenchmarkMode(state);
|
|
2672
3080
|
// Benchmark mode (Python parity): force action-based loop when benchmark context is present.
|
|
2673
|
-
const benchmarkMode = state.values.benchmark_has_context === true;
|
|
2674
3081
|
if (benchmarkMode) {
|
|
2675
3082
|
if (!responseContent.actions || responseContent.actions.length === 0) {
|
|
2676
3083
|
responseContent.actions = ["REPLY"];
|
|
@@ -2731,6 +3138,64 @@ Output ONLY the continuation, starting immediately after the last character abov
|
|
|
2731
3138
|
: "actions",
|
|
2732
3139
|
};
|
|
2733
3140
|
}
|
|
3141
|
+
async tryGroundedFallbackReply(runtime, message, state, responseId, promptAttachments) {
|
|
3142
|
+
let groundedState = state;
|
|
3143
|
+
const selectedProviders = await recoverProvidersForTurn({
|
|
3144
|
+
runtime,
|
|
3145
|
+
state,
|
|
3146
|
+
attachments: promptAttachments,
|
|
3147
|
+
});
|
|
3148
|
+
if (selectedProviders.length > 0) {
|
|
3149
|
+
groundedState = await composeFocusedProviderReplyState(runtime, message, selectedProviders);
|
|
3150
|
+
}
|
|
3151
|
+
const prompt = composePromptFromState({
|
|
3152
|
+
state: groundedState,
|
|
3153
|
+
template: buildGroundedFallbackReplyPrompt(),
|
|
3154
|
+
});
|
|
3155
|
+
try {
|
|
3156
|
+
const result = await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
3157
|
+
prompt,
|
|
3158
|
+
...(promptAttachments ? { attachments: promptAttachments } : {}),
|
|
3159
|
+
});
|
|
3160
|
+
const text = typeof result === "string" ? result.trim() : "";
|
|
3161
|
+
if (!text) {
|
|
3162
|
+
return null;
|
|
3163
|
+
}
|
|
3164
|
+
const responseContent = {
|
|
3165
|
+
thought: selectedProviders.length > 0
|
|
3166
|
+
? "Grounded fallback reply from selected providers"
|
|
3167
|
+
: "Grounded fallback reply",
|
|
3168
|
+
actions: ["REPLY"],
|
|
3169
|
+
providers: selectedProviders,
|
|
3170
|
+
text,
|
|
3171
|
+
simple: true,
|
|
3172
|
+
responseId,
|
|
3173
|
+
};
|
|
3174
|
+
const responseMessages = [
|
|
3175
|
+
{
|
|
3176
|
+
id: responseId,
|
|
3177
|
+
entityId: runtime.agentId,
|
|
3178
|
+
agentId: runtime.agentId,
|
|
3179
|
+
content: responseContent,
|
|
3180
|
+
roomId: message.roomId,
|
|
3181
|
+
createdAt: Date.now(),
|
|
3182
|
+
},
|
|
3183
|
+
];
|
|
3184
|
+
return {
|
|
3185
|
+
responseContent,
|
|
3186
|
+
responseMessages,
|
|
3187
|
+
state: groundedState,
|
|
3188
|
+
mode: "simple",
|
|
3189
|
+
};
|
|
3190
|
+
}
|
|
3191
|
+
catch (error) {
|
|
3192
|
+
runtime.logger.warn({
|
|
3193
|
+
src: "service:message",
|
|
3194
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3195
|
+
}, "Grounded fallback reply generation failed");
|
|
3196
|
+
return null;
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
2734
3199
|
async buildStructuredFailureReply(runtime, message, state, responseId, stage) {
|
|
2735
3200
|
const failure = getStructuredOutputFailure(state);
|
|
2736
3201
|
const recentMessages = typeof state.values?.recentMessages === "string" &&
|
|
@@ -246,6 +246,12 @@ export interface Provider {
|
|
|
246
246
|
* include in the planner's state composition for a given turn.
|
|
247
247
|
*/
|
|
248
248
|
contexts?: AgentContext[];
|
|
249
|
+
/**
|
|
250
|
+
* Additional providers that should run alongside this provider when it is
|
|
251
|
+
* selected by the planner. Use this for provider composition, not semantic
|
|
252
|
+
* routing.
|
|
253
|
+
*/
|
|
254
|
+
companionProviders?: string[];
|
|
249
255
|
/** Data retrieval function */
|
|
250
256
|
get: (runtime: IAgentRuntime, message: Memory, state: State) => Promise<ProviderResult>;
|
|
251
257
|
}
|