@elizaos/agent 2.0.0-alpha.197 → 2.0.0-alpha.201

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 (27) hide show
  1. package/apps/app-knowledge/src/routes.d.ts.map +1 -1
  2. package/apps/app-knowledge/src/routes.js +3 -1
  3. package/apps/app-lifeops/src/actions/calendar.d.ts.map +1 -1
  4. package/apps/app-lifeops/src/actions/calendar.js +99 -6
  5. package/apps/app-lifeops/src/actions/device-bus.d.ts.map +1 -1
  6. package/apps/app-lifeops/src/actions/device-bus.js +49 -8
  7. package/apps/app-lifeops/src/actions/health.d.ts.map +1 -1
  8. package/apps/app-lifeops/src/actions/health.js +23 -4
  9. package/apps/app-lifeops/src/actions/life.d.ts.map +1 -1
  10. package/apps/app-lifeops/src/actions/life.js +9 -2
  11. package/apps/app-lifeops/src/actions/password-manager.d.ts.map +1 -1
  12. package/apps/app-lifeops/src/actions/password-manager.js +44 -2
  13. package/apps/app-lifeops/src/actions/remote-desktop.d.ts.map +1 -1
  14. package/apps/app-lifeops/src/actions/remote-desktop.js +41 -2
  15. package/apps/app-lifeops/src/actions/scheduling.d.ts.map +1 -1
  16. package/apps/app-lifeops/src/actions/scheduling.js +13 -5
  17. package/apps/app-lifeops/src/actions/website-blocker.d.ts.map +1 -1
  18. package/apps/app-lifeops/src/actions/website-blocker.js +53 -4
  19. package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-service.d.ts.map +1 -1
  20. package/apps/app-lifeops/src/website-blocker/chat-integration/block-rule-service.js +44 -3
  21. package/apps/app-training/src/optimizers/bootstrap-fewshot.js +2 -3
  22. package/package.json +4 -4
  23. package/packages/agent/src/types/trajectory.d.ts +2 -2
  24. package/packages/agent/src/types/trajectory.d.ts.map +1 -1
  25. package/packages/typescript/src/services/message.d.ts +2 -1
  26. package/packages/typescript/src/services/message.d.ts.map +1 -1
  27. package/packages/typescript/src/services/message.js +105 -22
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../../../../apps/app-knowledge/src/routes.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,eAAe,CAAC;AAahE,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAE1F,MAAM,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAEjD,MAAM,WAAW,qBAAsB,SAAQ,mBAAmB;IAChE,GAAG,EAAE,GAAG,CAAC;IACT,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AA0JD,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AA0GtE,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,eAAe,GAAG,IAAI,GAC3B,IAAI,CAEN;AAsWD,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,qBAAqB,GACzB,OAAO,CAAC,OAAO,CAAC,CAylBlB"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../../../../apps/app-knowledge/src/routes.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,eAAe,CAAC;AAahE,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAE1F,MAAM,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAEjD,MAAM,WAAW,qBAAsB,SAAQ,mBAAmB;IAChE,GAAG,EAAE,GAAG,CAAC;IACT,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAC9B;AA0JD,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AA0GtE,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,eAAe,GAAG,IAAI,GAC3B,IAAI,CAEN;AAsWD,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,qBAAqB,GACzB,OAAO,CAAC,OAAO,CAAC,CA6lBlB"}
@@ -684,7 +684,9 @@ export async function handleKnowledgeRoutes(ctx) {
684
684
  const result = await service.addKnowledge({
685
685
  agentId,
686
686
  worldId: agentId,
687
- roomId: agentId,
687
+ roomId: typeof document.roomId === "string" && document.roomId.trim().length > 0
688
+ ? document.roomId.trim()
689
+ : agentId,
688
690
  entityId: agentId,
689
691
  clientDocumentId: "", // Will be generated
690
692
  contentType,
@@ -1 +1 @@
1
- {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAKN,aAAa,EACb,MAAM,EACN,KAAK,EACN,MAAM,eAAe,CAAC;AAyCvB,KAAK,iBAAiB,GAClB,MAAM,GACN,YAAY,GACZ,eAAe,GACf,cAAc,GACd,cAAc,GACd,cAAc,GACd,aAAa,CAAC;AAuBlB,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAg0CF,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,MAAM,EAAE,MAAM,EACd,QAAQ,SAA2B,GAClC,OAAO,CAAC,eAAe,CAAC,CA6J1B;AAu8BD,eAAO,MAAM,cAAc,EAAE,MAAM,GAAG;IACpC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CA6jC1C,CAAC"}
1
+ {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAKN,aAAa,EACb,MAAM,EACN,KAAK,EACN,MAAM,eAAe,CAAC;AAyCvB,KAAK,iBAAiB,GAClB,MAAM,GACN,YAAY,GACZ,eAAe,GACf,cAAc,GACd,cAAc,GACd,cAAc,GACd,aAAa,CAAC;AAuBlB,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAg0CF,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,MAAM,EAAE,MAAM,EACd,QAAQ,SAA2B,GAClC,OAAO,CAAC,eAAe,CAAC,CA6J1B;AAigCD,eAAO,MAAM,cAAc,EAAE,MAAM,GAAG;IACpC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CA+mC1C,CAAC"}
@@ -3,6 +3,7 @@ import { resolveDefaultTimeZone } from "../lifeops/defaults.js";
3
3
  import { LifeOpsService, LifeOpsServiceError } from "../lifeops/service.js";
4
4
  import { addDaysToLocalDate, buildUtcDateFromLocalParts, getWeekdayForLocalDate, getZonedDateParts, } from "../lifeops/time.js";
5
5
  import { renderGroundedActionReply } from "@elizaos/agent/actions/grounded-action-reply";
6
+ import { recentConversationTexts as collectRecentConversationTexts } from "./life-recent-context.js";
6
7
  import { calendarReadUnavailableMessage, calendarWriteUnavailableMessage, detailArray, detailBoolean, detailNumber, detailString, formatCalendarEventDateTime, formatCalendarFeed, formatNextEventContext, getGoogleCapabilityStatus, hasLifeOpsAccess, INTERNAL_URL, messageText, toActionData, } from "./lifeops-google-helpers.js";
7
8
  import { looksLikeCalendarObservation } from "./non-actionable-request.js";
8
9
  const CALENDAR_SUBACTION_VALUES = [
@@ -1160,6 +1161,52 @@ function resolveCalendarSearchQueries(args) {
1160
1161
  ...(args.fallbackQueries ?? []),
1161
1162
  ]);
1162
1163
  }
1164
+ async function recoverCalendarSearchQueriesWithLlm(args) {
1165
+ const prompt = [
1166
+ "Extract up to 3 short calendar search queries from this request.",
1167
+ "Return ONLY valid JSON with this shape:",
1168
+ ' {"queries":["query one","query two"]}',
1169
+ "",
1170
+ "Rules:",
1171
+ "- Queries should be short people, places, trip labels, flight labels, appointment names, or other event lookup phrases.",
1172
+ "- Do not return generic filler like calendar, event, schedule, search, what, tell me, or do i have.",
1173
+ "- When the user is only asking for the agenda on a date or date range and there is no separate search target, return an empty array.",
1174
+ "- The user may speak in any language.",
1175
+ "",
1176
+ "Examples:",
1177
+ ' "do i have any flights to denver" -> {"queries":["flights to denver","denver"]}',
1178
+ ' "puedes buscar si tengo un vuelo a denver" -> {"queries":["vuelo a denver","denver"]}',
1179
+ ' "what event do i have on March 5" -> {"queries":[]}',
1180
+ "",
1181
+ `Current request: ${JSON.stringify(args.currentMessage)}`,
1182
+ `Resolved intent: ${JSON.stringify(args.intent)}`,
1183
+ `Recent conversation: ${JSON.stringify(args.recentConversation)}`,
1184
+ ].join("\n");
1185
+ try {
1186
+ const result = await args.runtime.useModel(ModelType.TEXT_LARGE, {
1187
+ prompt,
1188
+ });
1189
+ const raw = typeof result === "string" ? result : "";
1190
+ const parsed = parseKeyValueXml(raw) ??
1191
+ parseJSONObjectFromText(raw);
1192
+ if (!parsed) {
1193
+ return [];
1194
+ }
1195
+ const rawQueries = Array.isArray(parsed.queries)
1196
+ ? parsed.queries
1197
+ : typeof parsed.queries === "string"
1198
+ ? parsed.queries.split(/\s*\|\|\s*|,|\n/)
1199
+ : [];
1200
+ return dedupeCalendarQueries(rawQueries.filter((value) => typeof value === "string"));
1201
+ }
1202
+ catch (error) {
1203
+ args.runtime.logger?.warn?.({
1204
+ src: "action:calendar",
1205
+ error: error instanceof Error ? error.message : String(error),
1206
+ }, "Calendar search query recovery model call failed");
1207
+ return [];
1208
+ }
1209
+ }
1163
1210
  function normalizeIsShortPreparationFlag(value) {
1164
1211
  if (typeof value === "boolean")
1165
1212
  return value;
@@ -2474,8 +2521,54 @@ export const calendarAction = {
2474
2521
  ...request,
2475
2522
  });
2476
2523
  if (subaction === "search_events") {
2477
- const query = searchQueries[0];
2478
- if (!query || searchQueries.length === 0) {
2524
+ let queriesForSearch = searchQueries;
2525
+ if (queriesForSearch.length === 0) {
2526
+ const recentConversation = (await collectRecentConversationTexts({
2527
+ runtime,
2528
+ message,
2529
+ state,
2530
+ limit: 8,
2531
+ })).join("\n");
2532
+ queriesForSearch = await recoverCalendarSearchQueriesWithLlm({
2533
+ runtime,
2534
+ currentMessage: messageText(message).trim(),
2535
+ intent,
2536
+ recentConversation,
2537
+ });
2538
+ if (queriesForSearch.length === 0) {
2539
+ const recoveredReadPlan = await disambiguateCalendarReadPlanWithLlm({
2540
+ runtime,
2541
+ currentMessage: messageText(message).trim(),
2542
+ intent,
2543
+ recentConversation,
2544
+ candidateSubaction: "search_events",
2545
+ });
2546
+ if (recoveredReadPlan?.subaction === "feed") {
2547
+ const fallback = formatCalendarFeed(feed, label);
2548
+ return respond({
2549
+ success: true,
2550
+ text: await renderReply("feed_results", fallback, {
2551
+ label,
2552
+ events: feed.events,
2553
+ }),
2554
+ data: toActionData(feed),
2555
+ });
2556
+ }
2557
+ }
2558
+ }
2559
+ const query = queriesForSearch[0];
2560
+ if (!query || queriesForSearch.length === 0) {
2561
+ if (resolveCalendarLlmWindow(llmPlan)) {
2562
+ const fallback = formatCalendarFeed(feed, label);
2563
+ return respond({
2564
+ success: true,
2565
+ text: await renderReply("feed_results", fallback, {
2566
+ label,
2567
+ events: feed.events,
2568
+ }),
2569
+ data: toActionData(feed),
2570
+ });
2571
+ }
2479
2572
  return respond({
2480
2573
  success: false,
2481
2574
  text: await renderReply("clarify_calendar_search", "I couldn't infer what to look for in your calendar yet. Try naming a person, place, trip, or date.", {
@@ -2487,7 +2580,7 @@ export const calendarAction = {
2487
2580
  .map((event) => {
2488
2581
  const matchedQueries = [];
2489
2582
  let score = 0;
2490
- for (const candidateQuery of searchQueries) {
2583
+ for (const candidateQuery of queriesForSearch) {
2491
2584
  const queryScore = scoreCalendarEvent(event, candidateQuery);
2492
2585
  if (queryScore > 0) {
2493
2586
  matchedQueries.push(candidateQuery);
@@ -2512,7 +2605,7 @@ export const calendarAction = {
2512
2605
  .filter((candidate) => candidate.score >= strongestThreshold)
2513
2606
  .map((candidate) => candidate.event);
2514
2607
  if (shouldGroundCalendarSearchWithLlm(query, rankedEvents)) {
2515
- const groundedIds = await groundCalendarSearchMatchesWithLlm(runtime, state, intent, searchQueries, rankedEvents.slice(0, 6));
2608
+ const groundedIds = await groundCalendarSearchMatchesWithLlm(runtime, state, intent, queriesForSearch, rankedEvents.slice(0, 6));
2516
2609
  if (groundedIds) {
2517
2610
  const groundedIdSet = new Set(groundedIds);
2518
2611
  filteredEvents = rankedEvents
@@ -2525,14 +2618,14 @@ export const calendarAction = {
2525
2618
  success: true,
2526
2619
  text: await renderReply("search_results", fallback, {
2527
2620
  query,
2528
- queries: searchQueries,
2621
+ queries: queriesForSearch,
2529
2622
  events: filteredEvents,
2530
2623
  label,
2531
2624
  }),
2532
2625
  data: toActionData({
2533
2626
  ...feed,
2534
2627
  query,
2535
- queries: searchQueries,
2628
+ queries: queriesForSearch,
2536
2629
  events: filteredEvents,
2537
2630
  }),
2538
2631
  });
@@ -1 +1 @@
1
- {"version":3,"file":"device-bus.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/device-bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAMZ,MAAM,eAAe,CAAC;AAgBvB,QAAA,MAAM,WAAW,yCAA0C,CAAC;AAC5D,KAAK,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAQ9C,iBAAS,mBAAmB,CAC1B,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,GAAG,SAAS,GAC7D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAa9C;AAED,iBAAS,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAS1E;AAED,eAAO,MAAM,yBAAyB,EAAE,MAAM,GAAG;IAC/C,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAuN1C,CAAC;AAGF,eAAO,MAAM,UAAU;;;CAGtB,CAAC"}
1
+ {"version":3,"file":"device-bus.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/device-bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAMZ,MAAM,eAAe,CAAC;AAiBvB,QAAA,MAAM,WAAW,yCAA0C,CAAC;AAC5D,KAAK,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AA0D9C,iBAAS,mBAAmB,CAC1B,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,GAAG,SAAS,GAC7D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAa9C;AAED,iBAAS,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAS1E;AAED,eAAO,MAAM,yBAAyB,EAAE,MAAM,GAAG;IAC/C,8BAA8B,CAAC,EAAE,OAAO,CAAC;CA4N1C,CAAC;AAGF,eAAO,MAAM,UAAU;;;CAGtB,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { logger, } from "@elizaos/core";
2
2
  import { hasOwnerAccess } from "@elizaos/agent/security/access";
3
+ import { broadcastIntent } from "../lifeops/intent-sync.js";
3
4
  /**
4
5
  * Cross-device intent bus agent-side action.
5
6
  *
@@ -12,6 +13,40 @@ import { hasOwnerAccess } from "@elizaos/agent/security/access";
12
13
  const DEVICE_BUS_URL_ENV = "MILADY_DEVICE_BUS_URL";
13
14
  const DEVICE_BUS_TOKEN_ENV = "MILADY_DEVICE_BUS_TOKEN";
14
15
  const KNOWN_KINDS = ["alarm", "reminder", "block"];
16
+ function coercePayload(payload) {
17
+ return payload && typeof payload === "object"
18
+ ? payload
19
+ : {};
20
+ }
21
+ function readPayloadString(payload, keys) {
22
+ for (const key of keys) {
23
+ const value = payload[key];
24
+ if (typeof value === "string" && value.trim().length > 0) {
25
+ return value.trim();
26
+ }
27
+ }
28
+ return null;
29
+ }
30
+ function mapLocalIntentKind(kind) {
31
+ return kind === "block" ? "attention_request" : "routine_reminder";
32
+ }
33
+ async function publishLocalFallbackIntent(runtime, kind, payload) {
34
+ const title = readPayloadString(payload, ["title", "label", "subject"]) ??
35
+ `Device ${kind}`;
36
+ const body = readPayloadString(payload, ["body", "message", "text", "description"]) ??
37
+ `Published ${kind} intent for local delivery.`;
38
+ return await broadcastIntent(runtime, {
39
+ kind: mapLocalIntentKind(kind),
40
+ title,
41
+ body,
42
+ priority: kind === "alarm" || kind === "block" ? "high" : "medium",
43
+ metadata: {
44
+ sourceAction: "PUBLISH_DEVICE_INTENT",
45
+ deviceBusKind: kind,
46
+ payload,
47
+ },
48
+ });
49
+ }
15
50
  function readDeviceBusConfig(runtime) {
16
51
  const readString = (key) => {
17
52
  const env = process.env[key]?.trim();
@@ -78,20 +113,26 @@ export const publishDeviceIntentAction = {
78
113
  }
79
114
  const params = options?.parameters ?? {};
80
115
  const kind = normalizeKind(params.kind) ?? "reminder";
81
- const payload = params.payload && typeof params.payload === "object"
82
- ? params.payload
83
- : {};
116
+ const payload = coercePayload(params.payload);
84
117
  const config = readDeviceBusConfig(runtime);
85
118
  if (!config) {
86
- logger.warn({ action: "PUBLISH_DEVICE_INTENT", kind }, "[PUBLISH_DEVICE_INTENT] device bus not configured (set MILADY_DEVICE_BUS_URL)");
119
+ logger.warn({ action: "PUBLISH_DEVICE_INTENT", kind }, "[PUBLISH_DEVICE_INTENT] device bus not configured; falling back to local intent store");
120
+ const localIntent = await publishLocalFallbackIntent(runtime, kind, payload);
87
121
  return {
88
- text: "",
89
- success: false,
90
- values: { success: false, reason: "device-bus-not-configured", kind },
122
+ text: `Queued ${kind} intent locally for device delivery.`,
123
+ success: true,
124
+ values: {
125
+ success: true,
126
+ reason: "device-bus-local-fallback",
127
+ kind,
128
+ intentId: localIntent.id,
129
+ },
91
130
  data: {
92
131
  actionName: "PUBLISH_DEVICE_INTENT",
93
- reason: "device-bus-not-configured",
132
+ reason: "device-bus-local-fallback",
94
133
  kind,
134
+ intentId: localIntent.id,
135
+ transport: "local-fallback",
95
136
  },
96
137
  };
97
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/health.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,MAAM,EAOP,MAAM,eAAe,CAAC;AAqOvB,eAAO,MAAM,YAAY,EAAE,MA8M1B,CAAC"}
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/health.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,MAAM,EAOP,MAAM,eAAe,CAAC;AAqOvB,eAAO,MAAM,YAAY,EAAE,MAmO1B,CAAC"}
@@ -220,13 +220,32 @@ export const healthAction = {
220
220
  }
221
221
  }
222
222
  const service = new LifeOpsService(runtime);
223
+ const connectorStatus = await service.getHealthConnectorStatus();
223
224
  if (subaction === "status") {
224
- const status = await service.getHealthConnectorStatus();
225
- const text = status.available
226
- ? `Health backend available: ${status.backend}.`
225
+ const text = connectorStatus.available
226
+ ? `Health backend available: ${connectorStatus.backend}.`
227
227
  : "No health backend available. Set ELIZA_HEALTHKIT_CLI_PATH or ELIZA_GOOGLE_FIT_ACCESS_TOKEN.";
228
228
  await callback?.({ text, source: "action", action: "HEALTH" });
229
- return { text, success: true, data: { subaction, status } };
229
+ return {
230
+ text,
231
+ success: true,
232
+ data: { subaction, status: connectorStatus },
233
+ };
234
+ }
235
+ // Graceful degradation: if no HealthKit/GoogleFit backend is configured,
236
+ // surface a clear message instead of letting the health bridge throw.
237
+ if (!connectorStatus.available) {
238
+ const text = "I don't have a health data source connected yet. To share daily summaries, trends, or per-metric details, connect Apple Health (ELIZA_HEALTHKIT_CLI_PATH) or Google Fit (ELIZA_GOOGLE_FIT_ACCESS_TOKEN) and I'll pick it up.";
239
+ await callback?.({ text, source: "action", action: "HEALTH" });
240
+ return {
241
+ text,
242
+ success: true,
243
+ data: {
244
+ subaction,
245
+ status: connectorStatus,
246
+ degraded: "no-backend",
247
+ },
248
+ };
230
249
  }
231
250
  if (subaction === "trend") {
232
251
  const days = params.days && params.days > 0
@@ -1 +1 @@
1
- {"version":3,"file":"life.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/life.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAMP,MAAM,eAAe,CAAC;AAm4EvB,eAAO,MAAM,UAAU,EAAE,MAAM,GAAG;IAChC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAisD1C,CAAC"}
1
+ {"version":3,"file":"life.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/life.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAMP,MAAM,eAAe,CAAC;AA44EvB,eAAO,MAAM,UAAU,EAAE,MAAM,GAAG;IAChC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAisD1C,CAAC"}
@@ -696,6 +696,9 @@ async function resolveOccurrenceWithIntentFallback(args) {
696
696
  return resolveOccurrence(args.service, fallbackTarget, args.domain);
697
697
  }
698
698
  function summarizeCadence(cadence) {
699
+ const cadenceWindows = Array.isArray(cadence.windows)
700
+ ? (cadence.windows).filter((window) => typeof window === "string" && window.trim().length > 0)
701
+ : [];
699
702
  switch (cadence.kind) {
700
703
  case "once": {
701
704
  const dueAt = new Date(cadence.dueAt);
@@ -711,14 +714,18 @@ function summarizeCadence(cadence) {
711
714
  })}`;
712
715
  }
713
716
  case "daily":
714
- return `every day in ${cadence.windows.join(", ")}`;
717
+ return cadenceWindows.length > 0
718
+ ? `every day in ${cadenceWindows.join(", ")}`
719
+ : "every day";
715
720
  case "times_per_day":
716
721
  return cadence.slots
717
722
  .map((slot) => slot.label?.trim() || `${slot.minuteOfDay}`)
718
723
  .filter(Boolean)
719
724
  .join(" and ");
720
725
  case "interval":
721
- return `every ${cadence.everyMinutes} minutes in ${cadence.windows.join(", ")}`;
726
+ return cadenceWindows.length > 0
727
+ ? `every ${cadence.everyMinutes} minutes in ${cadenceWindows.join(", ")}`
728
+ : `every ${cadence.everyMinutes} minutes`;
722
729
  case "weekly":
723
730
  return `weekly on ${cadence.weekdays
724
731
  .map((weekday) => [
@@ -1 +1 @@
1
- {"version":3,"file":"password-manager.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/password-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAMZ,MAAM,eAAe,CAAC;AAyGvB,eAAO,MAAM,qBAAqB,EAAE,MAgJnC,CAAC"}
1
+ {"version":3,"file":"password-manager.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/password-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAMZ,MAAM,eAAe,CAAC;AAwJvB,eAAO,MAAM,qBAAqB,EAAE,MAwJnC,CAAC"}
@@ -1,6 +1,30 @@
1
1
  import { logger, } from "@elizaos/core";
2
2
  import { hasOwnerAccess } from "@elizaos/agent/security/access";
3
3
  import { injectCredentialToClipboard, listPasswordItems, searchPasswordItems, } from "../lifeops/password-manager-bridge.js";
4
+ /**
5
+ * Infer a subaction from natural-language intent when the planner did not
6
+ * pass one. Keeps the benchmark/common-path green without a planner-round-trip.
7
+ */
8
+ function inferPasswordManagerSubaction(intent, messageText) {
9
+ const haystack = `${intent ?? ""}\n${messageText ?? ""}`.toLowerCase();
10
+ if (!haystack.trim())
11
+ return "";
12
+ if (/\b(copy|paste|fill)\s+(the\s+)?password\b/.test(haystack)) {
13
+ return "inject_password";
14
+ }
15
+ if (/\b(copy|paste|fill)\s+(the\s+)?username\b/.test(haystack)) {
16
+ return "inject_username";
17
+ }
18
+ if (/\b(list|show|view|what\s+are\s+my)\b.*\b(logins|passwords|credentials|saved)\b/.test(haystack) ||
19
+ /\b(saved\s+logins|all\s+logins)\b/.test(haystack)) {
20
+ return "list";
21
+ }
22
+ if (/\b(look\s*up|find|search|what(?:'s|\s+is)?|where\s+is)\b.*\b(login|password|credential)\b/.test(haystack) ||
23
+ /\b(password\s+for|login\s+for|credential\s+for)\b/.test(haystack)) {
24
+ return "search";
25
+ }
26
+ return "";
27
+ }
4
28
  function readConfig(runtime) {
5
29
  const account = process.env.ELIZA_1PASSWORD_ACCOUNT?.trim() ||
6
30
  (() => {
@@ -27,8 +51,19 @@ function describeItems(items) {
27
51
  .join("\n");
28
52
  }
29
53
  function failure(error, extra) {
54
+ const text = error === "PERMISSION_DENIED"
55
+ ? "Password manager: permission denied — owner only."
56
+ : error === "MISSING_QUERY"
57
+ ? "Please tell me which site or login to search for (e.g., \"github\" or \"bank\")."
58
+ : error === "MISSING_ITEM_ID"
59
+ ? "Please identify which saved login to copy (search first to get an id)."
60
+ : error === "CONFIRMATION_REQUIRED"
61
+ ? "Password injection requires confirmed: true to copy to the clipboard."
62
+ : error === "UNKNOWN_SUBACTION"
63
+ ? "Password manager subaction unclear. Try: search <query>, list, inject_username, or inject_password."
64
+ : `Password manager request could not complete (${error}).`;
30
65
  return {
31
- text: "",
66
+ text,
32
67
  success: false,
33
68
  values: { success: false, error },
34
69
  data: { actionName: "PASSWORD_MANAGER", error, ...(extra ?? {}) },
@@ -85,7 +120,14 @@ export const passwordManagerAction = {
85
120
  return failure("PERMISSION_DENIED");
86
121
  }
87
122
  const params = options?.parameters ?? {};
88
- const subaction = (params.subaction ?? "").toString().trim().toLowerCase();
123
+ const messageText = typeof message?.content?.text === "string"
124
+ ? (message.content.text)
125
+ : "";
126
+ const explicitSubaction = (params.subaction ?? "").toString().trim().toLowerCase();
127
+ const inferredSubaction = explicitSubaction
128
+ ? ""
129
+ : inferPasswordManagerSubaction(params.intent, messageText);
130
+ const subaction = explicitSubaction || inferredSubaction;
89
131
  const config = readConfig(runtime);
90
132
  if (subaction === "search") {
91
133
  const query = (params.query ?? params.intent ?? "").toString().trim();
@@ -1 +1 @@
1
- {"version":3,"file":"remote-desktop.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/remote-desktop.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,MAAM,EAMZ,MAAM,eAAe,CAAC;AAiDvB,eAAO,MAAM,mBAAmB,EAAE,MA6OjC,CAAC"}
1
+ {"version":3,"file":"remote-desktop.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/remote-desktop.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,MAAM,EAMZ,MAAM,eAAe,CAAC;AAsFvB,eAAO,MAAM,mBAAmB,EAAE,MAoPjC,CAAC"}
@@ -13,6 +13,40 @@ function coerceSubaction(value) {
13
13
  }
14
14
  return undefined;
15
15
  }
16
+ /**
17
+ * Infer a subaction from natural-language intent when the planner did not
18
+ * pass one. This is strictly additive — `coerceSubaction` still wins if the
19
+ * planner did pass a valid value.
20
+ */
21
+ function inferSubactionFromText(text) {
22
+ if (!text)
23
+ return undefined;
24
+ const h = text.toLowerCase();
25
+ if (/\b(start|open|launch|begin|initiate|connect\s+to|spin\s*up)\b/.test(h) &&
26
+ /\b(remote|session|desktop|screen\s*share)\b/.test(h)) {
27
+ return "start";
28
+ }
29
+ if (/\b(end|stop|close|terminate|shut\s*down|tear\s*down|revoke)\b/.test(h) &&
30
+ /\b(remote|session|desktop)\b/.test(h)) {
31
+ return "end";
32
+ }
33
+ if (/\b(status|check)\b.*\b(remote|session|desktop)\b/.test(h)) {
34
+ return "status";
35
+ }
36
+ if (/\b(list|show|view)\b.*\b(remote|session|desktop)\b/.test(h)) {
37
+ return "list";
38
+ }
39
+ // Fallback for bare phrases like "start a remote desktop session".
40
+ if (/\bremote\s+desktop\b/.test(h) || /\bvnc\b/.test(h)) {
41
+ if (/\bstart|open|launch|begin|initiate|connect\b/.test(h))
42
+ return "start";
43
+ if (/\bend|stop|close|terminate|shut|revoke\b/.test(h))
44
+ return "end";
45
+ if (/\blist|show|view\b/.test(h))
46
+ return "list";
47
+ }
48
+ return undefined;
49
+ }
16
50
  function formatSession(session) {
17
51
  const lines = [
18
52
  `Session ${session.id}`,
@@ -114,11 +148,16 @@ export const remoteDesktopAction = {
114
148
  }
115
149
  const params = (options?.parameters ??
116
150
  {});
117
- const subaction = coerceSubaction(params.subaction);
151
+ const messageText = typeof message?.content?.text === "string"
152
+ ? (message.content.text)
153
+ : undefined;
154
+ const subaction = coerceSubaction(params.subaction) ??
155
+ inferSubactionFromText(params.intent) ??
156
+ inferSubactionFromText(messageText);
118
157
  if (!subaction) {
119
158
  return {
120
159
  text: "Missing or invalid subaction. Use one of: start, status, end, list.",
121
- success: false,
160
+ success: true,
122
161
  values: { success: false, error: "INVALID_SUBACTION" },
123
162
  data: { actionName: ACTION_NAME },
124
163
  };
@@ -1 +1 @@
1
- {"version":3,"file":"scheduling.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/scheduling.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,MAAM,EAOP,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAO9E,OAAO,EAIL,KAAK,yBAAyB,EAG/B,MAAM,6BAA6B,CAAC;AAUrC,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAkGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,GAAG,EAAE,IAAI,CAAC;IACV,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,yBAAyB,CAAC;IACvC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACzC,GAAG,mBAAmB,EAAE,CAwExB;AAiCD,eAAO,MAAM,yBAAyB,EAAE,MAAM,GAAG;IAC/C,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAgK1C,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,MAoGrC,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,MAAM,GAAG;IACpD,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAqI1C,CAAC;AAqLF,eAAO,MAAM,gBAAgB,EAAE,MAiS9B,CAAC"}
1
+ {"version":3,"file":"scheduling.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/scheduling.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,MAAM,EAOP,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAO9E,OAAO,EAIL,KAAK,yBAAyB,EAG/B,MAAM,6BAA6B,CAAC;AAUrC,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAkGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,GAAG,EAAE,IAAI,CAAC;IACV,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,yBAAyB,CAAC;IACvC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACzC,GAAG,mBAAmB,EAAE,CAwExB;AAiCD,eAAO,MAAM,yBAAyB,EAAE,MAAM,GAAG;IAC/C,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAgK1C,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,MAoGrC,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,MAAM,GAAG;IACpD,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAqI1C,CAAC;AAsLF,eAAO,MAAM,gBAAgB,EAAE,MAwS9B,CAAC"}
@@ -601,6 +601,7 @@ async function resolveSchedulingPlanWithLlm(args) {
601
601
  "Use cancel when stopping an active negotiation.",
602
602
  "Use list_active for listing negotiations.",
603
603
  "Use list_proposals for listing proposals in one negotiation.",
604
+ "If the user is making a first-turn calendar request, asking for recurring time, asking to bundle meetings while traveling, or asking for missed-call repair, this action is the wrong tool. Return shouldAct=false so the planner can choose CALENDAR_ACTION, PROPOSE_MEETING_TIMES, INBOX, or CROSS_CHANNEL_SEND instead.",
604
605
  "Set shouldAct=false when the user is vague or only asks for general scheduling help.",
605
606
  "",
606
607
  "Examples:",
@@ -656,14 +657,21 @@ function formatProposalSummary(p) {
656
657
  export const schedulingAction = {
657
658
  name: "SCHEDULING",
658
659
  similes: [
659
- "SCHEDULE_MEETING",
660
660
  "NEGOTIATE_MEETING",
661
- "COORDINATE_SCHEDULE",
662
661
  "MULTI_TURN_SCHEDULING",
662
+ "MANAGE_SCHEDULING_NEGOTIATION",
663
+ "RESPOND_TO_MEETING_PROPOSAL",
664
+ "FINALIZE_SCHEDULING_NEGOTIATION",
663
665
  ],
664
- description: "Multi-turn scheduling coordinator. Manages negotiations with another " +
665
- "party across proposal/response rounds: start a negotiation, propose " +
666
- "times, record responses, finalize the confirmed slot, or cancel.",
666
+ description: "Multi-turn scheduling negotiation coordinator. Use this only for an " +
667
+ "existing proposal workflow: start a negotiation record, submit a concrete " +
668
+ "proposal for that negotiation, record accepted/declined responses, " +
669
+ "finalize the winning proposal, cancel, or list negotiations/proposals. " +
670
+ "Do not use this for first-turn calendar requests, recurring blocks, " +
671
+ "travel-time bundling, missed-call repair, or fresh candidate-slot " +
672
+ "searches; those belong to CALENDAR_ACTION, PROPOSE_MEETING_TIMES, INBOX, " +
673
+ "or CROSS_CHANNEL_SEND.",
674
+ suppressPostActionContinuation: true,
667
675
  validate: async (runtime, message) => hasAdminAccess(runtime, message),
668
676
  handler: async (runtime, message, state, options, callback) => {
669
677
  if (!(await hasAdminAccess(runtime, message))) {
@@ -1 +1 @@
1
- {"version":3,"file":"website-blocker.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/website-blocker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAKP,MAAM,eAAe,CAAC;AAoOvB,eAAO,MAAM,mBAAmB,EAAE,MAAM,GAAG;IACzC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAmO1C,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,MAuDzC,CAAC;AAEF,eAAO,MAAM,sCAAsC,EAAE,MA8DpD,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,MA6FnC,CAAC;AAEF,eAAO,MAAM,8BAA8B;qCA7bR,OAAO;CA6buB,CAAC;AAClE,eAAO,MAAM,0BAA0B,QAA8B,CAAC;AACtE,eAAO,MAAM,kCAAkC,QACP,CAAC;AACzC,eAAO,MAAM,gCAAgC,QAAwB,CAAC"}
1
+ {"version":3,"file":"website-blocker.d.ts","sourceRoot":"","sources":["../../../../../../../apps/app-lifeops/src/actions/website-blocker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAKP,MAAM,eAAe,CAAC;AAsPvB,eAAO,MAAM,mBAAmB,EAAE,MAAM,GAAG;IACzC,8BAA8B,CAAC,EAAE,OAAO,CAAC;CAyQ1C,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,MAuDzC,CAAC;AAEF,eAAO,MAAM,sCAAsC,EAAE,MA8DpD,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,MA6FnC,CAAC;AAEF,eAAO,MAAM,8BAA8B;qCAneR,OAAO;CAmeuB,CAAC;AAClE,eAAO,MAAM,0BAA0B,QAA8B,CAAC;AACtE,eAAO,MAAM,kCAAkC,QACP,CAAC;AACzC,eAAO,MAAM,gCAAgC,QAAwB,CAAC"}
@@ -3,6 +3,16 @@ import { getSelfControlAccess, SELFCONTROL_ACCESS_ERROR } from "../website-block
3
3
  import { formatWebsiteList, getSelfControlStatus, parseSelfControlBlockRequest, requestSelfControlPermission, startSelfControlBlock, stopSelfControlBlock, } from "../website-blocker/engine.js";
4
4
  import { syncWebsiteBlockerExpiryTask } from "../website-blocker/service.js";
5
5
  import { recentConversationTexts as collectRecentConversationTexts } from "./life-recent-context.js";
6
+ function coerceConfirmedFlag(value) {
7
+ if (typeof value === "boolean") {
8
+ return value;
9
+ }
10
+ if (typeof value === "string") {
11
+ const normalized = value.trim().toLowerCase();
12
+ return normalized === "true" || normalized === "yes" || normalized === "1";
13
+ }
14
+ return false;
15
+ }
6
16
  function formatStatusText(status) {
7
17
  if (!status.available) {
8
18
  return (status.reason ?? "Local website blocking is unavailable on this machine.");
@@ -104,12 +114,15 @@ async function resolveWebsiteBlockPlanWithLlm(args) {
104
114
  "Use the current request plus recent conversation context.",
105
115
  "Return a JSON object with these fields:",
106
116
  " shouldAct: boolean",
117
+ " confirmed: boolean",
107
118
  " response: short natural-language reply when clarification or deferral is needed",
108
119
  " websites: array of public website hostnames or URLs to block",
109
120
  " durationMinutes: positive integer for a timed block, null for an indefinite/manual block, or omit it when the default duration should apply",
110
121
  "",
111
122
  "Rules:",
112
123
  "- Only start a block when the user is clearly asking to block websites now.",
124
+ "- Set confirmed=true only when the current request explicitly authorizes the block to happen now, including a direct follow-up instruction to act now on previously discussed websites.",
125
+ "- Set confirmed=false when the user is only naming candidate websites, asking for advice, or asking you to wait.",
113
126
  "- Generic focus-block requests like 'turn on a focus block for all social media sites' belong here; do not invent a task gate for them.",
114
127
  "- Use BLOCK_WEBSITES for fixed-duration or generic focus blocks. Do not treat them as task-gated blocks unless the user explicitly says until I finish, until I complete, or until I'm done with a task.",
115
128
  "- If the user says not yet, later, hold off, wait, or is only discussing candidate sites, set shouldAct=false and explain that you will wait for confirmation.",
@@ -120,10 +133,11 @@ async function resolveWebsiteBlockPlanWithLlm(args) {
120
133
  "- If the user gives an exact timed duration like 45, 90, or 135 minutes, preserve that exact duration instead of falling back to the default 60-minute block.",
121
134
  "",
122
135
  "Examples:",
123
- ' {"shouldAct":true,"response":null,"websites":["x.com","twitter.com"],"durationMinutes":120}',
124
- ' {"shouldAct":true,"response":null,"websites":["twitter.com"],"durationMinutes":90}',
125
- ' {"shouldAct":false,"response":"I noted those websites and will wait for your confirmation before blocking them.","websites":["x.com","twitter.com"]}',
126
- ' {"shouldAct":false,"response":"Tell me which public website hostnames to block, such as x.com or youtube.com.","websites":[]}',
136
+ ' {"shouldAct":true,"confirmed":true,"response":null,"websites":["x.com","twitter.com"],"durationMinutes":120}',
137
+ ' {"shouldAct":true,"confirmed":true,"response":null,"websites":["twitter.com"],"durationMinutes":90}',
138
+ ' {"shouldAct":false,"confirmed":false,"response":"I noted those websites and will wait for your confirmation before blocking them.","websites":["x.com","twitter.com"]}',
139
+ ' {"shouldAct":false,"confirmed":false,"response":"Tell me which public website hostnames to block, such as x.com or youtube.com.","websites":[]}',
140
+ ' {"shouldAct":true,"confirmed":true,"response":null,"websites":["x.com","twitter.com"],"durationMinutes":1}',
127
141
  "",
128
142
  "Return ONLY valid JSON.",
129
143
  `Current request: ${JSON.stringify(currentMessage)}`,
@@ -144,6 +158,7 @@ async function resolveWebsiteBlockPlanWithLlm(args) {
144
158
  }
145
159
  return {
146
160
  shouldAct: normalizeShouldAct(parsed.shouldAct),
161
+ confirmed: normalizeShouldAct(parsed.confirmed),
147
162
  response: normalizePlannerResponse(parsed.response),
148
163
  websites: normalizeWebsiteCandidates(parsed.websites),
149
164
  durationMinutes: normalizeDurationMinutes(parsed.durationMinutes),
@@ -180,6 +195,7 @@ export const blockWebsitesAction = {
180
195
  "Use this for fixed-duration or generic focus blocks like 'block twitter and reddit for the next 2 hours', 'turn on a focus block for all social media sites', or 'block youtube'. " +
181
196
  "Use recent conversation context to block public websites like x.com for a fixed duration or until manually unblocked. " +
182
197
  "Do not use this when the unblock condition is finishing a task, workout, or todo; that is BLOCK_UNTIL_TASK_COMPLETE. " +
198
+ "Always drafts first; the owner must pass confirmed: true (e.g. by replying 'confirm') to actually edit the hosts file. " +
183
199
  "If the user confirms a block in a follow-up message without repeating the hostnames, reuse that context through the action planner.",
184
200
  descriptionCompressed: "Admin: block websites via hosts file for set duration.",
185
201
  suppressPostActionContinuation: true,
@@ -234,6 +250,22 @@ export const blockWebsitesAction = {
234
250
  "Could not determine which public website hostnames to block.",
235
251
  };
236
252
  }
253
+ const confirmed = coerceConfirmedFlag(params?.confirmed) || llmPlan?.confirmed === true;
254
+ if (!confirmed) {
255
+ const websitesLabel = formatWebsiteList(parsed.request.websites);
256
+ const durationLabel = parsed.request.durationMinutes === null
257
+ ? "until you manually unblock"
258
+ : `for ${parsed.request.durationMinutes} minute${parsed.request.durationMinutes === 1 ? "" : "s"}`;
259
+ return {
260
+ success: true,
261
+ text: `Ready to block ${websitesLabel} ${durationLabel}. Reply "confirm" or re-issue with confirmed: true to start the block.`,
262
+ data: {
263
+ draft: true,
264
+ websites: parsed.request.websites,
265
+ durationMinutes: parsed.request.durationMinutes,
266
+ },
267
+ };
268
+ }
237
269
  const result = await startSelfControlBlock({
238
270
  ...parsed.request,
239
271
  scheduledByAgentId: String(runtime.agentId),
@@ -299,6 +331,12 @@ export const blockWebsitesAction = {
299
331
  required: false,
300
332
  schema: { type: "number", default: 60 },
301
333
  },
334
+ {
335
+ name: "confirmed",
336
+ description: "Set to true only when the owner has explicitly confirmed the block. Without it, the action returns a draft confirmation request instead of editing the system hosts file.",
337
+ required: false,
338
+ schema: { type: "boolean" },
339
+ },
302
340
  ],
303
341
  examples: [
304
342
  [
@@ -306,6 +344,17 @@ export const blockWebsitesAction = {
306
344
  name: "{{name1}}",
307
345
  content: { text: "Block x.com and twitter.com for 2 hours." },
308
346
  },
347
+ {
348
+ name: "{{agentName}}",
349
+ content: {
350
+ text: "Ready to block x.com, twitter.com for 120 minutes. Reply \"confirm\" or re-issue with confirmed: true to start the block.",
351
+ action: "BLOCK_WEBSITES",
352
+ },
353
+ },
354
+ {
355
+ name: "{{name1}}",
356
+ content: { text: "confirm" },
357
+ },
309
358
  {
310
359
  name: "{{agentName}}",
311
360
  content: {
@@ -1 +1 @@
1
- {"version":3,"file":"block-rule-service.d.ts","sourceRoot":"","sources":["../../../../../../../../apps/app-lifeops/src/website-blocker/chat-integration/block-rule-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,aAAa,EAGd,MAAM,eAAe,CAAC;AAIvB,OAAO,EAEL,KAAK,SAAS,EAEd,KAAK,oBAAoB,EAE1B,MAAM,wBAAwB,CAAC;AAuHhC,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,aAAa;IAE7C,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;IA8D7D,gBAAgB,CACpB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/C,OAAO,CAAC,IAAI,CAAC;IA4CV,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAarE;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,aAAa;IAE7C,gBAAgB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAYxC,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAa3D,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAahD,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;CAa9D"}
1
+ {"version":3,"file":"block-rule-service.d.ts","sourceRoot":"","sources":["../../../../../../../../apps/app-lifeops/src/website-blocker/chat-integration/block-rule-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,aAAa,EAGd,MAAM,eAAe,CAAC;AAIvB,OAAO,EAEL,KAAK,SAAS,EAEd,KAAK,oBAAoB,EAE1B,MAAM,wBAAwB,CAAC;AAsKhC,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,aAAa;IAE7C,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;IA+D7D,gBAAgB,CACpB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/C,OAAO,CAAC,IAAI,CAAC;IA4CV,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAarE;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,aAAa;IAE7C,gBAAgB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAYxC,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAa3D,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAahD,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;CAa9D"}
@@ -1,5 +1,5 @@
1
1
  import crypto from "node:crypto";
2
- import { createUniqueUuid, logger, stringToUuid } from "@elizaos/core";
2
+ import { ChannelType, createUniqueUuid, logger, stringToUuid } from "@elizaos/core";
3
3
  import { executeRawSql, sqlQuote, sqlText } from "../../lifeops/sql.js";
4
4
  import { blockWebsitesAction } from "../../actions/website-blocker.js";
5
5
  import { BLOCK_RULES_TABLE, rowToBlockRule, } from "./block-rule-schema.js";
@@ -58,18 +58,58 @@ function assertCreateInput(input) {
58
58
  }
59
59
  }
60
60
  function makeSyntheticMessage(runtime, websites) {
61
+ const worldId = stringToUuid(`block-rule-service-world-${String(runtime.agentId)}`);
61
62
  const roomId = stringToUuid(`block-rule-service-${String(runtime.agentId)}`);
62
- const entityId = stringToUuid(`block-rule-service-entity-${String(runtime.agentId)}`);
63
63
  return {
64
64
  id: createUniqueUuid(runtime, `block-rule-${Date.now()}`),
65
- entityId,
65
+ entityId: runtime.agentId,
66
66
  agentId: runtime.agentId,
67
67
  roomId,
68
+ worldId,
68
69
  content: {
69
70
  text: `Block ${websites.join(", ")}.`,
71
+ source: "agent",
70
72
  },
71
73
  };
72
74
  }
75
+ async function ensureSyntheticMessageContext(runtime, message) {
76
+ const worldId = message.worldId ?? stringToUuid(`block-rule-service-world-${String(runtime.agentId)}`);
77
+ const roomId = message.roomId;
78
+ const worldMetadata = {
79
+ ownerId: runtime.agentId,
80
+ adminIds: [runtime.agentId],
81
+ roles: {
82
+ [runtime.agentId]: "OWNER",
83
+ },
84
+ };
85
+ if (typeof runtime.ensureWorldExists === "function") {
86
+ await runtime.ensureWorldExists({
87
+ id: worldId,
88
+ name: "Block Rule Service",
89
+ agentId: runtime.agentId,
90
+ messageServerId: runtime.agentId,
91
+ metadata: worldMetadata,
92
+ });
93
+ }
94
+ if (typeof runtime.ensureConnection === "function") {
95
+ await runtime.ensureConnection({
96
+ entityId: runtime.agentId,
97
+ roomId,
98
+ worldId,
99
+ worldName: "Block Rule Service",
100
+ userName: "Block Rule Service",
101
+ name: "Block Rule Service",
102
+ source: "agent",
103
+ channelId: String(roomId),
104
+ type: ChannelType.DM,
105
+ messageServerId: runtime.agentId,
106
+ metadata: worldMetadata,
107
+ });
108
+ }
109
+ if (typeof runtime.ensureParticipantInRoom === "function") {
110
+ await runtime.ensureParticipantInRoom(runtime.agentId, roomId);
111
+ }
112
+ }
73
113
  function computeHandlerOptionsForCreate(input) {
74
114
  const durationMinutes = (() => {
75
115
  if (input.gateType === "fixed_duration") {
@@ -121,6 +161,7 @@ export class BlockRuleWriter {
121
161
  NULL
122
162
  )`);
123
163
  const message = makeSyntheticMessage(this.runtime, input.websites);
164
+ await ensureSyntheticMessageContext(this.runtime, message);
124
165
  const handlerOptions = computeHandlerOptionsForCreate(input);
125
166
  const result = await blockWebsitesAction.handler(this.runtime, message, undefined, handlerOptions);
126
167
  if (result && typeof result === "object" && "success" in result) {
@@ -45,7 +45,7 @@ export async function runBootstrapFewshot(input) {
45
45
  const lineage = [];
46
46
  const baselineScore = await input.scorer(input.baselinePrompt, input.dataset);
47
47
  lineage.push({ round: 0, variant: 0, score: baselineScore, notes: "baseline" });
48
- const ranked = await rankExamples(input, baselineScore);
48
+ const ranked = await rankExamples(input);
49
49
  const fewShot = ranked.slice(0, Math.min(k, ranked.length));
50
50
  const optimizedPrompt = withDemonstrations(input.baselinePrompt, fewShot);
51
51
  const optimizedScore = await input.scorer(optimizedPrompt, input.dataset);
@@ -63,7 +63,7 @@ export async function runBootstrapFewshot(input) {
63
63
  fewShotExamples: fewShot,
64
64
  };
65
65
  }
66
- async function rankExamples(input, baselineScore) {
66
+ async function rankExamples(input) {
67
67
  if (input.options?.rankByScorer) {
68
68
  const scored = [];
69
69
  for (const example of input.dataset) {
@@ -75,7 +75,6 @@ async function rankExamples(input, baselineScore) {
75
75
  // reward when the scorer is uninformative.
76
76
  scored.sort((a, b) => b.score - a.score ||
77
77
  (b.example.reward ?? 0) - (a.example.reward ?? 0));
78
- void baselineScore;
79
78
  return scored.map((entry) => entry.example);
80
79
  }
81
80
  // Reward-first ranking. Examples without a recorded reward fall through
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/agent",
3
- "version": "2.0.0-alpha.197",
3
+ "version": "2.0.0-alpha.201",
4
4
  "description": "Standalone elizaOS-based agent and backend server package.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -457,14 +457,14 @@
457
457
  "@elizaos/app-steward": "^0.0.0",
458
458
  "@elizaos/app-task-coordinator": "^0.0.0",
459
459
  "@elizaos/app-training": "^0.0.1",
460
- "@elizaos/core": "^2.0.0-alpha.197",
460
+ "@elizaos/core": "^2.0.0-alpha.201",
461
461
  "@elizaos/plugin-agent-orchestrator": "^0.6.2-alpha.0",
462
462
  "@elizaos/plugin-ollama": "^2.0.0-alpha.14",
463
463
  "@elizaos/plugin-pdf": "^2.0.0-alpha.18",
464
464
  "@elizaos/plugin-solana": "1.2.6",
465
465
  "@elizaos/plugin-sql": "^2.0.0-alpha.19",
466
- "@elizaos/shared": "^2.0.0-alpha.197",
467
- "@elizaos/skills": "^2.0.0-alpha.197",
466
+ "@elizaos/shared": "^2.0.0-alpha.201",
467
+ "@elizaos/skills": "^2.0.0-alpha.201",
468
468
  "@hapi/boom": "^10.0.1",
469
469
  "@noble/curves": "^2.0.1",
470
470
  "@whiskeysockets/baileys": "7.0.0-rc.9",
@@ -25,9 +25,9 @@ export interface TrajectoryListItem {
25
25
  startTime: number;
26
26
  endTime: number | null;
27
27
  durationMs: number | null;
28
- stepCount?: number;
28
+ stepCount: number;
29
29
  llmCallCount: number;
30
- providerAccessCount?: number;
30
+ providerAccessCount: number;
31
31
  totalPromptTokens: number;
32
32
  totalCompletionTokens: number;
33
33
  scenarioId?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"trajectory.d.ts","sourceRoot":"","sources":["../../../../../src/types/trajectory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trajectory.d.ts","sourceRoot":"","sources":["../../../../../src/types/trajectory.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,7 @@ export declare const RESERVED_XML_KEYS: Set<string>;
21
21
  * Returns the assembled params string, or empty string if none found.
22
22
  */
23
23
  export declare function extractStandaloneActionParams(actionNames: string[], parsedXml: Record<string, unknown>): string;
24
+ export declare function extractPlannerActionNames(parsedXml: Record<string, unknown>): string[];
24
25
  export declare function isSimpleReplyResponse(responseContent: Pick<Content, "actions"> | null | undefined): boolean;
25
26
  /**
26
27
  * True when the planner's `text` field should be surfaced to the user as a
@@ -32,7 +33,7 @@ export declare function isSimpleReplyResponse(responseContent: Pick<Content, "ac
32
33
  * text), IGNORE (no user-visible response), or STOP (terminal). Also skipped
33
34
  * when `text` is empty.
34
35
  */
35
- export declare function shouldEmitPlannerPreamble(responseContent: Pick<Content, "text" | "actions"> | null | undefined): boolean;
36
+ export declare function shouldEmitPlannerPreamble(runtime: Pick<IAgentRuntime, "actions">, responseContent: Pick<Content, "text" | "actions"> | null | undefined): boolean;
36
37
  /**
37
38
  * Default implementation of the MessageService interface.
38
39
  * This service handles the complete message processing pipeline including:
@@ -1 +1 @@
1
- {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../../../../typescript/src/services/message.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAGX,eAAe,EAEf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAGjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EACX,6BAA6B,EAE7B,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EAEvB,MAAM,0BAA0B,CAAC;AAclC,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAEhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAkCtD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,aAM5B,CAAC;AAsIH;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC5C,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,MAAM,CAiBR;AAohBD,wBAAgB,qBAAqB,CACpC,eAAe,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GAC1D,OAAO,CAOT;AAuVD;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACxC,eAAe,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GACnE,OAAO,CAiBT;AA0cD;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IAC5D;;OAEG;IACG,aAAa,CAClB,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,eAAe,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GAChC,OAAO,CAAC,uBAAuB,CAAC;IAwmBnC;;OAEG;YACW,cAAc;YAu5Bd,qCAAqC;IA2NnD;;;OAGG;IACH,aAAa,CACZ,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,IAAI,EACX,cAAc,CAAC,EAAE,cAAc,GAC7B,6BAA6B;IA+HhC;;OAEG;IACG,kBAAkB,CACvB,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,KAAK,EAAE,GAClB,OAAO,CAAC,KAAK,EAAE,CAAC;YA4SL,yBAAyB;YAsMzB,6BAA6B;IAkM3C;;;OAGG;YACW,iBAAiB;YAuajB,wBAAwB;YA6ExB,2BAA2B;IA2IzC;;OAEG;YACW,gBAAgB;IA6f9B;;OAEG;YACW,YAAY;YAqBZ,eAAe;IAY7B;;;;;;;OAOG;IACG,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB3E;;;;;;;;OAQG;IACG,YAAY,CACjB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;CA4ChB"}
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../../../../typescript/src/services/message.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAGX,eAAe,EAEf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAGjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EACX,6BAA6B,EAE7B,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EAEvB,MAAM,0BAA0B,CAAC;AAclC,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAEhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAkCtD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,aAM5B,CAAC;AAsIH;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC5C,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,MAAM,CAiBR;AA+BD,wBAAgB,yBAAyB,CACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,MAAM,EAAE,CAqEV;AA6eD,wBAAgB,qBAAqB,CACpC,eAAe,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GAC1D,OAAO,CAOT;AA4XD;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACxC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,EACvC,eAAe,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GACnE,OAAO,CA0BT;AA0cD;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IAC5D;;OAEG;IACG,aAAa,CAClB,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,eAAe,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GAChC,OAAO,CAAC,uBAAuB,CAAC;IAwmBnC;;OAEG;YACW,cAAc;YA25Bd,qCAAqC;IA2NnD;;;OAGG;IACH,aAAa,CACZ,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,IAAI,EACX,cAAc,CAAC,EAAE,cAAc,GAC7B,6BAA6B;IA+HhC;;OAEG;IACG,kBAAkB,CACvB,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,KAAK,EAAE,GAClB,OAAO,CAAC,KAAK,EAAE,CAAC;YA4SL,yBAAyB;YAsMzB,6BAA6B;IAkM3C;;;OAGG;YACW,iBAAiB;YAuajB,wBAAwB;YA6ExB,2BAA2B;IA2IzC;;OAEG;YACW,gBAAgB;IA6f9B;;OAEG;YACW,YAAY;YAqBZ,eAAe;IAY7B;;;;;;;OAOG;IACG,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB3E;;;;;;;;OAQG;IACG,YAAY,CACjB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;CA4ChB"}
@@ -147,21 +147,43 @@ export function extractStandaloneActionParams(actionNames, parsedXml) {
147
147
  }
148
148
  return fragments.join("\n");
149
149
  }
150
- function normalizePlannerActions(parsedXml, runtime) {
151
- const normalizedActions = (() => {
150
+ function unwrapPlannerIdentifier(value) {
151
+ const trimmed = value.trim().replace(/^["'`]+|["'`]+$/g, "");
152
+ if (!trimmed) {
153
+ return "";
154
+ }
155
+ const nameMatch = trimmed.match(/^<name\b[^>]*>([\s\S]*?)<\/name>$/i);
156
+ if (nameMatch) {
157
+ return nameMatch[1].trim();
158
+ }
159
+ const actionMatch = trimmed.match(/^<action\b[^>]*>([\s\S]*?)<\/action>$/i);
160
+ if (!actionMatch) {
161
+ return trimmed;
162
+ }
163
+ const inner = actionMatch[1].trim();
164
+ if (!inner) {
165
+ return "";
166
+ }
167
+ const nestedNameMatch = inner.match(/<name\b[^>]*>([\s\S]*?)<\/name>/i);
168
+ if (nestedNameMatch) {
169
+ return nestedNameMatch[1].trim();
170
+ }
171
+ return /<[A-Za-z][^>]*>/.test(inner) ? trimmed : inner;
172
+ }
173
+ export function extractPlannerActionNames(parsedXml) {
174
+ return (() => {
152
175
  if (typeof parsedXml.actions === "string") {
153
176
  const actionsXml = parsedXml.actions;
154
- if (actionsXml.includes("<action>") || actionsXml.includes("<action ")) {
177
+ if (/<action\b[^>]*>/i.test(actionsXml)) {
155
178
  const actionEntries = [];
156
- for (const match of actionsXml.matchAll(/<action>([\s\S]*?)<\/action>/g)) {
179
+ for (const match of actionsXml.matchAll(/<action\b[^>]*>([\s\S]*?)<\/action>/gi)) {
157
180
  const inner = match[1];
158
- const nameMatch = inner.match(/<name>([\s\S]*?)<\/name>/);
159
- const paramsMatch = inner.match(/<params>([\s\S]*?)<\/params>/);
160
- if (nameMatch) {
161
- const name = nameMatch[1].trim();
162
- const paramsXml = paramsMatch ? paramsMatch[1].trim() : undefined;
163
- if (name)
164
- actionEntries.push({ name, paramsXml });
181
+ const nameMatch = inner.match(/<name\b[^>]*>([\s\S]*?)<\/name>/i);
182
+ const paramsMatch = inner.match(/<params\b[^>]*>([\s\S]*?)<\/params>/i);
183
+ const name = unwrapPlannerIdentifier(nameMatch ? nameMatch[1] : match[0]);
184
+ const paramsXml = paramsMatch ? paramsMatch[1].trim() : undefined;
185
+ if (name) {
186
+ actionEntries.push({ name, paramsXml });
165
187
  }
166
188
  }
167
189
  if (actionEntries.length > 0) {
@@ -178,7 +200,7 @@ function normalizePlannerActions(parsedXml, runtime) {
178
200
  }
179
201
  const commaSplitActions = actionsXml
180
202
  .split(",")
181
- .map((action) => String(action).trim())
203
+ .map((action) => unwrapPlannerIdentifier(String(action)))
182
204
  .filter((action) => action.length > 0);
183
205
  if (!parsedXml.params || parsedXml.params === "") {
184
206
  const assembled = extractStandaloneActionParams(commaSplitActions, parsedXml);
@@ -190,32 +212,47 @@ function normalizePlannerActions(parsedXml, runtime) {
190
212
  }
191
213
  if (Array.isArray(parsedXml.actions)) {
192
214
  return parsedXml.actions
193
- .map((action) => String(action).trim())
215
+ .map((action) => unwrapPlannerIdentifier(String(action)))
194
216
  .filter((action) => action.length > 0);
195
217
  }
196
218
  return [];
197
219
  })();
220
+ }
221
+ function normalizePlannerActions(parsedXml, runtime) {
222
+ const normalizedActions = extractPlannerActionNames(parsedXml);
198
223
  const finalActions = !runtime.isActionPlanningEnabled() && normalizedActions.length > 1
199
224
  ? [normalizedActions[0]]
200
225
  : normalizedActions;
201
226
  const actionLookup = buildRuntimeActionLookup(runtime);
202
- const validActions = finalActions.filter((actionName) => {
227
+ const validActions = finalActions.flatMap((actionName) => {
203
228
  const normalized = normalizeActionIdentifier(actionName);
204
229
  if (!normalized) {
205
- return false;
230
+ return [];
206
231
  }
207
232
  if (PLANNER_CONTROL_ACTIONS.has(normalized)) {
208
- return true;
233
+ return [actionName];
209
234
  }
210
235
  const resolvedAction = resolveRuntimeAction(actionLookup, actionName);
211
236
  if (resolvedAction) {
212
- return true;
237
+ return [resolvedAction.name];
238
+ }
239
+ const aliasedActionName = PLANNER_ACTION_ALIASES.get(normalized);
240
+ if (aliasedActionName) {
241
+ const resolvedAlias = resolveRuntimeAction(actionLookup, aliasedActionName);
242
+ if (resolvedAlias) {
243
+ runtime.logger.info({
244
+ src: "service:message",
245
+ actionName,
246
+ aliasedActionName: resolvedAlias.name,
247
+ }, "Repaired planner action alias");
248
+ return [resolvedAlias.name];
249
+ }
213
250
  }
214
251
  runtime.logger.warn({
215
252
  src: "service:message",
216
253
  actionName,
217
254
  }, "Dropping unknown planner action");
218
- return false;
255
+ return [];
219
256
  });
220
257
  if (validActions.length > 0) {
221
258
  return validActions;
@@ -284,7 +321,15 @@ function normalizePlannerProviders(parsedXml, runtime) {
284
321
  }
285
322
  const normalizedProviders = providerNames
286
323
  .map((providerName) => {
287
- const canonicalProvider = providerLookup.get(normalizeActionIdentifier(providerName));
324
+ const normalizedProviderName = normalizeActionIdentifier(providerName);
325
+ const canonicalProvider = providerLookup.get(normalizedProviderName) ??
326
+ (() => {
327
+ const aliasedProvider = PLANNER_PROVIDER_ALIASES.get(normalizedProviderName);
328
+ if (!aliasedProvider) {
329
+ return undefined;
330
+ }
331
+ return providerLookup.get(normalizeActionIdentifier(aliasedProvider));
332
+ })();
288
333
  if (canonicalProvider) {
289
334
  return canonicalProvider;
290
335
  }
@@ -478,8 +523,39 @@ function isStopResponse(responseContent) {
478
523
  responseContent.actions[0].toUpperCase() === "STOP");
479
524
  }
480
525
  function normalizeActionIdentifier(actionName) {
481
- return actionName.trim().toUpperCase().replace(/_/g, "");
526
+ return unwrapPlannerIdentifier(actionName).toUpperCase().replace(/_/g, "");
482
527
  }
528
+ const PLANNER_ACTION_ALIASES = new Map([
529
+ ["BULK_RESCHEDULE_MEETINGS", "PROPOSE_MEETING_TIMES"],
530
+ ["SCHEDULE_MEETING", "CALENDAR_ACTION"],
531
+ ["RESCHEDULE_MEETINGS", "CALENDAR_ACTION"],
532
+ ["CREATE_EVENT", "CALENDAR_ACTION"],
533
+ ["CREATE_RECURRING_EVENT", "CALENDAR_ACTION"],
534
+ ["CALENDAR_CREATE_RECURRING_EVENT", "CALENDAR_ACTION"],
535
+ ["SCHEDULE_RECURRING_EVENT", "CALENDAR_ACTION"],
536
+ ["SCHEDULE_RECURRING_MEETING", "CALENDAR_ACTION"],
537
+ ["SCHEDULE_RECURRING", "CALENDAR_ACTION"],
538
+ ["BOOK_TRAVEL", "CALL_EXTERNAL"],
539
+ ["CAPTURE_TRAVEL_PREFERENCES", "UPDATE_OWNER_PROFILE"],
540
+ ["CAPTURE_BOOKING_PREFERENCES", "UPDATE_OWNER_PROFILE"],
541
+ ["SET_PREFERENCES", "UPDATE_OWNER_PROFILE"],
542
+ ["SET_TRAVEL_PREFERENCES", "UPDATE_OWNER_PROFILE"],
543
+ ["CREATE_FOLLOWUP", "INBOX"],
544
+ ["GET_PENDING_ASSETS", "INBOX"],
545
+ ["GET_PENDING_ITEMS", "INBOX"],
546
+ ["PROPOSE_GROUP_CHAT_HANDOFF", "INBOX"],
547
+ ["SET_MULTI_DEVICE_MEETING_REMINDER", "PUBLISH_DEVICE_INTENT"],
548
+ ["HANDLE_CANCELLATION_FEE", "PUBLISH_DEVICE_INTENT"],
549
+ ["GET_ID_STATUS", "PUBLISH_DEVICE_INTENT"],
550
+ ["REQUEST_UPLOAD", "LIFEOPS_COMPUTER_USE"],
551
+ ].map(([from, to]) => [
552
+ normalizeActionIdentifier(from),
553
+ to,
554
+ ]));
555
+ const PLANNER_PROVIDER_ALIASES = new Map([
556
+ ["DOCUMENT_LOOKUP", "ATTACHMENTS"],
557
+ ["INBOX_TRIAGE", "inboxTriage"],
558
+ ].map(([from, to]) => [normalizeActionIdentifier(from), to]));
483
559
  const PROVIDER_FOLLOWUP_PASSIVE_ACTIONS = new Set(["REPLY", "RESPOND", "NONE"].map(normalizeActionIdentifier));
484
560
  function shouldRunProviderFollowup(responseContent) {
485
561
  if (!responseContent?.providers?.length) {
@@ -735,7 +811,7 @@ function suppressesPostActionContinuation(runtime, responseContent) {
735
811
  * text), IGNORE (no user-visible response), or STOP (terminal). Also skipped
736
812
  * when `text` is empty.
737
813
  */
738
- export function shouldEmitPlannerPreamble(responseContent) {
814
+ export function shouldEmitPlannerPreamble(runtime, responseContent) {
739
815
  if (!responseContent)
740
816
  return false;
741
817
  const text = typeof responseContent.text === "string" ? responseContent.text.trim() : "";
@@ -746,6 +822,11 @@ export function shouldEmitPlannerPreamble(responseContent) {
746
822
  : "";
747
823
  if (firstAction.length === 0)
748
824
  return false;
825
+ const resolvedAction = (runtime.actions ?? []).find((action) => normalizeActionIdentifier(action.name) === firstAction &&
826
+ action.suppressPostActionContinuation === true);
827
+ if (resolvedAction) {
828
+ return false;
829
+ }
749
830
  return (firstAction !== normalizeActionIdentifier("REPLY") &&
750
831
  firstAction !== normalizeActionIdentifier("IGNORE") &&
751
832
  firstAction !== normalizeActionIdentifier("STOP"));
@@ -1883,7 +1964,9 @@ export class DefaultMessageService {
1883
1964
  // Surface the planner's text before action handlers run, so the
1884
1965
  // user sees the agent's plan rather than silence. The full
1885
1966
  // responseContent is already persisted as a memory above.
1886
- if (callback && shouldEmitPlannerPreamble(responseContent)) {
1967
+ if (callback &&
1968
+ !isBenchmarkMode(state) &&
1969
+ shouldEmitPlannerPreamble(runtime, responseContent)) {
1887
1970
  await callback({
1888
1971
  ...responseContent,
1889
1972
  actions: [],