@yugenlab/vaayu 0.1.2 → 0.1.4

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 (33) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -1
  3. package/chunks/agentic-tool-loop-2FZK72JO.js +147 -0
  4. package/chunks/{chunk-E5A3SCDJ.js → chunk-6556EKOB.js} +2 -2
  5. package/chunks/{chunk-FPNQLJLD.js → chunk-7UOXFHEB.js} +6 -6
  6. package/chunks/{chunk-NBXCXQ3H.js → chunk-D3RVJGO7.js} +2 -2
  7. package/chunks/{chunk-XRHUKKBC.js → chunk-DOQMEQ5S.js} +6 -6
  8. package/chunks/{chunk-OWBBY5XP.js → chunk-IGBRBFXX.js} +2 -2
  9. package/chunks/{chunk-F35MWELH.js → chunk-LVE2EOOH.js} +7 -7
  10. package/chunks/{chunk-2ARPXEDC.js → chunk-NHRBVSN3.js} +3 -3
  11. package/chunks/{chunk-F4T7POKM.js → chunk-OBYBBGHA.js} +2 -2
  12. package/chunks/{chunk-UW6E7IC4.js → chunk-PJEYJQ2C.js} +4 -4
  13. package/chunks/{chunk-SLA2OIMG.js → chunk-S2HDNNC7.js} +3 -3
  14. package/chunks/{chunk-DQMAQ2VL.js → chunk-TEQKXGIK.js} +5 -5
  15. package/chunks/{chunk-UQLPHNGH.js → chunk-U62ABYKD.js} +2 -2
  16. package/chunks/{chunk-KC6NRZ7U.js → chunk-UZ6OIVEC.js} +1 -1
  17. package/chunks/{chunk-5Z2BKSFF.js → chunk-YSC77CKZ.js} +427 -85
  18. package/chunks/{consolidation-indexer-A46RJU4R.js → consolidation-indexer-CD6DS2HO.js} +6 -6
  19. package/chunks/{day-consolidation-GQ2FDCR2.js → day-consolidation-U3X6P4ZG.js} +3 -3
  20. package/chunks/{graphrag-6YZ5YPLK.js → graphrag-LAZSXLLI.js} +4 -4
  21. package/chunks/{hierarchical-temporal-search-VA4D3SON.js → hierarchical-temporal-search-ETXYYJZK.js} +2 -2
  22. package/chunks/{hybrid-search-6XMUT66S.js → hybrid-search-TX6T3KYH.js} +7 -7
  23. package/chunks/{memory-store-KNJPMBLQ.js → memory-store-A6WOWLWC.js} +3 -3
  24. package/chunks/periodic-consolidation-4MACZE6S.js +11 -0
  25. package/chunks/{recall-THTI6ZO2.js → recall-IUPQCBYP.js} +5 -5
  26. package/chunks/{search-V7DJ3VNL.js → search-HHSVHBXC.js} +6 -6
  27. package/chunks/{session-store-GRKGTMHI.js → session-store-NDUDYAC7.js} +4 -4
  28. package/chunks/{src-54LTTDTH.js → src-ZAKUL232.js} +51 -41
  29. package/chunks/vasana-engine-G6BPOFX7.js +10 -0
  30. package/gateway.js +581 -102
  31. package/package.json +1 -1
  32. package/chunks/periodic-consolidation-N5MR77ZN.js +0 -11
  33. package/chunks/vasana-engine-Z4RXW2SB.js +0 -10
package/gateway.js CHANGED
@@ -7,12 +7,12 @@ import {
7
7
  SqliteStorage
8
8
  } from "./chunks/chunk-PRXQW76U.js";
9
9
  import "./chunks/chunk-C76USAC5.js";
10
- import "./chunks/chunk-5Z2BKSFF.js";
11
- import "./chunks/chunk-F4T7POKM.js";
12
- import "./chunks/chunk-FPNQLJLD.js";
13
- import "./chunks/chunk-XRHUKKBC.js";
14
- import "./chunks/chunk-DQMAQ2VL.js";
15
- import "./chunks/chunk-OWBBY5XP.js";
10
+ import "./chunks/chunk-YSC77CKZ.js";
11
+ import "./chunks/chunk-DOQMEQ5S.js";
12
+ import "./chunks/chunk-7UOXFHEB.js";
13
+ import "./chunks/chunk-D3RVJGO7.js";
14
+ import "./chunks/chunk-OBYBBGHA.js";
15
+ import "./chunks/chunk-IGBRBFXX.js";
16
16
  import "./chunks/chunk-IEKAYVA3.js";
17
17
  import {
18
18
  IMessageAdapter,
@@ -23,14 +23,12 @@ import {
23
23
  require_lib,
24
24
  validateMantra
25
25
  } from "./chunks/chunk-MJ74G5RB.js";
26
- import "./chunks/chunk-SLA2OIMG.js";
27
- import "./chunks/chunk-F35MWELH.js";
28
- import "./chunks/chunk-JAWZ7ANC.js";
29
- import "./chunks/chunk-NBXCXQ3H.js";
30
26
  import {
31
27
  searchSessions
32
- } from "./chunks/chunk-UW6E7IC4.js";
33
- import "./chunks/chunk-E5A3SCDJ.js";
28
+ } from "./chunks/chunk-PJEYJQ2C.js";
29
+ import "./chunks/chunk-6556EKOB.js";
30
+ import "./chunks/chunk-S2HDNNC7.js";
31
+ import "./chunks/chunk-LVE2EOOH.js";
34
32
  import {
35
33
  addTurn,
36
34
  createSession,
@@ -40,10 +38,12 @@ import {
40
38
  listTurnsWithTimestamps,
41
39
  loadSession,
42
40
  updateSessionMeta
43
- } from "./chunks/chunk-2ARPXEDC.js";
41
+ } from "./chunks/chunk-NHRBVSN3.js";
42
+ import "./chunks/chunk-JAWZ7ANC.js";
43
+ import "./chunks/chunk-TEQKXGIK.js";
44
44
  import "./chunks/chunk-YJRXLRTE.js";
45
- import "./chunks/chunk-UQLPHNGH.js";
46
- import "./chunks/chunk-KC6NRZ7U.js";
45
+ import "./chunks/chunk-U62ABYKD.js";
46
+ import "./chunks/chunk-UZ6OIVEC.js";
47
47
  import {
48
48
  __commonJS,
49
49
  __export,
@@ -14387,10 +14387,33 @@ var OpenAICompatibleProvider = class {
14387
14387
  }
14388
14388
  const payload = {
14389
14389
  model: request.model,
14390
- messages: request.messages.map((message) => ({
14391
- role: message.role,
14392
- content: message.content
14393
- })),
14390
+ messages: request.messages.map((message) => {
14391
+ if (message.role === "assistant" && message.toolCalls?.length) {
14392
+ return {
14393
+ role: "assistant",
14394
+ content: message.content || null,
14395
+ tool_calls: message.toolCalls.map((call) => ({
14396
+ id: call.id ?? `call_${call.name}`,
14397
+ type: "function",
14398
+ function: {
14399
+ name: call.name,
14400
+ arguments: JSON.stringify(call.input)
14401
+ }
14402
+ }))
14403
+ };
14404
+ }
14405
+ if (message.role === "tool") {
14406
+ return {
14407
+ role: "tool",
14408
+ tool_call_id: message.toolCallId ?? message.name ?? "unknown",
14409
+ content: message.content
14410
+ };
14411
+ }
14412
+ return {
14413
+ role: message.role,
14414
+ content: message.content
14415
+ };
14416
+ }),
14394
14417
  temperature: request.temperature,
14395
14418
  top_p: request.topP,
14396
14419
  max_tokens: request.maxTokens,
@@ -14508,10 +14531,49 @@ function splitSystem(messages) {
14508
14531
  };
14509
14532
  }
14510
14533
  function toAnthropicMessages(messages) {
14511
- return messages.filter((message) => message.role !== "tool").map((message) => ({
14512
- role: message.role === "assistant" ? "assistant" : "user",
14513
- content: [{ type: "text", text: message.content }]
14514
- }));
14534
+ const result = [];
14535
+ for (let i = 0; i < messages.length; i++) {
14536
+ const message = messages[i];
14537
+ if (message.role === "system") continue;
14538
+ if (message.role === "tool") {
14539
+ const toolResults = [];
14540
+ let j = i;
14541
+ while (j < messages.length) {
14542
+ const tm = messages[j];
14543
+ if (tm.role !== "tool") break;
14544
+ toolResults.push({
14545
+ type: "tool_result",
14546
+ tool_use_id: tm.toolCallId ?? tm.name ?? "unknown",
14547
+ content: tm.content
14548
+ });
14549
+ j++;
14550
+ }
14551
+ result.push({ role: "user", content: toolResults });
14552
+ i = j - 1;
14553
+ continue;
14554
+ }
14555
+ if (message.role === "assistant" && message.toolCalls?.length) {
14556
+ const content = [];
14557
+ if (message.content) {
14558
+ content.push({ type: "text", text: message.content });
14559
+ }
14560
+ for (const call of message.toolCalls) {
14561
+ content.push({
14562
+ type: "tool_use",
14563
+ id: call.id ?? `call_${call.name}`,
14564
+ name: call.name,
14565
+ input: call.input
14566
+ });
14567
+ }
14568
+ result.push({ role: "assistant", content });
14569
+ continue;
14570
+ }
14571
+ result.push({
14572
+ role: message.role === "assistant" ? "assistant" : "user",
14573
+ content: [{ type: "text", text: message.content }]
14574
+ });
14575
+ }
14576
+ return result;
14515
14577
  }
14516
14578
  function buildUrl2(config) {
14517
14579
  if (config.path) {
@@ -24720,6 +24782,9 @@ function normalizeErrorMessage(error) {
24720
24782
  }
24721
24783
  function classifyFailure(message) {
24722
24784
  const lower = message.toLowerCase();
24785
+ if (lower.includes("state db missing rollout path") || lower.includes("rmcp::transport::asyncrw") || lower.includes("jsonrpcmessage")) {
24786
+ return { reason: "cli_state", baseCooldownMs: 5 * 6e4 };
24787
+ }
24723
24788
  if (/\b(unknown_error\s*-\s*not found|model_not_found|not found|404)\b/i.test(message) || lower.includes("model not found")) {
24724
24789
  return { reason: "not_found", baseCooldownMs: 5 * 6e4 };
24725
24790
  }
@@ -25910,7 +25975,7 @@ async function resolveContinuityDecision(params) {
25910
25975
  var YESTERDAY_RECAP_RE = /\b(what did we talk (yesterday|last night)|what were we discussing yesterday|yesterday recap|summary of yesterday)\b/i;
25911
25976
  var SEMANTIC_SMALLTALK_CONFIDENCE = 0.58;
25912
25977
  var SMALLTALK_JOKE_RE = /\b(?:tell\s+me\s+(?:a\s+)?joke|say\s+(?:a\s+)?joke|joke(?:\s+please)?|make\s+me\s+laugh|something\s+funny|any\s+jokes?)\b/i;
25913
- var SMALLTALK_CHECKIN_RE = /\b(?:how\s+(?:are|aer)\s+(?:you|u)(?:\s+doing)?|how(?:'s|\s+is)\s+it\s+going|hru|bagunava|bagunnava|ela\s+undh?i)\b/i;
25978
+ var SMALLTALK_CHECKIN_RE = /\b(?:how\s+(?:are|aer|r)\s+(?:you|u)(?:\s+doing)?|how(?:'s|\s+is)\s+it\s+going|hru|bagunava|bagunnava|ela\s+undh?i|como\s+estas|como\s+esta|que\s+tal|wie\s+geht(?:s|es)(?:\s+dir)?|comment\s+(?:ca|ça)\s+va|ca\s+va|ça\s+va|kaise\s+ho|nasilsin|nasilsiniz|как\s+дела|كيف\s+حالك)\b/i;
25914
25979
  var NEWS_BRIEF_RE = /\b(?:top|latest|breaking)\s+news\b|\bnews\s+(?:today|now|latest|updates?)\b/i;
25915
25980
  var SEMANTIC_SMALLTALK_ACTION_GUARD_RE = /\b(?:joke|funny|meme|story|poem|quote|news|latest|top|weather|forecast|time|clock|provider|model|set|switch|remember|memory|session|note|notes|remind|todo|search|find|nearest|hospital|train|router|network|devices?|scan|transcrib|translate|summarize|code|debug|review|install|delete|remove|forget|clear|tell\s+me|what\s+can\s+(?:you|u)\s+do|who\s+(?:are|r)\s+(?:you|u)|what\s+are\s+you)\b/i;
25916
25981
  var SMALLTALK_IDENTITY_RE = /^\s*(?:who\s+(?:are|r)\s+(?:you|u)|what(?:'s|\s+is)\s+your\s+name|your\s+name\??)\s*$/i;
@@ -25971,36 +26036,38 @@ function isSemanticSmalltalkCandidate(text) {
25971
26036
  return words.length > 0 && words.length <= 5;
25972
26037
  }
25973
26038
  function buildCheckinReply(params) {
25974
- const { assistantName, locale } = params;
26039
+ const { assistantName, userName, locale } = params;
26040
+ const userPrefix = userName ? `${userName}, ` : "";
25975
26041
  if (locale === "te") {
25976
- return `\u0C28\u0C47\u0C28\u0C41 \u0C2C\u0C3E\u0C17\u0C41\u0C28\u0C4D\u0C28\u0C3E\u0C28\u0C41. \u0C28\u0C47\u0C28\u0C41 ${assistantName} \u2014 ready\u0C17\u0C3E \u0C09\u0C28\u0C4D\u0C28\u0C3E\u0C28\u0C41. \u0C2E\u0C40\u0C30\u0C41 \u0C0F\u0C02 \u0C1A\u0C47\u0C2F\u0C3E\u0C32\u0C28\u0C41\u0C15\u0C41\u0C02\u0C1F\u0C41\u0C28\u0C4D\u0C28\u0C3E\u0C30\u0C41?`;
26042
+ return `${userPrefix}\u0C28\u0C47\u0C28\u0C41 \u0C2C\u0C3E\u0C17\u0C41\u0C28\u0C4D\u0C28\u0C3E\u0C28\u0C41. \u0C28\u0C47\u0C28\u0C41 ${assistantName} \u2014 calm\u0C17\u0C3E ready\u0C17\u0C3E \u0C09\u0C28\u0C4D\u0C28\u0C3E\u0C28\u0C41. \u0C2E\u0C40\u0C30\u0C41 \u0C0F\u0C02 \u0C1A\u0C47\u0C2F\u0C3E\u0C32\u0C28\u0C41\u0C15\u0C41\u0C02\u0C1F\u0C41\u0C28\u0C4D\u0C28\u0C3E\u0C30\u0C41?`;
25977
26043
  }
25978
26044
  if (locale === "es") {
25979
- return `Estoy bien. Soy ${assistantName} y estoy lista. Que quieres hacer ahora?`;
26045
+ return `${userPrefix}Estoy bien. Soy ${assistantName}, tranquila y lista. Que quieres hacer ahora?`;
25980
26046
  }
25981
26047
  if (locale === "de") {
25982
- return `Mir geht's gut. Ich bin ${assistantName} und bereit. Womit soll ich starten?`;
26048
+ return `${userPrefix}Mir geht's gut. Ich bin ${assistantName}, ruhig und bereit. Womit soll ich starten?`;
25983
26049
  }
25984
26050
  if (locale === "pl") {
25985
- return `Mam sie dobrze. Jestem ${assistantName} i jestem gotowa. Od czego zaczynamy?`;
26051
+ return `${userPrefix}Mam sie dobrze. Jestem ${assistantName}, spokojna i gotowa. Od czego zaczynamy?`;
25986
26052
  }
25987
- return `I'm good. I'm ${assistantName} and ready. What do you want to do next?`;
26053
+ return `${userPrefix}I'm good. I'm ${assistantName} - calm, direct, and ready. What do you want to do next?`;
25988
26054
  }
25989
26055
  function buildIdentityReply(params) {
25990
- const { assistantName, locale } = params;
26056
+ const { assistantName, userName, locale } = params;
26057
+ const userPrefix = userName ? `${userName}, ` : "";
25991
26058
  if (locale === "te") {
25992
- return `\u0C28\u0C47\u0C28\u0C41 ${assistantName}. \u0C28\u0C47\u0C28\u0C41 \u0C1A\u0C3E\u0C1F\u0C4D \u0C1A\u0C47\u0C2F\u0C17\u0C32\u0C28\u0C41, tools \u0C28\u0C21\u0C2A\u0C17\u0C32\u0C28\u0C41, \u0C2E\u0C30\u0C3F\u0C2F\u0C41 \u0C2E\u0C40 preferences \u0C17\u0C41\u0C30\u0C4D\u0C24\u0C41\u0C02\u0C1A\u0C41\u0C15\u0C4B\u0C17\u0C32\u0C28\u0C41.`;
26059
+ return `${userPrefix}\u0C28\u0C47\u0C28\u0C41 ${assistantName}. \u0C28\u0C47\u0C28\u0C41 calm\u0C17\u0C3E direct\u0C17\u0C3E \u0C38\u0C39\u0C3E\u0C2F\u0C02 \u0C1A\u0C47\u0C38\u0C4D\u0C24\u0C3E\u0C28\u0C41; chat \u0C1A\u0C47\u0C2F\u0C17\u0C32\u0C28\u0C41, tools \u0C28\u0C21\u0C2A\u0C17\u0C32\u0C28\u0C41, \u0C2E\u0C30\u0C3F\u0C2F\u0C41 \u0C2E\u0C40 preferences \u0C17\u0C41\u0C30\u0C4D\u0C24\u0C41\u0C02\u0C1A\u0C41\u0C15\u0C4B\u0C17\u0C32\u0C28\u0C41.`;
25993
26060
  }
25994
26061
  if (locale === "es") {
25995
- return `Soy ${assistantName}. Puedo conversar, ejecutar herramientas y recordar tus preferencias cuando me lo pides.`;
26062
+ return `${userPrefix}Soy ${assistantName}. Trabajo con calma y precision: puedo conversar, ejecutar herramientas y recordar tus preferencias cuando me lo pides.`;
25996
26063
  }
25997
26064
  if (locale === "de") {
25998
- return `Ich bin ${assistantName}. Ich kann chatten, Tools ausfuehren und mir deine Einstellungen merken, wenn du das willst.`;
26065
+ return `${userPrefix}Ich bin ${assistantName}. Ich arbeite ruhig und praezise: Ich kann chatten, Tools ausfuehren und mir deine Einstellungen merken, wenn du das willst.`;
25999
26066
  }
26000
26067
  if (locale === "pl") {
26001
- return `Jestem ${assistantName}. Potrafie rozmawiac, uruchamiac narzedzia i zapamietywac Twoje preferencje, gdy o to poprosisz.`;
26068
+ return `${userPrefix}Jestem ${assistantName}. Dzialam spokojnie i konkretnie: potrafie rozmawiac, uruchamiac narzedzia i zapamietywac Twoje preferencje, gdy o to poprosisz.`;
26002
26069
  }
26003
- return `I'm ${assistantName}. I can chat, run tools, and remember your preferences when you ask.`;
26070
+ return `${userPrefix}I'm ${assistantName} - calm, sharp, and privacy-first. I can chat, run tools, and remember your preferences when you ask.`;
26004
26071
  }
26005
26072
  function buildJokeReply(locale) {
26006
26073
  if (locale === "te") {
@@ -26115,10 +26182,8 @@ async function handleQuickResponses(params) {
26115
26182
  const { session, message, profile, routingDecision, routingResult, storage, isPureGreeting: isPureGreeting2, isPureAck: isPureAck2, buildSmalltalkReply: buildSmalltalkReply2, looksLikeRecentRecap: looksLikeRecentRecap2, formatRecentRecap: formatRecentRecap2, extractLocationAssignments: extractLocationAssignments2, updateProfile, broadcastEvent, appendPreferenceMemory, maybeAppendSmritiMemory, interpretNlu } = params;
26116
26183
  const trimmed = message.text.trim();
26117
26184
  const locale = params.locale ?? "en";
26118
- const recentEvents = await storage.listSessionEvents(session.id, { limit: 3 });
26119
- const lastEvent = recentEvents[recentEvents.length - 1];
26120
- const lastEventAge = lastEvent ? Date.now() - new Date(lastEvent.createdAt).getTime() : Infinity;
26121
- const isStaleSession = lastEventAge > 30 * 60 * 1e3;
26185
+ const mode = params.mode ?? "full";
26186
+ const locationAssignments = mode === "full" ? extractLocationAssignments2(message.text) : null;
26122
26187
  const emitLocal = async (model, replyText) => {
26123
26188
  const reply = normalizeAgentReply(replyText);
26124
26189
  await appendAssistantEvent(storage, session.id, reply, {
@@ -26174,6 +26239,7 @@ async function handleQuickResponses(params) {
26174
26239
  });
26175
26240
  return emitLocal("smalltalk.identity", buildIdentityReply({
26176
26241
  assistantName: profile.assistantName?.trim() || "Vaayu",
26242
+ userName: profile.userName?.trim(),
26177
26243
  locale
26178
26244
  }));
26179
26245
  };
@@ -26187,6 +26253,7 @@ async function handleQuickResponses(params) {
26187
26253
  });
26188
26254
  return emitLocal("smalltalk.checkin", buildCheckinReply({
26189
26255
  assistantName: profile.assistantName?.trim() || "Vaayu",
26256
+ userName: profile.userName?.trim(),
26190
26257
  locale
26191
26258
  }));
26192
26259
  }
@@ -26217,6 +26284,9 @@ async function handleQuickResponses(params) {
26217
26284
  return emitLocal("news.unavailable", formatNewsReply([], locale));
26218
26285
  }
26219
26286
  }
26287
+ if (mode === "smalltalk-only") {
26288
+ return null;
26289
+ }
26220
26290
  if (interpretNlu && isSemanticSmalltalkCandidate(trimmed)) {
26221
26291
  try {
26222
26292
  const interpreted = await interpretNlu({
@@ -26263,9 +26333,24 @@ async function handleQuickResponses(params) {
26263
26333
  } catch {
26264
26334
  }
26265
26335
  }
26266
- const lastAssistantEvent = [...recentEvents].reverse().find((event) => event.role === "assistant");
26336
+ const asksYesterday = YESTERDAY_RECAP_RE.test(message.text);
26337
+ const asksRecentRecap = !asksYesterday && looksLikeRecentRecap2(message.text);
26338
+ const mayBeWeatherFollowup = !locationAssignments && isLikelyLocationReply(trimmed);
26339
+ let recentEvents = [];
26340
+ let isStaleSession = false;
26341
+ if (mayBeWeatherFollowup || asksRecentRecap) {
26342
+ recentEvents = await storage.listSessionEvents(session.id, {
26343
+ limit: asksRecentRecap ? 8 : 3
26344
+ });
26345
+ if (asksRecentRecap) {
26346
+ const lastEvent = recentEvents[recentEvents.length - 1];
26347
+ const lastEventAge = lastEvent ? Date.now() - new Date(lastEvent.createdAt).getTime() : Infinity;
26348
+ isStaleSession = lastEventAge > 30 * 60 * 1e3;
26349
+ }
26350
+ }
26351
+ const lastAssistantEvent = mayBeWeatherFollowup ? [...recentEvents].reverse().find((event) => event.role === "assistant") : void 0;
26267
26352
  const lastModel = typeof lastAssistantEvent?.metadata?.model === "string" ? lastAssistantEvent.metadata.model : void 0;
26268
- if (!extractLocationAssignments2(message.text) && lastModel === "weather.prompt" && isLikelyLocationReply(trimmed)) {
26353
+ if (!locationAssignments && lastModel === "weather.prompt" && mayBeWeatherFollowup) {
26269
26354
  const location = trimmed.replace(/[?.!]+$/, "");
26270
26355
  const updated = updateProfile({ currentLocation: location });
26271
26356
  broadcastEvent("profile.updated", updated);
@@ -26281,14 +26366,13 @@ async function handleQuickResponses(params) {
26281
26366
  }, message);
26282
26367
  return buildEarlyResult(session, "profile.set", reply, routingDecision, routingResult);
26283
26368
  }
26284
- const asksYesterday = YESTERDAY_RECAP_RE.test(message.text);
26285
- if (asksYesterday || looksLikeRecentRecap2(message.text)) {
26369
+ if (asksYesterday || asksRecentRecap) {
26286
26370
  let recent = asksYesterday ? await collectYesterdayEvents({
26287
26371
  storage,
26288
26372
  session,
26289
26373
  message,
26290
26374
  profile
26291
- }) : await storage.listSessionEvents(session.id, { limit: 8 });
26375
+ }) : recentEvents.length ? recentEvents : await storage.listSessionEvents(session.id, { limit: 8 });
26292
26376
  let reply = formatRecentRecap2(recent, message.channel, locale);
26293
26377
  if (!recent.length || !asksYesterday && isStaleSession) {
26294
26378
  const prefs = await storage.getSessionPrefs(session.id);
@@ -26332,19 +26416,18 @@ ${cross.summary}` : `Here\u2019s what we were discussing${deviceLabel}: ${cross.
26332
26416
  });
26333
26417
  return buildEarlyResult(session, "memory.recap", reply, routingDecision, routingResult);
26334
26418
  }
26335
- const locations = extractLocationAssignments2(message.text);
26336
- if (locations) {
26419
+ if (locationAssignments) {
26337
26420
  const updated = updateProfile({
26338
- ...locations.currentLocation ? { currentLocation: locations.currentLocation } : {},
26339
- ...locations.homeLocation ? { homeLocation: locations.homeLocation } : {}
26421
+ ...locationAssignments.currentLocation ? { currentLocation: locationAssignments.currentLocation } : {},
26422
+ ...locationAssignments.homeLocation ? { homeLocation: locationAssignments.homeLocation } : {}
26340
26423
  });
26341
26424
  broadcastEvent("profile.updated", updated);
26342
26425
  const lines = [];
26343
- if (locations.currentLocation) {
26426
+ if (locationAssignments.currentLocation) {
26344
26427
  lines.push(`Current location set to ${updated.currentLocation}.`);
26345
26428
  await appendPreferenceMemory(`Current location: ${updated.currentLocation}`, ["preference", "location", "current"]);
26346
26429
  }
26347
- if (locations.homeLocation) {
26430
+ if (locationAssignments.homeLocation) {
26348
26431
  lines.push(`Home location set to ${updated.homeLocation}.`);
26349
26432
  await appendPreferenceMemory(`Home location: ${updated.homeLocation}`, ["preference", "location", "home"]);
26350
26433
  }
@@ -26432,7 +26515,7 @@ var WEATHER_TEMP_RE = /\b(hot|cold|humid|humidity|calor|frio|frío|humedo|húmed
26432
26515
  var WEATHER_CONVERSATIONAL_RE = /\b(is\s+it|will\s+it|how(?:'s|\s+is)?\s+it|what(?:'s|\s+is)\s+it\s+like|nice\s+out)\b/i;
26433
26516
  var SMALLTALK_TASK_RE = /\b(remind|reminder|note|notes|transcrib|forecast|bmi|music|play|panchangam|sunrise|sunset)\b/i;
26434
26517
  var SMALLTALK_STRIP_MARKS_RE = /[\u0300-\u036f]/g;
26435
- var EXTRA_GREETING_RE = /^(salut|coucou|merhaba|nasilsiniz|nasılsınız|iyi\s+akşamlar|здравствуйте|как\s+дела|السلام\s+عليكم|صباح\s+الخير|كيف\s+حالك|你好吗|お元気ですか|잘\s+지내세요)(?:$|[\s!,.?]+)/i;
26518
+ var EXTRA_GREETING_RE = /^(salut|coucou|merhaba|nasilsin|nasılsın|nasilsiniz|nasılsınız|iyi\s+akşamlar|здравствуйте|как\s+дела|السلام\s+عليكم|صباح\s+الخير|كيف\s+حالك|你好吗|お元気ですか|잘\s+지내세요)(?:$|[\s!,.?]+)/i;
26436
26519
  var EXTRA_ACK_RE = /^(vale|de\s+acuerdo|anladım|anladim|tamam|понял|хорошо|ладно|تمام|مفهوم|d'accord|compris|entendu|alles\s+klar|in\s+ordnung|verstanden|theek\s+hai)(?:$|[\s!,.?]+)/i;
26437
26520
  function normalizeSmalltalkToken(token) {
26438
26521
  const normalized = token.toLowerCase().normalize("NFD").replace(SMALLTALK_STRIP_MARKS_RE, "").replace(/[^\p{L}\p{N}']+/gu, "").replace(/([a-z])\1{2,}/g, "$1$1");
@@ -26484,7 +26567,7 @@ function isPureGreeting(text, assistantName) {
26484
26567
  if (!trimmed)
26485
26568
  return false;
26486
26569
  const lower = trimmed.toLowerCase();
26487
- let match = lower.match(/^(h+i+|hell+o+|he+y+|yo+|sup+|wassup+|namaste|namaskar(?:am|a)?|namaskaram|vanakkam|hola+|hallo+|bonjour|comment\s+(?:ca|ça)\s+va|ca\s+va|ça\s+va|ciao+|ola+|good\s+(morning|afternoon|evening)|guten\s+(morgen|tag|abend)|buen(?:os|as)\s+(dias|tardes|noches)|how\s+(?:are|aer)\s+you(?:\s+doing)?|how\s+(?:r|aer)\s+u|hru|how(?:'s|\s+is)\s+it\s+going|como\s+estas|como\s+esta|wie\s+geht(?:s|es)|kaise\s+ho|ela\s+unnav(?:u)?|ela\s+unnaru|ela\s+undh?i|bagunava|bagunnava|bagunnara|baga\s+unnav(?:a|u)?|baga\s+unnar(?:a|u)|all\s+good(?:\s+ha)?|привет|здравствуй|你好|您好|こんにちは|こんばんは|안녕하세요|안녕|مرحبا|أهلا|اهلا|नमस्ते|నమస్తే|హలో|హాయ్)(?:$|[\s!,.?]+)/i);
26570
+ let match = lower.match(/^(h+i+|hell+o+|he+y+|yo+|sup+|wassup+|namaste|namaskar(?:am|a)?|namaskaram|vanakkam|hola+|hallo+|bonjour|comment\s+(?:ca|ça)\s+va|ca\s+va|ça\s+va|ciao+|ola+|good\s+(morning|afternoon|evening)|guten\s+(morgen|tag|abend)|buen(?:os|as)\s+(dias|tardes|noches)|how\s+(?:are|aer)\s+you(?:\s+doing)?|how\s+(?:r|aer)\s+u|hru|how(?:'s|\s+is)\s+it\s+going|como\s+estas|como\s+esta|wie\s+geht(?:s|es)|kaise\s+ho|nasilsin|nasılsın|nasilsiniz|nasılsınız|ela\s+unnav(?:u)?|ela\s+unnaru|ela\s+undh?i|bagunava|bagunnava|bagunnara|baga\s+unnav(?:a|u)?|baga\s+unnar(?:a|u)|all\s+good(?:\s+ha)?|привет|здравствуй|你好|您好|こんにちは|こんばんは|안녕하세요|안녕|مرحبا|أهلا|اهلا|नमस्ते|నమస్తే|హలో|హాయ్)(?:$|[\s!,.?]+)/i);
26488
26571
  if (!match) {
26489
26572
  match = lower.match(EXTRA_GREETING_RE);
26490
26573
  }
@@ -26597,6 +26680,7 @@ function isPureGreeting(text, assistantName) {
26597
26680
  "salut",
26598
26681
  "coucou",
26599
26682
  "merhaba",
26683
+ "nasilsin",
26600
26684
  "nasilsiniz",
26601
26685
  "iyi",
26602
26686
  "aksamlar",
@@ -29701,7 +29785,7 @@ function buildForcedIntentPlan(params) {
29701
29785
  return null;
29702
29786
  }
29703
29787
  async function handleToolPlanning(params) {
29704
- const { session, message, runId, signal, profile, locale, contextMessages, combinedSystem, resolvedProviderId, resolvedModel, budgetFallbackTarget, routingDecision, routingResult, isPureGreeting: isPureGreeting2, isPureAck: isPureAck2, maybeAppendSmritiMemory, config, logger, storage, toolRegistry, toolPolicy, isToolAllowed: isToolAllowed2, interpretRules: interpretRules2, interpretNlu, planToolInvocation: planToolInvocation2, looksLikeWeatherAsk: looksLikeWeatherAsk2, cleanLocationInput: cleanLocationInput2, isTemporalLocation: isTemporalLocation2, getToolApprovalRequirement: getToolApprovalRequirement2, createToolApprovalRequest, skillSynthEngine, skillSynthEnabled, getProvider, chitraguptaBridge } = params;
29788
+ const { session, message, runId, signal, plannerMode = "default", profile, locale, contextMessages, combinedSystem, resolvedProviderId, resolvedModel, budgetFallbackTarget, routingDecision, routingResult, isPureGreeting: isPureGreeting2, isPureAck: isPureAck2, maybeAppendSmritiMemory, config, logger, storage, toolRegistry, toolPolicy, isToolAllowed: isToolAllowed2, interpretRules: interpretRules2, interpretNlu, planToolInvocation: planToolInvocation2, looksLikeWeatherAsk: looksLikeWeatherAsk2, cleanLocationInput: cleanLocationInput2, isTemporalLocation: isTemporalLocation2, getToolApprovalRequirement: getToolApprovalRequirement2, createToolApprovalRequest, skillSynthEngine, skillSynthEnabled, getProvider, chitraguptaBridge } = params;
29705
29789
  if (!message.text)
29706
29790
  return null;
29707
29791
  const normalized = normalizeIncomingText(message.text);
@@ -29915,6 +29999,10 @@ async function handleToolPlanning(params) {
29915
29999
  let plannerProvider = null;
29916
30000
  let plannerResult = null;
29917
30001
  if (!plan) {
30002
+ if (plannerMode === "deterministic_only") {
30003
+ await maybeRecordActiveToolDiscovery();
30004
+ return null;
30005
+ }
29918
30006
  const plannerRole = config.routing.roles?.planner;
29919
30007
  plannerProviderId = plannerRole?.providerId ?? resolvedProviderId;
29920
30008
  plannerModel = plannerRole?.model ?? resolvedModel;
@@ -30040,9 +30128,13 @@ async function handleToolPlanning(params) {
30040
30128
  break;
30041
30129
  } catch (error) {
30042
30130
  plannerError = error;
30131
+ const cooldown2 = registerProviderFailure(attempt.providerId, error, attemptProvider.type);
30043
30132
  logger.warn("planner_failed", {
30044
30133
  providerId: attempt.providerId,
30045
- error: error instanceof Error ? error.message : String(error)
30134
+ error: error instanceof Error ? error.message : String(error),
30135
+ cooldownReason: cooldown2.reason,
30136
+ cooldownUntil: new Date(cooldown2.until).toISOString(),
30137
+ cooldownFailures: cooldown2.failures
30046
30138
  });
30047
30139
  }
30048
30140
  }
@@ -30956,6 +31048,8 @@ async function runChatWithFallback(params) {
30956
31048
  messages: prunedMessages ?? baseMessages,
30957
31049
  maxTokens: config.routing.budgets?.maxTokensPerRequest,
30958
31050
  metadata: requestMeta,
31051
+ tools: params.tools,
31052
+ toolChoice: params.toolChoice,
30959
31053
  signal: attemptSignal
30960
31054
  });
30961
31055
  response = await chatWithPolicy({
@@ -31031,7 +31125,8 @@ async function runChatWithFallback(params) {
31031
31125
  reason: "no_healthy_provider",
31032
31126
  retryable: true,
31033
31127
  responseModel: "provider.failure"
31034
- }
31128
+ },
31129
+ friendlyMessage: "I'm switching routes right now and can still handle quick tasks like weather, reminders, and notes. Please retry this request in a moment."
31035
31130
  };
31036
31131
  }
31037
31132
  return {
@@ -31042,7 +31137,8 @@ async function runChatWithFallback(params) {
31042
31137
  reason: "attempts_exhausted",
31043
31138
  retryable: true,
31044
31139
  responseModel: "provider.failure"
31045
- }
31140
+ },
31141
+ friendlyMessage: "I couldn't complete that with the current model route. I'm rebalancing providers automatically - please retry this request now."
31046
31142
  };
31047
31143
  }
31048
31144
  return {
@@ -32679,6 +32775,21 @@ function storeSemanticResponseCache(params) {
32679
32775
  }
32680
32776
 
32681
32777
  // apps/gateway/dist/agent/loop-execute.js
32778
+ function resolveSmalltalkProviderFallback(params) {
32779
+ const { actionability, escalation, buildSmalltalkReply: buildSmalltalkReply2, profile, channel, locale } = params;
32780
+ if (actionability.kind !== "smalltalk") {
32781
+ return null;
32782
+ }
32783
+ if (escalation.reason !== "all_candidates_cooling_down" && escalation.reason !== "no_healthy_provider" && escalation.reason !== "attempts_exhausted") {
32784
+ return null;
32785
+ }
32786
+ const kind = actionability.reason === "smalltalk_ack" ? "ack" : "greeting";
32787
+ const model = kind === "ack" ? "smalltalk.ack" : "smalltalk.greeting";
32788
+ return {
32789
+ model,
32790
+ content: buildSmalltalkReply2(profile, kind, channel, locale)
32791
+ };
32792
+ }
32682
32793
  function mapMargaComplexityToTier(complexity) {
32683
32794
  if (!complexity)
32684
32795
  return "fast";
@@ -32695,7 +32806,74 @@ async function executeAgentRun(params) {
32695
32806
  const normalizedOutboundMeta = hasMatchingNormalization && normalizationFromMessage?.outbound ? normalizationFromMessage.outbound : buildNormalizationOutboundMeta(normalizedIncoming);
32696
32807
  const routingText = normalizedAuditContext.norm || payload.message.text;
32697
32808
  const retrievalText = normalizedAuditContext.search || normalizedAuditContext.norm || payload.message.text;
32809
+ const message = {
32810
+ text: payload.message.text,
32811
+ channel: payload.message.channel,
32812
+ chatId: payload.message.chatId,
32813
+ userId: payload.message.userId,
32814
+ deviceId: payload.message.deviceId,
32815
+ clientTag: payload.message.clientTag,
32816
+ clientHostHash: payload.message.clientHostHash,
32817
+ channelAccountId: payload.message.channelAccountId,
32818
+ raw: payload.message.raw,
32819
+ normalization: {
32820
+ audit: normalizedAuditContext,
32821
+ outbound: normalizedOutboundMeta
32822
+ }
32823
+ };
32698
32824
  const getProfile = () => runtime.profile;
32825
+ const preflightLanguageDecision = resolveLanguageDecision({
32826
+ text: payload.message.text,
32827
+ prefs: void 0,
32828
+ profile: getProfile()
32829
+ });
32830
+ const preflightLocale = preflightLanguageDecision.locale;
32831
+ const preflightNaturalCommand = detectNaturalLanguageCommand(routingText, preflightLocale);
32832
+ const preflightCommandText = preflightNaturalCommand ?? payload.message.text;
32833
+ const preflightCommand = parseCommand(preflightCommandText);
32834
+ if (!preflightCommand) {
32835
+ const allowMemoryPreflight = memoryAllowed() && payload.memoryMode !== "disabled";
32836
+ const maybeAppendSmritiMemoryPreflight = allowMemoryPreflight ? maybeAppendSmritiMemory : async () => {
32837
+ };
32838
+ const preflightQuickResult = await handleQuickResponses({
32839
+ session,
32840
+ message,
32841
+ profile: getProfile(),
32842
+ routingDecision: null,
32843
+ routingResult: {
32844
+ auto: false,
32845
+ language: preflightLocale,
32846
+ languageSource: preflightLanguageDecision.source
32847
+ },
32848
+ storage,
32849
+ isPureGreeting: deps.isPureGreeting,
32850
+ isPureAck: deps.isPureAck,
32851
+ buildSmalltalkReply: deps.buildSmalltalkReply,
32852
+ looksLikeRecentRecap: deps.looksLikeRecentRecap,
32853
+ formatRecentRecap: deps.formatRecentRecap,
32854
+ extractLocationAssignments: deps.extractLocationAssignments,
32855
+ updateProfile: runtime.updateProfile,
32856
+ broadcastEvent: runtime.broadcastEvent,
32857
+ appendPreferenceMemory: runtime.appendPreferenceMemory,
32858
+ maybeAppendSmritiMemory: maybeAppendSmritiMemoryPreflight,
32859
+ locale: preflightLocale,
32860
+ continuity: runtime.config.session?.continuity,
32861
+ mode: "smalltalk-only"
32862
+ });
32863
+ if (preflightQuickResult) {
32864
+ await persistUserEvent({
32865
+ storage,
32866
+ sessionId: session.id,
32867
+ message,
32868
+ providerId: "local",
32869
+ model: preflightQuickResult.response.model,
32870
+ memoryManager,
32871
+ allowMemory: allowMemoryPreflight,
32872
+ logger
32873
+ });
32874
+ return preflightQuickResult;
32875
+ }
32876
+ }
32699
32877
  let prefs = await storage.getSessionPrefs(session.id);
32700
32878
  let profile = getProfile();
32701
32879
  ({ prefs, profile } = await ensureValidSavedModels({
@@ -32836,6 +33014,54 @@ async function executeAgentRun(params) {
32836
33014
  hasTools
32837
33015
  }) : { decision: null, trace: null };
32838
33016
  const routingDecision = autoRouting ? scoringResult.decision ?? margaRoutingDecision ?? heuristicRoutingDecision : null;
33017
+ const earlyRoutingResult = {
33018
+ auto: autoRouting,
33019
+ language: locale,
33020
+ languageSource: languageDecision.source,
33021
+ actionability,
33022
+ policyClassifier
33023
+ };
33024
+ if (scoringResult.trace) {
33025
+ earlyRoutingResult.scoring = scoringResult.trace;
33026
+ }
33027
+ if (!command) {
33028
+ const allowMemoryEarly = memoryAllowed() && payload.memoryMode !== "disabled";
33029
+ const maybeAppendSmritiMemorySafeEarly = allowMemoryEarly ? maybeAppendSmritiMemory : async () => {
33030
+ };
33031
+ const earlyQuickResult = await handleQuickResponses({
33032
+ session,
33033
+ message,
33034
+ profile,
33035
+ routingDecision,
33036
+ routingResult: earlyRoutingResult,
33037
+ storage,
33038
+ isPureGreeting: deps.isPureGreeting,
33039
+ isPureAck: deps.isPureAck,
33040
+ buildSmalltalkReply: deps.buildSmalltalkReply,
33041
+ looksLikeRecentRecap: deps.looksLikeRecentRecap,
33042
+ formatRecentRecap: deps.formatRecentRecap,
33043
+ extractLocationAssignments: deps.extractLocationAssignments,
33044
+ updateProfile: runtime.updateProfile,
33045
+ broadcastEvent: runtime.broadcastEvent,
33046
+ appendPreferenceMemory: runtime.appendPreferenceMemory,
33047
+ maybeAppendSmritiMemory: maybeAppendSmritiMemorySafeEarly,
33048
+ locale,
33049
+ continuity: runtime.config.session?.continuity
33050
+ });
33051
+ if (earlyQuickResult) {
33052
+ await persistUserEvent({
33053
+ storage,
33054
+ sessionId: session.id,
33055
+ message,
33056
+ providerId: "local",
33057
+ model: earlyQuickResult.response.model,
33058
+ memoryManager,
33059
+ allowMemory: allowMemoryEarly,
33060
+ logger
33061
+ });
33062
+ return earlyQuickResult;
33063
+ }
33064
+ }
32839
33065
  const manualModelOverride = Boolean(payload.model) || !autoRouting && Boolean(prefs?.model);
32840
33066
  const reasoningEnabled = !manualModelOverride && (reasoningMode === "on" || reasoningMode === "auto" && complexitySignal?.tier === "deep");
32841
33067
  const budgetState = await evaluateBudgetState({ storage, config, logger });
@@ -33029,21 +33255,6 @@ async function executeAgentRun(params) {
33029
33255
  userId: payload.message.userId,
33030
33256
  skipExpensiveMemory
33031
33257
  });
33032
- const message = {
33033
- text: payload.message.text,
33034
- channel: payload.message.channel,
33035
- chatId: payload.message.chatId,
33036
- userId: payload.message.userId,
33037
- deviceId: payload.message.deviceId,
33038
- clientTag: payload.message.clientTag,
33039
- clientHostHash: payload.message.clientHostHash,
33040
- channelAccountId: payload.message.channelAccountId,
33041
- raw: payload.message.raw,
33042
- normalization: {
33043
- audit: normalizedAuditContext,
33044
- outbound: normalizedOutboundMeta
33045
- }
33046
- };
33047
33258
  await persistUserEvent({
33048
33259
  storage,
33049
33260
  sessionId: session.id,
@@ -33097,7 +33308,8 @@ async function executeAgentRun(params) {
33097
33308
  taskType: margaDecision.taskType,
33098
33309
  complexity: margaDecision.complexity
33099
33310
  });
33100
- const skipContent = "Hey! What can I help you with?";
33311
+ const skipKind = margaDecision.taskType === "heartbeat" ? "ack" : "greeting";
33312
+ const skipContent = deps.buildSmalltalkReply(runtime.profile, skipKind, payload.message.channel, locale);
33101
33313
  const skipModel = `marga:${margaDecision.taskType}`;
33102
33314
  await appendAssistantEvent(storage, session.id, skipContent, {
33103
33315
  providerId: "marga",
@@ -33161,6 +33373,11 @@ async function executeAgentRun(params) {
33161
33373
  routingResult.fallbackUsed = false;
33162
33374
  return buildEarlyResult(session, cacheModel, cached2.responseContent, routingDecision, routingResult);
33163
33375
  }
33376
+ const agenticTools = runtime.toolRegistry.list().filter((t2) => deps.isToolAllowed(toolPolicy, t2.name)).filter((t2) => !t2.name.startsWith("memory.")).map((t2) => ({
33377
+ name: t2.name,
33378
+ description: t2.description,
33379
+ inputSchema: t2.inputSchema
33380
+ }));
33164
33381
  const chatResult = await runChatWithFallback({
33165
33382
  sessionId: session.id,
33166
33383
  messageText: payload.message.text,
@@ -33197,11 +33414,92 @@ async function executeAgentRun(params) {
33197
33414
  providerHealth: runtime.providerHealth,
33198
33415
  lastAnthropicCallAt,
33199
33416
  logger,
33200
- signal: runSignal
33417
+ signal: runSignal,
33418
+ tools: agenticTools.length > 0 ? agenticTools : void 0
33201
33419
  });
33202
33420
  if (!chatResult.ok) {
33203
33421
  const escalation = chatResult.escalation;
33204
- const content = escalation.policy === "degraded_tools_only" && chatResult.friendlyMessage ? chatResult.friendlyMessage : formatProviderError2(chatResult.error ?? new Error("Provider failed"));
33422
+ if (escalation.reason !== "request_aborted" && actionability.kind !== "smalltalk") {
33423
+ const degradedToolResult = await handleToolPlanning({
33424
+ session,
33425
+ message,
33426
+ runId,
33427
+ signal: runSignal,
33428
+ plannerMode: "deterministic_only",
33429
+ profile,
33430
+ locale: locale ?? "en",
33431
+ contextMessages: context.messages,
33432
+ combinedSystem,
33433
+ resolvedProviderId,
33434
+ resolvedModel,
33435
+ budgetFallbackTarget,
33436
+ routingDecision,
33437
+ routingResult,
33438
+ isPureGreeting: deps.isPureGreeting,
33439
+ isPureAck: deps.isPureAck,
33440
+ maybeAppendSmritiMemory: maybeAppendSmritiMemorySafe,
33441
+ config,
33442
+ storage,
33443
+ logger,
33444
+ providerHealth: runtime.providerHealth,
33445
+ getProfile: () => runtime.profile,
33446
+ toolRegistry: runtime.toolRegistry,
33447
+ toolPolicy,
33448
+ isToolAllowed: deps.isToolAllowed,
33449
+ interpretRules: deps.interpretRules,
33450
+ interpretNlu: deps.interpretNlu,
33451
+ planToolInvocation: deps.planToolInvocation,
33452
+ looksLikeWeatherAsk: deps.looksLikeWeatherAsk,
33453
+ cleanLocationInput: deps.cleanLocationInput,
33454
+ isTemporalLocation: deps.isTemporalLocation,
33455
+ getToolApprovalRequirement: deps.getToolApprovalRequirement,
33456
+ createToolApprovalRequest: deps.createToolApprovalRequest,
33457
+ guardToolExecution: deps.guardToolExecution,
33458
+ updateWeatherDefaults: deps.updateWeatherDefaults,
33459
+ formatWeatherResponse: deps.formatWeatherResponse,
33460
+ formatWeatherForecastResponse: deps.formatWeatherForecastResponse,
33461
+ renderToolOutput: deps.renderToolOutput,
33462
+ renderToolFailure: deps.renderToolFailure,
33463
+ stripModelThinking: deps.stripModelThinking,
33464
+ getProvider,
33465
+ skillSynthEngine: deps.skillSynthEngine,
33466
+ skillSynthEnabled: deps.skillSynthEnabled,
33467
+ chitraguptaBridge: runtime.chitraguptaBridge
33468
+ });
33469
+ if (degradedToolResult) {
33470
+ routingResult.escalation = escalation;
33471
+ return degradedToolResult;
33472
+ }
33473
+ }
33474
+ const smalltalkFallback = resolveSmalltalkProviderFallback({
33475
+ actionability,
33476
+ escalation,
33477
+ buildSmalltalkReply: deps.buildSmalltalkReply,
33478
+ profile,
33479
+ channel: payload.message.channel,
33480
+ locale
33481
+ });
33482
+ if (smalltalkFallback) {
33483
+ routingResult.escalation = escalation;
33484
+ await appendAssistantEvent(storage, session.id, smalltalkFallback.content, {
33485
+ providerId: "local",
33486
+ model: smalltalkFallback.model
33487
+ }, payload.message);
33488
+ await maybeAppendSmritiMemorySafe({
33489
+ userText: payload.message.text,
33490
+ assistantText: smalltalkFallback.content,
33491
+ sessionId: session.id,
33492
+ channel: payload.message.channel,
33493
+ chatId: payload.message.chatId,
33494
+ userId: payload.message.userId,
33495
+ providerId: "local",
33496
+ model: smalltalkFallback.model
33497
+ });
33498
+ routingResult.selected = { providerId: "local", model: smalltalkFallback.model };
33499
+ routingResult.fallbackUsed = false;
33500
+ return buildEarlyResult(session, smalltalkFallback.model, smalltalkFallback.content, routingDecision, routingResult);
33501
+ }
33502
+ const content = chatResult.friendlyMessage ? chatResult.friendlyMessage : formatProviderError2(chatResult.error ?? new Error("Provider failed"));
33205
33503
  const errorModel = escalation.responseModel;
33206
33504
  routingResult.escalation = escalation;
33207
33505
  await appendAssistantEvent(storage, session.id, content, {
@@ -33223,6 +33521,43 @@ async function executeAgentRun(params) {
33223
33521
  return buildEarlyResult(session, errorModel, content, routingDecision, routingResult);
33224
33522
  }
33225
33523
  const { response, provider, model, fallbackUsed } = chatResult;
33524
+ let finalResponse = response;
33525
+ if (response.toolCalls?.length && agenticTools.length > 0) {
33526
+ const { runAgenticToolLoop } = await import("./chunks/agentic-tool-loop-2FZK72JO.js");
33527
+ const agenticResult = await runAgenticToolLoop({
33528
+ toolCalls: response.toolCalls,
33529
+ initialContent: response.content,
33530
+ initialModel: model,
33531
+ contextMessages: [...context.messages, { role: "user", content: payload.message.text }],
33532
+ tools: agenticTools,
33533
+ getToolRegistration: (name) => runtime.toolRegistry.get(name),
33534
+ isToolAllowed: (name) => deps.isToolAllowed(toolPolicy, name),
33535
+ reChat: async (msgs, tools) => {
33536
+ return provider.chat({
33537
+ model,
33538
+ messages: msgs,
33539
+ tools,
33540
+ maxTokens: config.routing.budgets?.maxTokensPerRequest,
33541
+ signal: runSignal
33542
+ });
33543
+ },
33544
+ maxIterations: config.routing.agenticMaxIterations ?? 5,
33545
+ signal: runSignal,
33546
+ logger,
33547
+ sessionId: session.id
33548
+ });
33549
+ finalResponse = {
33550
+ ...response,
33551
+ content: agenticResult.finalContent,
33552
+ model: agenticResult.finalModel,
33553
+ toolCalls: void 0
33554
+ };
33555
+ logger.info("agentic_loop_complete", {
33556
+ sessionId: session.id,
33557
+ iterations: agenticResult.iterations,
33558
+ toolsExecuted: agenticResult.toolResults.length
33559
+ });
33560
+ }
33226
33561
  if (runSignal.aborted) {
33227
33562
  throw new Error("Request aborted");
33228
33563
  }
@@ -33230,7 +33565,7 @@ async function executeAgentRun(params) {
33230
33565
  sessionId: session.id,
33231
33566
  category: semanticCacheCategory,
33232
33567
  query: routingText,
33233
- responseContent: response.content,
33568
+ responseContent: finalResponse.content,
33234
33569
  selected: { providerId: provider.id, model },
33235
33570
  ttlMs: semanticCacheRule.ttlMs
33236
33571
  });
@@ -33255,7 +33590,7 @@ async function executeAgentRun(params) {
33255
33590
  config,
33256
33591
  provider,
33257
33592
  model,
33258
- response,
33593
+ response: finalResponse,
33259
33594
  fallbackUsed,
33260
33595
  routingDecision,
33261
33596
  routingResult,
@@ -38284,6 +38619,7 @@ var routingSchema = external_exports.object({
38284
38619
  chatTimeoutMs: external_exports.number().int().min(1e3).max(12e4).default(15e3),
38285
38620
  maxAttempts: external_exports.number().int().min(1).max(10).default(2),
38286
38621
  plannerMaxAttempts: external_exports.number().int().min(1).max(10).default(1),
38622
+ agenticMaxIterations: external_exports.number().int().min(1).max(20).default(5),
38287
38623
  strategy: external_exports.enum(["first", "hash"]).default("hash"),
38288
38624
  minChars: external_exports.number().int().min(10).max(5e3).default(280),
38289
38625
  minWords: external_exports.number().int().min(5).max(500).default(60),
@@ -40835,6 +41171,9 @@ function formatProviderError(error) {
40835
41171
  return "I hit an error while handling that.";
40836
41172
  const raw = error instanceof Error ? error.message : String(error);
40837
41173
  const sanitized = sanitizeProviderError(raw);
41174
+ if (/^(i['’]m|please try)/i.test(sanitized)) {
41175
+ return sanitized;
41176
+ }
40838
41177
  return `I hit an error while handling that: ${sanitized}`;
40839
41178
  }
40840
41179
  function stripAnsi(input) {
@@ -40878,10 +41217,12 @@ function sanitizeProviderError(message) {
40878
41217
  if (/\b(timeout|timed out|etimedout|econnrefused|econnreset|fetch failed|network)\b/i.test(cleaned)) {
40879
41218
  return `${providerLabel} is temporarily unreachable.`;
40880
41219
  }
41220
+ if (/\b(no healthy provider|all providers on cooldown|all candidates on cooldown)\b/i.test(cleaned) || /\bprovider\s+[a-z0-9._-]+\s+unavailable\b/i.test(cleaned)) {
41221
+ return "I'm switching routes automatically right now. Please retry your request in a moment.";
41222
+ }
40881
41223
  const cooling = cleaned.match(/\bcooling down\s*\(([^)]+)\)/i);
40882
41224
  if (cooling) {
40883
- const reason = cooling[1]?.trim() || "temporary_error";
40884
- return `${providerLabel} is cooling down (${reason}). You can run /provider reset all or wait briefly.`;
41225
+ return "I'm switching routes automatically right now. Please retry your request in a moment.";
40885
41226
  }
40886
41227
  if (providerId) {
40887
41228
  return `${providerLabel} failed.`;
@@ -45569,8 +45910,72 @@ function getTodayStart() {
45569
45910
  now.setHours(0, 0, 0, 0);
45570
45911
  return now.toISOString();
45571
45912
  }
45913
+ var pickCountField = (record) => {
45914
+ for (const key of ["totalMemories", "total", "count", "totalCount"]) {
45915
+ const value = record[key];
45916
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
45917
+ return Math.floor(value);
45918
+ }
45919
+ }
45920
+ return void 0;
45921
+ };
45922
+ var parseSmritiTotalMemories = (payload) => {
45923
+ if (Array.isArray(payload)) {
45924
+ return payload.length;
45925
+ }
45926
+ if (!payload || typeof payload !== "object") {
45927
+ return void 0;
45928
+ }
45929
+ const record = payload;
45930
+ const direct = pickCountField(record);
45931
+ if (typeof direct === "number") {
45932
+ return direct;
45933
+ }
45934
+ const items = record.items;
45935
+ if (Array.isArray(items)) {
45936
+ const fromItems = pickCountField(record);
45937
+ if (typeof fromItems === "number")
45938
+ return fromItems;
45939
+ return items.length;
45940
+ }
45941
+ const data2 = record.data;
45942
+ if (Array.isArray(data2)) {
45943
+ return data2.length;
45944
+ }
45945
+ if (data2 && typeof data2 === "object") {
45946
+ const nested = parseSmritiTotalMemories(data2);
45947
+ if (typeof nested === "number") {
45948
+ return nested;
45949
+ }
45950
+ }
45951
+ return void 0;
45952
+ };
45953
+ async function resolveTotalMemories(params) {
45954
+ const { smritiClient, logger } = params;
45955
+ if (!smritiClient) {
45956
+ return 0;
45957
+ }
45958
+ try {
45959
+ const result = await smritiClient.list({
45960
+ limit: 1,
45961
+ scope: "memory"
45962
+ });
45963
+ if (!result.ok) {
45964
+ return 0;
45965
+ }
45966
+ const parsed = parseSmritiTotalMemories(result.data);
45967
+ if (typeof parsed === "number") {
45968
+ return parsed;
45969
+ }
45970
+ } catch (error) {
45971
+ logger.warn("usage_flow_total_memories_failed", {
45972
+ error: error instanceof Error ? error.message : String(error)
45973
+ });
45974
+ }
45975
+ return 0;
45976
+ }
45572
45977
  function createUsageRpcMethods(deps) {
45573
- const { storage, logger, getProfile, providerRegistry, startedAt, getSessionResetInfo } = deps;
45978
+ const { storage, logger, getProfile, providerRegistry, smritiClient, startedAt, getSessionResetInfo } = deps;
45574
45979
  return {
45575
45980
  /**
45576
45981
  * Get usage overview for dashboard
@@ -45652,7 +46057,10 @@ function createUsageRpcMethods(deps) {
45652
46057
  * Get data flow statistics
45653
46058
  */
45654
46059
  "usage.flow": async (params) => {
45655
- let totalMemories = 0;
46060
+ const totalMemories = await resolveTotalMemories({
46061
+ smritiClient,
46062
+ logger
46063
+ });
45656
46064
  return {
45657
46065
  messages: {
45658
46066
  total: flowStats.messagesTotal,
@@ -52976,6 +53384,61 @@ async function runWithTimeout(action, timeoutMs) {
52976
53384
  }
52977
53385
  }
52978
53386
 
53387
+ // apps/gateway/dist/kaala/session-route.js
53388
+ var isSessionPinExpired = (route) => {
53389
+ const pinUntilMs = route.pinUntil ? Date.parse(route.pinUntil) : Number.NaN;
53390
+ return Boolean(route.pinProviderId) && Number.isFinite(pinUntilMs) && pinUntilMs <= Date.now();
53391
+ };
53392
+ var clearSessionPin = (route) => ({
53393
+ ...route,
53394
+ pinProviderId: void 0,
53395
+ pinModel: void 0,
53396
+ pinReason: void 0,
53397
+ pinUntil: void 0,
53398
+ updatedAt: nowIso()
53399
+ });
53400
+ async function getActiveKaalaSessionRoute(params) {
53401
+ const { storage, sessionId, logger, cache } = params;
53402
+ if (!sessionId || !storage.getSessionRoute) {
53403
+ return void 0;
53404
+ }
53405
+ const cached2 = cache?.get(sessionId);
53406
+ if (cached2 || cache?.has(sessionId)) {
53407
+ return cached2;
53408
+ }
53409
+ const route = await storage.getSessionRoute(sessionId);
53410
+ if (!route) {
53411
+ cache?.set(sessionId, void 0);
53412
+ return void 0;
53413
+ }
53414
+ if (!isSessionPinExpired(route)) {
53415
+ cache?.set(sessionId, route);
53416
+ return route;
53417
+ }
53418
+ const unpinned = clearSessionPin(route);
53419
+ if (!storage.setSessionRoute) {
53420
+ cache?.set(sessionId, unpinned);
53421
+ return unpinned;
53422
+ }
53423
+ try {
53424
+ const persisted = await storage.setSessionRoute(sessionId, {
53425
+ agentId: route.agentId,
53426
+ laneId: route.laneId,
53427
+ queueMode: route.queueMode,
53428
+ announceMode: route.announceMode
53429
+ });
53430
+ cache?.set(sessionId, persisted);
53431
+ return persisted;
53432
+ } catch (error) {
53433
+ logger.warn("kaala_session_route_pin_clear_failed", {
53434
+ sessionId,
53435
+ error: error instanceof Error ? error.message : String(error)
53436
+ });
53437
+ cache?.set(sessionId, unpinned);
53438
+ return unpinned;
53439
+ }
53440
+ }
53441
+
52979
53442
  // apps/gateway/dist/kaala/announce.js
52980
53443
  var shouldAnnounce = (event) => event.type === "queued" || event.type === "completed" || event.type === "failed" || event.type === "timeout";
52981
53444
  var formatDuration3 = (ms) => {
@@ -53018,13 +53481,15 @@ function createKaalaAnnouncer(deps) {
53018
53481
  const session = await storage.getSessionById(event.parentSessionId);
53019
53482
  if (!session?.channel || !session.chatId)
53020
53483
  return;
53021
- if (storage.getSessionRoute) {
53022
- const route = await storage.getSessionRoute(event.parentSessionId);
53023
- if (route?.announceMode === "none")
53024
- return;
53025
- if (route?.announceMode === "hub")
53026
- return;
53027
- }
53484
+ const route = await getActiveKaalaSessionRoute({
53485
+ storage,
53486
+ sessionId: event.parentSessionId,
53487
+ logger
53488
+ });
53489
+ if (route?.announceMode === "none")
53490
+ return;
53491
+ if (route?.announceMode === "hub")
53492
+ return;
53028
53493
  const shortId = event.taskId.slice(0, 8);
53029
53494
  const duration = formatDuration3(event.metrics?.durationMs);
53030
53495
  const tokens = formatTokens(event);
@@ -53762,10 +54227,12 @@ function createKaalaMonitor(params) {
53762
54227
  continue;
53763
54228
  if (!record.text)
53764
54229
  continue;
53765
- const route = record.sessionId && storage.getSessionRoute ? routeCache.get(record.sessionId) ?? await storage.getSessionRoute(record.sessionId) : void 0;
53766
- if (record.sessionId && storage.getSessionRoute && !routeCache.has(record.sessionId)) {
53767
- routeCache.set(record.sessionId, route);
53768
- }
54230
+ const route = record.sessionId ? await getActiveKaalaSessionRoute({
54231
+ storage,
54232
+ sessionId: record.sessionId,
54233
+ logger,
54234
+ cache: routeCache
54235
+ }) : void 0;
53769
54236
  const { agentId, parentAgentId } = resolveAgentIds({
53770
54237
  agentId: record.agentId ?? route?.agentId,
53771
54238
  parentAgentId: record.parentAgentId,
@@ -54062,10 +54529,12 @@ function createKaalaPersistence(params) {
54062
54529
  for (const record of queued2) {
54063
54530
  if (!record.text)
54064
54531
  continue;
54065
- const route = record.sessionId && storage.getSessionRoute ? routeCache.get(record.sessionId) ?? await storage.getSessionRoute(record.sessionId) : void 0;
54066
- if (record.sessionId && storage.getSessionRoute && !routeCache.has(record.sessionId)) {
54067
- routeCache.set(record.sessionId, route);
54068
- }
54532
+ const route = record.sessionId ? await getActiveKaalaSessionRoute({
54533
+ storage,
54534
+ sessionId: record.sessionId,
54535
+ logger,
54536
+ cache: routeCache
54537
+ }) : void 0;
54069
54538
  const { agentId, parentAgentId } = resolveAgentIds({
54070
54539
  agentId: record.agentId ?? route?.agentId,
54071
54540
  parentAgentId: record.parentAgentId,
@@ -54156,10 +54625,12 @@ function createKaalaPersistence(params) {
54156
54625
  if (!record.text)
54157
54626
  continue;
54158
54627
  const toolPolicyOverride = record.metadata?.toolPolicy;
54159
- const route = record.sessionId && storage.getSessionRoute ? runRouteCache.get(record.sessionId) ?? await storage.getSessionRoute(record.sessionId) : void 0;
54160
- if (record.sessionId && storage.getSessionRoute && !runRouteCache.has(record.sessionId)) {
54161
- runRouteCache.set(record.sessionId, route);
54162
- }
54628
+ const route = record.sessionId ? await getActiveKaalaSessionRoute({
54629
+ storage,
54630
+ sessionId: record.sessionId,
54631
+ logger,
54632
+ cache: runRouteCache
54633
+ }) : void 0;
54163
54634
  const { agentId, parentAgentId } = resolveAgentIds({
54164
54635
  agentId: record.agentId ?? route?.agentId,
54165
54636
  parentAgentId: record.parentAgentId,
@@ -54286,6 +54757,7 @@ function createKaalaQueueRunner(params) {
54286
54757
  orderBy: "priority"
54287
54758
  });
54288
54759
  const ordered = queued.slice().sort((a, b) => sortQueue(a, b, Date.now(), queueBoostIntervalMs));
54760
+ const routeCache = /* @__PURE__ */ new Map();
54289
54761
  const countsCache = /* @__PURE__ */ new Map();
54290
54762
  for (const record of ordered) {
54291
54763
  if (inflight.has(record.id))
@@ -54301,7 +54773,12 @@ function createKaalaQueueRunner(params) {
54301
54773
  continue;
54302
54774
  }
54303
54775
  const needsRoute = !record.lane || !record.agentId;
54304
- const route = needsRoute && record.sessionId && storage.getSessionRoute ? await storage.getSessionRoute(record.sessionId) : void 0;
54776
+ const route = needsRoute && record.sessionId ? await getActiveKaalaSessionRoute({
54777
+ storage,
54778
+ sessionId: record.sessionId,
54779
+ logger,
54780
+ cache: routeCache
54781
+ }) : void 0;
54305
54782
  const { agentId, parentAgentId } = resolveAgentIds({
54306
54783
  agentId: record.agentId ?? route?.agentId,
54307
54784
  parentAgentId: record.parentAgentId,
@@ -58714,7 +59191,7 @@ import { spawn as spawn6 } from "node:child_process";
58714
59191
  var _chitraguptaMemory = null;
58715
59192
  async function getChitraguptaMemory() {
58716
59193
  if (!_chitraguptaMemory) {
58717
- _chitraguptaMemory = await import("./chunks/src-54LTTDTH.js");
59194
+ _chitraguptaMemory = await import("./chunks/src-ZAKUL232.js");
58718
59195
  }
58719
59196
  return _chitraguptaMemory;
58720
59197
  }
@@ -62872,6 +63349,7 @@ async function startGateway() {
62872
63349
  logger,
62873
63350
  getProfile,
62874
63351
  providerRegistry: providers,
63352
+ smritiClient,
62875
63353
  startedAt: state.startedAt,
62876
63354
  getSessionResetInfo: async () => {
62877
63355
  return { mode: "off" };
@@ -63075,6 +63553,7 @@ async function startGateway() {
63075
63553
  }
63076
63554
  const shutdown = () => {
63077
63555
  logger.info("gateway_shutdown_initiated");
63556
+ inboxWorker.stop();
63078
63557
  proactiveManager.stop();
63079
63558
  runtimeServices.stop();
63080
63559
  setSessionResetListener(void 0);